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:
parent
49c26f70f7
commit
a48ac5080b
@ -19,3 +19,4 @@
|
|||||||
# These are code-server code symlinks.
|
# These are code-server code symlinks.
|
||||||
src/vs/base/node/proxy_agent.ts
|
src/vs/base/node/proxy_agent.ts
|
||||||
src/vs/ipc.d.ts
|
src/vs/ipc.d.ts
|
||||||
|
src/vs/server/common/util.ts
|
||||||
|
@ -13,10 +13,18 @@ import { Registry } from 'vs/platform/registry/common/platform';
|
|||||||
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||||
import { TelemetryChannelClient } from 'vs/server/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/contrib/localizations/browser/localizations.contribution';
|
||||||
import 'vs/workbench/services/localizations/browser/localizationsService';
|
import 'vs/workbench/services/localizations/browser/localizationsService';
|
||||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
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 {
|
class TelemetryService extends TelemetryChannelClient {
|
||||||
public constructor(
|
public constructor(
|
||||||
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
|
@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';
|
const TELEMETRY_SECTION_ID = 'telemetry';
|
||||||
Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfiguration({
|
Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfiguration({
|
||||||
'id': TELEMETRY_SECTION_ID,
|
'id': TELEMETRY_SECTION_ID,
|
||||||
|
1
lib/vscode/src/vs/server/common/util.ts
Symbolic link
1
lib/vscode/src/vs/server/common/util.ts
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../../../../../src/common/util.ts
|
@ -1,3 +1,4 @@
|
|||||||
|
import { logger } from "@coder/logger"
|
||||||
import { getOptions, normalize, logError } from "../common/util"
|
import { getOptions, normalize, logError } from "../common/util"
|
||||||
|
|
||||||
import "./pages/error.css"
|
import "./pages/error.css"
|
||||||
@ -6,6 +7,8 @@ import "./pages/login.css"
|
|||||||
|
|
||||||
export async function registerServiceWorker(): Promise<void> {
|
export async function registerServiceWorker(): Promise<void> {
|
||||||
const options = getOptions()
|
const options = getOptions()
|
||||||
|
logger.level = options.logLevel
|
||||||
|
|
||||||
const path = normalize(`${options.csStaticBase}/dist/serviceWorker.js`)
|
const path = normalize(`${options.csStaticBase}/dist/serviceWorker.js`)
|
||||||
try {
|
try {
|
||||||
await navigator.serviceWorker.register(path, {
|
await navigator.serviceWorker.register(path, {
|
||||||
@ -13,7 +16,7 @@ export async function registerServiceWorker(): Promise<void> {
|
|||||||
})
|
})
|
||||||
console.log("[Service Worker] registered")
|
console.log("[Service Worker] registered")
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logError(`[Service Worker] registration`, error)
|
logError(logger, `[Service Worker] registration`, error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
export interface Options {
|
||||||
base: string
|
base: string
|
||||||
csStaticBase: string
|
csStaticBase: string
|
||||||
@ -78,13 +86,9 @@ export const getOptions = <T extends Options>(): T => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.level = options.logLevel
|
|
||||||
|
|
||||||
options.base = resolveBase(options.base)
|
options.base = resolveBase(options.base)
|
||||||
options.csStaticBase = resolveBase(options.csStaticBase)
|
options.csStaticBase = resolveBase(options.csStaticBase)
|
||||||
|
|
||||||
logger.debug("got options", field("options", options))
|
|
||||||
|
|
||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +117,8 @@ export const getFirstString = (value: string | string[] | object | undefined): s
|
|||||||
return typeof value === "string" ? value : undefined
|
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) {
|
if (err instanceof Error) {
|
||||||
logger.error(`${prefix}: ${err.message} ${err.stack}`)
|
logger.error(`${prefix}: ${err.message} ${err.stack}`)
|
||||||
} else {
|
} else {
|
||||||
|
@ -37,7 +37,7 @@ export const createApp = async (args: DefaultedArgs): Promise<[Express, Express,
|
|||||||
reject(err)
|
reject(err)
|
||||||
} else {
|
} else {
|
||||||
// Promise resolved earlier so this is an unrelated error.
|
// Promise resolved earlier so this is an unrelated error.
|
||||||
util.logError("http server error", err)
|
util.logError(logger, "http server error", err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -18,9 +18,6 @@ global.document = dom.window.document
|
|||||||
|
|
||||||
export type LocationLike = Pick<Location, "pathname" | "origin">
|
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("util", () => {
|
||||||
describe("normalize", () => {
|
describe("normalize", () => {
|
||||||
it("should remove multiple slashes", () => {
|
it("should remove multiple slashes", () => {
|
||||||
@ -236,14 +233,14 @@ describe("util", () => {
|
|||||||
const message = "You don't have access to that folder."
|
const message = "You don't have access to that folder."
|
||||||
const error = new Error(message)
|
const error = new Error(message)
|
||||||
|
|
||||||
logError("ui", error)
|
logError(loggerModule.logger, "ui", error)
|
||||||
|
|
||||||
expect(loggerModule.logger.error).toHaveBeenCalled()
|
expect(loggerModule.logger.error).toHaveBeenCalled()
|
||||||
expect(loggerModule.logger.error).toHaveBeenCalledWith(`ui: ${error.message} ${error.stack}`)
|
expect(loggerModule.logger.error).toHaveBeenCalledWith(`ui: ${error.message} ${error.stack}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should log an error, even if not an instance of error", () => {
|
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).toHaveBeenCalled()
|
||||||
expect(loggerModule.logger.error).toHaveBeenCalledWith("api: oh no")
|
expect(loggerModule.logger.error).toHaveBeenCalledWith("api: oh no")
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { logger } from "@coder/logger"
|
||||||
import * as express from "express"
|
import * as express from "express"
|
||||||
import * as http from "http"
|
import * as http from "http"
|
||||||
import * as net from "net"
|
import * as net from "net"
|
||||||
@ -45,7 +46,7 @@ export class HttpServer {
|
|||||||
rej(err)
|
rej(err)
|
||||||
} else {
|
} else {
|
||||||
// Promise resolved earlier so this is some other error.
|
// 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
2
typings/ipc.d.ts
vendored
@ -8,8 +8,10 @@
|
|||||||
export interface Options {
|
export interface Options {
|
||||||
authed: boolean
|
authed: boolean
|
||||||
base: string
|
base: string
|
||||||
|
csStaticBase: string
|
||||||
disableTelemetry: boolean
|
disableTelemetry: boolean
|
||||||
disableUpdateCheck: boolean
|
disableUpdateCheck: boolean
|
||||||
|
logLevel: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InitMessage {
|
export interface InitMessage {
|
||||||
|
Reference in New Issue
Block a user