UNPKG

@microsoft/dev-tunnels-ssh-tcp

Version:

SSH TCP extensions library for Dev Tunnels

148 lines 6.26 kB
"use strict"; // // Copyright (c) Microsoft Corporation. All rights reserved. // Object.defineProperty(exports, "__esModule", { value: true }); exports.ForwardedPortsCollection = void 0; const vscode_jsonrpc_1 = require("vscode-jsonrpc"); const forwardedPortEventArgs_1 = require("./forwardedPortEventArgs"); /** * Tracks the list of ports that are currently being forwarded between the SSH client and server, * along with the set of channel connections for each forwarded port. * * Ports forwarded in either direction (client->server or server->client) are tracked in separate * collections. Typically within a session the forwarding is done only in one direction, though * the protocol supports bi-directional forwarding. * * @see PortForwardingService.RemoteForwardedPorts * @see PortForwardingService.LocalForwardedPorts */ class ForwardedPortsCollection { constructor() { /** * Maintains a mapping from port keys to port objects and channels for the port. * * The ForwardedPort string representation is used as the keys. */ this.portChannelMap = new Map(); this.portAddedEmitter = new vscode_jsonrpc_1.Emitter(); /** Event raised when a port is added to the collection. */ this.onPortAdded = this.portAddedEmitter.event; this.portUpdatedEmitter = new vscode_jsonrpc_1.Emitter(); /** * Event raised when a port in the collection is updated. "Updating" a port doesn't * change anything at the SSH protocol level, but the application may use this event * as a signal to update or refresh its state for the forwarded port. */ this.onPortUpdated = this.portUpdatedEmitter.event; this.portRemovedEmitter = new vscode_jsonrpc_1.Emitter(); /** Event raised when a port is removed from the collection. */ this.onPortRemoved = this.portRemovedEmitter.event; this.portChannelAddedEmitter = new vscode_jsonrpc_1.Emitter(); /** Event raised when a channel is added to the collection. */ this.onPortChannelAdded = this.portChannelAddedEmitter.event; this.portChannelRemovedEmitter = new vscode_jsonrpc_1.Emitter(); /** Event raised when a channel is removed from the collection. */ this.onPortChannelRemoved = this.portChannelRemovedEmitter.event; } /** Gets the number of ports in the collection. */ get size() { return this.portChannelMap.size; } /** Checks whether a port is in the collection. */ has(port) { return this.portChannelMap.has(port.toString()); } /** Lists all the ports in the collection. */ *values() { for (const [port, channels] of this.portChannelMap.values()) { yield port; } } /** Iterates over all the ports in the collection. */ [Symbol.iterator]() { return this.values(); } /** Lists all the ports in the collection. */ *entries() { for (const [port, channels] of this.portChannelMap.values()) { yield [port, port]; } } /** * Lists all the ports in the collection. * (In a set, the keys are the same as the values.) */ keys() { return this.values(); } /** Iterates over all the ports in the collection, invoking a callback function on each. */ forEach(callbackfn, thisArg) { for (const [port, channels] of this.portChannelMap.values()) { callbackfn.apply(thisArg, [port, port, this]); } } getChannels(port) { const portAndChannels = this.portChannelMap.get(port.toString()); if (!portAndChannels) { throw new Error(`Port ${port} is not in the collection.`); } return portAndChannels[1]; } /** Finds the first port in the collection that matches a predicate. */ find(predicate) { for (const port of this.values()) { if (predicate(port)) { return port; } } return undefined; } /* @internal */ addOrUpdatePort(port) { if (this.has(port)) { this.portUpdatedEmitter.fire(new forwardedPortEventArgs_1.ForwardedPortEventArgs(port)); } this.portChannelMap.set(port.toString(), [port, []]); this.portAddedEmitter.fire(new forwardedPortEventArgs_1.ForwardedPortEventArgs(port)); } /* @internal */ removePort(port) { if (!this.has(port)) { return false; } this.portChannelMap.delete(port.toString()); this.portRemovedEmitter.fire(new forwardedPortEventArgs_1.ForwardedPortEventArgs(port)); return true; } /* @internal */ addChannel(port, channel) { const portAndChannels = this.portChannelMap.get(port.toString()); if (!portAndChannels) { throw new Error(`Port ${port} is not in the collection.`); } const portChannels = portAndChannels[1]; if (portChannels.find((c) => c.channelId === channel.channelId)) { throw new Error(`Channel ${channel.channelId} is already in the collection for port ${port}`); } portChannels.push(channel); channel.onClosed(() => this.tryRemoveChannel(port, channel)); this.portChannelAddedEmitter.fire(new forwardedPortEventArgs_1.ForwardedPortChannelEventArgs(port, channel)); } tryRemoveChannel(port, channel) { const portAndChannels = this.portChannelMap.get(port.toString()); if (portAndChannels) { const portChannels = portAndChannels[1]; const index = portChannels.findIndex((c) => c.channelId === channel.channelId); if (index >= 0) { portChannels.splice(index, 1); this.portChannelRemovedEmitter.fire(new forwardedPortEventArgs_1.ForwardedPortChannelEventArgs(port, channel)); } } } toString() { return [...this].join(', '); } } exports.ForwardedPortsCollection = ForwardedPortsCollection; //# sourceMappingURL=forwardedPortsCollection.js.map