Skip to content

Convert code-server http code to use Express #2238

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 84 commits into from
Nov 12, 2020
Merged
Changes from 1 commit
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
dcb303a
Move argument defaults into setDefaults
code-asher Oct 15, 2020
2928d36
Move heart and AuthType out of http
code-asher Oct 15, 2020
6000e38
Add Express as a dep and regenerate lockfile
code-asher Oct 15, 2020
9f25cc6
Move providers from `app` to `routes`
code-asher Oct 15, 2020
8e93e28
Strip config file password from debug log
code-asher Oct 16, 2020
71dc5c7
Switch to Express
code-asher Oct 16, 2020
4b6cbac
Add file for global constants
code-asher Oct 16, 2020
112eda4
Convert routes to Express
code-asher Oct 20, 2020
257d9a4
Make authentication work with sub-domain proxy
code-asher Oct 26, 2020
6422a8d
Fix webview resource path
code-asher Oct 27, 2020
6ab6cb4
Fix error handler types
code-asher Oct 27, 2020
305348f
Improve proxy fallthrough logic
code-asher Oct 27, 2020
cde94d5
Remove redundant serverAddress check
code-asher Oct 27, 2020
dc177ab
Unambiguify address replacement
code-asher Oct 27, 2020
504d896
Fix open line being printed when open fails
code-asher Oct 27, 2020
f2f1fee
Short-circuit heartbeat when alive
code-asher Oct 27, 2020
1067507
Proxy to 0.0.0.0 instead of localhost
code-asher Oct 28, 2020
8a9e61d
Use Addr interface everywhere and loop over arg sources
code-asher Nov 3, 2020
3a074fd
Skip unnecessary auth type check when using --link
code-asher Nov 3, 2020
f4e5855
Simplify update request
code-asher Nov 3, 2020
c72c53f
Fix not being able to dispose vscode after failed disposal
code-asher Nov 3, 2020
c10450c
Move isFile into util
code-asher Nov 3, 2020
e243f6e
Return early when forking to reduce indentation
code-asher Nov 3, 2020
03e0013
Unbind error/exit events once handshakes resolve
code-asher Nov 3, 2020
8066da1
Remove unused Locals interface
code-asher Nov 3, 2020
75b93f9
Fix bind address priority
code-asher Nov 4, 2020
e2c35fa
Remove invalid comment on maybeProxy
code-asher Nov 3, 2020
a653b93
Include protocol on printed address
code-asher Nov 3, 2020
c5ce365
Use query variable to force update check
code-asher Nov 3, 2020
e5c8e0a
Remove useless ||
code-asher Nov 3, 2020
210fc04
Document VS Code endpoints
code-asher Nov 3, 2020
476379a
Fix cookie domain
code-asher Nov 3, 2020
34225e2
Use ensureAuthenticated as middleware
code-asher Nov 3, 2020
396af23
Kill VS Code when process exits
code-asher Nov 3, 2020
8252c37
Provide a way to tell when event handlers are finished
code-asher Nov 4, 2020
9e09c1f
Upgrade to Express 5
code-asher Nov 5, 2020
7b2752a
Move websocket routes into a separate app
code-asher Nov 5, 2020
3f1750c
Fix destroying response in update again
code-asher Nov 5, 2020
cb991a9
Handle errors for JSON requests
code-asher Nov 5, 2020
f6c4434
Tweak proxy fallthrough behavior
code-asher Nov 5, 2020
f707624
Move domain proxy to routes
code-asher Nov 5, 2020
9594970
Document HttpError
code-asher Nov 5, 2020
aa2cfa2
typings/plugin.d.ts: Create
nhooyr Oct 30, 2020
481df70
ci/dev/test.sh: Pass through args
nhooyr Oct 30, 2020
e08a55d
src/node/plugin.ts: Implement new plugin API
nhooyr Oct 30, 2020
bea185b
plugin: Add basic loading test
nhooyr Oct 30, 2020
82e8a00
Fix CI
nhooyr Oct 30, 2020
30d2962
src/node/plugin.ts: Warn on duplicate plugin and only load first
nhooyr Oct 30, 2020
ef97100
plugin.test.ts: Make it clear iconPath is a path
nhooyr Oct 30, 2020
f4d7f00
plugin.ts: Fixes for @wbobeirne
nhooyr Nov 3, 2020
75e52a3
plugin.ts: Fixes for @code-asher
nhooyr Nov 3, 2020
8d3a772
plugin.d.ts: Document plugin priority correctly
nhooyr Nov 3, 2020
6638daf
plugin.d.ts: Add explicit path field and adjust types to reflect
nhooyr Nov 3, 2020
fed545e
plugin.d.ts -> pluginapi.d.ts
nhooyr Nov 3, 2020
afff86a
plugin.ts: Adjust to implement pluginapi.d.ts correctly
nhooyr Nov 4, 2020
e03bbe3
routes/apps.ts: Implement /api/applications endpoint
nhooyr Nov 4, 2020
139a28e
plugin.ts: Describe private counterpart functions
nhooyr Nov 4, 2020
6870948
plugin.ts: Make application endpoint paths absolute
nhooyr Nov 4, 2020
2a13d00
plugin.ts: Add homepageURL to plugin and application
nhooyr Nov 4, 2020
af73b96
routes/apps.ts: Add example output
nhooyr Nov 4, 2020
706bc23
plugin: Fixes for CI
nhooyr Nov 4, 2020
8a8159c
plugin: More review fixes
nhooyr Nov 5, 2020
14f408a
plugin: Plugin modules now export a single top level identifier
nhooyr Nov 5, 2020
9453f89
plugin.ts: Fix usage of routerPath in mount
nhooyr Nov 5, 2020
197a09f
plugin: Test endpoints via supertest
nhooyr Nov 6, 2020
9d39c53
plugin: Give test-plugin some html to test overlay
nhooyr Nov 6, 2020
277211c
plugin: Make init and applications callbacks optional
nhooyr Nov 6, 2020
fe399ff
Fix formatting
nhooyr Nov 6, 2020
d969a5b
Merge pull request #2252 from cdr/plugin-5d60
nhooyr Nov 6, 2020
0a01338
Deduplicate child process message dance
code-asher Nov 10, 2020
de49495
Document getFirstPath better
code-asher Nov 10, 2020
f706039
Re-add TLS socket proxy
code-asher Nov 10, 2020
b8340a2
Close sockets correctly
code-asher Nov 10, 2020
71850e3
Avoid setting ?to=/
code-asher Nov 11, 2020
4574593
Refactor vscode init to use async
code-asher Nov 11, 2020
79478eb
Clarify some points around the cookie domain
code-asher Nov 11, 2020
72931ed
Fix cleanup after getting message from vscode
code-asher Nov 12, 2020
31b6706
Remove <type> from onMessage
code-asher Nov 12, 2020
5499a3d
Use baseUrl when redirecting from domain proxy
code-asher Nov 12, 2020
e1702a1
Merge branch master into code-asher/ch1385
code-asher Nov 12, 2020
b73ea2f
Unbind message handler itself after getting message
code-asher Nov 12, 2020
6f14b8b
Add separate handler for error
code-asher Nov 12, 2020
96995b7
Update cert flag test
code-asher Nov 12, 2020
9889f30
Remove unused ts-expect-error from VS Code
code-asher Nov 12, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Deduplicate child process message dance
  • Loading branch information
