1
- import { Logger , field , logger } from "@coder/logger"
1
+ import { field , Logger , logger } from "@coder/logger"
2
2
import * as cp from "child_process"
3
3
import * as path from "path"
4
4
import * as rfs from "rotating-file-stream"
5
5
import { Emitter } from "../common/emitter"
6
+ import { DefaultedArgs } from "./cli"
6
7
import { paths } from "./util"
7
8
8
9
const timeoutInterval = 10000 // 10s, matches VS Code's timeouts.
@@ -58,7 +59,12 @@ export function onMessage<M, T extends M>(
58
59
} )
59
60
}
60
61
61
- interface HandshakeMessage {
62
+ interface ParentHandshakeMessage {
63
+ type : "handshake"
64
+ args : DefaultedArgs
65
+ }
66
+
67
+ interface ChildHandshakeMessage {
62
68
type : "handshake"
63
69
}
64
70
@@ -67,7 +73,8 @@ interface RelaunchMessage {
67
73
version : string
68
74
}
69
75
70
- type Message = RelaunchMessage | HandshakeMessage
76
+ type ChildMessage = RelaunchMessage | ChildHandshakeMessage
77
+ type ParentMessage = ParentHandshakeMessage
71
78
72
79
class ProcessError extends Error {
73
80
public constructor ( message : string , public readonly code : number | undefined ) {
@@ -164,15 +171,16 @@ class ChildProcess extends Process {
164
171
/**
165
172
* Initiate the handshake and wait for a response from the parent.
166
173
*/
167
- public async handshake ( ) : Promise < void > {
174
+ public async handshake ( ) : Promise < DefaultedArgs > {
168
175
this . send ( { type : "handshake" } )
169
- await onMessage < Message , HandshakeMessage > (
176
+ const message = await onMessage < ParentMessage , ParentHandshakeMessage > (
170
177
process ,
171
- ( message ) : message is HandshakeMessage => {
178
+ ( message ) : message is ParentHandshakeMessage => {
172
179
return message . type === "handshake"
173
180
} ,
174
181
this . logger ,
175
182
)
183
+ return message . args
176
184
}
177
185
178
186
/**
@@ -185,7 +193,7 @@ class ChildProcess extends Process {
185
193
/**
186
194
* Send a message to the parent.
187
195
*/
188
- private send ( message : Message ) : void {
196
+ private send ( message : ChildMessage ) : void {
189
197
if ( ! process . send ) {
190
198
throw new Error ( "not spawned with IPC" )
191
199
}
@@ -211,12 +219,19 @@ export class ParentProcess extends Process {
211
219
private readonly logStdoutStream : rfs . RotatingFileStream
212
220
private readonly logStderrStream : rfs . RotatingFileStream
213
221
214
- protected readonly _onChildMessage = new Emitter < Message > ( )
222
+ protected readonly _onChildMessage = new Emitter < ChildMessage > ( )
215
223
protected readonly onChildMessage = this . _onChildMessage . event
216
224
225
+ private args ?: DefaultedArgs
226
+
217
227
public constructor ( private currentVersion : string , private readonly options ?: WrapperOptions ) {
218
228
super ( )
219
229
230
+ process . on ( "SIGUSR1" , async ( ) => {
231
+ this . logger . info ( "Received SIGUSR1; hotswapping" )
232
+ this . relaunch ( )
233
+ } )
234
+
220
235
const opts = {
221
236
size : "10M" ,
222
237
maxFiles : 10 ,
@@ -253,21 +268,17 @@ export class ParentProcess extends Process {
253
268
private async relaunch ( ) : Promise < void > {
254
269
this . disposeChild ( )
255
270
try {
256
- await this . start ( )
271
+ this . started = this . _start ( )
272
+ await this . started
257
273
} catch ( error ) {
258
274
this . logger . error ( error . message )
259
275
this . exit ( typeof error . code === "number" ? error . code : 1 )
260
276
}
261
277
}
262
278
263
- public start ( ) : Promise < void > {
264
- // If we have a process then we've already bound this.
265
- if ( ! this . child ) {
266
- process . on ( "SIGUSR1" , async ( ) => {
267
- this . logger . info ( "Received SIGUSR1; hotswapping" )
268
- this . relaunch ( )
269
- } )
270
- }
279
+ public start ( args : DefaultedArgs ) : Promise < void > {
280
+ // Store for relaunches.
281
+ this . args = args
271
282
if ( ! this . started ) {
272
283
this . started = this . _start ( )
273
284
}
@@ -320,14 +331,24 @@ export class ParentProcess extends Process {
320
331
* Wait for a handshake from the child then reply.
321
332
*/
322
333
private async handshake ( child : cp . ChildProcess ) : Promise < void > {
323
- await onMessage < Message , HandshakeMessage > (
334
+ if ( ! this . args ) {
335
+ throw new Error ( "started without args" )
336
+ }
337
+ await onMessage < ChildMessage , ChildHandshakeMessage > (
324
338
child ,
325
- ( message ) : message is HandshakeMessage => {
339
+ ( message ) : message is ChildHandshakeMessage => {
326
340
return message . type === "handshake"
327
341
} ,
328
342
this . logger ,
329
343
)
330
- child . send ( { type : "handshake" } )
344
+ this . send ( child , { type : "handshake" , args : this . args } )
345
+ }
346
+
347
+ /**
348
+ * Send a message to the child.
349
+ */
350
+ private send ( child : cp . ChildProcess , message : ParentMessage ) : void {
351
+ child . send ( message )
331
352
}
332
353
}
333
354
0 commit comments