2019-07-03 04:55:54 +07:00
|
|
|
import * as os from "os";
|
2019-07-13 03:21:00 +07:00
|
|
|
import * as path from "path";
|
2019-07-12 05:12:52 +07:00
|
|
|
|
2019-07-03 04:55:54 +07:00
|
|
|
import { validatePaths } from "vs/code/node/paths";
|
|
|
|
import { parseMainProcessArgv } from "vs/platform/environment/node/argvHelper";
|
|
|
|
import { ParsedArgs } from "vs/platform/environment/common/environment";
|
2019-07-03 06:29:48 +07:00
|
|
|
import { buildHelpMessage, buildVersionMessage, options } from "vs/platform/environment/node/argv";
|
2019-07-03 04:55:54 +07:00
|
|
|
import pkg from "vs/platform/product/node/package";
|
2019-07-17 02:57:02 +07:00
|
|
|
import product from "vs/platform/product/node/product";
|
2019-07-12 05:12:52 +07:00
|
|
|
|
|
|
|
import { MainServer, WebviewServer } from "vs/server/src/server";
|
|
|
|
import "vs/server/src/tar";
|
2019-07-16 01:31:05 +07:00
|
|
|
import { generateCertificate, generatePassword, open } from "vs/server/src/util";
|
2019-07-03 04:55:54 +07:00
|
|
|
|
2019-07-03 06:29:48 +07:00
|
|
|
interface Args extends ParsedArgs {
|
2019-07-11 06:33:18 +07:00
|
|
|
"allow-http"?: boolean;
|
2019-07-13 03:21:00 +07:00
|
|
|
auth?: boolean;
|
2019-07-11 06:33:18 +07:00
|
|
|
cert?: string;
|
|
|
|
"cert-key"?: string;
|
|
|
|
"extra-builtin-extensions-dir"?: string;
|
|
|
|
"extra-extensions-dir"?: string;
|
|
|
|
host?: string;
|
|
|
|
open?: string;
|
2019-07-03 06:29:48 +07:00
|
|
|
port?: string;
|
2019-07-11 06:33:18 +07:00
|
|
|
socket?: string;
|
2019-07-03 06:29:48 +07:00
|
|
|
"webview-port"?: string;
|
2019-07-11 06:33:18 +07:00
|
|
|
"webview-socket"?: string;
|
2019-07-03 06:29:48 +07:00
|
|
|
}
|
|
|
|
|
2019-07-11 06:33:18 +07:00
|
|
|
// The last item is _ which is like -- so our options need to come before it.
|
|
|
|
const last = options.pop()!;
|
|
|
|
|
|
|
|
// Remove options that won't work or don't make sense.
|
|
|
|
let i = options.length;
|
|
|
|
while (i--) {
|
|
|
|
switch (options[i].id) {
|
|
|
|
case "add":
|
|
|
|
case "diff":
|
|
|
|
case "file-uri":
|
|
|
|
case "folder-uri":
|
|
|
|
case "goto":
|
|
|
|
case "new-window":
|
|
|
|
case "reuse-window":
|
|
|
|
case "wait":
|
|
|
|
case "disable-gpu":
|
|
|
|
// TODO: pretty sure these don't work but not 100%.
|
|
|
|
case "max-memory":
|
|
|
|
case "prof-startup":
|
|
|
|
case "inspect-extensions":
|
|
|
|
case "inspect-brk-extensions":
|
|
|
|
options.splice(i, 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
options.push({ id: "allow-http", type: "boolean", cat: "o", description: "Allow http connections." });
|
|
|
|
options.push({ id: "cert", type: "string", cat: "o", description: "Path to certificate." });
|
|
|
|
options.push({ id: "cert-key", type: "string", cat: "o", description: "Path to certificate key." });
|
|
|
|
options.push({ id: "extra-builtin-extensions-dir", type: "string", cat: "o", description: "Path to extra builtin extension directory." });
|
|
|
|
options.push({ id: "extra-extensions-dir", type: "string", cat: "o", description: "Path to extra user extension directory." });
|
|
|
|
options.push({ id: "host", type: "string", cat: "o", description: "Host for the main and webview servers." });
|
2019-07-13 03:21:00 +07:00
|
|
|
options.push({ id: "no-auth", type: "boolean", cat: "o", description: "Disable password authentication." });
|
2019-07-11 06:33:18 +07:00
|
|
|
options.push({ id: "open", type: "boolean", cat: "o", description: "Open in the browser on startup." });
|
2019-07-03 06:29:48 +07:00
|
|
|
options.push({ id: "port", type: "string", cat: "o", description: "Port for the main server." });
|
2019-07-11 06:33:18 +07:00
|
|
|
options.push({ id: "socket", type: "string", cat: "o", description: "Listen on a socket instead of host:port." });
|
2019-07-03 06:29:48 +07:00
|
|
|
options.push({ id: "webview-port", type: "string", cat: "o", description: "Port for the webview server." });
|
2019-07-11 06:33:18 +07:00
|
|
|
options.push({ id: "webview-socket", type: "string", cat: "o", description: "Listen on a socket instead of host:port." });
|
|
|
|
|
|
|
|
options.push(last);
|
2019-07-03 06:29:48 +07:00
|
|
|
|
2019-07-03 04:55:54 +07:00
|
|
|
interface IMainCli {
|
|
|
|
main: (argv: ParsedArgs) => Promise<void>;
|
|
|
|
}
|
|
|
|
|
|
|
|
const main = async (): Promise<void> => {
|
2019-07-03 06:29:48 +07:00
|
|
|
const args = validatePaths(parseMainProcessArgv(process.argv)) as Args;
|
2019-07-13 04:39:38 +07:00
|
|
|
["extra-extensions-dir", "extra-builtin-extensions-dir"].forEach((key) => {
|
|
|
|
if (typeof args[key] === "string") {
|
|
|
|
args[key] = [args[key]];
|
|
|
|
}
|
|
|
|
});
|
2019-07-03 04:55:54 +07:00
|
|
|
|
|
|
|
if (!product.extensionsGallery) {
|
|
|
|
product.extensionsGallery = {
|
|
|
|
serviceUrl: process.env.SERVICE_URL || "https://v1.extapi.coder.com",
|
|
|
|
itemUrl: process.env.ITEM_URL || "",
|
|
|
|
controlUrl: "",
|
|
|
|
recommendationsUrl: "",
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-07-11 06:33:18 +07:00
|
|
|
const version = `${(pkg as any).codeServerVersion || "development"}-vsc${pkg.version}`;
|
2019-07-03 04:55:54 +07:00
|
|
|
if (args.help) {
|
|
|
|
const executable = `${product.applicationName}${os.platform() === "win32" ? ".exe" : ""}`;
|
2019-07-11 06:33:18 +07:00
|
|
|
return console.log(buildHelpMessage(
|
|
|
|
product.nameLong, executable,
|
|
|
|
version,
|
|
|
|
undefined,
|
|
|
|
false,
|
|
|
|
));
|
2019-07-03 04:55:54 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (args.version) {
|
2019-07-11 06:33:18 +07:00
|
|
|
return console.log(buildVersionMessage(version, product.commit));
|
2019-07-03 04:55:54 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
const shouldSpawnCliProcess = (): boolean => {
|
|
|
|
return !!args["install-source"]
|
|
|
|
|| !!args["list-extensions"]
|
|
|
|
|| !!args["install-extension"]
|
|
|
|
|| !!args["uninstall-extension"]
|
|
|
|
|| !!args["locate-extension"]
|
|
|
|
|| !!args["telemetry"];
|
|
|
|
};
|
|
|
|
|
|
|
|
if (shouldSpawnCliProcess()) {
|
|
|
|
const cli = await new Promise<IMainCli>((c, e) => require(["vs/code/node/cliProcessMain"], c, e));
|
|
|
|
await cli.main(args);
|
|
|
|
// There is some WriteStream instance keeping it open so force an exit.
|
|
|
|
return process.exit(0);
|
|
|
|
}
|
|
|
|
|
2019-07-12 05:12:52 +07:00
|
|
|
const options = {
|
2019-07-13 03:21:00 +07:00
|
|
|
host: args.host,
|
2019-07-12 05:12:52 +07:00
|
|
|
allowHttp: args["allow-http"],
|
2019-07-13 03:21:00 +07:00
|
|
|
cert: args.cert,
|
|
|
|
certKey: args["cert-key"],
|
|
|
|
auth: typeof args.auth !== "undefined" ? args.auth : true,
|
|
|
|
password: process.env.PASSWORD,
|
2019-07-13 06:41:56 +07:00
|
|
|
folderUri: args["_"] && args["_"].length > 1
|
|
|
|
? args["_"][args["_"].length - 1]
|
|
|
|
: undefined,
|
2019-07-12 05:12:52 +07:00
|
|
|
};
|
|
|
|
|
2019-07-13 03:21:00 +07:00
|
|
|
if (!options.host) {
|
|
|
|
options.host = !options.auth || options.allowHttp
|
|
|
|
? "localhost"
|
|
|
|
: "0.0.0.0";
|
|
|
|
}
|
|
|
|
|
|
|
|
let usingGeneratedCert = false;
|
2019-07-12 05:12:52 +07:00
|
|
|
if (!options.allowHttp && (!options.cert || !options.certKey)) {
|
|
|
|
const { cert, certKey } = await generateCertificate();
|
|
|
|
options.cert = cert;
|
|
|
|
options.certKey = certKey;
|
2019-07-13 03:21:00 +07:00
|
|
|
usingGeneratedCert = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
let usingGeneratedPassword = false;
|
|
|
|
if (options.auth && !options.password) {
|
|
|
|
options.password = await generatePassword();
|
|
|
|
usingGeneratedPassword = true;
|
2019-07-12 05:12:52 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
const webviewPort = typeof args["webview-port"] !== "undefined"
|
|
|
|
&& parseInt(args["webview-port"], 10) || 8444;
|
|
|
|
const webviewServer = new WebviewServer({
|
|
|
|
...options,
|
|
|
|
port: webviewPort,
|
|
|
|
socket: args["webview-socket"],
|
|
|
|
});
|
|
|
|
|
|
|
|
const port = typeof args.port !== "undefined" && parseInt(args.port, 10) || 8443;
|
|
|
|
const server = new MainServer({
|
|
|
|
...options,
|
|
|
|
port,
|
|
|
|
socket: args.socket,
|
|
|
|
}, webviewServer, args);
|
|
|
|
|
2019-07-05 22:54:44 +07:00
|
|
|
const [webviewAddress, serverAddress] = await Promise.all([
|
|
|
|
webviewServer.listen(),
|
|
|
|
server.listen()
|
|
|
|
]);
|
2019-07-12 05:12:52 +07:00
|
|
|
console.log(`Main server listening on ${serverAddress}`);
|
|
|
|
console.log(`Webview server listening on ${webviewAddress}`);
|
2019-07-13 03:21:00 +07:00
|
|
|
|
|
|
|
if (usingGeneratedPassword) {
|
|
|
|
console.log(" - Password is", options.password);
|
|
|
|
console.log(" - To use your own password, set the PASSWORD environment variable");
|
|
|
|
} else if (options.auth) {
|
|
|
|
console.log(" - Using custom password for authentication");
|
|
|
|
} else {
|
|
|
|
console.log(" - No authentication");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!options.allowHttp && options.cert && options.certKey) {
|
|
|
|
console.log(
|
|
|
|
usingGeneratedCert
|
|
|
|
? ` - Using generated certificate and key in ${path.dirname(options.cert)} for HTTPS`
|
|
|
|
: " - Using provided certificate and key for HTTPS",
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
console.log(" - Not serving HTTPS");
|
|
|
|
}
|
2019-07-16 01:31:05 +07:00
|
|
|
|
2019-07-17 07:23:58 +07:00
|
|
|
if (!args.socket && args.open) {
|
|
|
|
// The web socket doesn't seem to work if using 0.0.0.0.
|
|
|
|
const openAddress = `http://localhost:${port}`;
|
|
|
|
await open(openAddress).catch(console.error);
|
|
|
|
console.log(` - Opened ${openAddress}`);
|
2019-07-16 01:31:05 +07:00
|
|
|
}
|
2019-07-03 04:55:54 +07:00
|
|
|
};
|
|
|
|
|
|
|
|
main().catch((error) => {
|
|
|
|
console.error(error);
|
|
|
|
process.exit(1);
|
|
|
|
});
|