diff --git a/src/vs/base/common/network.ts b/src/vs/base/common/network.ts index a68e020f9f..b4ee8a5886 100644 --- a/src/vs/base/common/network.ts +++ b/src/vs/base/common/network.ts @@ -88,7 +88,7 @@ class RemoteAuthoritiesImpl { if (host && host.indexOf(':') !== -1) { host = `[${host}]`; } - const port = this._ports[authority]; + // const port = this._ports[authority]; const connectionToken = this._connectionTokens[authority]; let query = `path=${encodeURIComponent(uri.path)}`; if (typeof connectionToken === 'string') { @@ -96,8 +96,8 @@ class RemoteAuthoritiesImpl { } return URI.from({ scheme: platform.isWeb ? this._preferredWebSchema : Schemas.vscodeRemoteResource, - authority: `${host}:${port}`, - path: `/vscode-remote-resource`, + authority: window.location.host, + path: `${window.location.pathname.replace(/\/+$/, '')}/vscode-remote-resource`, query }); } diff --git a/src/vs/base/common/platform.ts b/src/vs/base/common/platform.ts index 5a631e0b39..8a2b1518d6 100644 --- a/src/vs/base/common/platform.ts +++ b/src/vs/base/common/platform.ts @@ -59,6 +59,17 @@ if (typeof navigator === 'object' && !isElectronRenderer) { _isWeb = true; _locale = navigator.language; _language = _locale; + // NOTE@coder: make languages work. + const el = typeof document !== 'undefined' && document.getElementById('vscode-remote-nls-configuration'); + const rawNlsConfig = el && el.getAttribute('data-settings'); + if (rawNlsConfig) { + try { + const nlsConfig: NLSConfig = JSON.parse(rawNlsConfig); + _locale = nlsConfig.locale; + _translationsConfigFile = nlsConfig._translationsConfigFile; + _language = nlsConfig.availableLanguages['*'] || LANGUAGE_DEFAULT; + } catch (error) { /* Oh well. */ } + } } else if (typeof process === 'object') { _isWindows = (process.platform === 'win32'); _isMacintosh = (process.platform === 'darwin'); diff --git a/src/vs/base/common/processes.ts b/src/vs/base/common/processes.ts index c52f7b3774..5a7e7f579e 100644 --- a/src/vs/base/common/processes.ts +++ b/src/vs/base/common/processes.ts @@ -110,7 +110,10 @@ export function sanitizeProcessEnvironment(env: IProcessEnvironment, ...preserve /^ELECTRON_.+$/, /^GOOGLE_API_KEY$/, /^VSCODE_.+$/, - /^SNAP(|_.*)$/ + /^SNAP(|_.*)$/, + // NOTE@coder: add our own environment variables. + /^NBIN_BYPASS$/, + /^LAUNCH_VSCODE$/ ]; const envKeys = Object.keys(env); envKeys diff --git a/src/vs/base/node/languagePacks.js b/src/vs/base/node/languagePacks.js index 2c64061da7..c0ef8faedd 100644 --- a/src/vs/base/node/languagePacks.js +++ b/src/vs/base/node/languagePacks.js @@ -128,7 +128,10 @@ function factory(nodeRequire, path, fs, perf) { function getLanguagePackConfigurations(userDataPath) { const configFile = path.join(userDataPath, 'languagepacks.json'); try { - return nodeRequire(configFile); + // NOTE@coder: Swapped require with readFile since require is cached and + // we don't restart the server-side portion of code-server when the + // language changes. + return JSON.parse(fs.readFileSync(configFile, "utf8")); } catch (err) { // Do nothing. If we can't read the file we have no // language pack config. diff --git a/src/vs/code/browser/workbench/workbench.ts b/src/vs/code/browser/workbench/workbench.ts index a599f5a7eb..ec7ccd43f8 100644 --- a/src/vs/code/browser/workbench/workbench.ts +++ b/src/vs/code/browser/workbench/workbench.ts @@ -298,35 +298,6 @@ class WorkspaceProvider implements IWorkspaceProvider { let workspace: IWorkspace; let payload = Object.create(null); - const query = new URL(document.location.href).searchParams; - query.forEach((value, key) => { - switch (key) { - - // Folder - case WorkspaceProvider.QUERY_PARAM_FOLDER: - workspace = { folderUri: URI.parse(value) }; - foundWorkspace = true; - break; - - // Workspace - case WorkspaceProvider.QUERY_PARAM_WORKSPACE: - workspace = { workspaceUri: URI.parse(value) }; - foundWorkspace = true; - break; - - // Empty - case WorkspaceProvider.QUERY_PARAM_EMPTY_WINDOW: - workspace = undefined; - foundWorkspace = true; - break; - - // Payload - case WorkspaceProvider.QUERY_PARAM_PAYLOAD: - payload = JSON.parse(value); - break; - } - }); - // If no workspace is provided through the URL, check for config attribute from server if (!foundWorkspace) { if (config.folderUri) { diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index abd1e33b18..bf75952ce1 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -37,6 +37,8 @@ export interface ParsedArgs { logExtensionHostCommunication?: boolean; 'extensions-dir'?: string; 'builtin-extensions-dir'?: string; + 'extra-extensions-dir'?: string[]; + 'extra-builtin-extensions-dir'?: string[]; extensionDevelopmentPath?: string[]; // // undefined or array of 1 or more local paths or URIs extensionTestsPath?: string; // either a local path or a URI 'extension-development-confirm-save'?: boolean; @@ -147,6 +149,8 @@ export interface IEnvironmentService extends IUserHomeProvider { disableExtensions: boolean | string[]; builtinExtensionsPath: string; extensionsPath?: string; + extraExtensionPaths: string[]; + extraBuiltinExtensionPaths: string[]; extensionDevelopmentLocationURI?: URI[]; extensionTestsLocationURI?: URI; logExtensionHostCommunication?: boolean; diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index e68e0647c3..49a5aae2fa 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -55,6 +55,8 @@ export const OPTIONS: OptionDescriptions> = { 'extensions-dir': { type: 'string', deprecates: 'extensionHomePath', cat: 'e', args: 'dir', description: localize('extensionHomePath', "Set the root path for extensions.") }, 'builtin-extensions-dir': { type: 'string' }, + 'extra-builtin-extensions-dir': { type: 'string[]', cat: 'o', description: 'Path to an extra builtin extension directory.' }, + 'extra-extensions-dir': { type: 'string[]', cat: 'o', description: 'Path to an extra user extension directory.' }, 'list-extensions': { type: 'boolean', cat: 'e', description: localize('listExtensions', "List the installed extensions.") }, 'show-versions': { type: 'boolean', cat: 'e', description: localize('showVersions', "Show versions of installed extensions, when using --list-extension.") }, 'category': { type: 'string', cat: 'e', description: localize('category', "Filters installed extensions by provided category, when using --list-extension.") }, @@ -310,4 +312,3 @@ export function buildHelpMessage(productName: string, executableName: string, ve export function buildVersionMessage(version: string | undefined, commit: string | undefined): string { return `${version || localize('unknownVersion', "Unknown version")}\n${commit || localize('unknownCommit', "Unknown commit")}\n${process.arch}`; } - diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts index 0428e1e888..9b3cddcb3a 100644 --- a/src/vs/platform/environment/node/environmentService.ts +++ b/src/vs/platform/environment/node/environmentService.ts @@ -197,6 +197,13 @@ export class EnvironmentService implements IEnvironmentService { return path.join(this.userHome, product.dataFolderName, 'extensions'); } + @memoize get extraExtensionPaths(): string[] { + return (this._args['extra-extensions-dir'] || []).map((p) => parsePathArg(p, process)); + } + @memoize get extraBuiltinExtensionPaths(): string[] { + return (this._args['extra-builtin-extensions-dir'] || []).map((p) => parsePathArg(p, process)); + } + @memoize get extensionDevelopmentLocationURI(): URI[] | undefined { const s = this._args.extensionDevelopmentPath; diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index 5b05650591..dc5140410e 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -743,11 +743,15 @@ export class ExtensionManagementService extends Disposable implements IExtension private scanSystemExtensions(): Promise { this.logService.trace('Started scanning system extensions'); - const systemExtensionsPromise = this.scanExtensions(this.systemExtensionsPath, ExtensionType.System) - .then(result => { - this.logService.trace('Scanned system extensions:', result.length); - return result; - }); + const systemExtensionsPromise = Promise.all([ + this.scanExtensions(this.systemExtensionsPath, ExtensionType.System), + ...this.environmentService.extraBuiltinExtensionPaths + .map((path) => this.scanExtensions(path, ExtensionType.System)) + ]).then((results) => { + const result = results.reduce((flat, current) => flat.concat(current), []); + this.logService.trace('Scanned system extensions:', result.length); + return result; + }); if (this.environmentService.isBuilt) { return systemExtensionsPromise; } @@ -769,9 +773,17 @@ export class ExtensionManagementService extends Disposable implements IExtension .then(([systemExtensions, devSystemExtensions]) => [...systemExtensions, ...devSystemExtensions]); } + private scanAllUserExtensions(folderName: string, type: ExtensionType): Promise { + return Promise.all([ + this.scanExtensions(folderName, type), + ...this.environmentService.extraExtensionPaths.map((p) => this.scanExtensions(p, ExtensionType.User)) + ]).then((results) => results.reduce((flat, current) => flat.concat(current), [])); + } + + private scanUserExtensions(excludeOutdated: boolean): Promise { this.logService.trace('Started scanning user extensions'); - return Promise.all([this.getUninstalledExtensions(), this.scanExtensions(this.extensionsPath, ExtensionType.User)]) + return Promise.all([this.getUninstalledExtensions(), this.scanAllUserExtensions(this.extensionsPath, ExtensionType.User)]) .then(([uninstalled, extensions]) => { extensions = extensions.filter(e => !uninstalled[new ExtensionIdentifierWithVersion(e.identifier, e.manifest.version).key()]); if (excludeOutdated) { @@ -786,6 +798,12 @@ export class ExtensionManagementService extends Disposable implements IExtension private scanExtensions(root: string, type: ExtensionType): Promise { const limiter = new Limiter(10); return pfs.readdir(root) + .catch((error) => { + if (error.code !== 'ENOENT') { + throw error; + } + return []; + }) .then(extensionsFolders => Promise.all(extensionsFolders.map(extensionFolder => limiter.queue(() => this.scanExtension(extensionFolder, root, type))))) .then(extensions => extensions.filter(e => e && e.identifier)); } @@ -824,7 +842,7 @@ export class ExtensionManagementService extends Disposable implements IExtension private async removeUninstalledExtensions(): Promise { const uninstalled = await this.getUninstalledExtensions(); - const extensions = await this.scanExtensions(this.extensionsPath, ExtensionType.User); // All user extensions + const extensions = await this.scanAllUserExtensions(this.extensionsPath, ExtensionType.User); // All user extensions const installed: Set = new Set(); for (const e of extensions) { if (!uninstalled[new ExtensionIdentifierWithVersion(e.identifier, e.manifest.version).key()]) { @@ -843,7 +861,7 @@ export class ExtensionManagementService extends Disposable implements IExtension } private removeOutdatedExtensions(): Promise { - return this.scanExtensions(this.extensionsPath, ExtensionType.User) // All user extensions + return this.scanAllUserExtensions(this.extensionsPath, ExtensionType.User) // All user extensions .then(extensions => { const toRemove: ILocalExtension[] = []; diff --git a/src/vs/platform/product/common/product.ts b/src/vs/platform/product/common/product.ts index 804d113856..4b651e5c77 100644 --- a/src/vs/platform/product/common/product.ts +++ b/src/vs/platform/product/common/product.ts @@ -22,11 +22,19 @@ if (isWeb) { if (Object.keys(product).length === 0) { assign(product, { version: '1.41.0-dev', + codeServerVersion: 'dev', nameLong: 'Visual Studio Code Web Dev', nameShort: 'VSCode Web Dev', urlProtocol: 'code-oss' }); } + + // NOTE@coder: enable injecting settings from the server. + const el = document.getElementById('vscode-remote-product-configuration'); + const rawProductConfiguration = el && el.getAttribute('data-settings'); + if (rawProductConfiguration) { + assign(product, JSON.parse(rawProductConfiguration)); + } } // Node: AMD loader @@ -36,7 +44,7 @@ else if (typeof require !== 'undefined' && typeof require.__$__nodeRequire === ' const rootPath = path.dirname(getPathFromAmdModule(require, '')); product = assign({}, require.__$__nodeRequire(path.join(rootPath, 'product.json')) as IProductConfiguration); - const pkg = require.__$__nodeRequire(path.join(rootPath, 'package.json')) as { version: string; }; + const pkg = require.__$__nodeRequire(path.join(rootPath, 'package.json')) as { version: string; codeServerVersion: string; }; // Running out of sources if (env['VSCODE_DEV']) { @@ -48,7 +56,8 @@ else if (typeof require !== 'undefined' && typeof require.__$__nodeRequire === ' } assign(product, { - version: pkg.version + version: pkg.version, + codeServerVersion: pkg.codeServerVersion, }); } diff --git a/src/vs/platform/product/common/productService.ts b/src/vs/platform/product/common/productService.ts index 120fd66644..52547bdb0e 100644 --- a/src/vs/platform/product/common/productService.ts +++ b/src/vs/platform/product/common/productService.ts @@ -16,6 +16,7 @@ export interface IProductService extends Readonly { export interface IProductConfiguration { readonly version: string; + readonly codeServerVersion: string; readonly date?: string; readonly quality?: string; readonly commit?: string; diff --git a/src/vs/platform/remote/browser/browserSocketFactory.ts b/src/vs/platform/remote/browser/browserSocketFactory.ts index d0f6e6b18a..1966fd297d 100644 --- a/src/vs/platform/remote/browser/browserSocketFactory.ts +++ b/src/vs/platform/remote/browser/browserSocketFactory.ts @@ -205,7 +205,8 @@ export class BrowserSocketFactory implements ISocketFactory { } connect(host: string, port: number, query: string, callback: IConnectCallback): void { - const socket = this._webSocketFactory.create(`ws://${host}:${port}/?${query}&skipWebSocketFrames=false`); + // NOTE@coder: Modified to work against the current path. + const socket = this._webSocketFactory.create(`${window.location.protocol === 'https:' ? 'wss' : 'ws'}://${window.location.host}${window.location.pathname}?${query}&skipWebSocketFrames=false`); const errorListener = socket.onError((err) => callback(err, undefined)); socket.onOpen(() => { errorListener.dispose(); @@ -213,6 +214,3 @@ export class BrowserSocketFactory implements ISocketFactory { }); } } - - - diff --git a/src/vs/platform/request/common/request.ts b/src/vs/platform/request/common/request.ts index 81ec255e65..c94829fc6a 100644 --- a/src/vs/platform/request/common/request.ts +++ b/src/vs/platform/request/common/request.ts @@ -16,7 +16,7 @@ export const IRequestService = createDecorator('requestService' export interface IRequestService { _serviceBrand: undefined; - request(options: IRequestOptions, token: CancellationToken): Promise; + request(options: IRequestOptions, token: CancellationToken, gzip?: boolean): Promise; resolveProxy(url: string): Promise; } diff --git a/src/vs/platform/request/node/requestService.ts b/src/vs/platform/request/node/requestService.ts index ad44dcbc33..7a7b5261ff 100644 --- a/src/vs/platform/request/node/requestService.ts +++ b/src/vs/platform/request/node/requestService.ts @@ -57,7 +57,7 @@ export class RequestService extends Disposable implements IRequestService { this.authorization = config.http && config.http.proxyAuthorization; } - async request(options: NodeRequestOptions, token: CancellationToken): Promise { + async request(options: NodeRequestOptions, token: CancellationToken, gzip?: boolean): Promise { this.logService.trace('RequestService#request', options.url); const { proxyUrl, strictSSL } = this; @@ -70,7 +70,7 @@ export class RequestService extends Disposable implements IRequestService { options.headers = assign(options.headers || {}, { 'Proxy-Authorization': this.authorization }); } - return this._request(options, token); + return this._request(options, token, gzip); } private async getNodeRequest(options: IRequestOptions): Promise { @@ -79,7 +79,7 @@ export class RequestService extends Disposable implements IRequestService { return module.request; } - private _request(options: NodeRequestOptions, token: CancellationToken): Promise { + private _request(options: NodeRequestOptions, token: CancellationToken, gzip?: boolean): Promise { return new Promise(async (c, e) => { let req: http.ClientRequest; @@ -114,7 +114,7 @@ export class RequestService extends Disposable implements IRequestService { } else { let stream: streams.ReadableStream = res; - if (res.headers['content-encoding'] === 'gzip') { + if (gzip || res.headers['content-encoding'] === 'gzip') { stream = res.pipe(createGunzip()); } diff --git a/src/vs/platform/update/electron-main/abstractUpdateService.ts b/src/vs/platform/update/electron-main/abstractUpdateService.ts index d8bf464fed..748715da3b 100644 --- a/src/vs/platform/update/electron-main/abstractUpdateService.ts +++ b/src/vs/platform/update/electron-main/abstractUpdateService.ts @@ -6,7 +6,6 @@ import { Event, Emitter } from 'vs/base/common/event'; import { timeout } from 'vs/base/common/async'; import { IConfigurationService, getMigratedSettingValue } from 'vs/platform/configuration/common/configuration'; -import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import product from 'vs/platform/product/common/product'; import { IUpdateService, State, StateType, AvailableForDownload, UpdateType } from 'vs/platform/update/common/update'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -44,7 +43,7 @@ export abstract class AbstractUpdateService implements IUpdateService { } constructor( - @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, + _: any, // NOTE@coder: This depends on Electron so we skip it. @IConfigurationService protected configurationService: IConfigurationService, @IEnvironmentService private readonly environmentService: IEnvironmentService, @IRequestService protected requestService: IRequestService, @@ -156,15 +155,8 @@ export abstract class AbstractUpdateService implements IUpdateService { this.logService.trace('update#quitAndInstall(): before lifecycle quit()'); - this.lifecycleMainService.quit(true /* from update */).then(vetod => { - this.logService.trace(`update#quitAndInstall(): after lifecycle quit() with veto: ${vetod}`); - if (vetod) { - return; - } - this.logService.trace('update#quitAndInstall(): running raw#quitAndInstall()'); this.doQuitAndInstall(); - }); return Promise.resolve(undefined); } diff --git a/src/vs/workbench/api/browser/extensionHost.contribution.ts b/src/vs/workbench/api/browser/extensionHost.contribution.ts index e69aa80159..2960d00456 100644 --- a/src/vs/workbench/api/browser/extensionHost.contribution.ts +++ b/src/vs/workbench/api/browser/extensionHost.contribution.ts @@ -62,6 +62,7 @@ import './mainThreadTunnelService'; import './mainThreadAuthentication'; import './mainThreadTimeline'; import 'vs/workbench/api/common/apiCommands'; +import 'vs/server/src/browser/mainThreadNodeProxy'; export class ExtensionPoints implements IWorkbenchContribution { diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 91045fcda6..d93d3286d8 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -72,6 +72,7 @@ import { IExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelServ import { IExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService'; import { ExtHostAuthentication } from 'vs/workbench/api/common/extHostAuthentication'; import { ExtHostTimeline } from 'vs/workbench/api/common/extHostTimeline'; +import { IExtHostNodeProxy } from 'vs/server/src/browser/extHostNodeProxy'; export interface IExtensionApiFactory { (extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode; @@ -93,6 +94,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I const extHostLogService = accessor.get(ILogService); const extHostTunnelService = accessor.get(IExtHostTunnelService); const extHostApiDeprecation = accessor.get(IExtHostApiDeprecationService); + const extHostNodeProxy = accessor.get(IExtHostNodeProxy); // register addressable instances rpcProtocol.set(ExtHostContext.ExtHostLogService, extHostLogService); @@ -101,6 +103,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I rpcProtocol.set(ExtHostContext.ExtHostExtensionService, extensionService); rpcProtocol.set(ExtHostContext.ExtHostStorage, extHostStorage); rpcProtocol.set(ExtHostContext.ExtHostTunnelService, extHostTunnelService); + rpcProtocol.set(ExtHostContext.ExtHostNodeProxy, extHostNodeProxy); // automatically create and register addressable instances const extHostDecorations = rpcProtocol.set(ExtHostContext.ExtHostDecorations, accessor.get(IExtHostDecorations)); diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 55130ff918..032534b23e 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -667,6 +667,16 @@ export interface MainThreadLabelServiceShape extends IDisposable { $unregisterResourceLabelFormatter(handle: number): void; } +export interface MainThreadNodeProxyShape extends IDisposable { + $send(message: string): void; +} +export interface ExtHostNodeProxyShape { + $onMessage(message: string): void; + $onClose(): void; + $onDown(): void; + $onUp(): void; +} + export interface MainThreadSearchShape extends IDisposable { $registerFileSearchProvider(handle: number, scheme: string): void; $registerTextSearchProvider(handle: number, scheme: string): void; @@ -1498,7 +1508,8 @@ export const MainContext = { MainThreadLabelService: createMainId('MainThreadLabelService'), MainThreadTheming: createMainId('MainThreadTheming'), MainThreadTunnelService: createMainId('MainThreadTunnelService'), - MainThreadTimeline: createMainId('MainThreadTimeline') + MainThreadTimeline: createMainId('MainThreadTimeline'), + MainThreadNodeProxy: createMainId('MainThreadNodeProxy'), }; export const ExtHostContext = { @@ -1536,5 +1547,6 @@ export const ExtHostContext = { ExtHostTheming: createMainId('ExtHostTheming'), ExtHostTunnelService: createMainId('ExtHostTunnelService'), ExtHostAuthentication: createMainId('ExtHostAuthentication'), - ExtHostTimeline: createMainId('ExtHostTimeline') + ExtHostTimeline: createMainId('ExtHostTimeline'), + ExtHostNodeProxy: createMainId('ExtHostNodeProxy') }; diff --git a/src/vs/workbench/api/common/extHostExtensionService.ts b/src/vs/workbench/api/common/extHostExtensionService.ts index 978bf32fcd..a63954cce0 100644 --- a/src/vs/workbench/api/common/extHostExtensionService.ts +++ b/src/vs/workbench/api/common/extHostExtensionService.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import * as path from 'vs/base/common/path'; -import { originalFSPath, joinPath } from 'vs/base/common/resources'; +import { originalFSPath } from 'vs/base/common/resources'; import { Barrier } from 'vs/base/common/async'; import { dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { TernarySearchTree } from 'vs/base/common/map'; @@ -33,6 +33,7 @@ import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePa import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { IExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelService'; +import { IExtHostNodeProxy } from 'vs/server/src/browser/extHostNodeProxy'; interface ITestRunner { /** Old test runner API, as exported from `vscode/lib/testrunner` */ @@ -78,6 +79,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio protected readonly _extHostConfiguration: ExtHostConfiguration; protected readonly _logService: ILogService; protected readonly _extHostTunnelService: IExtHostTunnelService; + protected readonly _nodeProxy: IExtHostNodeProxy; protected readonly _mainThreadWorkspaceProxy: MainThreadWorkspaceShape; protected readonly _mainThreadTelemetryProxy: MainThreadTelemetryShape; @@ -107,7 +109,8 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio @ILogService logService: ILogService, @IExtHostInitDataService initData: IExtHostInitDataService, @IExtensionStoragePaths storagePath: IExtensionStoragePaths, - @IExtHostTunnelService extHostTunnelService: IExtHostTunnelService + @IExtHostTunnelService extHostTunnelService: IExtHostTunnelService, + @IExtHostNodeProxy nodeProxy: IExtHostNodeProxy, ) { this._hostUtils = hostUtils; this._extHostContext = extHostContext; @@ -116,6 +119,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio this._extHostWorkspace = extHostWorkspace; this._extHostConfiguration = extHostConfiguration; this._logService = logService; + this._nodeProxy = nodeProxy; this._extHostTunnelService = extHostTunnelService; this._disposables = new DisposableStore(); @@ -341,14 +345,14 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio const activationTimesBuilder = new ExtensionActivationTimesBuilder(reason.startup); return Promise.all([ - this._loadCommonJSModule(joinPath(extensionDescription.extensionLocation, extensionDescription.main), activationTimesBuilder), + this._loadCommonJSModule(extensionDescription, activationTimesBuilder), this._loadExtensionContext(extensionDescription) ]).then(values => { return AbstractExtHostExtensionService._callActivate(this._logService, extensionDescription.identifier, values[0], values[1], activationTimesBuilder); }); } - protected abstract _loadCommonJSModule(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise; + protected abstract _loadCommonJSModule(module: URI | IExtensionDescription, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise; private _loadExtensionContext(extensionDescription: IExtensionDescription): Promise { diff --git a/src/vs/workbench/api/node/extHost.services.ts b/src/vs/workbench/api/node/extHost.services.ts index 72ad75d63e..8c4edee5e3 100644 --- a/src/vs/workbench/api/node/extHost.services.ts +++ b/src/vs/workbench/api/node/extHost.services.ts @@ -29,6 +29,8 @@ import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService'; import { IExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelService'; import { ExtHostTunnelService } from 'vs/workbench/api/node/extHostTunnelService'; import { IExtHostApiDeprecationService, ExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService'; +import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { IExtHostNodeProxy } from 'vs/server/src/browser/extHostNodeProxy'; // register singleton services registerSingleton(ILogService, ExtHostLogService); @@ -47,3 +49,19 @@ registerSingleton(IExtensionStoragePaths, ExtensionStoragePaths); registerSingleton(IExtHostExtensionService, ExtHostExtensionService); registerSingleton(IExtHostStorage, ExtHostStorage); registerSingleton(IExtHostTunnelService, ExtHostTunnelService); + +function NotImplementedProxy(name: ServiceIdentifier): { new(): T } { + return class { + constructor() { + return new Proxy({}, { + get(target: any, prop: string | number) { + if (target[prop]) { + return target[prop]; + } + throw new Error(`Not Implemented: ${name}->${String(prop)}`); + } + }); + } + }; +} +registerSingleton(IExtHostNodeProxy, class extends NotImplementedProxy(IExtHostNodeProxy) {}); diff --git a/src/vs/workbench/api/node/extHostExtensionService.ts b/src/vs/workbench/api/node/extHostExtensionService.ts index a1c3e50ffd..910627aaf9 100644 --- a/src/vs/workbench/api/node/extHostExtensionService.ts +++ b/src/vs/workbench/api/node/extHostExtensionService.ts @@ -13,6 +13,8 @@ import { ExtHostDownloadService } from 'vs/workbench/api/node/extHostDownloadSer import { CLIServer } from 'vs/workbench/api/node/extHostCLIServer'; import { URI } from 'vs/base/common/uri'; import { Schemas } from 'vs/base/common/network'; +import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { joinPath } from 'vs/base/common/resources'; class NodeModuleRequireInterceptor extends RequireInterceptor { @@ -76,7 +78,10 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { }; } - protected _loadCommonJSModule(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise { + protected _loadCommonJSModule(module: URI | IExtensionDescription, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise { + if (!URI.isUri(module)) { + module = joinPath(module.extensionLocation, module.main!); + } if (module.scheme !== Schemas.file) { throw new Error(`Cannot load URI: '${module}', must be of file-scheme`); } diff --git a/src/vs/workbench/api/node/extHostStoragePaths.ts b/src/vs/workbench/api/node/extHostStoragePaths.ts index afdd6bf398..ac91318ce3 100644 --- a/src/vs/workbench/api/node/extHostStoragePaths.ts +++ b/src/vs/workbench/api/node/extHostStoragePaths.ts @@ -5,13 +5,14 @@ import * as path from 'vs/base/common/path'; import { URI } from 'vs/base/common/uri'; -import * as pfs from 'vs/base/node/pfs'; -import { IEnvironment, IStaticWorkspaceData } from 'vs/workbench/api/common/extHost.protocol'; +import { IEnvironment, IStaticWorkspaceData, MainContext } from 'vs/workbench/api/common/extHost.protocol'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; import { withNullAsUndefined } from 'vs/base/common/types'; import { ILogService } from 'vs/platform/log/common/log'; +import { IExtHostRpcService } from '../common/extHostRpcService'; +import { VSBuffer } from 'vs/base/common/buffer'; export class ExtensionStoragePaths implements IExtensionStoragePaths { @@ -26,6 +27,7 @@ export class ExtensionStoragePaths implements IExtensionStoragePaths { constructor( @IExtHostInitDataService initData: IExtHostInitDataService, @ILogService private readonly _logService: ILogService, + @IExtHostRpcService private readonly _extHostRpc: IExtHostRpcService, ) { this._workspace = withNullAsUndefined(initData.workspace); this._environment = initData.environment; @@ -54,21 +56,25 @@ export class ExtensionStoragePaths implements IExtensionStoragePaths { const storageName = this._workspace.id; const storagePath = path.join(this._environment.appSettingsHome.fsPath, 'workspaceStorage', storageName); - const exists = await pfs.dirExists(storagePath); + // NOTE@coder: Use the file system proxy so this will work in the browser. + // writeFile performs a mkdirp so we don't need to bother ourselves. + const fileSystem = this._extHostRpc.getProxy(MainContext.MainThreadFileSystem); + const exists = fileSystem.$stat(URI.file(storagePath)) if (exists) { return storagePath; } try { - await pfs.mkdirp(storagePath); - await pfs.writeFile( - path.join(storagePath, 'meta.json'), - JSON.stringify({ - id: this._workspace.id, - configuration: this._workspace.configuration && URI.revive(this._workspace.configuration).toString(), - name: this._workspace.name - }, undefined, 2) + await fileSystem.$writeFile( + URI.file(path.join(storagePath, 'meta.json')), + VSBuffer.fromString( + JSON.stringify({ + id: this._workspace.id, + configuration: this._workspace.configuration && URI.revive(this._workspace.configuration).toString(), + name: this._workspace.name + }, undefined, 2) + ) ); return storagePath; diff --git a/src/vs/workbench/api/worker/extHostExtensionService.ts b/src/vs/workbench/api/worker/extHostExtensionService.ts index 4781f22676..25143a97c0 100644 --- a/src/vs/workbench/api/worker/extHostExtensionService.ts +++ b/src/vs/workbench/api/worker/extHostExtensionService.ts @@ -9,6 +9,9 @@ import { AbstractExtHostExtensionService } from 'vs/workbench/api/common/extHost import { endsWith } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import { RequireInterceptor } from 'vs/workbench/api/common/extHostRequireInterceptor'; +import { joinPath } from 'vs/base/common/resources'; +import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { loadCommonJSModule } from 'vs/server/src/browser/worker'; class WorkerRequireInterceptor extends RequireInterceptor { @@ -41,7 +44,14 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { await this._fakeModules.install(); } - protected async _loadCommonJSModule(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise { + protected async _loadCommonJSModule(module: URI | IExtensionDescription, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise { + if (!URI.isUri(module) && module.extensionKind !== 'web') { + return loadCommonJSModule(module, activationTimesBuilder, this._nodeProxy, this._logService, this._fakeModules!.getModule('vscode', module.extensionLocation)); + } + + if (!URI.isUri(module)) { + module = joinPath(module.extensionLocation, module.main!); + } module = module.with({ path: ensureSuffix(module.path, '.js') }); const response = await fetch(module.toString(true)); @@ -57,7 +67,7 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { const _exports = {}; const _module = { exports: _exports }; const _require = (request: string) => { - const result = this._fakeModules!.getModule(request, module); + const result = this._fakeModules!.getModule(request, module); if (result === undefined) { throw new Error(`Cannot load module '${request}'`); } diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts index 94e7052574..7e5563b417 100644 --- a/src/vs/workbench/browser/web.main.ts +++ b/src/vs/workbench/browser/web.main.ts @@ -49,6 +49,7 @@ import { IndexedDBLogProvider } from 'vs/workbench/services/log/browser/indexedD import { InMemoryLogProvider } from 'vs/workbench/services/log/common/inMemoryLogProvider'; import { isWorkspaceToOpen, isFolderToOpen } from 'vs/platform/windows/common/windows'; import { getWorkspaceIdentifier } from 'vs/workbench/services/workspaces/browser/workspaces'; +import { initialize } from 'vs/server/src/browser/client'; class BrowserMain extends Disposable { @@ -85,6 +86,7 @@ class BrowserMain extends Disposable { // Startup workbench.startup(); + await initialize(services.serviceCollection); } private registerListeners(workbench: Workbench, storageService: BrowserStorageService): void { diff --git a/src/vs/workbench/common/resources.ts b/src/vs/workbench/common/resources.ts index c509716fc4..e416413084 100644 --- a/src/vs/workbench/common/resources.ts +++ b/src/vs/workbench/common/resources.ts @@ -15,6 +15,7 @@ import { ParsedExpression, IExpression, parse } from 'vs/base/common/glob'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { withNullAsUndefined } from 'vs/base/common/types'; +import { Schemas } from 'vs/base/common/network'; export class ResourceContextKey extends Disposable implements IContextKey { @@ -63,7 +64,8 @@ export class ResourceContextKey extends Disposable implements IContextKey { set(value: URI | null) { if (!ResourceContextKey._uriEquals(this._resourceKey.get(), value)) { this._resourceKey.set(value); - this._schemeKey.set(value ? value.scheme : null); + // NOTE@coder: fixes extensions matching against file schemas. + this._schemeKey.set(value ? (value.scheme === Schemas.vscodeRemote ? Schemas.file : value.scheme) : null); this._filenameKey.set(value ? basename(value) : null); this._langIdKey.set(value ? this._modeService.getModeIdByFilepathOrFirstLine(value) : null); this._extensionKey.set(value ? extname(value) : null); diff --git a/src/vs/workbench/contrib/webview/browser/pre/main.js b/src/vs/workbench/contrib/webview/browser/pre/main.js index 63c9af47e2..021358fef9 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/main.js +++ b/src/vs/workbench/contrib/webview/browser/pre/main.js @@ -329,7 +329,8 @@ if (data.endpoint) { try { const endpointUrl = new URL(data.endpoint); - csp.setAttribute('content', csp.getAttribute('content').replace(/vscode-resource:(?=(\s|;|$))/g, endpointUrl.origin)); + // NOTE@coder: Add back the trailing slash so it'll work for sub-paths. + csp.setAttribute('content', csp.getAttribute('content').replace(/vscode-resource:(?=(\s|;|$))/g, endpointUrl.origin + "/")); } catch (e) { console.error('Could not rewrite csp'); } diff --git a/src/vs/workbench/services/dialogs/browser/dialogService.ts b/src/vs/workbench/services/dialogs/browser/dialogService.ts index f67f9aa064..add754cd5a 100644 --- a/src/vs/workbench/services/dialogs/browser/dialogService.ts +++ b/src/vs/workbench/services/dialogs/browser/dialogService.ts @@ -122,11 +122,12 @@ export class DialogService implements IDialogService { async about(): Promise { const detail = nls.localize('aboutDetail', - "Version: {0}\nCommit: {1}\nDate: {2}\nBrowser: {3}", + "Version: {0}\nCommit: {1}\nDate: {2}\nBrowser: {3}\nCode Server Version: {4}", this.productService.version || 'Unknown', this.productService.commit || 'Unknown', this.productService.date || 'Unknown', - navigator.userAgent + navigator.userAgent, + this.productService.codeServerVersion || 'Unknown', ); const { choice } = await this.show(Severity.Info, this.productService.nameLong, [nls.localize('copy', "Copy"), nls.localize('ok', "OK")], { detail, cancelId: 1 }); diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index 1bf4cfad2a..924a2fcd87 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -195,8 +195,8 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment @memoize get webviewExternalEndpoint(): string { - // TODO: get fallback from product.json - return (this.options.webviewEndpoint || 'https://{{uuid}}.vscode-webview-test.com/{{commit}}').replace('{{commit}}', product.commit || '0d728c31ebdf03869d2687d9be0b017667c9ff37'); + // NOTE@coder: Modified to work against the current URL. + return `${window.location.origin}${window.location.pathname.replace(/\/+$/, '')}/webview/`; } @memoize @@ -249,6 +249,8 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment installSourcePath!: string; builtinExtensionsPath!: string; + extraExtensionPaths!: string[]; + extraBuiltinExtensionPaths!: string[]; globalStorageHome!: string; workspaceStorageHome!: string; diff --git a/src/vs/workbench/services/extensions/browser/extensionService.ts b/src/vs/workbench/services/extensions/browser/extensionService.ts index fe891a042e..21d0d4bf61 100644 --- a/src/vs/workbench/services/extensions/browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/browser/extensionService.ts @@ -119,6 +119,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten } else { // remote: only enabled and none-web'ish extension + localExtensions.push(...remoteEnv.extensions.filter(extension => this._isEnabled(extension) && canExecuteOnWeb(extension, this._productService, this._configService))); remoteEnv.extensions = remoteEnv.extensions.filter(extension => this._isEnabled(extension) && !canExecuteOnWeb(extension, this._productService, this._configService)); this._checkEnableProposedApi(remoteEnv.extensions); diff --git a/src/vs/workbench/services/extensions/common/extensionsUtil.ts b/src/vs/workbench/services/extensions/common/extensionsUtil.ts index 9e8352ac88..2d1cb0a107 100644 --- a/src/vs/workbench/services/extensions/common/extensionsUtil.ts +++ b/src/vs/workbench/services/extensions/common/extensionsUtil.ts @@ -32,7 +32,8 @@ export function canExecuteOnWorkspace(manifest: IExtensionManifest, productServi export function canExecuteOnWeb(manifest: IExtensionManifest, productService: IProductService, configurationService: IConfigurationService): boolean { const extensionKind = getExtensionKind(manifest, productService, configurationService); - return extensionKind.some(kind => kind === 'web'); + // NOTE@coder: hardcode vim for now. + return extensionKind.some(kind => kind === 'web') || manifest.name === 'vim'; } export function getExtensionKind(manifest: IExtensionManifest, productService: IProductService, configurationService: IConfigurationService): ExtensionKind[] { diff --git a/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts b/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts index 0f35c54431..32fff09b18 100644 --- a/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts +++ b/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts @@ -53,12 +53,13 @@ const args = minimist(process.argv.slice(2), { const Module = require.__$__nodeRequire('module') as any; const originalLoad = Module._load; - Module._load = function (request: string) { + Module._load = function (request: string, parent: object, isMain: boolean) { if (request === 'natives') { throw new Error('Either the extension or a NPM dependency is using the "natives" node module which is unsupported as it can cause a crash of the extension host. Click [here](https://go.microsoft.com/fwlink/?linkid=871887) to find out more'); } - return originalLoad.apply(this, arguments); + // NOTE@coder: Map node_module.asar requests to regular node_modules. + return originalLoad.apply(this, [request.replace(/node_modules\.asar(\.unpacked)?/, 'node_modules'), parent, isMain]); }; })(); @@ -131,8 +132,11 @@ function _createExtHostProtocol(): Promise { // Wait for rich client to reconnect protocol.onSocketClose(() => { - // The socket has closed, let's give the renderer a certain amount of time to reconnect - disconnectRunner1.schedule(); + // NOTE@coder: Inform the server so we can manage offline + // connections there instead. Our goal is to persist connections + // forever (to a reasonable point) to account for things like + // hibernating overnight. + process.send!({ type: 'VSCODE_EXTHOST_DISCONNECTED' }); }); } } diff --git a/src/vs/workbench/services/extensions/worker/extHost.services.ts b/src/vs/workbench/services/extensions/worker/extHost.services.ts index bbb72e9511..63f1f6ff46 100644 --- a/src/vs/workbench/services/extensions/worker/extHost.services.ts +++ b/src/vs/workbench/services/extensions/worker/extHost.services.ts @@ -18,11 +18,12 @@ import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePa import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService'; import { IExtHostStorage, ExtHostStorage } from 'vs/workbench/api/common/extHostStorage'; import { ExtHostExtensionService } from 'vs/workbench/api/worker/extHostExtensionService'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; import { ExtHostLogService } from 'vs/workbench/api/worker/extHostLogService'; import { IExtHostTunnelService, ExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelService'; import { IExtHostApiDeprecationService, ExtHostApiDeprecationService, } from 'vs/workbench/api/common/extHostApiDeprecationService'; +import { ExtHostNodeProxy, IExtHostNodeProxy } from 'vs/server/src/browser/extHostNodeProxy'; +import { ExtensionStoragePaths } from 'vs/workbench/api/node/extHostStoragePaths'; // register singleton services registerSingleton(ILogService, ExtHostLogService); @@ -37,23 +38,9 @@ registerSingleton(IExtHostStorage, ExtHostStorage); registerSingleton(IExtHostExtensionService, ExtHostExtensionService); registerSingleton(IExtHostSearch, ExtHostSearch); registerSingleton(IExtHostTunnelService, ExtHostTunnelService); +registerSingleton(IExtHostNodeProxy, ExtHostNodeProxy); -// register services that only throw errors -function NotImplementedProxy(name: ServiceIdentifier): { new(): T } { - return class { - constructor() { - return new Proxy({}, { - get(target: any, prop: string | number) { - if (target[prop]) { - return target[prop]; - } - throw new Error(`Not Implemented: ${name}->${String(prop)}`); - } - }); - } - }; -} registerSingleton(IExtHostTerminalService, WorkerExtHostTerminalService); registerSingleton(IExtHostTask, WorkerExtHostTask); registerSingleton(IExtHostDebugService, WorkerExtHostDebugService); -registerSingleton(IExtensionStoragePaths, class extends NotImplementedProxy(IExtensionStoragePaths) { whenReady = Promise.resolve(); }); +registerSingleton(IExtensionStoragePaths, ExtensionStoragePaths); diff --git a/src/vs/workbench/services/localizations/electron-browser/localizationsService.ts b/src/vs/workbench/services/localizations/electron-browser/localizationsService.ts index 99394090da..4891e0fece 100644 --- a/src/vs/workbench/services/localizations/electron-browser/localizationsService.ts +++ b/src/vs/workbench/services/localizations/electron-browser/localizationsService.ts @@ -5,17 +5,17 @@ import { createChannelSender } from 'vs/base/parts/ipc/node/ipc'; import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; -import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; export class LocalizationsService { _serviceBrand: undefined; constructor( - @ISharedProcessService sharedProcessService: ISharedProcessService, + @IRemoteAgentService remoteAgentService: IRemoteAgentService, ) { - return createChannelSender(sharedProcessService.getChannel('localizations')); + return createChannelSender(remoteAgentService.getConnection()!.getChannel('localizations')); } } diff --git a/src/vs/workbench/services/update/electron-browser/updateService.ts b/src/vs/workbench/services/update/electron-browser/updateService.ts index b8f6558b2c..7aeafe6e0e 100644 --- a/src/vs/workbench/services/update/electron-browser/updateService.ts +++ b/src/vs/workbench/services/update/electron-browser/updateService.ts @@ -6,8 +6,8 @@ import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { Event, Emitter } from 'vs/base/common/event'; import { IUpdateService, State } from 'vs/platform/update/common/update'; -import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; export class NativeUpdateService implements IUpdateService { @@ -21,8 +21,9 @@ export class NativeUpdateService implements IUpdateService { private channel: IChannel; - constructor(@IMainProcessService mainProcessService: IMainProcessService) { - this.channel = mainProcessService.getChannel('update'); + // NOTE@coder: patched to work in the browser. + constructor(@IRemoteAgentService remoteAgentService: IRemoteAgentService) { + this.channel = remoteAgentService.getConnection()!.getChannel('update'); // always set this._state as the state changes this.onStateChange(state => this._state = state); diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index 0719b361e0..3a4c5cefe8 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -34,11 +34,14 @@ import 'vs/workbench/services/textfile/browser/browserTextFileService'; import 'vs/workbench/services/keybinding/browser/keymapService'; import 'vs/workbench/services/extensions/browser/extensionService'; import 'vs/workbench/services/extensionManagement/common/extensionManagementServerService'; -import 'vs/workbench/services/telemetry/browser/telemetryService'; +// NOTE@coder: We send it all to the server side to be processed there instead. +// import 'vs/workbench/services/telemetry/browser/telemetryService'; import 'vs/workbench/services/configurationResolver/browser/configurationResolverService'; import 'vs/workbench/services/credentials/browser/credentialsService'; import 'vs/workbench/services/url/browser/urlService'; -import 'vs/workbench/services/update/browser/updateService'; +// NOTE@coder: Use the electron-browser version since it already comes with a +// channel which lets us actually perform updates. +import 'vs/workbench/services/update/electron-browser/updateService'; import 'vs/workbench/contrib/tags/browser/workspaceTagsService'; import 'vs/workbench/services/workspaces/browser/workspacesService'; import 'vs/workbench/services/workspaces/browser/workspaceEditingService';