Add base path to update endpoint from VS Code

This will make it work regardless of what the current URL happens to be.

Also move the telemetry setting into the options since we might as well
make use of it seeing as how we have to parse it for the base path
anyway.
This commit is contained in:
Asher 2020-03-13 16:44:56 -05:00
parent a00fa85d77
commit 6cb228037b
No known key found for this signature in database
GPG Key ID: D63C1EF81242354A
4 changed files with 75 additions and 25 deletions

View File

@ -486,10 +486,10 @@ index eab8591492..26668701f7 100644
options.logService.error(`${logPrefix} socketFactory.connect() failed. Error:`); options.logService.error(`${logPrefix} socketFactory.connect() failed. Error:`);
diff --git a/src/vs/server/browser/client.ts b/src/vs/server/browser/client.ts diff --git a/src/vs/server/browser/client.ts b/src/vs/server/browser/client.ts
new file mode 100644 new file mode 100644
index 0000000000..3f53907de0 index 0000000000..4042e32f74
--- /dev/null --- /dev/null
+++ b/src/vs/server/browser/client.ts +++ b/src/vs/server/browser/client.ts
@@ -0,0 +1,227 @@ @@ -0,0 +1,263 @@
+import { Emitter } from 'vs/base/common/event'; +import { Emitter } from 'vs/base/common/event';
+import { URI } from 'vs/base/common/uri'; +import { URI } from 'vs/base/common/uri';
+import { localize } from 'vs/nls'; +import { localize } from 'vs/nls';
@ -507,6 +507,7 @@ index 0000000000..3f53907de0
+import 'vs/workbench/contrib/localizations/browser/localizations.contribution'; +import 'vs/workbench/contrib/localizations/browser/localizations.contribution';
+import { LocalizationsService } from 'vs/workbench/services/localizations/electron-browser/localizationsService'; +import { LocalizationsService } from 'vs/workbench/services/localizations/electron-browser/localizationsService';
+import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; +import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
+import { Options } from 'vs/server/ipc.d';
+ +
+class TelemetryService extends TelemetryChannelClient { +class TelemetryService extends TelemetryChannelClient {
+ public constructor( + public constructor(
@ -516,11 +517,46 @@ index 0000000000..3f53907de0
+ } + }
+} +}
+ +
+/**
+ * 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 from the server.
+ */
+export const getOptions = <T extends Options>(): T => {
+ if (typeof document === "undefined") {
+ return {} as T;
+ }
+ const el = document.getElementById("coder-options");
+ try {
+ if (!el) {
+ throw new Error("no options element");
+ }
+ const value = el.getAttribute("data-settings");
+ if (!value) {
+ throw new Error("no options value");
+ }
+ const options = JSON.parse(value);
+ const parts = window.location.pathname.replace(/^\//g, "").split("/");
+ parts[parts.length - 1] = options.base;
+ const url = new URL(window.location.origin + "/" + parts.join("/"));
+ return {
+ ...options,
+ base: normalize(url.pathname, true),
+ };
+ } catch (error) {
+ console.warn(error);
+ return {} as T;
+ }
+};
+
+const options = getOptions();
+
+const TELEMETRY_SECTION_ID = 'telemetry'; +const TELEMETRY_SECTION_ID = 'telemetry';
+
+const el = document.getElementById("vscode-disable-telemetry");
+const disableTelemetry = el && el.getAttribute("data-value") === "true" || false;
+
+Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfiguration({ +Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfiguration({
+ 'id': TELEMETRY_SECTION_ID, + 'id': TELEMETRY_SECTION_ID,
+ 'order': 110, + 'order': 110,
@ -530,7 +566,7 @@ index 0000000000..3f53907de0
+ 'telemetry.enableTelemetry': { + 'telemetry.enableTelemetry': {
+ 'type': 'boolean', + 'type': 'boolean',
+ 'description': localize('telemetry.enableTelemetry', 'Enable usage data and errors to be sent to a Microsoft online service.'), + 'description': localize('telemetry.enableTelemetry', 'Enable usage data and errors to be sent to a Microsoft online service.'),
+ 'default': !disableTelemetry, + 'default': !options.disableTelemetry,
+ 'tags': ['usesOnlineServices'] + 'tags': ['usesOnlineServices']
+ } + }
+ } + }
@ -625,7 +661,7 @@ index 0000000000..3f53907de0
+ const applyUpdate = async (): Promise<void> => { + const applyUpdate = async (): Promise<void> => {
+ (services.get(ILogService) as ILogService).debug("Applying update..."); + (services.get(ILogService) as ILogService).debug("Applying update...");
+ +
+ const response = await fetch("./update/apply", { + const response = await fetch(normalize(`${options.base}/update/apply`), {
+ headers: { "content-type": "application/json" }, + headers: { "content-type": "application/json" },
+ }); + });
+ if (response.status !== 200) { + if (response.status !== 200) {
@ -643,7 +679,7 @@ index 0000000000..3f53907de0
+ const getUpdate = async (): Promise<void> => { + const getUpdate = async (): Promise<void> => {
+ (services.get(ILogService) as ILogService).debug("Checking for update..."); + (services.get(ILogService) as ILogService).debug("Checking for update...");
+ +
+ const response = await fetch("./update", { + const response = await fetch(normalize(`${options.base}/update`), {
+ headers: { "content-type": "application/json" }, + headers: { "content-type": "application/json" },
+ }); + });
+ if (response.status !== 200) { + if (response.status !== 200) {
@ -1076,14 +1112,20 @@ index 0000000000..56331ff1fc
+require('../../bootstrap-amd').load('vs/server/entry'); +require('../../bootstrap-amd').load('vs/server/entry');
diff --git a/src/vs/server/ipc.d.ts b/src/vs/server/ipc.d.ts diff --git a/src/vs/server/ipc.d.ts b/src/vs/server/ipc.d.ts
new file mode 100644 new file mode 100644
index 0000000000..a0d1d0df54 index 0000000000..15d2ba55d1
--- /dev/null --- /dev/null
+++ b/src/vs/server/ipc.d.ts +++ b/src/vs/server/ipc.d.ts
@@ -0,0 +1,108 @@ @@ -0,0 +1,114 @@
+/** +/**
+ * External interfaces for integration into code-server over IPC. No vs imports + * External interfaces for integration into code-server over IPC. No vs imports
+ * should be made in this file. + * should be made in this file.
+ */ + */
+export interface Options {
+ base: string
+ commit: string
+ disableTelemetry: boolean
+ nlsConfiguration: NLSConfiguration
+}
+ +
+export interface InitMessage { +export interface InitMessage {
+ type: 'init'; + type: 'init';

View File

@ -20,10 +20,8 @@
<!-- Workarounds/Hacks (remote user data uri) --> <!-- Workarounds/Hacks (remote user data uri) -->
<meta id="vscode-remote-user-data-uri" data-settings="{{REMOTE_USER_DATA_URI}}" /> <meta id="vscode-remote-user-data-uri" data-settings="{{REMOTE_USER_DATA_URI}}" />
<meta id="vscode-remote-commit" data-settings="{{COMMIT}}" />
<meta id="vscode-remote-product-configuration" data-settings="{{PRODUCT_CONFIGURATION}}" /> <meta id="vscode-remote-product-configuration" data-settings="{{PRODUCT_CONFIGURATION}}" />
<meta id="vscode-remote-nls-configuration" data-settings="{{NLS_CONFIGURATION}}" /> <meta id="vscode-remote-nls-configuration" data-settings="{{NLS_CONFIGURATION}}" />
<meta id="vscode-disable-telemetry" data-value="{{DISABLE_TELEMETRY}}" />
<!-- Workbench Icon/Manifest/CSS --> <!-- Workbench Icon/Manifest/CSS -->
<link rel="icon" href="{{BASE}}/static/{{COMMIT}}/src/browser/media/favicon.ico" type="image/x-icon" /> <link rel="icon" href="{{BASE}}/static/{{COMMIT}}/src/browser/media/favicon.ico" type="image/x-icon" />
@ -53,9 +51,7 @@
const parts = window.location.pathname.replace(/^\//g, "").split("/") const parts = window.location.pathname.replace(/^\//g, "").split("/")
parts[parts.length - 1] = "{{BASE}}" parts[parts.length - 1] = "{{BASE}}"
const url = new URL(window.location.origin + "/" + parts.join("/")) const url = new URL(window.location.origin + "/" + parts.join("/"))
const el = document.getElementById("vscode-remote-commit") const staticBase = url.href.replace(/\/+$/, "") + "/static/{{COMMIT}}/lib/vscode"
const commit = el ? el.getAttribute("data-settings") : ""
const staticBase = url.href.replace(/\/+$/, "") + "/static/" + commit + "/lib/vscode"
let nlsConfig let nlsConfig
try { try {
nlsConfig = JSON.parse(document.getElementById("vscode-remote-nls-configuration").getAttribute("data-settings")) nlsConfig = JSON.parse(document.getElementById("vscode-remote-nls-configuration").getAttribute("data-settings"))

View File

@ -8,6 +8,7 @@ import * as path from "path"
import * as url from "url" import * as url from "url"
import { import {
CodeServerMessage, CodeServerMessage,
Options,
StartPath, StartPath,
VscodeMessage, VscodeMessage,
VscodeOptions, VscodeOptions,
@ -205,8 +206,11 @@ export class VscodeHttpProvider extends HttpProvider {
.replace(`"{{PRODUCT_CONFIGURATION}}"`, `'${JSON.stringify(options.productConfiguration)}'`) .replace(`"{{PRODUCT_CONFIGURATION}}"`, `'${JSON.stringify(options.productConfiguration)}'`)
.replace(`"{{WORKBENCH_WEB_CONFIGURATION}}"`, `'${JSON.stringify(options.workbenchWebConfiguration)}'`) .replace(`"{{WORKBENCH_WEB_CONFIGURATION}}"`, `'${JSON.stringify(options.workbenchWebConfiguration)}'`)
.replace(`"{{NLS_CONFIGURATION}}"`, `'${JSON.stringify(options.nlsConfiguration)}'`) .replace(`"{{NLS_CONFIGURATION}}"`, `'${JSON.stringify(options.nlsConfiguration)}'`)
.replace("{{DISABLE_TELEMETRY}}", this.args["disable-telemetry"] ? "true" : "false") return this.replaceTemplates<Options>(route, response, {
return this.replaceTemplates(route, response) base: this.base(route),
commit: this.options.commit,
disableTelemetry: !!this.args["disable-telemetry"],
})
} }
/** /**

View File

@ -185,22 +185,30 @@ export abstract class HttpProvider {
/** /**
* Replace common templates strings. * Replace common templates strings.
*/ */
protected replaceTemplates(route: Route, response: HttpStringFileResponse, sessionId?: string): HttpStringFileResponse
protected replaceTemplates<T extends object>(
route: Route,
response: HttpStringFileResponse,
options: T,
): HttpStringFileResponse
protected replaceTemplates( protected replaceTemplates(
route: Route, route: Route,
response: HttpStringFileResponse, response: HttpStringFileResponse,
sessionId?: string, sessionIdOrOptions?: string | object,
): HttpStringFileResponse { ): HttpStringFileResponse {
const options: Options = { if (typeof sessionIdOrOptions === "undefined" || typeof sessionIdOrOptions === "string") {
sessionIdOrOptions = {
base: this.base(route), base: this.base(route),
commit: this.options.commit, commit: this.options.commit,
logLevel: logger.level, logLevel: logger.level,
sessionId, sessionID: sessionIdOrOptions,
} as Options
} }
response.content = response.content response.content = response.content
.replace(/{{COMMIT}}/g, this.options.commit) .replace(/{{COMMIT}}/g, this.options.commit)
.replace(/{{TO}}/g, Array.isArray(route.query.to) ? route.query.to[0] : route.query.to || "/dashboard") .replace(/{{TO}}/g, Array.isArray(route.query.to) ? route.query.to[0] : route.query.to || "/dashboard")
.replace(/{{BASE}}/g, this.base(route)) .replace(/{{BASE}}/g, this.base(route))
.replace(/"{{OPTIONS}}"/, `'${JSON.stringify(options)}'`) .replace(/"{{OPTIONS}}"/, `'${JSON.stringify(sessionIdOrOptions)}'`)
return response return response
} }