@@ -5,6 +5,59 @@ import * as rfs from "rotating-file-stream"
55import { Emitter } from "../common/emitter"
66import { paths } from "./util"
77
8+ const timeoutInterval = 10000 // 10s, matches VS Code's timeouts.
9+
10+ /**
11+ * Listen to a single message from a process. Reject if the process errors,
12+ * exits, or times out.
13+ *
14+ * `fn` is a function that determines whether the message is the one we're
15+ * waiting for.
16+ */
17+ export function onMessage < M , T extends M > (
18+ proc : cp . ChildProcess | NodeJS . Process ,
19+ fn : ( message : M ) => message is T ,
20+ customLogger ?: Logger ,
21+ ) : Promise < T > {
22+ return new Promise ( ( resolve , reject ) => {
23+ const cleanup = ( ) => {
24+ proc . off ( "error" , onError )
25+ proc . off ( "exit" , onExit )
26+ proc . off ( "message" , onMessage )
27+ clearTimeout ( timeout )
28+ }
29+
30+ const timeout = setTimeout ( ( ) => {
31+ cleanup ( )
32+ reject ( new Error ( "timed out" ) )
33+ } , timeoutInterval )
34+
35+ const onError = ( error : Error ) => {
36+ cleanup ( )
37+ reject ( error )
38+ }
39+
40+ const onExit = ( code : number ) => {
41+ cleanup ( )
42+ reject ( new Error ( `exited unexpectedly with code ${ code } ` ) )
43+ }
44+
45+ const onMessage = ( message : M ) => {
46+ ; ( customLogger || logger ) . trace ( "got message" , field ( "message" , message ) )
47+ if ( fn ( message ) ) {
48+ cleanup ( )
49+ resolve ( message )
50+ }
51+ }
52+
53+ proc . on ( "message" , onMessage )
54+ // NodeJS.Process doesn't have `error` but binding anyway shouldn't break
55+ // anything. It does have `exit` but the types aren't working.
56+ ; ( proc as cp . ChildProcess ) . on ( "error" , onError )
57+ ; ( proc as cp . ChildProcess ) . on ( "exit" , onExit )
58+ } )
59+ }
60+
861interface HandshakeMessage {
962 type : "handshake"
1063}
@@ -111,19 +164,15 @@ class ChildProcess extends Process {
111164 /**
112165 * Initiate the handshake and wait for a response from the parent.
113166 */
114- public handshake ( ) : Promise < void > {
115- return new Promise ( ( resolve ) => {
116- const onMessage = ( message : Message ) : void => {
117- logger . debug ( `received message from ${ this . parentPid } ` , field ( "message" , message ) )
118- if ( message . type === "handshake" ) {
119- process . removeListener ( "message" , onMessage )
120- resolve ( )
121- }
122- }
123- // Initiate the handshake and wait for the reply.
124- process . on ( "message" , onMessage )
125- this . send ( { type : "handshake" } )
126- } )
167+ public async handshake ( ) : Promise < void > {
168+ this . send ( { type : "handshake" } )
169+ await onMessage < Message , HandshakeMessage > (
170+ process ,
171+ ( message ) : message is HandshakeMessage => {
172+ return message . type === "handshake"
173+ } ,
174+ this . logger ,
175+ )
127176 }
128177
129178 /**
@@ -270,23 +319,15 @@ export class ParentProcess extends Process {
270319 /**
271320 * Wait for a handshake from the child then reply.
272321 */
273- private handshake ( child : cp . ChildProcess ) : Promise < void > {
274- return new Promise ( ( resolve , reject ) => {
275- const onMessage = ( message : Message ) : void => {
276- logger . debug ( `received message from ${ child . pid } ` , field ( "message" , message ) )
277- if ( message . type === "handshake" ) {
278- child . removeListener ( "message" , onMessage )
279- child . on ( "message" , ( msg ) => this . _onChildMessage . emit ( msg ) )
280- child . send ( { type : "handshake" } )
281- resolve ( )
282- }
283- }
284- child . on ( "message" , onMessage )
285- child . once ( "error" , reject )
286- child . once ( "exit" , ( code ) => {
287- reject ( new ProcessError ( `Unexpected exit with code ${ code } ` , code !== null ? code : undefined ) )
288- } )
289- } )
322+ private async handshake ( child : cp . ChildProcess ) : Promise < void > {
323+ await onMessage < Message , HandshakeMessage > (
324+ child ,
325+ ( message ) : message is HandshakeMessage => {
326+ return message . type === "handshake"
327+ } ,
328+ this . logger ,
329+ )
330+ child . send ( { type : "handshake" } )
290331 }
291332}
292333
0 commit comments