1- import { Logger , field , logger } from "@coder/logger"
1+ import { field , Logger , logger } from "@coder/logger"
22import * as cp from "child_process"
33import * as path from "path"
44import * as rfs from "rotating-file-stream"
55import { Emitter } from "../common/emitter"
6+ import { DefaultedArgs } from "./cli"
67import { paths } from "./util"
78
89const timeoutInterval = 10000 // 10s, matches VS Code's timeouts.
@@ -58,7 +59,12 @@ export function onMessage<M, T extends M>(
5859 } )
5960}
6061
61- interface HandshakeMessage {
62+ interface ParentHandshakeMessage {
63+ type : "handshake"
64+ args : DefaultedArgs
65+ }
66+
67+ interface ChildHandshakeMessage {
6268 type : "handshake"
6369}
6470
@@ -67,7 +73,8 @@ interface RelaunchMessage {
6773 version : string
6874}
6975
70- type Message = RelaunchMessage | HandshakeMessage
76+ type ChildMessage = RelaunchMessage | ChildHandshakeMessage
77+ type ParentMessage = ParentHandshakeMessage
7178
7279class ProcessError extends Error {
7380 public constructor ( message : string , public readonly code : number | undefined ) {
@@ -164,15 +171,16 @@ class ChildProcess extends Process {
164171 /**
165172 * Initiate the handshake and wait for a response from the parent.
166173 */
167- public async handshake ( ) : Promise < void > {
174+ public async handshake ( ) : Promise < DefaultedArgs > {
168175 this . send ( { type : "handshake" } )
169- await onMessage < Message , HandshakeMessage > (
176+ const message = await onMessage < ParentMessage , ParentHandshakeMessage > (
170177 process ,
171- ( message ) : message is HandshakeMessage => {
178+ ( message ) : message is ParentHandshakeMessage => {
172179 return message . type === "handshake"
173180 } ,
174181 this . logger ,
175182 )
183+ return message . args
176184 }
177185
178186 /**
@@ -185,7 +193,7 @@ class ChildProcess extends Process {
185193 /**
186194 * Send a message to the parent.
187195 */
188- private send ( message : Message ) : void {
196+ private send ( message : ChildMessage ) : void {
189197 if ( ! process . send ) {
190198 throw new Error ( "not spawned with IPC" )
191199 }
@@ -211,12 +219,19 @@ export class ParentProcess extends Process {
211219 private readonly logStdoutStream : rfs . RotatingFileStream
212220 private readonly logStderrStream : rfs . RotatingFileStream
213221
214- protected readonly _onChildMessage = new Emitter < Message > ( )
222+ protected readonly _onChildMessage = new Emitter < ChildMessage > ( )
215223 protected readonly onChildMessage = this . _onChildMessage . event
216224
225+ private args ?: DefaultedArgs
226+
217227 public constructor ( private currentVersion : string , private readonly options ?: WrapperOptions ) {
218228 super ( )
219229
230+ process . on ( "SIGUSR1" , async ( ) => {
231+ this . logger . info ( "Received SIGUSR1; hotswapping" )
232+ this . relaunch ( )
233+ } )
234+
220235 const opts = {
221236 size : "10M" ,
222237 maxFiles : 10 ,
@@ -253,21 +268,17 @@ export class ParentProcess extends Process {
253268 private async relaunch ( ) : Promise < void > {
254269 this . disposeChild ( )
255270 try {
256- await this . start ( )
271+ this . started = this . _start ( )
272+ await this . started
257273 } catch ( error ) {
258274 this . logger . error ( error . message )
259275 this . exit ( typeof error . code === "number" ? error . code : 1 )
260276 }
261277 }
262278
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
271282 if ( ! this . started ) {
272283 this . started = this . _start ( )
273284 }
@@ -320,14 +331,24 @@ export class ParentProcess extends Process {
320331 * Wait for a handshake from the child then reply.
321332 */
322333 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 > (
324338 child ,
325- ( message ) : message is HandshakeMessage => {
339+ ( message ) : message is ChildHandshakeMessage => {
326340 return message . type === "handshake"
327341 } ,
328342 this . logger ,
329343 )
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 )
331352 }
332353}
333354
0 commit comments