forked from coder/code-server
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcli.ts
More file actions
159 lines (139 loc) · 5.53 KB
/
Copy pathcli.ts
File metadata and controls
159 lines (139 loc) · 5.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import { field, logger, Level } from "@coder/logger";
import { ServerMessage, SharedProcessActiveMessage } from "@coder/protocol/src/proto";
import { Command, flags } from "@oclif/command";
import * as fs from "fs";
import * as os from "os";
import * as path from "path";
import * as WebSocket from "ws";
import { createApp } from "./server";
import { requireModule } from "./vscode/bootstrapFork";
import { SharedProcess, SharedProcessState } from "./vscode/sharedProcess";
export class Entry extends Command {
public static description = "Start your own self-hosted browser-accessible VS Code";
public static flags = {
cert: flags.string(),
"cert-key": flags.string(),
"data-dir": flags.string({ char: "d" }),
help: flags.help(),
host: flags.string({ char: "h", default: "0.0.0.0" }),
open: flags.boolean({ char: "o", description: "Open in browser on startup" }),
port: flags.integer({ char: "p", default: 8080, description: "Port to bind on" }),
logLevel: flags.enum({ char: "l", options: [ "debug", "info", "warn", "error" ]}),
version: flags.version({ char: "v" }),
// Dev flags
"bootstrap-fork": flags.string({ hidden: true }),
};
public static args = [{
name: "workdir",
description: "Specify working dir",
default: (): string => process.cwd(),
}];
public async run(): Promise<void> {
try {
/**
* Suuuper janky
* Comes from - https://github.com/nexe/nexe/issues/524
* Seems to cleanup by removing this path immediately
* If any native module is added its assumed this pathname
* will change.
*/
require("spdlog");
const nodePath = path.join(process.cwd(), "e91a410b");
fs.unlinkSync(path.join(nodePath, "spdlog.node"));
fs.rmdirSync(nodePath);
} catch (ex) {
logger.warn("Failed to remove extracted dependency.", field("dependency", "spdlog"), field("error", ex.message));
}
const { args, flags } = this.parse(Entry);
if (flags.logLevel) {
switch (flags.logLevel) {
case "debug": logger.level = Level.Debug; break;
case "info": logger.level = Level.Info; break;
case "warn": logger.level = Level.Warn; break;
case "error": logger.level = Level.Error; break;
}
}
if (flags["bootstrap-fork"]) {
const modulePath = flags["bootstrap-fork"];
if (!modulePath) {
logger.error("No module path specified to fork!");
process.exit(1);
}
return requireModule(modulePath);
}
const dataDir = flags["data-dir"] || path.join(os.homedir(), ".vscode-online");
const workingDir = args["workdir"];
logger.info("\u001B[1mvscode-remote v1.0.0");
// TODO: fill in appropriate doc url
logger.info("Additional documentation: https://coder.com/docs");
logger.info("Initializing", field("data-dir", dataDir), field("working-dir", workingDir));
const sharedProcess = new SharedProcess(dataDir);
logger.info("Starting shared process...", field("socket", sharedProcess.socketPath));
const sendSharedProcessReady = (socket: WebSocket): void => {
const active = new SharedProcessActiveMessage();
active.setSocketPath(sharedProcess.socketPath);
const serverMessage = new ServerMessage();
serverMessage.setSharedProcessActive(active);
socket.send(serverMessage.serializeBinary());
};
sharedProcess.onState((event) => {
if (event.state === SharedProcessState.Stopped) {
logger.error("Shared process stopped. Restarting...", field("error", event.error));
} else if (event.state === SharedProcessState.Starting) {
logger.info("Starting shared process...");
} else if (event.state === SharedProcessState.Ready) {
logger.info("Shared process is ready!");
app.wss.clients.forEach((c) => sendSharedProcessReady(c));
}
});
const app = createApp((app) => {
app.use((req, res, next) => {
res.on("finish", () => {
logger.debug(`\u001B[1m${req.method} ${res.statusCode} \u001B[0m${req.url}`, field("host", req.hostname), field("ip", req.ip));
});
next();
});
if (process.env.CLI === "false" || !process.env.CLI) {
const webpackConfig = require(path.join(__dirname, "..", "..", "web", "webpack.dev.config.js"));
const compiler = require("webpack")(webpackConfig);
app.use(require("webpack-dev-middleware")(compiler, {
logger,
publicPath: webpackConfig.output.publicPath,
stats: webpackConfig.stats,
}));
app.use(require("webpack-hot-middleware")(compiler));
}
}, {
dataDirectory: dataDir,
workingDirectory: workingDir,
});
logger.info("Starting webserver...", field("host", flags.host), field("port", flags.port));
app.server.listen(flags.port, flags.host);
let clientId = 1;
app.wss.on("connection", (ws, req) => {
const id = clientId++;
if (sharedProcess.state === SharedProcessState.Ready) {
sendSharedProcessReady(ws);
}
logger.info(`WebSocket opened \u001B[0m${req.url}`, field("client", id), field("ip", req.socket.remoteAddress));
ws.on("close", (code) => {
logger.info(`WebSocket closed \u001B[0m${req.url}`, field("client", id), field("code", code));
});
});
if (!flags["cert-key"] && !flags.cert) {
logger.warn("No certificate specified. \u001B[1mThis could be insecure.");
// TODO: fill in appropriate doc url
logger.warn("Documentation on securing your setup: https://coder.com/docs");
}
logger.info(" ");
logger.info("Password:\u001B[1m 023450wf09");
logger.info(" ");
logger.info("Started (click the link below to open):");
logger.info(`http://localhost:${flags.port}/`);
logger.info(" ");
}
}
Entry.run(undefined, {
root: process.env.BUILD_DIR as string || __dirname,
//@ts-ignore
}).catch(require("@oclif/errors/handle"));