mirror of
https://github.com/coder/code-server.git
synced 2026-02-04 20:46:08 +08:00
* Add tests for relativeRoot * Remove path.posix.join Since this is for file system paths it feels incorrect to use it on URL paths as they are different in many ways. * Rewrite cookie path logic Before we relied on the client to resolve the base given to it by the backend against the path. Instead have the client pass that information along so we can resolve it on the backend. This means the client has to do less work. * Do not remove out directory before watch This is re-used for incremental compilation. Also remove del since that was the only use (and we can use fs.rmdir in the future if we need something like this). * Remove unused function resolveBase
117 lines
3.4 KiB
TypeScript
117 lines
3.4 KiB
TypeScript
import { logger } from "@coder/logger"
|
|
import * as express from "express"
|
|
import { WebsocketRequest } from "../../../typings/pluginapi"
|
|
import { logError } from "../../common/util"
|
|
import { isDevMode } from "../constants"
|
|
import { ensureAuthenticated, authenticated, redirect } from "../http"
|
|
import { loadAMDModule, readCompilationStats } from "../util"
|
|
import { Router as WsRouter } from "../wsRouter"
|
|
import { errorHandler } from "./errors"
|
|
|
|
export class CodeServerRouteWrapper {
|
|
/** Assigned in `ensureCodeServerLoaded` */
|
|
private _codeServerMain!: CodeServerLib.IServerAPI
|
|
private _wsRouterWrapper = WsRouter()
|
|
public router = express.Router()
|
|
|
|
public get wsRouter() {
|
|
return this._wsRouterWrapper.router
|
|
}
|
|
|
|
//#region Route Handlers
|
|
|
|
private $root: express.Handler = async (req, res, next) => {
|
|
const isAuthenticated = await authenticated(req)
|
|
|
|
if (!isAuthenticated) {
|
|
return redirect(req, res, "login", {
|
|
// req.baseUrl can be blank if already at the root.
|
|
to: req.baseUrl && req.baseUrl !== "/" ? req.baseUrl : undefined,
|
|
})
|
|
}
|
|
|
|
next()
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
private $proxyWebsocket = async (req: WebsocketRequest) => {
|
|
this._codeServerMain.handleUpgrade(req, req.socket)
|
|
|
|
req.socket.resume()
|
|
}
|
|
|
|
//#endregion
|
|
|
|
/**
|
|
* Fetches a code server instance asynchronously to avoid an initial memory overhead.
|
|
*/
|
|
private ensureCodeServerLoaded: express.Handler = async (req, _res, next) => {
|
|
if (this._codeServerMain) {
|
|
// Already loaded...
|
|
return next()
|
|
}
|
|
|
|
if (isDevMode) {
|
|
// Is the development mode file watcher still busy?
|
|
const compileStats = await readCompilationStats()
|
|
|
|
if (!compileStats || !compileStats.lastCompiledAt) {
|
|
return next(new Error("VS Code may still be compiling..."))
|
|
}
|
|
}
|
|
|
|
// Create the server...
|
|
|
|
const { args } = req
|
|
|
|
/**
|
|
* @file ../../../vendor/modules/code-oss-dev/src/vs/server/main.js
|
|
*/
|
|
const createVSServer = await loadAMDModule<CodeServerLib.CreateServer>(
|
|
"vs/server/remoteExtensionHostAgent",
|
|
"createServer",
|
|
)
|
|
|
|
try {
|
|
this._codeServerMain = await createVSServer(null, {
|
|
"connection-token": "0000",
|
|
"accept-server-license-terms": true,
|
|
...args,
|
|
/** Type casting. */
|
|
help: !!args.help,
|
|
version: !!args.version,
|
|
port: args.port?.toString(),
|
|
})
|
|
} catch (createServerError) {
|
|
logError(logger, "CodeServerRouteWrapper", createServerError)
|
|
return next(createServerError)
|
|
}
|
|
|
|
return next()
|
|
}
|
|
|
|
constructor() {
|
|
this.router.get("/", this.ensureCodeServerLoaded, this.$root)
|
|
this.router.all("*", ensureAuthenticated, this.ensureCodeServerLoaded, this.$proxyRequest)
|
|
this._wsRouterWrapper.ws("/", ensureAuthenticated, this.ensureCodeServerLoaded, this.$proxyWebsocket)
|
|
}
|
|
|
|
dispose() {
|
|
this._codeServerMain?.dispose()
|
|
}
|
|
}
|