Getting the client to run (#12)
* Clean up workbench and integrate initialization data * Uncomment Electron fill * Run server & client together * Clean up Electron fill & patch * Bind fs methods This makes them usable with the promise form: `promisify(access)(...)`. * Add space between tag and title to browser logger * Add typescript dep to server and default __dirname for path * Serve web files from server * Adjust some dev options * Rework workbench a bit to use a class and catch unexpected errors * No mkdirs for now, fix util fill, use bash with exec * More fills, make general client abstract * More fills * Fix cp.exec * Fix require calls in fs fill being aliased * Create data and storage dir * Implement fs.watch Using exec for now. * Implement storage database fill * Fix os export and homedir * Add comment to use navigator.sendBeacon * Fix fs callbacks (some args are optional) * Make sure data directory exists when passing it back * Update patch * Target es5 * More fills * Add APIs required for bootstrap-fork to function (#15) * Add bootstrap-fork execution * Add createConnection * Bundle bootstrap-fork into cli * Remove .node directory created from spdlog * Fix npm start * Remove unnecessary comment * Add webpack-hot-middleware if CLI env is not set * Add restarting to shared process * Fix starting with yarn
This commit is contained in:
29
packages/server/src/vscode/bootstrapFork.ts
Normal file
29
packages/server/src/vscode/bootstrapFork.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import * as cp from "child_process";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
declare var __non_webpack_require__: typeof require;
|
||||
|
||||
export const requireModule = (modulePath: string): void => {
|
||||
process.env.AMD_ENTRYPOINT = modulePath;
|
||||
process.env.VSCODE_ALLOW_IO = "true";
|
||||
const content = fs.readFileSync(path.join(process.env.BUILD_DIR as string || path.join(__dirname, "../.."), "./build/bootstrap-fork.js"));
|
||||
eval(content.toString());
|
||||
};
|
||||
|
||||
/**
|
||||
* Uses the internal bootstrap-fork.js to load a module
|
||||
* @example
|
||||
* const cp = forkModule("vs/code/electron-browser/sharedProcess/sharedProcessMain");
|
||||
* cp.stdout.on("data", (data) => console.log(data.toString("utf8")));
|
||||
* cp.stderr.on("data", (data) => console.log(data.toString("utf8")));
|
||||
* @param modulePath
|
||||
*/
|
||||
export const forkModule = (modulePath: string): cp.ChildProcess => {
|
||||
const args = ["--bootstrap-fork", modulePath];
|
||||
if (process.env.CLI === "true") {
|
||||
return cp.spawn(process.execPath, args);
|
||||
} else {
|
||||
return cp.spawn("npm", ["start", "--scripts-prepend-node-path", "--", ...args]);
|
||||
}
|
||||
};
|
106
packages/server/src/vscode/sharedProcess.ts
Normal file
106
packages/server/src/vscode/sharedProcess.ts
Normal file
@ -0,0 +1,106 @@
|
||||
import { ChildProcess } from "child_process";
|
||||
import * as fs from "fs";
|
||||
import * as os from "os";
|
||||
import * as path from "path";
|
||||
import { forkModule } from "./bootstrapFork";
|
||||
import { StdioIpcHandler } from "../ipc";
|
||||
import { logger, field } from "@coder/logger/src";
|
||||
import { ParsedArgs } from "vs/platform/environment/common/environment";
|
||||
import { LogLevel } from "vs/platform/log/common/log";
|
||||
import { Emitter, Event } from '@coder/events/src';
|
||||
|
||||
export class SharedProcess {
|
||||
public readonly socketPath: string = path.join(os.tmpdir(), `.vscode-online${Math.random().toString()}`);
|
||||
private _ready: Promise<void> | undefined;
|
||||
private activeProcess: ChildProcess | undefined;
|
||||
private ipcHandler: StdioIpcHandler | undefined;
|
||||
private readonly willRestartEmitter: Emitter<void>;
|
||||
|
||||
public constructor(
|
||||
private readonly userDataDir: string,
|
||||
) {
|
||||
this.willRestartEmitter = new Emitter();
|
||||
|
||||
this.restart();
|
||||
}
|
||||
|
||||
public get onWillRestart(): Event<void> {
|
||||
return this.willRestartEmitter.event;
|
||||
}
|
||||
|
||||
public get ready(): Promise<void> {
|
||||
return this._ready!;
|
||||
}
|
||||
|
||||
public restart(): void {
|
||||
if (this.activeProcess) {
|
||||
this.willRestartEmitter.emit();
|
||||
}
|
||||
|
||||
if (this.activeProcess && !this.activeProcess.killed) {
|
||||
this.activeProcess.kill();
|
||||
}
|
||||
|
||||
let resolve: () => void;
|
||||
let reject: (err: Error) => void;
|
||||
|
||||
const extensionsDir = path.join(this.userDataDir, "extensions");
|
||||
const mkdir = (dir: string): void => {
|
||||
try {
|
||||
fs.mkdirSync(dir);
|
||||
} catch (ex) {
|
||||
if (ex.code !== "EEXIST") {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
};
|
||||
mkdir(this.userDataDir);
|
||||
mkdir(extensionsDir);
|
||||
|
||||
this._ready = new Promise<void>((res, rej) => {
|
||||
resolve = res;
|
||||
reject = rej;
|
||||
});
|
||||
|
||||
let resolved: boolean = false;
|
||||
this.activeProcess = forkModule("vs/code/electron-browser/sharedProcess/sharedProcessMain");
|
||||
this.activeProcess.on("exit", () => {
|
||||
this.restart();
|
||||
});
|
||||
this.ipcHandler = new StdioIpcHandler(this.activeProcess);
|
||||
this.ipcHandler.once("handshake:hello", () => {
|
||||
const data: {
|
||||
sharedIPCHandle: string;
|
||||
args: ParsedArgs;
|
||||
logLevel: LogLevel;
|
||||
} = {
|
||||
args: {
|
||||
"builtin-extensions-dir": path.join(process.env.BUILD_DIR || path.join(__dirname, "../.."), "build/extensions"),
|
||||
"user-data-dir": this.userDataDir,
|
||||
"extensions-dir": extensionsDir,
|
||||
} as any,
|
||||
logLevel: 0,
|
||||
sharedIPCHandle: this.socketPath,
|
||||
};
|
||||
this.ipcHandler!.send("handshake:hey there", "", data);
|
||||
});
|
||||
this.ipcHandler.once("handshake:im ready", () => {
|
||||
resolved = true;
|
||||
resolve();
|
||||
});
|
||||
this.activeProcess.stderr.on("data", (data) => {
|
||||
if (!resolved) {
|
||||
reject(data.toString());
|
||||
} else {
|
||||
logger.named("SHRD PROC").debug("stderr", field("message", data.toString()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
if (this.ipcHandler) {
|
||||
this.ipcHandler.send("handshake:goodbye");
|
||||
}
|
||||
this.ipcHandler = undefined;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user