diff --git a/.gitignore b/.gitignore index 8ac56410..5c922b9d 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ node_modules node-* /plugins /lib/coder-cloud-agent +/lib/linkup .home coverage **/.DS_Store diff --git a/ci/build/build-code-server.sh b/ci/build/build-code-server.sh index c1772539..61932f88 100755 --- a/ci/build/build-code-server.sh +++ b/ci/build/build-code-server.sh @@ -29,6 +29,20 @@ main() { set -e fi + if ! [ -f ./lib/linkup ]; then + echo "Downloading Link agent..." + + # for arch; we do not use OS from lib.sh and get our own. + # lib.sh normalizes macos to darwin - but cloud-agent's binaries do not + source ./ci/lib.sh + OS="$(uname | tr '[:upper:]' '[:lower:]')" + + set +e + curl -fsSL "https://storage.googleapis.com/coder-link-releases/latest/linkup-$OS-$ARCH" -o ./lib/linkup + chmod +x ./lib/linkup + set -e + fi + yarn browserify out/browser/register.js -o out/browser/register.browserified.js yarn browserify out/browser/pages/login.js -o out/browser/pages/login.browserified.js yarn browserify out/browser/pages/vscode.js -o out/browser/pages/vscode.browserified.js diff --git a/ci/build/build-release.sh b/ci/build/build-release.sh index fe788d7c..2f61c9f9 100755 --- a/ci/build/build-release.sh +++ b/ci/build/build-release.sh @@ -60,6 +60,7 @@ EOF rsync node_modules/ "$RELEASE_PATH/node_modules" mkdir -p "$RELEASE_PATH/lib" rsync ./lib/coder-cloud-agent "$RELEASE_PATH/lib" + rsync ./lib/linkup "$RELEASE_PATH/lib" fi } diff --git a/ci/build/npm-postinstall.sh b/ci/build/npm-postinstall.sh index a1110ccd..469f2ee5 100755 --- a/ci/build/npm-postinstall.sh +++ b/ci/build/npm-postinstall.sh @@ -63,6 +63,12 @@ main() { echo "Failed to download cloud agent; --link will not work" fi + if curl -fsSL "https://storage.googleapis.com/coder-link-releases/latest/linkup-$OS-$ARCH" -o ./lib/linkup; then + chmod +x ./lib/linkup + else + echo "Failed to download Link agent; the Link extension will not work" + fi + if ! vscode_yarn; then echo "You may not have the required dependencies to build the native modules." echo "Please see https://github.com/cdr/code-server/blob/master/docs/npm.md" diff --git a/src/node/link.ts b/src/node/link.ts new file mode 100644 index 00000000..633c193e --- /dev/null +++ b/src/node/link.ts @@ -0,0 +1,23 @@ +import { logger } from "@coder/logger" +import { spawn } from "child_process" +import path from "path" + +export function startLink(port: number): Promise { + logger.debug(`running link targetting ${port}`) + + const agent = spawn(path.resolve(__dirname, "../../lib/linkup"), ["--devurl", `code:${port}:code-server`], { + stdio: "ignore", + shell: false, + }) + return new Promise((res, rej) => { + agent.on("error", rej) + agent.on("close", (code) => { + if (code !== 0) { + return rej({ + message: `Link exited with ${code}`, + }) + } + res() + }) + }) +} diff --git a/src/node/main.ts b/src/node/main.ts index e0036413..e22496e1 100644 --- a/src/node/main.ts +++ b/src/node/main.ts @@ -8,6 +8,7 @@ import { createApp, ensureAddress } from "./app" import { AuthType, DefaultedArgs, Feature } from "./cli" import { coderCloudBind } from "./coder_cloud" import { commit, version } from "./constants" +import { startLink } from "./link" import { register } from "./routes" import { humanPath, isFile, open } from "./util" @@ -128,6 +129,15 @@ export const runCodeServer = async (args: DefaultedArgs): Promise = await coderCloudBind(serverAddress.replace(/^https?:\/\//, ""), args.link.value) logger.info(" - Connected to cloud agent") } + + try { + const port = parseInt(serverAddress.split(":").pop() as string, 10) + startLink(port).catch((ex) => { + logger.debug("Link daemon exited!", field("error", ex)) + }) + } catch (ex) { + logger.debug("Failed to start link daemon!", ex) + } if (args.enable && args.enable.length > 0) { logger.info("Enabling the following experimental features:")