diff --git a/src/node/app/vscode.ts b/src/node/app/vscode.ts index e80a2b23..a41212ca 100644 --- a/src/node/app/vscode.ts +++ b/src/node/app/vscode.ts @@ -134,7 +134,6 @@ export class VscodeHttpProvider extends HttpProvider { return { redirect: "/login", query: { to: this.options.base } } } try { - this.persistRouteQuery(request, route) return await this.getRoot(request, route) } catch (error) { const message = `
VS Code failed to load.
${ @@ -165,13 +164,6 @@ export class VscodeHttpProvider extends HttpProvider { throw new HttpError("Not found", HttpCode.NotFound) } - - private persistRouteQuery(request: http.IncomingMessage, route: Route): void { - const content = Object.keys(route.query).reduce((content, next) => { - return (content += `${next}=${route.query[next]}\n`) - }, "") - fs.writeFile(path.resolve(paths.data, "query"), content) - } private async getRoot(request: http.IncomingMessage, route: Route): Promise { const remoteAuthority = request.headers.host as string @@ -191,11 +183,15 @@ export class VscodeHttpProvider extends HttpProvider { }), ]) + let promise = Promise.resolve() if (startPath) { - settings.write({ - lastVisited: startPath, - }) + promise = settings.write({ lastVisited: startPath }) } + // `settings.write` depends on `settings.read` internally. To avoid race conditions, a promise is added here to synchronize. + promise.then(() => { + // the query should not be extends, but should be replaced directly. + settings.write({ query: route.query }, true) + }) if (!this.isDev) { response.content = response.content.replace(//g, "") diff --git a/src/node/settings.ts b/src/node/settings.ts index 32166ddb..abb8f63b 100644 --- a/src/node/settings.ts +++ b/src/node/settings.ts @@ -2,6 +2,7 @@ import * as fs from "fs-extra" import * as path from "path" import { extend, paths } from "./util" import { logger } from "@coder/logger" +import { Route } from "./http" export type Settings = { [key: string]: Settings | string | boolean | number } @@ -31,9 +32,11 @@ export class SettingsProvider { * Write settings combined with current settings. On failure log a warning. * Objects will be merged and everything else will be replaced. */ - public async write(settings: Partial): Promise { + public async write(settings: Partial, shallow?: boolean): Promise { try { - await fs.writeFile(this.settingsPath, JSON.stringify(extend(await this.read(), settings), null, 2)) + const oldSettings = await this.read() + const nextSettings = shallow ? Object.assign({}, oldSettings, settings) : extend(oldSettings, settings) + await fs.writeFile(this.settingsPath, JSON.stringify(nextSettings, null, 2)) } catch (error) { logger.warn(error.message) } @@ -55,6 +58,7 @@ export interface CoderSettings extends UpdateSettings { url: string workspace: boolean } + query: Route["query"] } /**