chore: move to patches (#4997)
* Move integration types into code-server This will be easier to maintain than to have it as a patch. * Disable connection token Using a flag means we will not need to patch it out. I think this is new from 1.64? * Add product.json to build process This way we do not have to patch it. * Ship with remote agent package.json Instead of the root one. This contains fewer dependencies. * Let Code handle errors This way we will not have to patch Code to make this work and I think it makes sense to let Code handle the request. If we do want to handle errors we can do it cleanly by patching their error handler to throw instead. * Move manifest override into code-server This way we will not have to patch it. * Move to patches - Switch submodule to track upstream - Add quilt to the process - Add patches The node-* ignore was ignoring one of the diffs so I removed it. This was added when we were curling Node as node-v{version}-darwin-x64 for the macOS build but this no longer happens (we use the Node action to install a specific version now so we just use the system-wide Node). * Use pre-packaged Code
This commit is contained in:
14
src/browser/serviceWorker.ts
Normal file
14
src/browser/serviceWorker.ts
Normal file
@ -0,0 +1,14 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
self.addEventListener("install", () => {
|
||||
console.debug("[Service Worker] installed")
|
||||
})
|
||||
|
||||
self.addEventListener("activate", (event: any) => {
|
||||
event.waitUntil((self as any).clients.claim())
|
||||
console.debug("[Service Worker] activated")
|
||||
})
|
||||
|
||||
self.addEventListener("fetch", () => {
|
||||
// Without this event handler we won't be recognized as a PWA.
|
||||
})
|
@ -31,13 +31,33 @@ export enum LogLevel {
|
||||
|
||||
export class OptionalString extends Optional<string> {}
|
||||
|
||||
/**
|
||||
* Code flags provided by the user.
|
||||
*/
|
||||
export interface UserProvidedCodeArgs {
|
||||
"disable-telemetry"?: boolean
|
||||
force?: boolean
|
||||
"user-data-dir"?: string
|
||||
"enable-proposed-api"?: string[]
|
||||
"extensions-dir"?: string
|
||||
"builtin-extensions-dir"?: string
|
||||
"install-extension"?: string[]
|
||||
"uninstall-extension"?: string[]
|
||||
"list-extensions"?: boolean
|
||||
"locate-extension"?: string[]
|
||||
"show-versions"?: boolean
|
||||
category?: string
|
||||
"github-auth"?: string
|
||||
"disable-update-check"?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Arguments that the user explicitly provided on the command line. All
|
||||
* arguments must be optional.
|
||||
*
|
||||
* For arguments with defaults see DefaultedArgs.
|
||||
*/
|
||||
export interface UserProvidedArgs {
|
||||
export interface UserProvidedArgs extends UserProvidedCodeArgs {
|
||||
config?: string
|
||||
auth?: AuthType
|
||||
password?: string
|
||||
@ -45,7 +65,6 @@ export interface UserProvidedArgs {
|
||||
cert?: OptionalString
|
||||
"cert-host"?: string
|
||||
"cert-key"?: string
|
||||
"disable-update-check"?: boolean
|
||||
enable?: string[]
|
||||
help?: boolean
|
||||
host?: string
|
||||
@ -66,21 +85,6 @@ export interface UserProvidedArgs {
|
||||
verbose?: boolean
|
||||
/* Positional arguments. */
|
||||
_?: string[]
|
||||
|
||||
// VS Code flags.
|
||||
"disable-telemetry"?: boolean
|
||||
force?: boolean
|
||||
"user-data-dir"?: string
|
||||
"enable-proposed-api"?: string[]
|
||||
"extensions-dir"?: string
|
||||
"builtin-extensions-dir"?: string
|
||||
"install-extension"?: string[]
|
||||
"uninstall-extension"?: string[]
|
||||
"list-extensions"?: boolean
|
||||
"locate-extension"?: string[]
|
||||
"show-versions"?: boolean
|
||||
category?: string
|
||||
"github-auth"?: string
|
||||
}
|
||||
|
||||
interface Option<T> {
|
||||
@ -761,14 +765,37 @@ export const shouldOpenInExistingInstance = async (args: UserProvidedArgs): Prom
|
||||
return undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Arguments for running Code's server.
|
||||
*
|
||||
* A subset of ../../lib/vscode/src/vs/server/node/serverEnvironmentService.ts:90
|
||||
*/
|
||||
export interface CodeArgs extends UserProvidedCodeArgs {
|
||||
"accept-server-license-terms"?: boolean
|
||||
"connection-token"?: string
|
||||
help: boolean
|
||||
port?: string
|
||||
version: boolean
|
||||
"without-connection-token"?: boolean
|
||||
"without-browser-env-var"?: boolean
|
||||
compatibility: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Types for ../../lib/vscode/src/vs/server/node/server.main.ts:65.
|
||||
*/
|
||||
export type SpawnCodeCli = (args: CodeArgs) => Promise<void>
|
||||
|
||||
/**
|
||||
* Convert our arguments to VS Code server arguments.
|
||||
*/
|
||||
export const toVsCodeArgs = async (args: DefaultedArgs): Promise<CodeServerLib.ServerParsedArgs> => {
|
||||
export const toCodeArgs = async (args: DefaultedArgs): Promise<CodeArgs> => {
|
||||
return {
|
||||
"connection-token": "0000",
|
||||
...args,
|
||||
"accept-server-license-terms": true,
|
||||
// This seems to be used to make the connection token flags optional (when
|
||||
// set to 1.63) but we have always included them.
|
||||
compatibility: "1.64",
|
||||
/** Type casting. */
|
||||
help: !!args.help,
|
||||
version: !!args.version,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { logger } from "@coder/logger"
|
||||
import { optionDescriptions, parse, readConfigFile, setDefaults, shouldOpenInExistingInstance } from "./cli"
|
||||
import { getVersionString, getVersionJsonString } from "./constants"
|
||||
import { openInExistingInstance, runCodeServer, runVsCodeCli, shouldSpawnCliProcess } from "./main"
|
||||
import { openInExistingInstance, runCodeServer, runCodeCli, shouldSpawnCliProcess } from "./main"
|
||||
import { isChild, wrapper } from "./wrapper"
|
||||
|
||||
async function entry(): Promise<void> {
|
||||
@ -48,7 +48,7 @@ async function entry(): Promise<void> {
|
||||
|
||||
if (shouldSpawnCliProcess(args)) {
|
||||
logger.debug("Found VS Code arguments; spawning VS Code CLI")
|
||||
return runVsCodeCli(args)
|
||||
return runCodeCli(args)
|
||||
}
|
||||
|
||||
const socketPath = await shouldOpenInExistingInstance(cliArgs)
|
||||
|
@ -5,7 +5,7 @@ import path from "path"
|
||||
import { Disposable } from "../common/emitter"
|
||||
import { plural } from "../common/util"
|
||||
import { createApp, ensureAddress } from "./app"
|
||||
import { AuthType, DefaultedArgs, Feature, toVsCodeArgs, UserProvidedArgs } from "./cli"
|
||||
import { AuthType, DefaultedArgs, Feature, SpawnCodeCli, toCodeArgs, UserProvidedArgs } from "./cli"
|
||||
import { coderCloudBind } from "./coder_cloud"
|
||||
import { commit, version } from "./constants"
|
||||
import { register } from "./routes"
|
||||
@ -24,27 +24,46 @@ export const shouldSpawnCliProcess = (args: UserProvidedArgs): boolean => {
|
||||
}
|
||||
|
||||
/**
|
||||
* This is useful when an CLI arg should be passed to VS Code directly,
|
||||
* such as when managing extensions.
|
||||
* @deprecated This should be removed when code-server merges with lib/vscode.
|
||||
* This is copy of OpenCommandPipeArgs from
|
||||
* ../../lib/vscode/src/vs/workbench/api/node/extHostCLIServer.ts:15
|
||||
*
|
||||
* Arguments supported by Code's socket. It can be used to perform actions from
|
||||
* the CLI in a running instance of Code (for example to open a file).
|
||||
*
|
||||
* TODO: Can we import this (and other types) directly?
|
||||
*/
|
||||
export const runVsCodeCli = async (args: DefaultedArgs): Promise<void> => {
|
||||
logger.debug("Running VS Code CLI")
|
||||
export interface OpenCommandPipeArgs {
|
||||
type: "open"
|
||||
fileURIs?: string[]
|
||||
folderURIs: string[]
|
||||
forceNewWindow?: boolean
|
||||
diffMode?: boolean
|
||||
addMode?: boolean
|
||||
gotoLineMode?: boolean
|
||||
forceReuseWindow?: boolean
|
||||
waitMarkerFilePath?: string
|
||||
}
|
||||
|
||||
// See ../../lib/vscode/src/vs/server/node/server.main.js.
|
||||
const spawnCli = await loadAMDModule<CodeServerLib.SpawnCli>("vs/server/node/server.main", "spawnCli")
|
||||
/**
|
||||
* Run Code's CLI for things like managing extensions.
|
||||
*/
|
||||
export const runCodeCli = async (args: DefaultedArgs): Promise<void> => {
|
||||
logger.debug("Running Code CLI")
|
||||
|
||||
// See ../../lib/vscode/src/vs/server/node/server.main.ts:65.
|
||||
const spawnCli = await loadAMDModule<SpawnCodeCli>("vs/server/node/server.main", "spawnCli")
|
||||
|
||||
try {
|
||||
await spawnCli(await toVsCodeArgs(args))
|
||||
await spawnCli(await toCodeArgs(args))
|
||||
} catch (error: any) {
|
||||
logger.error("Got error from VS Code", error)
|
||||
logger.error("Got error from Code", error)
|
||||
}
|
||||
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
export const openInExistingInstance = async (args: DefaultedArgs, socketPath: string): Promise<void> => {
|
||||
const pipeArgs: CodeServerLib.OpenCommandPipeArgs & { fileURIs: string[] } = {
|
||||
const pipeArgs: OpenCommandPipeArgs & { fileURIs: string[] } = {
|
||||
type: "open",
|
||||
folderURIs: [],
|
||||
fileURIs: [],
|
||||
@ -76,12 +95,12 @@ export const openInExistingInstance = async (args: DefaultedArgs, socketPath: st
|
||||
},
|
||||
(response) => {
|
||||
response.on("data", (message) => {
|
||||
logger.debug("got message from VS Code", field("message", message.toString()))
|
||||
logger.debug("got message from Code", field("message", message.toString()))
|
||||
})
|
||||
},
|
||||
)
|
||||
vscode.on("error", (error: unknown) => {
|
||||
logger.error("got error from VS Code", field("error", error))
|
||||
logger.error("got error from Code", field("error", error))
|
||||
})
|
||||
vscode.write(JSON.stringify(pipeArgs))
|
||||
vscode.end()
|
||||
|
@ -129,6 +129,14 @@ export const register = async (app: App, args: DefaultedArgs): Promise<Disposabl
|
||||
express.static(rootPath, {
|
||||
cacheControl: commit !== "development",
|
||||
fallthrough: false,
|
||||
setHeaders: (res, path, stat) => {
|
||||
// The service worker is served from a sub-path on the static route so
|
||||
// this is required to allow it to register a higher scope (by default
|
||||
// the browser only allows it to register from its own path or lower).
|
||||
if (path.endsWith("/serviceWorker.js")) {
|
||||
res.setHeader("Service-Worker-Allowed", "/")
|
||||
}
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
|
@ -1,19 +1,34 @@
|
||||
import { logger } from "@coder/logger"
|
||||
import * as express from "express"
|
||||
import * as http from "http"
|
||||
import * as net from "net"
|
||||
import * as path from "path"
|
||||
import { WebsocketRequest } from "../../../typings/pluginapi"
|
||||
import { logError } from "../../common/util"
|
||||
import { toVsCodeArgs } from "../cli"
|
||||
import { CodeArgs, toCodeArgs } from "../cli"
|
||||
import { isDevMode } from "../constants"
|
||||
import { authenticated, ensureAuthenticated, redirect, self } from "../http"
|
||||
import { authenticated, ensureAuthenticated, redirect, replaceTemplates, self } from "../http"
|
||||
import { SocketProxyProvider } from "../socket"
|
||||
import { isFile, loadAMDModule } from "../util"
|
||||
import { Router as WsRouter } from "../wsRouter"
|
||||
import { errorHandler } from "./errors"
|
||||
|
||||
/**
|
||||
* This is the API of Code's web client server. code-server delegates requests
|
||||
* to Code here.
|
||||
*/
|
||||
export interface IServerAPI {
|
||||
handleRequest(req: http.IncomingMessage, res: http.ServerResponse): Promise<void>
|
||||
handleUpgrade(req: http.IncomingMessage, socket: net.Socket): void
|
||||
handleServerError(err: Error): void
|
||||
dispose(): void
|
||||
}
|
||||
|
||||
// Types for ../../../lib/vscode/src/vs/server/node/server.main.ts:72.
|
||||
export type CreateServer = (address: string | net.AddressInfo | null, args: CodeArgs) => Promise<IServerAPI>
|
||||
|
||||
export class CodeServerRouteWrapper {
|
||||
/** Assigned in `ensureCodeServerLoaded` */
|
||||
private _codeServerMain!: CodeServerLib.IServerAPI
|
||||
private _codeServerMain!: IServerAPI
|
||||
private _wsRouterWrapper = WsRouter()
|
||||
private _socketProxyProvider = new SocketProxyProvider()
|
||||
public router = express.Router()
|
||||
@ -24,6 +39,32 @@ export class CodeServerRouteWrapper {
|
||||
|
||||
//#region Route Handlers
|
||||
|
||||
private manifest: express.Handler = async (req, res, next) => {
|
||||
res.writeHead(200, { "Content-Type": "application/manifest+json" })
|
||||
|
||||
return res.end(
|
||||
replaceTemplates(
|
||||
req,
|
||||
JSON.stringify(
|
||||
{
|
||||
name: "code-server",
|
||||
short_name: "code-server",
|
||||
start_url: ".",
|
||||
display: "fullscreen",
|
||||
description: "Run Code on a remote server.",
|
||||
icons: [192, 512].map((size) => ({
|
||||
src: `{{BASE}}/_static/src/browser/media/pwa-icon-${size}.png`,
|
||||
type: "image/png",
|
||||
sizes: `${size}x${size}`,
|
||||
})),
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private $root: express.Handler = async (req, res, next) => {
|
||||
const isAuthenticated = await authenticated(req)
|
||||
const NO_FOLDER_OR_WORKSPACE_QUERY = !req.query.folder && !req.query.workspace
|
||||
@ -81,17 +122,6 @@ export class CodeServerRouteWrapper {
|
||||
}
|
||||
|
||||
private $proxyRequest: express.Handler = async (req, res, next) => {
|
||||
// We allow certain errors to propagate so that other routers may handle requests
|
||||
// outside VS Code
|
||||
const requestErrorHandler = (error: any) => {
|
||||
if (error instanceof Error && ["EntryNotFound", "FileNotFound", "HttpError"].includes(error.message)) {
|
||||
next()
|
||||
}
|
||||
errorHandler(error, req, res, next)
|
||||
}
|
||||
|
||||
req.once("error", requestErrorHandler)
|
||||
|
||||
this._codeServerMain.handleRequest(req, res)
|
||||
}
|
||||
|
||||
@ -117,15 +147,14 @@ export class CodeServerRouteWrapper {
|
||||
|
||||
const { args } = req
|
||||
|
||||
/**
|
||||
* @file ../../../lib/vscode/src/vs/server/node/server.main.js
|
||||
*/
|
||||
const createVSServer = await loadAMDModule<CodeServerLib.CreateServer>("vs/server/node/server.main", "createServer")
|
||||
// See ../../../lib/vscode/src/vs/server/node/server.main.ts:72.
|
||||
const createVSServer = await loadAMDModule<CreateServer>("vs/server/node/server.main", "createServer")
|
||||
|
||||
try {
|
||||
this._codeServerMain = await createVSServer(null, {
|
||||
...(await toVsCodeArgs(args)),
|
||||
...(await toCodeArgs(args)),
|
||||
// TODO: Make the browser helper script work.
|
||||
"without-connection-token": true,
|
||||
"without-browser-env-var": true,
|
||||
})
|
||||
} catch (error) {
|
||||
@ -141,6 +170,7 @@ export class CodeServerRouteWrapper {
|
||||
|
||||
constructor() {
|
||||
this.router.get("/", this.ensureCodeServerLoaded, this.$root)
|
||||
this.router.get(/manifest.json$/, this.manifest)
|
||||
this.router.all("*", ensureAuthenticated, this.ensureCodeServerLoaded, this.$proxyRequest)
|
||||
this._wsRouterWrapper.ws("/", ensureAuthenticated, this.ensureCodeServerLoaded, this.$proxyWebsocket)
|
||||
}
|
||||
|
Reference in New Issue
Block a user