From 3ba93e8aac7d0779703f042d8db0b3aeeaecd104 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Mon, 25 Mar 2019 19:05:26 +0100 Subject: [PATCH] Move more code to /common/ --- src/vs/code/electron-main/app.ts | 2 +- .../browser/remoteAuthorityResolverService.ts | 30 +++++ .../remoteAgentFileSystemChannel.ts | 12 +- src/vs/workbench/electron-browser/main.ts | 2 +- .../common/abstractRemoteAgentService.ts | 113 ++++++++++++++++++ .../remote/common/remoteAgentService.ts | 2 +- .../remoteAgentServiceImpl.ts | 105 ++-------------- 7 files changed, 158 insertions(+), 108 deletions(-) create mode 100644 src/vs/platform/remote/browser/remoteAuthorityResolverService.ts rename src/vs/platform/remote/{node => common}/remoteAgentFileSystemChannel.ts (91%) create mode 100644 src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index a156b9bc205..b76eb018ad3 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -68,7 +68,7 @@ import { homedir } from 'os'; import { join, sep } from 'vs/base/common/path'; import { localize } from 'vs/nls'; import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; -import { REMOTE_FILE_SYSTEM_CHANNEL_NAME } from 'vs/platform/remote/node/remoteAgentFileSystemChannel'; +import { REMOTE_FILE_SYSTEM_CHANNEL_NAME } from 'vs/platform/remote/common/remoteAgentFileSystemChannel'; import { ResolvedAuthority } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { SnapUpdateService } from 'vs/platform/update/electron-main/updateService.snap'; import { IStorageMainService, StorageMainService } from 'vs/platform/storage/node/storageMainService'; diff --git a/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts b/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts new file mode 100644 index 00000000000..bddaea9c666 --- /dev/null +++ b/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ResolvedAuthority, IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; + +export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverService { + + _serviceBrand: any; + + constructor() { + } + + resolveAuthority(authority: string): Promise { + if (authority.indexOf(':') >= 0) { + const pieces = authority.split(':'); + return Promise.resolve({ authority, host: pieces[0], port: parseInt(pieces[1], 10) }); + } + return Promise.resolve({ authority, host: authority, port: 80 }); + } + + setResolvedAuthority(resolvedAuthority: ResolvedAuthority) { + throw new Error(`Not implemented`); + } + + setResolvedAuthorityError(authority: string, err: any): void { + throw new Error(`Not implemented`); + } +} diff --git a/src/vs/platform/remote/node/remoteAgentFileSystemChannel.ts b/src/vs/platform/remote/common/remoteAgentFileSystemChannel.ts similarity index 91% rename from src/vs/platform/remote/node/remoteAgentFileSystemChannel.ts rename to src/vs/platform/remote/common/remoteAgentFileSystemChannel.ts index 4bec2ec3c79..7e4a90e4ce5 100644 --- a/src/vs/platform/remote/node/remoteAgentFileSystemChannel.ts +++ b/src/vs/platform/remote/common/remoteAgentFileSystemChannel.ts @@ -9,6 +9,7 @@ import { URI, UriComponents } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { FileChangeType, FileDeleteOptions, FileOverwriteOptions, FileSystemProviderCapabilities, FileType, FileWriteOptions, IFileChange, IFileSystemProvider, IStat, IWatchOptions } from 'vs/platform/files/common/files'; +import { VSBuffer } from 'vs/base/common/buffer'; export const REMOTE_FILE_SYSTEM_CHANNEL_NAME = 'remotefilesystem'; @@ -71,20 +72,17 @@ export class RemoteExtensionsFileSystemProvider extends Disposable implements IF // --- forwarding calls - private static _asBuffer(data: Uint8Array): Buffer { - return Buffer.isBuffer(data) ? data : Buffer.from(data.buffer, data.byteOffset, data.byteLength); - } - stat(resource: URI): Promise { return this._channel.call('stat', [resource]); } - readFile(resource: URI): Promise { - return this._channel.call('readFile', [resource]); + async readFile(resource: URI): Promise { + const buff = await this._channel.call('readFile', [resource]); + return buff.buffer; } writeFile(resource: URI, content: Uint8Array, opts: FileWriteOptions): Promise { - const contents = RemoteExtensionsFileSystemProvider._asBuffer(content); + const contents = VSBuffer.wrap(content); return this._channel.call('writeFile', [resource, contents, opts]); } diff --git a/src/vs/workbench/electron-browser/main.ts b/src/vs/workbench/electron-browser/main.ts index 91f9630101c..5188d02ef9f 100644 --- a/src/vs/workbench/electron-browser/main.ts +++ b/src/vs/workbench/electron-browser/main.ts @@ -47,7 +47,7 @@ import { FileService2 } from 'vs/workbench/services/files2/common/fileService2'; import { IFileService } from 'vs/platform/files/common/files'; import { DiskFileSystemProvider } from 'vs/workbench/services/files2/electron-browser/diskFileSystemProvider'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; -import { REMOTE_FILE_SYSTEM_CHANNEL_NAME, RemoteExtensionsFileSystemProvider } from 'vs/platform/remote/node/remoteAgentFileSystemChannel'; +import { REMOTE_FILE_SYSTEM_CHANNEL_NAME, RemoteExtensionsFileSystemProvider } from 'vs/platform/remote/common/remoteAgentFileSystemChannel'; class CodeRendererMain extends Disposable { diff --git a/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts b/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts new file mode 100644 index 00000000000..23ea5e1d709 --- /dev/null +++ b/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts @@ -0,0 +1,113 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as nls from 'vs/nls'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { IChannel, IServerChannel, getDelayedChannel } from 'vs/base/parts/ipc/common/ipc'; +import { Client } from 'vs/base/parts/ipc/common/ipc.net'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { connectRemoteAgentManagement, IConnectionOptions, IWebSocketFactory } from 'vs/platform/remote/common/remoteAgentConnection'; +import { IRemoteAgentConnection, IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; +import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; +import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; +import { RemoteAgentConnectionContext, IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; +import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions } from 'vs/workbench/common/contributions'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { RemoteExtensionEnvironmentChannelClient } from 'vs/workbench/services/remote/common/remoteAgentEnvironmentChannel'; +import { INotificationService } from 'vs/platform/notification/common/notification'; + +export abstract class AbstractRemoteAgentService extends Disposable implements IRemoteAgentService { + + _serviceBrand: any; + + private _environment: Promise | null; + + constructor( + @IEnvironmentService protected readonly _environmentService: IEnvironmentService + ) { + super(); + } + + abstract getConnection(): IRemoteAgentConnection | null; + + getEnvironment(bail?: boolean): Promise { + if (!this._environment) { + const connection = this.getConnection(); + if (connection) { + const client = new RemoteExtensionEnvironmentChannelClient(connection.getChannel('remoteextensionsenvironment')); + this._environment = client.getEnvironmentData(connection.remoteAuthority, this._environmentService.extensionDevelopmentLocationURI); + } else { + this._environment = Promise.resolve(null); + } + } + return bail ? this._environment : this._environment.then(undefined, () => null); + } +} + +export class RemoteAgentConnection extends Disposable implements IRemoteAgentConnection { + + readonly remoteAuthority: string; + private _connection: Promise> | null; + + constructor( + remoteAuthority: string, + private _commit: string | undefined, + private _webSocketFactory: IWebSocketFactory, + private _environmentService: IEnvironmentService, + private _remoteAuthorityResolverService: IRemoteAuthorityResolverService + ) { + super(); + this.remoteAuthority = remoteAuthority; + this._connection = null; + } + + getChannel(channelName: string): T { + return getDelayedChannel(this._getOrCreateConnection().then(c => c.getChannel(channelName))); + } + + registerChannel>(channelName: string, channel: T): void { + this._getOrCreateConnection().then(client => client.registerChannel(channelName, channel)); + } + + private _getOrCreateConnection(): Promise> { + if (!this._connection) { + this._connection = this._createConnection(); + } + return this._connection; + } + + private async _createConnection(): Promise> { + const options: IConnectionOptions = { + isBuilt: this._environmentService.isBuilt, + commit: this._commit, + webSocketFactory: this._webSocketFactory, + addressProvider: { + getAddress: async () => { + const { host, port } = await this._remoteAuthorityResolverService.resolveAuthority(this.remoteAuthority); + return { host, port }; + } + } + }; + const connection = await connectRemoteAgentManagement(options, this.remoteAuthority, `renderer`); + this._register(connection); + return connection.client; + } +} + +class RemoteConnectionFailureNotificationContribution implements IWorkbenchContribution { + + constructor( + @IRemoteAgentService remoteAgentService: IRemoteAgentService, + @INotificationService notificationService: INotificationService, + ) { + // Let's cover the case where connecting to fetch the remote extension info fails + remoteAgentService.getEnvironment(true) + .then(undefined, err => notificationService.error(nls.localize('connectionError', "Failed to connect to the remote extension host agent (Error: {0})", err ? err.message : ''))); + } + +} + +const workbenchRegistry = Registry.as(Extensions.Workbench); +workbenchRegistry.registerWorkbenchContribution(RemoteConnectionFailureNotificationContribution, LifecyclePhase.Ready); diff --git a/src/vs/workbench/services/remote/common/remoteAgentService.ts b/src/vs/workbench/services/remote/common/remoteAgentService.ts index 184e775f2e8..d8ac4d6addd 100644 --- a/src/vs/workbench/services/remote/common/remoteAgentService.ts +++ b/src/vs/workbench/services/remote/common/remoteAgentService.ts @@ -15,7 +15,7 @@ export interface IRemoteAgentService { _serviceBrand: any; getConnection(): IRemoteAgentConnection | null; - getEnvironment(): Promise; + getEnvironment(bail?: boolean): Promise; } export interface IRemoteAgentConnection { diff --git a/src/vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl.ts b/src/vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl.ts index c71c4b23cb0..4415f1cf118 100644 --- a/src/vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl.ts +++ b/src/vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl.ts @@ -3,120 +3,29 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable } from 'vs/base/common/lifecycle'; -import { IChannel, IServerChannel, getDelayedChannel } from 'vs/base/parts/ipc/common/ipc'; -import { Client } from 'vs/base/parts/ipc/common/ipc.net'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { connectRemoteAgentManagement, IConnectionOptions } from 'vs/platform/remote/common/remoteAgentConnection'; import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; -import { IRemoteAgentConnection, IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; +import { IRemoteAgentConnection } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; -import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; -import { RemoteAgentConnectionContext, IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; -import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions } from 'vs/workbench/common/contributions'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { RemoteExtensionEnvironmentChannelClient } from 'vs/workbench/services/remote/common/remoteAgentEnvironmentChannel'; -import { INotificationService } from 'vs/platform/notification/common/notification'; -import { localize } from 'vs/nls'; import product from 'vs/platform/product/node/product'; import { nodeWebSocketFactory } from 'vs/platform/remote/node/nodeWebSocketFactory'; +import { AbstractRemoteAgentService, RemoteAgentConnection } from 'vs/workbench/services/remote/common/abstractRemoteAgentService'; -export class RemoteAgentService extends Disposable implements IRemoteAgentService { - - _serviceBrand: any; +export class RemoteAgentService extends AbstractRemoteAgentService { private readonly _connection: IRemoteAgentConnection | null = null; - private _environment: Promise | null; - constructor( - { remoteAuthority }: IWindowConfiguration, - @IEnvironmentService private readonly _environmentService: IEnvironmentService, + constructor({ remoteAuthority }: IWindowConfiguration, + @IEnvironmentService environmentService: IEnvironmentService, @IRemoteAuthorityResolverService remoteAuthorityResolverService: IRemoteAuthorityResolverService ) { - super(); + super(environmentService); if (remoteAuthority) { - this._connection = this._register(new RemoteAgentConnection(remoteAuthority, _environmentService, remoteAuthorityResolverService)); + this._connection = this._register(new RemoteAgentConnection(remoteAuthority, product.commit, nodeWebSocketFactory, environmentService, remoteAuthorityResolverService)); } } getConnection(): IRemoteAgentConnection | null { return this._connection; } - - getEnvironment(bail?: boolean): Promise { - if (!this._environment) { - const connection = this.getConnection(); - if (connection) { - const client = new RemoteExtensionEnvironmentChannelClient(connection.getChannel('remoteextensionsenvironment')); - this._environment = client.getEnvironmentData(connection.remoteAuthority, this._environmentService.extensionDevelopmentLocationURI); - } else { - this._environment = Promise.resolve(null); - } - } - return bail ? this._environment : this._environment.then(undefined, () => null); - } } - -class RemoteAgentConnection extends Disposable implements IRemoteAgentConnection { - - readonly remoteAuthority: string; - private _connection: Promise> | null; - - constructor( - remoteAuthority: string, - private _environmentService: IEnvironmentService, - private _remoteAuthorityResolverService: IRemoteAuthorityResolverService - ) { - super(); - this.remoteAuthority = remoteAuthority; - this._connection = null; - } - - getChannel(channelName: string): T { - return getDelayedChannel(this._getOrCreateConnection().then(c => c.getChannel(channelName))); - } - - registerChannel>(channelName: string, channel: T): void { - this._getOrCreateConnection().then(client => client.registerChannel(channelName, channel)); - } - - private _getOrCreateConnection(): Promise> { - if (!this._connection) { - this._connection = this._createConnection(); - } - return this._connection; - } - - private async _createConnection(): Promise> { - const options: IConnectionOptions = { - isBuilt: this._environmentService.isBuilt, - commit: product.commit, - webSocketFactory: nodeWebSocketFactory, - addressProvider: { - getAddress: async () => { - const { host, port } = await this._remoteAuthorityResolverService.resolveAuthority(this.remoteAuthority); - return { host, port }; - } - } - }; - const connection = await connectRemoteAgentManagement(options, this.remoteAuthority, `renderer`); - this._register(connection); - return connection.client; - } -} - -class RemoteConnectionFailureNotificationContribution implements IWorkbenchContribution { - - constructor( - @IRemoteAgentService remoteAgentService: RemoteAgentService, - @INotificationService notificationService: INotificationService, - ) { - // Let's cover the case where connecting to fetch the remote extension info fails - remoteAgentService.getEnvironment(true) - .then(undefined, err => notificationService.error(localize('connectionError', "Failed to connect to the remote extension host agent (Error: {0})", err ? err.message : ''))); - } - -} - -const workbenchRegistry = Registry.as(Extensions.Workbench); -workbenchRegistry.registerWorkbenchContribution(RemoteConnectionFailureNotificationContribution, LifecyclePhase.Ready); \ No newline at end of file -- GitLab