diff --git a/lib/vscode/.eslintignore b/lib/vscode/.eslintignore index be2d47d3..b67a8161 100644 --- a/lib/vscode/.eslintignore +++ b/lib/vscode/.eslintignore @@ -19,3 +19,4 @@ # These are code-server code symlinks. src/vs/base/node/proxy_agent.ts src/vs/ipc.d.ts +src/vs/server/common/util.ts diff --git a/lib/vscode/src/vs/server/browser/client.ts b/lib/vscode/src/vs/server/browser/client.ts index 16a82b0b..c1c5b450 100644 --- a/lib/vscode/src/vs/server/browser/client.ts +++ b/lib/vscode/src/vs/server/browser/client.ts @@ -13,10 +13,18 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { TelemetryChannelClient } from 'vs/server/common/telemetry'; +import { getOptions } from 'vs/server/common/util'; import 'vs/workbench/contrib/localizations/browser/localizations.contribution'; import 'vs/workbench/services/localizations/browser/localizationsService'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; +/** + * All client-side customization to VS Code should live in this file when + * possible. + */ + +const options = getOptions(); + class TelemetryService extends TelemetryChannelClient { public constructor( @IRemoteAgentService remoteAgentService: IRemoteAgentService, @@ -25,26 +33,6 @@ class TelemetryService extends TelemetryChannelClient { } } -/** - * Remove extra slashes in a URL. - */ -export const normalize = (url: string, keepTrailing = false): string => { - return url.replace(/\/\/+/g, '/').replace(/\/+$/, keepTrailing ? '/' : ''); -}; - -/** - * Get options embedded in the HTML. - */ -export const getOptions = (): T => { - try { - return JSON.parse(document.getElementById('coder-options')!.getAttribute('data-settings')!); - } catch (error) { - return {} as T; - } -}; - -const options = getOptions(); - const TELEMETRY_SECTION_ID = 'telemetry'; Registry.as(Extensions.Configuration).registerConfiguration({ 'id': TELEMETRY_SECTION_ID, diff --git a/lib/vscode/src/vs/server/common/util.ts b/lib/vscode/src/vs/server/common/util.ts new file mode 120000 index 00000000..625cfa1c --- /dev/null +++ b/lib/vscode/src/vs/server/common/util.ts @@ -0,0 +1 @@ +../../../../../../src/common/util.ts \ No newline at end of file diff --git a/src/browser/register.ts b/src/browser/register.ts index e99d64c6..00411110 100644 --- a/src/browser/register.ts +++ b/src/browser/register.ts @@ -1,3 +1,4 @@ +import { logger } from "@coder/logger" import { getOptions, normalize, logError } from "../common/util" import "./pages/error.css" @@ -6,6 +7,8 @@ import "./pages/login.css" export async function registerServiceWorker(): Promise { const options = getOptions() + logger.level = options.logLevel + const path = normalize(`${options.csStaticBase}/dist/serviceWorker.js`) try { await navigator.serviceWorker.register(path, { @@ -13,7 +16,7 @@ export async function registerServiceWorker(): Promise { }) console.log("[Service Worker] registered") } catch (error) { - logError(`[Service Worker] registration`, error) + logError(logger, `[Service Worker] registration`, error) } } diff --git a/src/common/util.ts b/src/common/util.ts index 87ca6f59..122cd176 100644 --- a/src/common/util.ts +++ b/src/common/util.ts @@ -1,5 +1,13 @@ -import { logger, field } from "@coder/logger" +/* + * This file exists in two locations: + * - src/common/util.ts + * - lib/vscode/src/vs/server/common/util.ts + * The second is a symlink to the first. + */ +/** + * Base options included on every page. + */ export interface Options { base: string csStaticBase: string @@ -78,13 +86,9 @@ export const getOptions = (): T => { } } - logger.level = options.logLevel - options.base = resolveBase(options.base) options.csStaticBase = resolveBase(options.csStaticBase) - logger.debug("got options", field("options", options)) - return options } @@ -113,7 +117,8 @@ export const getFirstString = (value: string | string[] | object | undefined): s return typeof value === "string" ? value : undefined } -export function logError(prefix: string, err: any): void { +// TODO: Might make sense to add Error handling to the logger itself. +export function logError(logger: { error: (msg: string) => void }, prefix: string, err: Error | string): void { if (err instanceof Error) { logger.error(`${prefix}: ${err.message} ${err.stack}`) } else { diff --git a/src/node/app.ts b/src/node/app.ts index b487dd8f..97ad62c3 100644 --- a/src/node/app.ts +++ b/src/node/app.ts @@ -37,7 +37,7 @@ export const createApp = async (args: DefaultedArgs): Promise<[Express, Express, reject(err) } else { // Promise resolved earlier so this is an unrelated error. - util.logError("http server error", err) + util.logError(logger, "http server error", err) } }) diff --git a/test/unit/util.test.ts b/test/unit/util.test.ts index e4d6349a..66ea0ce2 100644 --- a/test/unit/util.test.ts +++ b/test/unit/util.test.ts @@ -18,9 +18,6 @@ global.document = dom.window.document export type LocationLike = Pick -// jest.mock is hoisted above the imports so we must use `require` here. -jest.mock("@coder/logger", () => require("../utils/helpers").loggerModule) - describe("util", () => { describe("normalize", () => { it("should remove multiple slashes", () => { @@ -236,14 +233,14 @@ describe("util", () => { const message = "You don't have access to that folder." const error = new Error(message) - logError("ui", error) + logError(loggerModule.logger, "ui", error) expect(loggerModule.logger.error).toHaveBeenCalled() expect(loggerModule.logger.error).toHaveBeenCalledWith(`ui: ${error.message} ${error.stack}`) }) it("should log an error, even if not an instance of error", () => { - logError("api", "oh no") + logError(loggerModule.logger, "api", "oh no") expect(loggerModule.logger.error).toHaveBeenCalled() expect(loggerModule.logger.error).toHaveBeenCalledWith("api: oh no") diff --git a/test/utils/httpserver.ts b/test/utils/httpserver.ts index a66bbbff..bbd25a6c 100644 --- a/test/utils/httpserver.ts +++ b/test/utils/httpserver.ts @@ -1,3 +1,4 @@ +import { logger } from "@coder/logger" import * as express from "express" import * as http from "http" import * as net from "net" @@ -45,7 +46,7 @@ export class HttpServer { rej(err) } else { // Promise resolved earlier so this is some other error. - util.logError("http server error", err) + util.logError(logger, "http server error", err) } }) }) diff --git a/typings/ipc.d.ts b/typings/ipc.d.ts index c54004f2..e93e3ab1 100644 --- a/typings/ipc.d.ts +++ b/typings/ipc.d.ts @@ -8,8 +8,10 @@ export interface Options { authed: boolean base: string + csStaticBase: string disableTelemetry: boolean disableUpdateCheck: boolean + logLevel: number } export interface InitMessage {