mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-21 17:19:01 +01:00
Basic implementation of resolveExternalUri
This commit is contained in:
@@ -19,7 +19,7 @@ export class MainThreadWindow implements MainThreadWindowShape {
|
||||
|
||||
private readonly proxy: ExtHostWindowShape;
|
||||
private readonly disposables = new DisposableStore();
|
||||
private readonly _tunnels = new Map<number, Promise<RemoteTunnel>>();
|
||||
private readonly _tunnels = new Map<number, { refcount: number, readonly value: Promise<RemoteTunnel> }>();
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@@ -37,8 +37,8 @@ export class MainThreadWindow implements MainThreadWindowShape {
|
||||
dispose(): void {
|
||||
this.disposables.dispose();
|
||||
|
||||
for (const tunnel of this._tunnels.values()) {
|
||||
tunnel.then(tunnel => tunnel.dispose());
|
||||
for (const { value } of this._tunnels.values()) {
|
||||
value.then(tunnel => tunnel.dispose());
|
||||
}
|
||||
this._tunnels.clear();
|
||||
}
|
||||
@@ -47,29 +47,52 @@ export class MainThreadWindow implements MainThreadWindowShape {
|
||||
return this.windowService.isFocused();
|
||||
}
|
||||
|
||||
async $openUri(uriComponent: UriComponents, options: IOpenUriOptions): Promise<boolean> {
|
||||
let uri = URI.revive(uriComponent);
|
||||
if (options.allowTunneling && !!this.environmentService.configuration.remoteAuthority) {
|
||||
const portMappingRequest = extractLocalHostUriMetaDataForPortMapping(uri);
|
||||
if (portMappingRequest) {
|
||||
const tunnel = await this.getOrCreateTunnel(portMappingRequest.port);
|
||||
if (tunnel) {
|
||||
uri = uri.with({ authority: `127.0.0.1:${tunnel.tunnelLocalPort}` });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async $openUri(uriComponents: UriComponents, options: IOpenUriOptions): Promise<boolean> {
|
||||
const uri = await this.resolveExternalUri(URI.from(uriComponents), options);
|
||||
return this.openerService.open(uri, { openExternal: true });
|
||||
}
|
||||
|
||||
private getOrCreateTunnel(remotePort: number): Promise<RemoteTunnel> | undefined {
|
||||
async $resolveExternalUri(uriComponents: UriComponents, options: IOpenUriOptions): Promise<UriComponents> {
|
||||
const uri = URI.revive(uriComponents);
|
||||
return this.resolveExternalUri(uri, options);
|
||||
}
|
||||
|
||||
async $releaseResolvedExternalUri(uriComponents: UriComponents): Promise<boolean> {
|
||||
const portMappingRequest = extractLocalHostUriMetaDataForPortMapping(URI.from(uriComponents));
|
||||
if (portMappingRequest) {
|
||||
const existing = this._tunnels.get(portMappingRequest.port);
|
||||
if (existing) {
|
||||
if (--existing.refcount <= 0) {
|
||||
existing.value.then(tunnel => tunnel.dispose());
|
||||
this._tunnels.delete(portMappingRequest.port);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private async resolveExternalUri(uri: URI, options: IOpenUriOptions): Promise<URI> {
|
||||
if (options.allowTunneling && !!this.environmentService.configuration.remoteAuthority) {
|
||||
const portMappingRequest = extractLocalHostUriMetaDataForPortMapping(uri);
|
||||
if (portMappingRequest) {
|
||||
const tunnel = await this.retainOrCreateTunnel(portMappingRequest.port);
|
||||
if (tunnel) {
|
||||
return uri.with({ authority: `127.0.0.1:${tunnel.tunnelLocalPort}` });
|
||||
}
|
||||
}
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
|
||||
private retainOrCreateTunnel(remotePort: number): Promise<RemoteTunnel> | undefined {
|
||||
const existing = this._tunnels.get(remotePort);
|
||||
if (existing) {
|
||||
return existing;
|
||||
++existing.refcount;
|
||||
return existing.value;
|
||||
}
|
||||
const tunnel = this.tunnelService.openTunnel(remotePort);
|
||||
if (tunnel) {
|
||||
this._tunnels.set(remotePort, tunnel);
|
||||
this._tunnels.set(remotePort, { refcount: 1, value: tunnel });
|
||||
}
|
||||
return tunnel;
|
||||
}
|
||||
|
||||
@@ -248,6 +248,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
openExternal(uri: URI) {
|
||||
return extHostWindow.openUri(uri, { allowTunneling: !!initData.remote.isRemote });
|
||||
},
|
||||
resolveExternalUri(uri: URI) {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostWindow.resolveExternalUri(uri, { allowTunneling: !!initData.remote.isRemote });
|
||||
},
|
||||
get remoteName() {
|
||||
return getRemoteName(initData.remote.authority);
|
||||
},
|
||||
|
||||
@@ -738,6 +738,8 @@ export interface IOpenUriOptions {
|
||||
export interface MainThreadWindowShape extends IDisposable {
|
||||
$getWindowVisibility(): Promise<boolean>;
|
||||
$openUri(uri: UriComponents, options: IOpenUriOptions): Promise<boolean>;
|
||||
$resolveExternalUri(uri: UriComponents, options: IOpenUriOptions): Promise<UriComponents>;
|
||||
$releaseResolvedExternalUri(uri: UriComponents): Promise<boolean>;
|
||||
}
|
||||
|
||||
// -- extension host
|
||||
|
||||
@@ -9,6 +9,7 @@ import { WindowState } from 'vscode';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { isFalsyOrWhitespace } from 'vs/base/common/strings';
|
||||
import { once } from 'vs/base/common/functional';
|
||||
|
||||
export class ExtHostWindow implements ExtHostWindowShape {
|
||||
|
||||
@@ -53,4 +54,20 @@ export class ExtHostWindow implements ExtHostWindowShape {
|
||||
}
|
||||
return this._proxy.$openUri(stringOrUri, options);
|
||||
}
|
||||
|
||||
async resolveExternalUri(uri: URI, options: IOpenUriOptions): Promise<{ resolved: URI, dispose(): void }> {
|
||||
if (isFalsyOrWhitespace(uri.scheme)) {
|
||||
return Promise.reject('Invalid scheme - cannot be empty');
|
||||
} else if (!new Set([Schemas.http, Schemas.https]).has(uri.scheme)) {
|
||||
return Promise.reject(`Invalid scheme '${uri.scheme}'`);
|
||||
}
|
||||
|
||||
const resolved = await this._proxy.$resolveExternalUri(uri, options);
|
||||
return {
|
||||
resolved: URI.from(resolved),
|
||||
dispose: once(() => {
|
||||
this._proxy.$releaseResolvedExternalUri(uri);
|
||||
}),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user