diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 4b7ea910891..945c9bd2aae 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -16,7 +16,7 @@ declare module 'vscode' { - //#region Alex - resolvers + //#region Alex - resolvers, AlexR - ports export interface RemoteAuthorityResolverContext { resolveAttempt: number; @@ -33,7 +33,31 @@ declare module 'vscode' { extensionHostEnv?: { [key: string]: string | null }; } - export type ResolverResult = ResolvedAuthority & ResolvedOptions; + export interface TunnelOptions { + remote: { port: number, host: string }; + localPort?: number; + name?: string; + closeable?: boolean; + } + + export interface Tunnel extends Disposable { + remote: { port: number, host: string }; + local: { port: number, host: string }; + } + + /** + * Used as part of the ResolverResult if the extension has any candidate, published, or forwarded ports. + */ + export interface TunnelInformation { + /** + * Tunnels that are detected by the extension. The remotePort is used for display purposes. + * The localAddress should be the complete local address(ex. localhost:1234) for connecting to the port. Tunnels provided through + * detected are read-only from the forwarded ports UI. + */ + detectedTunnels?: { remotePort: number, localAddress: string }[]; + } + + export type ResolverResult = ResolvedAuthority & ResolvedOptions & TunnelInformation; export class RemoteAuthorityResolverError extends Error { static NotAvailable(message?: string, handled?: boolean): RemoteAuthorityResolverError; @@ -44,6 +68,20 @@ declare module 'vscode' { export interface RemoteAuthorityResolver { resolve(authority: string, context: RemoteAuthorityResolverContext): ResolverResult | Thenable; + /** + * Can be optionally implemented if the extension can forward ports better than the core. + * When not implemented, the core will use its default forwarding logic. + * When implemented, the core will use this to forward ports. + */ + forwardPort?(tunnelOptions: TunnelOptions): Thenable; + } + + export namespace workspace { + /** + * Forwards a port. + * @param forward The `localPort` is a suggestion only. If that port is not available another will be chosen. + */ + export function makeTunnel(forward: TunnelOptions): Thenable; } export interface ResourceLabelFormatter { diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 17d88ec6b3d..69fee57eace 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -67,6 +67,7 @@ import { ILogService } from 'vs/platform/log/common/log'; import { IURITransformerService } from 'vs/workbench/api/common/extHostUriTransformerService'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; +import { IExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelService'; export interface IExtensionApiFactory { (extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode; @@ -86,6 +87,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I const rpcProtocol = accessor.get(IExtHostRpcService); const extHostStorage = accessor.get(IExtHostStorage); const extHostLogService = accessor.get(ILogService); + const extHostTunnelService = accessor.get(IExtHostTunnelService); // register addressable instances rpcProtocol.set(ExtHostContext.ExtHostLogService, extHostLogService); @@ -93,6 +95,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I rpcProtocol.set(ExtHostContext.ExtHostConfiguration, extHostConfiguration); rpcProtocol.set(ExtHostContext.ExtHostExtensionService, extensionService); rpcProtocol.set(ExtHostContext.ExtHostStorage, extHostStorage); + rpcProtocol.set(ExtHostContext.ExtHostTunnelService, extHostTunnelService); // automatically create and register addressable instances const extHostDecorations = rpcProtocol.set(ExtHostContext.ExtHostDecorations, accessor.get(IExtHostDecorations)); @@ -710,6 +713,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I }, onWillRenameFiles: (listener: (e: vscode.FileWillRenameEvent) => any, thisArg?: any, disposables?: vscode.Disposable[]) => { return extHostFileSystemEvent.getOnWillRenameFileEvent(extension)(listener, thisArg, disposables); + }, + makeTunnel: (forward: vscode.TunnelOptions) => { + checkProposedApiEnabled(extension); + return extHostTunnelService.makeTunnel(forward); } }; diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 597271afd93..dc89753a162 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1390,6 +1390,11 @@ export interface ExtHostStorageShape { $acceptValue(shared: boolean, key: string, value: object | undefined): void; } + +export interface ExtHostTunnelServiceShape { + +} + // --- proxy identifiers export const MainContext = { @@ -1464,5 +1469,6 @@ export const ExtHostContext = { ExtHostStorage: createMainId('ExtHostStorage'), ExtHostUrls: createExtId('ExtHostUrls'), ExtHostOutputService: createMainId('ExtHostOutputService'), - ExtHosLabelService: createMainId('ExtHostLabelService') + ExtHosLabelService: createMainId('ExtHostLabelService'), + ExtHostTunnelService: createMainId('ExtHostTunnelService') }; diff --git a/src/vs/workbench/api/common/extHostTunnelService.ts b/src/vs/workbench/api/common/extHostTunnelService.ts new file mode 100644 index 00000000000..20ddef9845d --- /dev/null +++ b/src/vs/workbench/api/common/extHostTunnelService.ts @@ -0,0 +1,21 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ExtHostTunnelServiceShape } from 'vs/workbench/api/common/extHost.protocol'; +import * as vscode from 'vscode'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; + +export interface IExtHostTunnelService extends ExtHostTunnelServiceShape { + makeTunnel(forward: vscode.TunnelOptions): Promise; +} + +export const IExtHostTunnelService = createDecorator('IExtHostTunnelService'); + +export class ExtHostTunnelService implements IExtHostTunnelService { + makeTunnel(forward: vscode.TunnelOptions): Promise { + throw new Error('Method not implemented.'); + } +} + diff --git a/src/vs/workbench/api/node/extHost.services.ts b/src/vs/workbench/api/node/extHost.services.ts index 9ae085f5366..7dd3169394c 100644 --- a/src/vs/workbench/api/node/extHost.services.ts +++ b/src/vs/workbench/api/node/extHost.services.ts @@ -26,6 +26,7 @@ import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionS import { IExtHostStorage, ExtHostStorage } from 'vs/workbench/api/common/extHostStorage'; import { ILogService } from 'vs/platform/log/common/log'; import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService'; +import { IExtHostTunnelService, ExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelService'; // register singleton services registerSingleton(ILogService, ExtHostLogService); @@ -42,3 +43,4 @@ registerSingleton(IExtHostSearch, NativeExtHostSearch); registerSingleton(IExtensionStoragePaths, ExtensionStoragePaths); registerSingleton(IExtHostExtensionService, ExtHostExtensionService); registerSingleton(IExtHostStorage, ExtHostStorage); +registerSingleton(IExtHostTunnelService, ExtHostTunnelService); diff --git a/src/vs/workbench/services/extensions/worker/extHost.services.ts b/src/vs/workbench/services/extensions/worker/extHost.services.ts index 8a65101aa4e..de59a448147 100644 --- a/src/vs/workbench/services/extensions/worker/extHost.services.ts +++ b/src/vs/workbench/services/extensions/worker/extHost.services.ts @@ -21,6 +21,7 @@ import { ExtHostExtensionService } from 'vs/workbench/api/worker/extHostExtensio 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'; // register singleton services registerSingleton(ILogService, ExtHostLogService); @@ -33,6 +34,7 @@ registerSingleton(IExtHostDocumentsAndEditors, ExtHostDocumentsAndEditors); registerSingleton(IExtHostStorage, ExtHostStorage); registerSingleton(IExtHostExtensionService, ExtHostExtensionService); registerSingleton(IExtHostSearch, ExtHostSearch); +registerSingleton(IExtHostTunnelService, ExtHostTunnelService); // register services that only throw errors function NotImplementedProxy(name: ServiceIdentifier): { new(): T } {