diff --git a/package.json b/package.json index 878eebf1..cc3edd30 100644 --- a/package.json +++ b/package.json @@ -82,8 +82,7 @@ "tar-fs": "^2.0.0", "ws": "^7.2.0", "xdg-basedir": "^4.0.0", - "yarn": "^1.22.4", - "delay": "^4.4.0" + "yarn": "^1.22.4" }, "bin": { "code-server": "out/node/entry.js" diff --git a/src/node/coder-cloud.ts b/src/node/coder-cloud.ts index 5f7b7c0a..a3c3c590 100644 --- a/src/node/coder-cloud.ts +++ b/src/node/coder-cloud.ts @@ -1,11 +1,7 @@ import { logger } from "@coder/logger" import { spawn } from "child_process" -import delay from "delay" -import fs from "fs" import path from "path" import split2 from "split2" -import { promisify } from "util" -import xdgBasedir from "xdg-basedir" const coderCloudAgent = path.resolve(__dirname, "../../lib/coder-cloud-agent") @@ -39,17 +35,7 @@ export function coderCloudProxy(addr: string) { // So we trim the protocol. addr = addr.replace(/^https?:\/\//, "") - if (!xdgBasedir.config) { - return - } - - const sessionTokenPath = path.join(xdgBasedir.config, "coder-cloud", "session") - const _proxy = async () => { - await waitForPath(sessionTokenPath) - - logger.info("exposing coder-server with coder-cloud") - const agent = spawn(coderCloudAgent, ["proxy", "--code-server-addr", addr], { stdio: ["inherit", "inherit", "pipe"], }) @@ -84,74 +70,3 @@ export function coderCloudProxy(addr: string) { } proxy() } - -/** - * waitForPath efficiently implements waiting for the existence of a path. - * - * We intentionally do not use fs.watchFile as it is very slow from testing. - * I believe it polls instead of watching. - * - * The way this works is for each level of the path it will check if it exists - * and if not, it will wait for it. e.g. if the path is /home/nhooyr/.config/coder-cloud/session - * then first it will check if /home exists, then /home/nhooyr and so on. - * - * The wait works by first creating a watch promise for the p segment. - * We call fs.watch on the dirname of the p segment. When the dirname has a change, - * we check if the p segment exists and if it does, we resolve the watch promise. - * On any error or the watcher being closed, we reject the watch promise. - * - * Once that promise is setup, we check if the p segment exists with fs.exists - * and if it does, we close the watcher and return. - * - * Now we race the watch promise and a 2000ms delay promise. Once the race - * is complete, we close the watcher. - * - * If the watch promise was the one to resolve, we return. - * Otherwise we setup the watch promise again and retry. - * - * This combination of polling and watching is very reliable and efficient. - */ -async function waitForPath(p: string): Promise { - const segs = p.split(path.sep) - for (let i = 0; i < segs.length; i++) { - const s = path.join("/", ...segs.slice(0, i + 1)) - // We need to wait for each segment to exist. - await _waitForPath(s) - } -} - -async function _waitForPath(p: string): Promise { - const watchDir = path.dirname(p) - - logger.debug(`waiting for ${p}`) - - for (;;) { - const w = fs.watch(watchDir) - const watchPromise = new Promise((res, rej) => { - w.on("change", async () => { - if (await promisify(fs.exists)(p)) { - res() - } - }) - w.on("close", () => rej(new Error("watcher closed"))) - w.on("error", rej) - }) - - // We want to ignore any errors from this promise being rejected if the file - // already exists below. - watchPromise.catch(() => {}) - - if (await promisify(fs.exists)(p)) { - // The path exists! - w.close() - return - } - - // Now we wait for either the watch promise to resolve/reject or 2000ms. - const s = await Promise.race([watchPromise.then(() => "exists"), delay(2000)]) - w.close() - if (s === "exists") { - return - } - } -} diff --git a/src/node/entry.ts b/src/node/entry.ts index 1be886e0..901c732f 100644 --- a/src/node/entry.ts +++ b/src/node/entry.ts @@ -142,14 +142,14 @@ const main = async (args: Args, cliArgs: Args, configArgs: Args): Promise } if (args["coder-bind"]) { - logger.info(`linking code-server to the cloud with name ${args["coder-bind"]}`) try { + logger.info(`binding code-server to the cloud with name ${args["coder-bind"]}`) await coderCloudBind(args["coder-bind"]) coderCloudProxy(serverAddress!) } catch (err) { logger.error(err.message) - process.exit(1) + ipcMain().exit(1) } } }