@sussudio/platform
Version:
Internal APIs for VS Code's service injection the base services.
81 lines (80 loc) • 2.56 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Schemas } from '@sussudio/base/common/network.mjs';
import { URI } from '@sussudio/base/common/uri.mjs';
import { extractLocalHostUriMetaDataForPortMapping } from '../../tunnel/common/tunnel.mjs';
/**
* Manages port mappings for a single webview.
*/
export class WebviewPortMappingManager {
_getExtensionLocation;
_getMappings;
tunnelService;
_tunnels = new Map();
constructor(_getExtensionLocation, _getMappings, tunnelService) {
this._getExtensionLocation = _getExtensionLocation;
this._getMappings = _getMappings;
this.tunnelService = tunnelService;
}
async getRedirect(resolveAuthority, url) {
const uri = URI.parse(url);
const requestLocalHostInfo = extractLocalHostUriMetaDataForPortMapping(uri);
if (!requestLocalHostInfo) {
return undefined;
}
for (const mapping of this._getMappings()) {
if (mapping.webviewPort === requestLocalHostInfo.port) {
const extensionLocation = this._getExtensionLocation();
if (extensionLocation && extensionLocation.scheme === Schemas.vscodeRemote) {
const tunnel =
resolveAuthority && (await this.getOrCreateTunnel(resolveAuthority, mapping.extensionHostPort));
if (tunnel) {
if (tunnel.tunnelLocalPort === mapping.webviewPort) {
return undefined;
}
return encodeURI(
uri
.with({
authority: `127.0.0.1:${tunnel.tunnelLocalPort}`,
})
.toString(true),
);
}
}
if (mapping.webviewPort !== mapping.extensionHostPort) {
return encodeURI(
uri
.with({
authority: `${requestLocalHostInfo.address}:${mapping.extensionHostPort}`,
})
.toString(true),
);
}
}
}
return undefined;
}
async dispose() {
for (const tunnel of this._tunnels.values()) {
await tunnel.dispose();
}
this._tunnels.clear();
}
async getOrCreateTunnel(remoteAuthority, remotePort) {
const existing = this._tunnels.get(remotePort);
if (existing) {
return existing;
}
const tunnel = await this.tunnelService.openTunnel(
{ getAddress: async () => remoteAuthority },
undefined,
remotePort,
);
if (tunnel) {
this._tunnels.set(remotePort, tunnel);
}
return tunnel;
}
}