Skip to content

Commit a3904bf

Browse files
committed
Add shared process active message (#16)
* Add shared process active message * Add client function for calling bootstrap fork
1 parent b865d62 commit a3904bf

15 files changed

+260
-241
lines changed

packages/protocol/src/browser/client.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,15 @@ export class Client {
155155
return this.doSpawn(modulePath, args, options, true);
156156
}
157157

158+
/**
159+
* VS Code specific.
160+
* Forks a module from bootstrap-fork
161+
* @param modulePath Path of the module
162+
*/
163+
public bootstrapFork(modulePath: string): ChildProcess {
164+
return this.doSpawn(modulePath, [], undefined, true, true);
165+
}
166+
158167
public createConnection(path: string, callback?: () => void): Socket;
159168
public createConnection(port: number, callback?: () => void): Socket;
160169
public createConnection(target: string | number, callback?: () => void): Socket {
@@ -176,13 +185,14 @@ export class Client {
176185
return socket;
177186
}
178187

179-
private doSpawn(command: string, args: string[] = [], options?: SpawnOptions, isFork: boolean = false): ChildProcess {
188+
private doSpawn(command: string, args: string[] = [], options?: SpawnOptions, isFork: boolean = false, isBootstrapFork: boolean = true): ChildProcess {
180189
const id = this.sessionId++;
181190
const newSess = new NewSessionMessage();
182191
newSess.setId(id);
183192
newSess.setCommand(command);
184193
newSess.setArgsList(args);
185194
newSess.setIsFork(isFork);
195+
newSess.setIsBootstrapFork(isBootstrapFork);
186196
if (options) {
187197
if (options.cwd) {
188198
newSess.setCwd(options.cwd);

packages/protocol/src/node/command.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import * as stream from "stream";
55
import { TextEncoder } from "text-encoding";
66
import { NewSessionMessage, ServerMessage, SessionDoneMessage, SessionOutputMessage, ShutdownSessionMessage, IdentifySessionMessage, ClientMessage, NewConnectionMessage, ConnectionEstablishedMessage, NewConnectionFailureMessage, ConnectionCloseMessage, ConnectionOutputMessage } from "../proto";
77
import { SendableConnection } from "../common/connection";
8+
import { ServerOptions } from "./server";
89

910
export interface Process {
1011
stdin?: stream.Writable;
@@ -22,7 +23,7 @@ export interface Process {
2223
title?: number;
2324
}
2425

25-
export const handleNewSession = (connection: SendableConnection, newSession: NewSessionMessage, onExit: () => void): Process => {
26+
export const handleNewSession = (connection: SendableConnection, newSession: NewSessionMessage, serverOptions: ServerOptions | undefined, onExit: () => void): Process => {
2627
let process: Process;
2728

2829
const env = {} as any;
@@ -44,7 +45,15 @@ export const handleNewSession = (connection: SendableConnection, newSession: New
4445
};
4546
let proc: cp.ChildProcess;
4647
if (newSession.getIsFork()) {
47-
proc = cp.fork(newSession.getCommand(), newSession.getArgsList());
48+
if (!serverOptions) {
49+
throw new Error("No forkProvider set for bootstrap-fork request");
50+
}
51+
52+
if (!serverOptions.forkProvider) {
53+
throw new Error("No forkProvider set for server options");
54+
}
55+
56+
proc = serverOptions.forkProvider(newSession);
4857
} else {
4958
proc = cp.spawn(newSession.getCommand(), newSession.getArgsList(), options);
5059
}
@@ -107,7 +116,7 @@ export const handleNewSession = (connection: SendableConnection, newSession: New
107116

108117
export const handleNewConnection = (connection: SendableConnection, newConnection: NewConnectionMessage, onExit: () => void): net.Socket => {
109118
const id = newConnection.getId();
110-
let socket: net.Socket;
119+
let socket: net.Socket;
111120
let didConnect = false;
112121
const connectCallback = () => {
113122
didConnect = true;
@@ -134,7 +143,7 @@ export const handleNewConnection = (connection: SendableConnection, newConnectio
134143
const servMsg = new ServerMessage();
135144
servMsg.setConnectionFailure(errMsg);
136145
connection.send(servMsg.serializeBinary());
137-
146+
138147
onExit();
139148
}
140149
});

packages/protocol/src/node/server.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import * as os from "os";
2+
import * as cp from "child_process";
23
import * as path from "path";
34
import { mkdir } from "fs";
45
import { promisify } from "util";
56
import { TextDecoder } from "text-encoding";
67
import { logger, field } from "@coder/logger";
7-
import { ClientMessage, WorkingInitMessage, ServerMessage } from "../proto";
8+
import { ClientMessage, WorkingInitMessage, ServerMessage, NewSessionMessage } from "../proto";
89
import { evaluate } from "./evaluate";
910
import { ReadWriteConnection } from "../common/connection";
1011
import { Process, handleNewSession, handleNewConnection } from "./command";
@@ -13,6 +14,8 @@ import * as net from "net";
1314
export interface ServerOptions {
1415
readonly workingDirectory: string;
1516
readonly dataDirectory: string;
17+
18+
forkProvider?(message: NewSessionMessage): cp.ChildProcess;
1619
}
1720

1821
export class Server {
@@ -22,7 +25,7 @@ export class Server {
2225

2326
public constructor(
2427
private readonly connection: ReadWriteConnection,
25-
options?: ServerOptions,
28+
private readonly options?: ServerOptions,
2629
) {
2730
connection.onMessage((data) => {
2831
try {
@@ -89,7 +92,7 @@ export class Server {
8992
if (message.hasNewEval()) {
9093
evaluate(this.connection, message.getNewEval()!);
9194
} else if (message.hasNewSession()) {
92-
const session = handleNewSession(this.connection, message.getNewSession()!, () => {
95+
const session = handleNewSession(this.connection, message.getNewSession()!, this.options, () => {
9396
this.sessions.delete(message.getNewSession()!.getId());
9497
});
9598
this.sessions.set(message.getNewSession()!.getId(), session);

packages/protocol/src/proto/client.proto

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ message ClientMessage {
1717

1818
// node.proto
1919
NewEvalMessage new_eval = 9;
20-
21-
SharedProcessInitMessage shared_process_init = 10;
2220
}
2321
}
2422

@@ -39,6 +37,9 @@ message ServerMessage {
3937
EvalDoneMessage eval_done = 10;
4038

4139
WorkingInitMessage init = 11;
40+
41+
// vscode.proto
42+
SharedProcessActiveMessage shared_process_active = 12;
4243
}
4344
}
4445

packages/protocol/src/proto/client_pb.d.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,6 @@ export class ClientMessage extends jspb.Message {
5252
getNewEval(): node_pb.NewEvalMessage | undefined;
5353
setNewEval(value?: node_pb.NewEvalMessage): void;
5454

55-
hasSharedProcessInit(): boolean;
56-
clearSharedProcessInit(): void;
57-
getSharedProcessInit(): vscode_pb.SharedProcessInitMessage | undefined;
58-
setSharedProcessInit(value?: vscode_pb.SharedProcessInitMessage): void;
59-
6055
getMsgCase(): ClientMessage.MsgCase;
6156
serializeBinary(): Uint8Array;
6257
toObject(includeInstance?: boolean): ClientMessage.AsObject;
@@ -79,7 +74,6 @@ export namespace ClientMessage {
7974
connectionOutput?: command_pb.ConnectionOutputMessage.AsObject,
8075
connectionClose?: command_pb.ConnectionCloseMessage.AsObject,
8176
newEval?: node_pb.NewEvalMessage.AsObject,
82-
sharedProcessInit?: vscode_pb.SharedProcessInitMessage.AsObject,
8377
}
8478

8579
export enum MsgCase {
@@ -93,7 +87,6 @@ export namespace ClientMessage {
9387
CONNECTION_OUTPUT = 7,
9488
CONNECTION_CLOSE = 8,
9589
NEW_EVAL = 9,
96-
SHARED_PROCESS_INIT = 10,
9790
}
9891
}
9992

@@ -153,6 +146,11 @@ export class ServerMessage extends jspb.Message {
153146
getInit(): WorkingInitMessage | undefined;
154147
setInit(value?: WorkingInitMessage): void;
155148

149+
hasSharedProcessActive(): boolean;
150+
clearSharedProcessActive(): void;
151+
getSharedProcessActive(): vscode_pb.SharedProcessActiveMessage | undefined;
152+
setSharedProcessActive(value?: vscode_pb.SharedProcessActiveMessage): void;
153+
156154
getMsgCase(): ServerMessage.MsgCase;
157155
serializeBinary(): Uint8Array;
158156
toObject(includeInstance?: boolean): ServerMessage.AsObject;
@@ -177,6 +175,7 @@ export namespace ServerMessage {
177175
evalFailed?: node_pb.EvalFailedMessage.AsObject,
178176
evalDone?: node_pb.EvalDoneMessage.AsObject,
179177
init?: WorkingInitMessage.AsObject,
178+
sharedProcessActive?: vscode_pb.SharedProcessActiveMessage.AsObject,
180179
}
181180

182181
export enum MsgCase {
@@ -192,6 +191,7 @@ export namespace ServerMessage {
192191
EVAL_FAILED = 9,
193192
EVAL_DONE = 10,
194193
INIT = 11,
194+
SHARED_PROCESS_ACTIVE = 12,
195195
}
196196
}
197197

packages/protocol/src/proto/client_pb.js

Lines changed: 51 additions & 51 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/protocol/src/proto/command.proto

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ message NewSessionMessage {
1313
string cwd = 5;
1414
TTYDimensions tty_dimensions = 6;
1515
bool is_fork = 7;
16+
17+
// Janky, but required for having custom handling of the bootstrap fork
18+
bool is_bootstrap_fork = 8;
1619
}
1720

1821
// Sent when starting a session failed.

0 commit comments

Comments
 (0)