diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 575f399d2d8..0a2309b5668 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -141,6 +141,12 @@ declare module 'vscode' { * @param tunnelOptions The `localPort` is a suggestion only. If that port is not available another will be chosen. */ export function openTunnel(tunnelOptions: TunnelOptions): Thenable; + + /** + * Gets an array of the currently available tunnels. This does not include environment tunnels, only tunnels that have been created by the user. + * Note that these are of type TunnelDescription and cannot be disposed. + */ + export let tunnels: Thenable; } export interface ResourceLabelFormatter { diff --git a/src/vs/workbench/api/browser/mainThreadTunnelService.ts b/src/vs/workbench/api/browser/mainThreadTunnelService.ts index f70bad49228..57718a1cbbb 100644 --- a/src/vs/workbench/api/browser/mainThreadTunnelService.ts +++ b/src/vs/workbench/api/browser/mainThreadTunnelService.ts @@ -9,6 +9,7 @@ import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { IRemoteExplorerService } from 'vs/workbench/services/remote/common/remoteExplorerService'; import { ITunnelProvider, ITunnelService, TunnelOptions } from 'vs/platform/remote/common/tunnel'; import { Disposable } from 'vs/base/common/lifecycle'; +import type { TunnelDescription } from 'vs/platform/remote/common/remoteAuthorityResolver'; @extHostNamedCustomer(MainContext.MainThreadTunnelService) export class MainThreadTunnelService extends Disposable implements MainThreadTunnelServiceShape { @@ -35,6 +36,15 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun return this.remoteExplorerService.close(remote); } + async $getTunnels(): Promise { + return (await this.tunnelService.tunnels).map(tunnel => { + return { + remoteAddress: { port: tunnel.tunnelRemotePort, host: tunnel.tunnelRemoteHost }, + localAddress: tunnel.localAddress + }; + }); + } + async $registerCandidateFinder(): Promise { this.remoteExplorerService.registerCandidateFinder(() => this._proxy.$findCandidatePorts()); } diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 6a8dc3eaa66..fa2f702323b 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -762,6 +762,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I openTunnel: (forward: vscode.TunnelOptions) => { checkProposedApiEnabled(extension); return extHostTunnelService.openTunnel(forward); + }, + get tunnels() { + return extHostTunnelService.getTunnels(); } }; diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 768f36f950a..7c62fad573d 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -31,7 +31,7 @@ import { LogLevel } from 'vs/platform/log/common/log'; import { IMarkerData } from 'vs/platform/markers/common/markers'; import { IProgressOptions, IProgressStep } from 'vs/platform/progress/common/progress'; import * as quickInput from 'vs/platform/quickinput/common/quickInput'; -import { RemoteAuthorityResolverErrorCode, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver'; +import { RemoteAuthorityResolverErrorCode, ResolverResult, TunnelDescription } from 'vs/platform/remote/common/remoteAuthorityResolver'; import * as statusbar from 'vs/workbench/services/statusbar/common/statusbar'; import { ClassifiedEvent, GDPRClassification, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings'; import { ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry'; @@ -785,6 +785,7 @@ export interface MainThreadWindowShape extends IDisposable { export interface MainThreadTunnelServiceShape extends IDisposable { $openTunnel(tunnelOptions: TunnelOptions): Promise; $closeTunnel(remote: { host: string, port: number }): Promise; + $getTunnels(): Promise; $registerCandidateFinder(): Promise; $setTunnelProvider(): Promise; $setCandidateFilter(): Promise; diff --git a/src/vs/workbench/api/common/extHostTunnelService.ts b/src/vs/workbench/api/common/extHostTunnelService.ts index 06ce1da7cdf..d92b8be4daf 100644 --- a/src/vs/workbench/api/common/extHostTunnelService.ts +++ b/src/vs/workbench/api/common/extHostTunnelService.ts @@ -31,6 +31,7 @@ export interface Tunnel extends vscode.Disposable { export interface IExtHostTunnelService extends ExtHostTunnelServiceShape { readonly _serviceBrand: undefined; openTunnel(forward: TunnelOptions): Promise; + getTunnels(): Promise; setTunnelExtensionFunctions(provider: vscode.RemoteAuthorityResolver | undefined): Promise; } @@ -41,6 +42,9 @@ export class ExtHostTunnelService implements IExtHostTunnelService { async openTunnel(forward: TunnelOptions): Promise { return undefined; } + async getTunnels(): Promise { + return []; + } async $findCandidatePorts(): Promise<{ host: string, port: number; detail: string; }[]> { return []; } diff --git a/src/vs/workbench/api/node/extHostTunnelService.ts b/src/vs/workbench/api/node/extHostTunnelService.ts index 7d3e3abdb8f..9af73f1b770 100644 --- a/src/vs/workbench/api/node/extHostTunnelService.ts +++ b/src/vs/workbench/api/node/extHostTunnelService.ts @@ -62,6 +62,10 @@ export class ExtHostTunnelService extends Disposable implements IExtHostTunnelSe return undefined; } + async getTunnels(): Promise { + return this._proxy.$getTunnels(); + } + registerCandidateFinder(): Promise { return this._proxy.$registerCandidateFinder(); }