code-asher committed Nov 10, 2020
commit 0a01338edd3a618a943567b8b95c7fce37890f9c
112 changes: 72 additions & 40 deletions src/node/vscode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export class VscodeProvider {
public readonly serverRootPath: string
public readonly vsRootPath: string
private _vscode?: Promise<cp.ChildProcess>
private timeoutInterval = 10000 // 10s, matches VS Code's timeouts.

public constructor() {
this.vsRootPath = path.resolve(rootPath, "lib/vscode")
Expand Down Expand Up @@ -52,33 +53,25 @@ export class VscodeProvider {
const vscode = await this.fork()

logger.debug("setting up vs code...")
return new Promise<ipc.WorkbenchOptions>((resolve, reject) => {
const onExit = (code: number | null) => reject(new Error(`VS Code exited unexpectedly with code ${code}`))

vscode.once("message", (message: ipc.VscodeMessage) => {
logger.debug("got message from vs code", field("message", message))
vscode.off("error", reject)
vscode.off("exit", onExit)
return message.type === "options" && message.id === id
? resolve(message.options)
: reject(new Error("Unexpected response during initialization"))
})

vscode.once("error", reject)
vscode.once("exit", onExit)

this.send(
{
type: "init",
id,
options: {
...options,
startPath,
},
this.send(
{
type: "init",
id,
options: {
...options,
startPath,
},
vscode,
)
},
vscode,
)

const message = await this.onMessage<ipc.OptionsMessage>(vscode, (message): message is ipc.OptionsMessage => {
// There can be parallel initializations so wait for the right ID.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would a parallel init occur?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Loading the page in two separate tabs is the main way I think. If we had some sort of collaborative mode it would probably be a bigger problem then.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess in theory it could also happen if you refresh a page before it finishes loading to send off two almost-parallel requests although I don't think I've hit it that way before.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Loading the page in two separate tabs is the main way I think. If we had some sort of collaborative mode it would probably be a bigger problem then.

Shouldn't we prevent sending parallel init's at the same time?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or actually, doesn't each websocket get it's own vscode process? Or is that only its own extension host?

Copy link
Member Author

@code-asher code-asher Nov 12, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a single VS Code process for all websockets and an extension host for each websocket. Each page also gets its own "management" websocket where we initialize all the services VS Code uses (like the file service, environment service, language initialization, and so on).

Copy link
Member Author

@code-asher code-asher Nov 12, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The services are shared too actually, come to think. Language stuff isn't though, and there are some other differences in the initialization like which folder to open up (depending on the query parameter for example).

return message.type === "options" && message.id === id
})

return message.options
}

private fork(): Promise<cp.ChildProcess> {
Expand All @@ -88,32 +81,71 @@ export class VscodeProvider {

logger.debug("forking vs code...")
const vscode = cp.fork(path.join(this.serverRootPath, "fork"))
vscode.on("error", (error) => {
logger.error(error.message)

const dispose = () => {
vscode.removeAllListeners()
vscode.kill()
this._vscode = undefined
}

vscode.on("error", (error: Error) => {
logger.error(error.message)
if (error.stack) {
logger.debug(error.stack)
}
dispose()
})

vscode.on("exit", (code) => {
logger.error(`VS Code exited unexpectedly with code ${code}`)
this._vscode = undefined
dispose()
})

this._vscode = new Promise((resolve, reject) => {
const onExit = (code: number | null) => reject(new Error(`VS Code exited unexpectedly with code ${code}`))
this._vscode = this.onMessage<ipc.ReadyMessage>(vscode, (message): message is ipc.ReadyMessage => {
return message.type === "ready"
}).then(() => vscode)

vscode.once("message", (message: ipc.VscodeMessage) => {
logger.debug("got message from vs code", field("message", message))
vscode.off("error", reject)
vscode.off("exit", onExit)
return message.type === "ready"
? resolve(vscode)
: reject(new Error("Unexpected response waiting for ready response"))
return this._vscode
}

/**
* Listen to a single message from a process. Reject if the process errors,
* exits, or times out.
*
* `fn` is a function that determines whether the message is the one we're
* waiting for.
*/
private onMessage<T extends ipc.VscodeMessage>(
proc: cp.ChildProcess,
fn: (message: ipc.VscodeMessage) => message is T,
): Promise<T> {
return new Promise((resolve, _reject) => {
const reject = (error: Error) => {
clearTimeout(timeout)
_reject(error)
}

const onExit = (code: number | null) => {
reject(new Error(`VS Code exited unexpectedly with code ${code}`))
}

const timeout = setTimeout(() => {
reject(new Error("timed out"))
}, this.timeoutInterval)

proc.on("message", (message: ipc.VscodeMessage) => {
logger.debug("got message from vscode", field("message", message))
proc.off("error", reject)
proc.off("exit", onExit)
if (fn(message)) {
clearTimeout(timeout)
resolve(message)
}
})

vscode.once("error", reject)
vscode.once("exit", onExit)
proc.once("error", reject)
proc.once("exit", onExit)
})

return this._vscode
}

/**
Expand Down