Skip to content

Commit 4380356

Browse files
authored
Merge pull request #2334 from cdr/wrappers
Separate process wrappers and pass arguments
2 parents 72caafe + 95ef6db commit 4380356

File tree

3 files changed

+240
-189
lines changed

3 files changed

+240
-189
lines changed

src/node/entry.ts

+15-13
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { coderCloudBind } from "./coder-cloud"
1919
import { commit, version } from "./constants"
2020
import { register } from "./routes"
2121
import { humanPath, isFile, open } from "./util"
22-
import { ipcMain, WrapperProcess } from "./wrapper"
22+
import { isChild, wrapper } from "./wrapper"
2323

2424
export const runVsCodeCli = (args: DefaultedArgs): void => {
2525
logger.debug("forking vs code cli...")
@@ -137,7 +137,7 @@ const main = async (args: DefaultedArgs): Promise<void> => {
137137
logger.info(" - Connected to cloud agent")
138138
} catch (err) {
139139
logger.error(err.message)
140-
ipcMain.exit(1)
140+
wrapper.exit(1)
141141
}
142142
}
143143

@@ -154,19 +154,22 @@ const main = async (args: DefaultedArgs): Promise<void> => {
154154
}
155155

156156
async function entry(): Promise<void> {
157-
const cliArgs = parse(process.argv.slice(2))
158-
const configArgs = await readConfigFile(cliArgs.config)
159-
const args = await setDefaults(cliArgs, configArgs)
160-
161157
// There's no need to check flags like --help or to spawn in an existing
162158
// instance for the child process because these would have already happened in
163-
// the parent and the child wouldn't have been spawned.
164-
if (ipcMain.isChild) {
165-
await ipcMain.handshake()
166-
ipcMain.preventExit()
159+
// the parent and the child wouldn't have been spawned. We also get the
160+
// arguments from the parent so we don't have to parse twice and to account
161+
// for environment manipulation (like how PASSWORD gets removed to avoid
162+
// leaking to child processes).
163+
if (isChild(wrapper)) {
164+
const args = await wrapper.handshake()
165+
wrapper.preventExit()
167166
return main(args)
168167
}
169168

169+
const cliArgs = parse(process.argv.slice(2))
170+
const configArgs = await readConfigFile(cliArgs.config)
171+
const args = await setDefaults(cliArgs, configArgs)
172+
170173
if (args.help) {
171174
console.log("code-server", version, commit)
172175
console.log("")
@@ -201,11 +204,10 @@ async function entry(): Promise<void> {
201204
return openInExistingInstance(args, socketPath)
202205
}
203206

204-
const wrapper = new WrapperProcess(require("../../package.json").version)
205-
return wrapper.start()
207+
return wrapper.start(args)
206208
}
207209

208210
entry().catch((error) => {
209211
logger.error(error.message)
210-
ipcMain.exit(error)
212+
wrapper.exit(error)
211213
})

src/node/vscode.ts

+11-57
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { field, logger } from "@coder/logger"
1+
import { logger } from "@coder/logger"
22
import * as cp from "child_process"
33
import * as net from "net"
44
import * as path from "path"
@@ -8,19 +8,18 @@ import { rootPath } from "./constants"
88
import { settings } from "./settings"
99
import { SocketProxyProvider } from "./socket"
1010
import { isFile } from "./util"
11-
import { ipcMain } from "./wrapper"
11+
import { onMessage, wrapper } from "./wrapper"
1212

1313
export class VscodeProvider {
1414
public readonly serverRootPath: string
1515
public readonly vsRootPath: string
1616
private _vscode?: Promise<cp.ChildProcess>
17-
private timeoutInterval = 10000 // 10s, matches VS Code's timeouts.
1817
private readonly socketProvider = new SocketProxyProvider()
1918

2019
public constructor() {
2120
this.vsRootPath = path.resolve(rootPath, "lib/vscode")
2221
this.serverRootPath = path.join(this.vsRootPath, "out/vs/server")
23-
ipcMain.onDispose(() => this.dispose())
22+
wrapper.onDispose(() => this.dispose())
2423
}
2524

2625
public async dispose(): Promise<void> {
@@ -69,10 +68,13 @@ export class VscodeProvider {
6968
vscode,
7069
)
7170

72-
const message = await this.onMessage(vscode, (message): message is ipc.OptionsMessage => {
73-
// There can be parallel initializations so wait for the right ID.
74-
return message.type === "options" && message.id === id
75-
})
71+
const message = await onMessage<ipc.VscodeMessage, ipc.OptionsMessage>(
72+
vscode,
73+
(message): message is ipc.OptionsMessage => {
74+
// There can be parallel initializations so wait for the right ID.
75+
return message.type === "options" && message.id === id
76+
},
77+
)
7678

7779
return message.options
7880
}
@@ -104,61 +106,13 @@ export class VscodeProvider {
104106
dispose()
105107
})
106108

107-
this._vscode = this.onMessage(vscode, (message): message is ipc.ReadyMessage => {
109+
this._vscode = onMessage<ipc.VscodeMessage, ipc.ReadyMessage>(vscode, (message): message is ipc.ReadyMessage => {
108110
return message.type === "ready"
109111
}).then(() => vscode)
110112

111113
return this._vscode
112114
}
113115

114-
/**
115-
* Listen to a single message from a process. Reject if the process errors,
116-
* exits, or times out.
117-
*
118-
* `fn` is a function that determines whether the message is the one we're
119-
* waiting for.
120-
*/
121-
private onMessage<T extends ipc.VscodeMessage>(
122-
proc: cp.ChildProcess,
123-
fn: (message: ipc.VscodeMessage) => message is T,
124-
): Promise<T> {
125-
return new Promise((resolve, reject) => {
126-
const cleanup = () => {
127-
proc.off("error", onError)
128-
proc.off("exit", onExit)
129-
proc.off("message", onMessage)
130-
clearTimeout(timeout)
131-
}
132-
133-
const timeout = setTimeout(() => {
134-
cleanup()
135-
reject(new Error("timed out"))
136-
}, this.timeoutInterval)
137-
138-
const onError = (error: Error) => {
139-
cleanup()
140-
reject(error)
141-
}
142-
143-
const onExit = (code: number | null) => {
144-
cleanup()
145-
reject(new Error(`VS Code exited unexpectedly with code ${code}`))
146-
}
147-
148-
const onMessage = (message: ipc.VscodeMessage) => {
149-
logger.trace("got message from vscode", field("message", message))
150-
if (fn(message)) {
151-
cleanup()
152-
resolve(message)
153-
}
154-
}
155-
156-
proc.on("message", onMessage)
157-
proc.on("error", onError)
158-
proc.on("exit", onExit)
159-
})
160-
}
161-
162116
/**
163117
* VS Code expects a raw socket. It will handle all the web socket frames.
164118
*/

0 commit comments

Comments
 (0)