diff --git a/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts b/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts index 3fdec068db9..cfe1929acff 100644 --- a/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts +++ b/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts @@ -6,16 +6,21 @@ import { ResolvedAuthority, IRemoteAuthorityResolverService, ResolverResult, IRemoteConnectionData } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { RemoteAuthorities } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; +import { Emitter } from 'vs/base/common/event'; +import { Disposable } from 'vs/base/common/lifecycle'; -export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverService { +export class RemoteAuthorityResolverService extends Disposable implements IRemoteAuthorityResolverService { declare readonly _serviceBrand: undefined; + + private readonly _onDidChangeConnectionData = this._register(new Emitter()); + public readonly onDidChangeConnectionData = this._onDidChangeConnectionData.event; + private readonly _cache: Map; private readonly _connectionTokens: Map; - constructor( - resourceUriProvider: ((uri: URI) => URI) | undefined - ) { + constructor(resourceUriProvider: ((uri: URI) => URI) | undefined) { + super(); this._cache = new Map(); this._connectionTokens = new Map(); if (resourceUriProvider) { @@ -28,6 +33,7 @@ export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverS const result = this._doResolveAuthority(authority); RemoteAuthorities.set(authority, result.authority.host, result.authority.port); this._cache.set(authority, result); + this._onDidChangeConnectionData.fire(); } return this._cache.get(authority)!; } @@ -65,5 +71,6 @@ export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverS _setAuthorityConnectionToken(authority: string, connectionToken: string): void { this._connectionTokens.set(authority, connectionToken); RemoteAuthorities.setConnectionToken(authority, connectionToken); + this._onDidChangeConnectionData.fire(); } } diff --git a/src/vs/platform/remote/common/remoteAuthorityResolver.ts b/src/vs/platform/remote/common/remoteAuthorityResolver.ts index 43d60729415..075d086fd52 100644 --- a/src/vs/platform/remote/common/remoteAuthorityResolver.ts +++ b/src/vs/platform/remote/common/remoteAuthorityResolver.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { Event } from 'vs/base/common/event'; export const IRemoteAuthorityResolverService = createDecorator('remoteAuthorityResolverService'); @@ -85,6 +86,8 @@ export interface IRemoteAuthorityResolverService { readonly _serviceBrand: undefined; + readonly onDidChangeConnectionData: Event; + resolveAuthority(authority: string): Promise; getConnectionData(authority: string): IRemoteConnectionData | null; diff --git a/src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts b/src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts index 7333b457bcd..4dd702b53ec 100644 --- a/src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts +++ b/src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts @@ -6,6 +6,8 @@ import { ResolvedAuthority, IRemoteAuthorityResolverService, ResolverResult, ResolvedOptions, IRemoteConnectionData } from 'vs/platform/remote/common/remoteAuthorityResolver'; import * as errors from 'vs/base/common/errors'; import { RemoteAuthorities } from 'vs/base/common/network'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { Emitter } from 'vs/base/common/event'; class PendingResolveAuthorityRequest { @@ -29,14 +31,18 @@ class PendingResolveAuthorityRequest { } } -export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverService { +export class RemoteAuthorityResolverService extends Disposable implements IRemoteAuthorityResolverService { declare readonly _serviceBrand: undefined; + private readonly _onDidChangeConnectionData = this._register(new Emitter()); + public readonly onDidChangeConnectionData = this._onDidChangeConnectionData.event; + private readonly _resolveAuthorityRequests: Map; private readonly _connectionTokens: Map; constructor() { + super(); this._resolveAuthorityRequests = new Map(); this._connectionTokens = new Map(); } @@ -82,6 +88,7 @@ export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverS const request = this._resolveAuthorityRequests.get(resolvedAuthority.authority)!; RemoteAuthorities.set(resolvedAuthority.authority, resolvedAuthority.host, resolvedAuthority.port); request.resolve({ authority: resolvedAuthority, options }); + this._onDidChangeConnectionData.fire(); } } @@ -95,5 +102,6 @@ export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverS _setAuthorityConnectionToken(authority: string, connectionToken: string): void { this._connectionTokens.set(authority, connectionToken); RemoteAuthorities.setConnectionToken(authority, connectionToken); + this._onDidChangeConnectionData.fire(); } } diff --git a/src/vs/workbench/api/browser/extensionHost.contribution.ts b/src/vs/workbench/api/browser/extensionHost.contribution.ts index 3f2de2c7380..3d77009b908 100644 --- a/src/vs/workbench/api/browser/extensionHost.contribution.ts +++ b/src/vs/workbench/api/browser/extensionHost.contribution.ts @@ -41,6 +41,7 @@ import './mainThreadMessageService'; import './mainThreadOutputService'; import './mainThreadProgress'; import './mainThreadQuickOpen'; +import './mainThreadRemoteConnectionData'; import './mainThreadSaveParticipant'; import './mainThreadSCM'; import './mainThreadSearch'; diff --git a/src/vs/workbench/api/browser/mainThreadRemoteConnectionData.ts b/src/vs/workbench/api/browser/mainThreadRemoteConnectionData.ts new file mode 100644 index 00000000000..bf40ca23528 --- /dev/null +++ b/src/vs/workbench/api/browser/mainThreadRemoteConnectionData.ts @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers'; +import { ExtHostContext, IExtHostContext, ExtHostExtensionServiceShape } from '../common/extHost.protocol'; +import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; + +@extHostCustomer +export class MainThreadRemoteConnectionData extends Disposable { + + private readonly _proxy: ExtHostExtensionServiceShape; + + constructor( + extHostContext: IExtHostContext, + @IWorkbenchEnvironmentService protected readonly _environmentService: IWorkbenchEnvironmentService, + @IRemoteAuthorityResolverService remoteAuthorityResolverService: IRemoteAuthorityResolverService + ) { + super(); + this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostExtensionService); + + const remoteAuthority = this._environmentService.configuration.remoteAuthority; + if (remoteAuthority) { + this._register(remoteAuthorityResolverService.onDidChangeConnectionData(() => { + const connectionData = remoteAuthorityResolverService.getConnectionData(remoteAuthority); + if (connectionData) { + this._proxy.$updateRemoteConnectionData(connectionData); + } + })); + } + } +} diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index b8c0a74bf3a..35a3875039c 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -99,7 +99,7 @@ export interface IInitData { logsLocation: URI; logFile: URI; autoStart: boolean; - remote: { isRemote: boolean; authority: string | undefined; connectionData: IRemoteConnectionData | undefined; }; + remote: { isRemote: boolean; authority: string | undefined; connectionData: IRemoteConnectionData | null; }; uiKind: UIKind; } @@ -1046,6 +1046,7 @@ export interface ExtHostExtensionServiceShape { $activateByEvent(activationEvent: string): Promise; $activate(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise; $setRemoteEnvironment(env: { [key: string]: string | null; }): Promise; + $updateRemoteConnectionData(connectionData: IRemoteConnectionData): Promise; $deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise; diff --git a/src/vs/workbench/api/common/extHostExtensionService.ts b/src/vs/workbench/api/common/extHostExtensionService.ts index eb378e53b92..83fdbfcb107 100644 --- a/src/vs/workbench/api/common/extHostExtensionService.ts +++ b/src/vs/workbench/api/common/extHostExtensionService.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import * as path from 'vs/base/common/path'; import { originalFSPath, joinPath } from 'vs/base/common/resources'; import { Barrier, timeout } from 'vs/base/common/async'; -import { dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { dispose, toDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle'; import { TernarySearchTree } from 'vs/base/common/map'; import { URI } from 'vs/base/common/uri'; import { ILogService } from 'vs/platform/log/common/log'; @@ -26,7 +26,7 @@ import { Schemas } from 'vs/base/common/network'; import { VSBuffer } from 'vs/base/common/buffer'; import { ExtensionMemento } from 'vs/workbench/api/common/extHostMemento'; import { RemoteAuthorityResolverError, ExtensionMode } from 'vs/workbench/api/common/extHostTypes'; -import { ResolvedAuthority, ResolvedOptions, RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver'; +import { ResolvedAuthority, ResolvedOptions, RemoteAuthorityResolverErrorCode, IRemoteConnectionData } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths'; @@ -34,6 +34,7 @@ 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 { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService'; +import { Emitter, Event } from 'vs/base/common/event'; interface ITestRunner { /** Old test runner API, as exported from `vscode/lib/testrunner` */ @@ -65,12 +66,15 @@ type TelemetryActivationEventFragment = { reasonId: { classification: 'PublicNonPersonalData', purpose: 'FeatureInsight' }; }; -export abstract class AbstractExtHostExtensionService implements ExtHostExtensionServiceShape { +export abstract class AbstractExtHostExtensionService extends Disposable implements ExtHostExtensionServiceShape { readonly _serviceBrand: undefined; private static readonly WORKSPACE_CONTAINS_TIMEOUT = 7000; + private readonly _onDidChangeRemoteConnectionData = this._register(new Emitter()); + public readonly onDidChangeRemoteConnectionData = this._onDidChangeRemoteConnectionData.event; + protected readonly _hostUtils: IHostUtils; protected readonly _initData: IInitData; protected readonly _extHostContext: IExtHostRpcService; @@ -97,6 +101,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio private readonly _resolvers: { [authorityPrefix: string]: vscode.RemoteAuthorityResolver; }; private _started: boolean; + private _remoteConnectionData: IRemoteConnectionData | null; private readonly _disposables: DisposableStore; @@ -112,6 +117,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio @IExtHostTunnelService extHostTunnelService: IExtHostTunnelService, @IExtHostTerminalService extHostTerminalService: IExtHostTerminalService ) { + super(); this._hostUtils = hostUtils; this._extHostContext = extHostContext; this._initData = initData; @@ -164,6 +170,11 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio this._extensionPathIndex = null; this._resolvers = Object.create(null); this._started = false; + this._remoteConnectionData = this._initData.remote.connectionData; + } + + public getRemoteConnectionData(): IRemoteConnectionData | null { + return this._remoteConnectionData; } public async initialize(): Promise { @@ -793,6 +804,11 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio return buff; } + public async $updateRemoteConnectionData(connectionData: IRemoteConnectionData): Promise { + this._remoteConnectionData = connectionData; + this._onDidChangeRemoteConnectionData.fire(); + } + public abstract async $setRemoteEnvironment(env: { [key: string]: string | null }): Promise; } @@ -836,4 +852,7 @@ export interface IExtHostExtensionService extends AbstractExtHostExtensionServic getExtensionRegistry(): Promise; getExtensionPathIndex(): Promise>; registerRemoteAuthorityResolver(authorityPrefix: string, resolver: vscode.RemoteAuthorityResolver): vscode.Disposable; + + onDidChangeRemoteConnectionData: Event; + getRemoteConnectionData(): IRemoteConnectionData | null; } diff --git a/src/vs/workbench/services/extensions/browser/extensionService.ts b/src/vs/workbench/services/extensions/browser/extensionService.ts index 256aa4e80f7..a0d121f7efb 100644 --- a/src/vs/workbench/services/extensions/browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/browser/extensionService.ts @@ -78,7 +78,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten remoteAuthority: remoteAuthority, getInitData: async () => { await this.whenInstalledExtensionsRegistered(); - const connectionData = this._remoteAuthorityResolverService.getConnectionData(remoteAuthority) || undefined; + const connectionData = this._remoteAuthorityResolverService.getConnectionData(remoteAuthority); const remoteEnvironment = this._remoteExtensionsEnvironmentData!; return { connectionData, remoteEnvironment }; } diff --git a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHostStarter.ts b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHostStarter.ts index c7a93a63df8..10e02003330 100644 --- a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHostStarter.ts +++ b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHostStarter.ts @@ -160,7 +160,7 @@ export class WebWorkerExtensionHostStarter implements IExtensionHostStarter { autoStart: this._autoStart, remote: { authority: this._environmentService.configuration.remoteAuthority, - connectionData: undefined, + connectionData: null, isRemote: false }, uiKind: platform.isWeb ? UIKind.Web : UIKind.Desktop diff --git a/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts b/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts index f1de40cdc2b..17f9e6cdf6b 100644 --- a/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts +++ b/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts @@ -34,7 +34,7 @@ import { IOutputChannelRegistry, Extensions } from 'vs/workbench/services/output import { localize } from 'vs/nls'; export interface IRemoteInitData { - readonly connectionData: IRemoteConnectionData | undefined; + readonly connectionData: IRemoteConnectionData | null; readonly remoteEnvironment: IRemoteAgentEnvironment; } diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts index 3545bee8b77..0006c2111c3 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts @@ -440,7 +440,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { }, remote: { authority: this._environmentService.configuration.remoteAuthority, - connectionData: undefined, + connectionData: null, isRemote: false }, resolvedExtensions: [], diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts index f6a15301ce4..ba9b0fec2c3 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts @@ -346,7 +346,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten remoteAuthority: remoteAuthority, getInitData: async () => { await this.whenInstalledExtensionsRegistered(); - const connectionData = this._remoteAuthorityResolverService.getConnectionData(remoteAuthority) || undefined; + const connectionData = this._remoteAuthorityResolverService.getConnectionData(remoteAuthority); const remoteEnvironment = this._remoteEnvironment.get(remoteAuthority)!; return { connectionData, remoteEnvironment }; } diff --git a/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts b/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts index 644e62d83c8..ff6d95047f9 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts @@ -144,7 +144,7 @@ suite('ExtHostSearch', () => { constructor() { super( rpcProtocol, - new class extends mock() { remote = { isRemote: false, authority: undefined, connectionData: undefined }; }, + new class extends mock() { remote = { isRemote: false, authority: undefined, connectionData: null }; }, new URITransformerService(null), logService );