Share common util code with VS Code

This lets us re-use the normalized base path so when we expire/clear the
cookie we use the same base path.
This commit is contained in:
Asher 2021-05-03 14:42:24 -05:00
parent 49c26f70f7
commit a48ac5080b
No known key found for this signature in database
GPG Key ID: D63C1EF81242354A
9 changed files with 32 additions and 34 deletions

View File

@ -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

View File

@ -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<Options>();
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 extends Options>(): 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<IConfigurationRegistry>(Extensions.Configuration).registerConfiguration({
'id': TELEMETRY_SECTION_ID,

View File

@ -0,0 +1 @@
../../../../../../src/common/util.ts

View File

@ -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<void> {
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<void> {
})
console.log("[Service Worker] registered")
} catch (error) {
logError(`[Service Worker] registration`, error)
logError(logger, `[Service Worker] registration`, error)
}
}

View File

@ -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 extends Options>(): 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 {

View File

@ -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)
}
})

View File

@ -18,9 +18,6 @@ global.document = dom.window.document
export type LocationLike = Pick<Location, "pathname" | "origin">
// 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")

View File

@ -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)
}
})
})

2
typings/ipc.d.ts vendored
View File

@ -8,8 +8,10 @@
export interface Options {
authed: boolean
base: string
csStaticBase: string
disableTelemetry: boolean
disableUpdateCheck: boolean
logLevel: number
}
export interface InitMessage {