diff --git a/src/node/app/vscode.ts b/src/node/app/vscode.ts
index e80a2b238..a41212ca6 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 32166ddb7..abb8f63b7 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"]
}
/**