import debug from 'debug'; import { hri } from 'human-readable-ids'; import { Client } from './Client.js'; import { TunnelAgent } from './TunnelAgent.js'; export class ClientManager { stats; clients; clientTunnelInfo; log; opt; constructor(opt = {}) { this.opt = opt; this.clients = new Map(); this.clientTunnelInfo = new Map(); this.stats = { tunnels: 0 }; this.log = debug('lt:ClientManager'); } getClient(id) { return this.clients.get(id); } hasClient(id) { return this.clients.has(id); } async newClient(requestedId, url, domain) { let id; if (requestedId && !this.clients.has(requestedId)) { id = requestedId; } else { id = hri.random(); } const maxSockets = this.opt.maxTcpSockets; const agent = new TunnelAgent({ clientId: id, maxTcpSockets: 10, tunnelServer: this.opt.tunnelServer, }); const client = new Client({ agent, id }); this.clients.set(id, client); this.clientTunnelInfo.set(id, { domain, url }); client.once('close', () => { this.removeClient(id); }); try { const info = await agent.listen(); ++this.stats.tunnels; // Call the onTunnelCreated hook if (this.opt.onTunnelCreated) { this.opt.onTunnelCreated({ domain, id, url }); } return { domain, id: id, maxConnCount: maxSockets, port: info.port, url, }; } catch (err) { this.removeClient(id); throw err; } } removeClient(id) { this.log('removing client: %s', id); const client = this.clients.get(id); if (!client) return; const tunnelInfo = this.clientTunnelInfo.get(id); const domain = tunnelInfo?.domain || ''; const url = tunnelInfo?.url || ''; --this.stats.tunnels; this.clients.delete(id); this.clientTunnelInfo.delete(id); client.close(); // Call the onTunnelClosed hook if (this.opt.onTunnelClosed) { this.opt.onTunnelClosed({ domain, id, url }); } } } //# sourceMappingURL=ClientManager.js.map