UNPKG

vibetunnel

Version:

Terminal sharing server with web interface - supports macOS, Linux, and headless environments

176 lines 24 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.RemoteRegistry = void 0; const chalk_1 = __importDefault(require("chalk")); const server_js_1 = require("../server.js"); const logger_js_1 = require("../utils/logger.js"); const logger = (0, logger_js_1.createLogger)('remote-registry'); class RemoteRegistry { constructor() { this.remotes = new Map(); this.remotesByName = new Map(); this.sessionToRemote = new Map(); // sessionId -> remoteId this.healthCheckInterval = null; this.HEALTH_CHECK_INTERVAL = 15000; // Check every 15 seconds this.HEALTH_CHECK_TIMEOUT = 5000; // 5 second timeout per check this.startHealthChecker(); logger.debug('remote registry initialized with health check interval', { interval: this.HEALTH_CHECK_INTERVAL, timeout: this.HEALTH_CHECK_TIMEOUT, }); } register(remote) { // Check if a remote with the same name already exists if (this.remotesByName.has(remote.name)) { throw new Error(`Remote with name '${remote.name}' is already registered`); } const now = new Date(); const registeredRemote = { ...remote, registeredAt: now, lastHeartbeat: now, sessionIds: new Set(), }; this.remotes.set(remote.id, registeredRemote); this.remotesByName.set(remote.name, registeredRemote); logger.log(chalk_1.default.green(`remote registered: ${remote.name} (${remote.id}) from ${remote.url}`)); // Immediately check health of new remote this.checkRemoteHealth(registeredRemote); return registeredRemote; } unregister(remoteId) { const remote = this.remotes.get(remoteId); if (remote) { logger.log(chalk_1.default.yellow(`remote unregistered: ${remote.name} (${remoteId})`)); // Clean up session mappings for (const sessionId of remote.sessionIds) { this.sessionToRemote.delete(sessionId); } this.remotesByName.delete(remote.name); return this.remotes.delete(remoteId); } return false; } getRemote(remoteId) { const remote = this.remotes.get(remoteId); if (!remote) { logger.debug(`remote not found: ${remoteId}`); } return remote; } getRemoteByUrl(url) { return Array.from(this.remotes.values()).find((r) => r.url === url); } getRemotes() { return Array.from(this.remotes.values()); } getRemoteBySessionId(sessionId) { const remoteId = this.sessionToRemote.get(sessionId); return remoteId ? this.remotes.get(remoteId) : undefined; } updateRemoteSessions(remoteId, sessionIds) { const remote = this.remotes.get(remoteId); if (!remote) { logger.debug(`cannot update sessions: remote ${remoteId} not found`); return; } const oldCount = remote.sessionIds.size; // Remove old session mappings for (const oldSessionId of remote.sessionIds) { this.sessionToRemote.delete(oldSessionId); } // Update with new sessions remote.sessionIds = new Set(sessionIds); for (const sessionId of sessionIds) { this.sessionToRemote.set(sessionId, remoteId); } logger.debug(`updated sessions for remote ${remote.name}`, { oldCount, newCount: sessionIds.length, }); } addSessionToRemote(remoteId, sessionId) { const remote = this.remotes.get(remoteId); if (!remote) { logger.warn(`cannot add session ${sessionId}: remote ${remoteId} not found`); return; } remote.sessionIds.add(sessionId); this.sessionToRemote.set(sessionId, remoteId); logger.debug(`session ${sessionId} added to remote ${remote.name}`); } removeSessionFromRemote(sessionId) { const remoteId = this.sessionToRemote.get(sessionId); if (!remoteId) { logger.debug(`session ${sessionId} not mapped to any remote`); return; } const remote = this.remotes.get(remoteId); if (remote) { remote.sessionIds.delete(sessionId); logger.debug(`session ${sessionId} removed from remote ${remote.name}`); } this.sessionToRemote.delete(sessionId); } async checkRemoteHealth(remote) { // Skip health checks during shutdown if ((0, server_js_1.isShuttingDown)()) { return; } try { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), this.HEALTH_CHECK_TIMEOUT); // Use the token provided by the remote for authentication const headers = { Authorization: `Bearer ${remote.token}`, }; // Only check health endpoint - all remotes MUST have it const response = await fetch(`${remote.url}/api/health`, { headers, signal: controller.signal, }); clearTimeout(timeoutId); if (response.ok) { remote.lastHeartbeat = new Date(); logger.debug(`health check passed for ${remote.name}`); } else { throw new Error(`HTTP ${response.status}`); } } catch (error) { // During shutdown, don't log errors or unregister remotes if (!(0, server_js_1.isShuttingDown)()) { logger.warn(`remote failed health check: ${remote.name} (${remote.id})`, error); // Remove the remote if it fails health check this.unregister(remote.id); } } } startHealthChecker() { logger.debug('starting health checker'); this.healthCheckInterval = setInterval(() => { // Skip health checks during shutdown if ((0, server_js_1.isShuttingDown)()) { return; } // Check all remotes in parallel const healthChecks = Array.from(this.remotes.values()).map((remote) => this.checkRemoteHealth(remote)); Promise.all(healthChecks).catch((err) => { logger.error('error in health checks:', err); }); }, this.HEALTH_CHECK_INTERVAL); } destroy() { logger.log(chalk_1.default.yellow('destroying remote registry')); if (this.healthCheckInterval) { clearInterval(this.healthCheckInterval); logger.debug('health checker stopped'); } } } exports.RemoteRegistry = RemoteRegistry; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVtb3RlLXJlZ2lzdHJ5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3NlcnZlci9zZXJ2aWNlcy9yZW1vdGUtcmVnaXN0cnkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsa0RBQTBCO0FBQzFCLDRDQUE4QztBQUM5QyxrREFBa0Q7QUFFbEQsTUFBTSxNQUFNLEdBQUcsSUFBQSx3QkFBWSxFQUFDLGlCQUFpQixDQUFDLENBQUM7QUFZL0MsTUFBYSxjQUFjO0lBUXpCO1FBUFEsWUFBTyxHQUE4QixJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQy9DLGtCQUFhLEdBQThCLElBQUksR0FBRyxFQUFFLENBQUM7UUFDckQsb0JBQWUsR0FBd0IsSUFBSSxHQUFHLEVBQUUsQ0FBQyxDQUFDLHdCQUF3QjtRQUMxRSx3QkFBbUIsR0FBMEIsSUFBSSxDQUFDO1FBQ3pDLDBCQUFxQixHQUFHLEtBQUssQ0FBQyxDQUFDLHlCQUF5QjtRQUN4RCx5QkFBb0IsR0FBRyxJQUFJLENBQUMsQ0FBQyw2QkFBNkI7UUFHekUsSUFBSSxDQUFDLGtCQUFrQixFQUFFLENBQUM7UUFDMUIsTUFBTSxDQUFDLEtBQUssQ0FBQyx3REFBd0QsRUFBRTtZQUNyRSxRQUFRLEVBQUUsSUFBSSxDQUFDLHFCQUFxQjtZQUNwQyxPQUFPLEVBQUUsSUFBSSxDQUFDLG9CQUFvQjtTQUNuQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQsUUFBUSxDQUNOLE1BQTJFO1FBRTNFLHNEQUFzRDtRQUN0RCxJQUFJLElBQUksQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQ3hDLE1BQU0sSUFBSSxLQUFLLENBQUMscUJBQXFCLE1BQU0sQ0FBQyxJQUFJLHlCQUF5QixDQUFDLENBQUM7UUFDN0UsQ0FBQztRQUVELE1BQU0sR0FBRyxHQUFHLElBQUksSUFBSSxFQUFFLENBQUM7UUFDdkIsTUFBTSxnQkFBZ0IsR0FB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LENBQUMsR0FBRyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FDcEUsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE1BQU0sQ0FBQyxDQUMvQixDQUFDO1lBRUYsT0FBTyxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRTtnQkFDdEMsTUFBTSxDQUFDLEtBQUssQ0FBQyx5QkFBeUIsRUFBRSxHQUFHLENBQUMsQ0FBQztZQUMvQyxDQUFDLENBQUMsQ0FBQztRQUNMLENBQUMsRUFBRSxJQUFJLENBQUMscUJBQXFCLENBQUMsQ0FBQztJQUNqQyxDQUFDO0lBRUQsT0FBTztRQUNMLE1BQU0sQ0FBQyxHQUFHLENBQUMsZUFBSyxDQUFDLE1BQU0sQ0FBQyw0QkFBNEIsQ0FBQyxDQUFDLENBQUM7UUFDdkQsSUFBSSxJQUFJLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztZQUM3QixhQUFhLENBQUMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLENBQUM7WUFDeEMsTUFBTSxDQUFDLEtBQUssQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO1FBQ3pDLENBQUM7SUFDSCxDQUFDO0NBQ0Y7QUF0TUQsd0NBc01DIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGNoYWxrIGZyb20gJ2NoYWxrJztcbmltcG9ydCB7IGlzU2h1dHRpbmdEb3duIH0gZnJvbSAnLi4vc2VydmVyLmpzJztcbmltcG9ydCB7IGNyZWF0ZUxvZ2dlciB9IGZyb20gJy4uL3V0aWxzL2xvZ2dlci5qcyc7XG5cbmNvbnN0IGxvZ2dlciA9IGNyZWF0ZUxvZ2dlcigncmVtb3RlLXJlZ2lzdHJ5Jyk7XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmVtb3RlU2VydmVyIHtcbiAgaWQ6IHN0cmluZztcbiAgbmFtZTogc3RyaW5nO1xuICB1cmw6IHN0cmluZztcbiAgdG9rZW46IHN0cmluZztcbiAgcmVnaXN0ZXJlZEF0OiBEYXRlO1xuICBsYXN0SGVhcnRiZWF0OiBEYXRlO1xuICBzZXNzaW9uSWRzOiBTZXQ8c3RyaW5nPjsgLy8gVHJhY2sgd2hpY2ggc2Vzc2lvbnMgYmVsb25nIHRvIHRoaXMgcmVtb3RlXG59XG5cbmV4cG9ydCBjbGFzcyBSZW1vdGVSZWdpc3RyeSB7XG4gIHByaXZhdGUgcmVtb3RlczogTWFwPHN0cmluZywgUmVtb3RlU2VydmVyPiA9IG5ldyBNYXAoKTtcbiAgcHJpdmF0ZSByZW1vdGVzQnlOYW1lOiBNYXA8c3RyaW5nLCBSZW1vdGVTZXJ2ZXI+ID0gbmV3IE1hcCgpO1xuICBwcml2YXRlIHNlc3Npb25Ub1JlbW90ZTogTWFwPHN0cmluZywgc3RyaW5nPiA9IG5ldyBNYXAoKTsgLy8gc2Vzc2lvbklkIC0+IHJlbW90ZUlkXG4gIHByaXZhdGUgaGVhbHRoQ2hlY2tJbnRlcnZhbDogTm9kZUpTLlRpbWVvdXQgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSByZWFkb25seSBIRUFMVEhfQ0hFQ0tfSU5URVJWQUwgPSAxNTAwMDsgLy8gQ2hlY2sgZXZlcnkgMTUgc2Vjb25kc1xuICBwcml2YXRlIHJlYWRvbmx5IEhFQUxUSF9DSEVDS19USU1FT1VUID0gNTAwMDsgLy8gNSBzZWNvbmQgdGltZW91dCBwZXIgY2hlY2tcblxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICB0aGlzLnN0YXJ0SGVhbHRoQ2hlY2tlcigpO1xuICAgIGxvZ2dlci5kZWJ1ZygncmVtb3RlIHJlZ2lzdHJ5IGluaXRpYWxpemVkIHdpdGggaGVhbHRoIGNoZWNrIGludGVydmFsJywge1xuICAgICAgaW50ZXJ2YWw6IHRoaXMuSEVBTFRIX0NIRUNLX0lOVEVSVkFMLFxuICAgICAgdGltZW91dDogdGhpcy5IRUFMVEhfQ0hFQ0tfVElNRU9VVCxcbiAgICB9KTtcbiAgfVxuXG4gIHJlZ2lzdGVyKFxuICAgIHJlbW90ZTogT21pdDxSZW1vdGVTZXJ2ZXIsICdyZWdpc3RlcmVkQXQnIHwgJ2xhc3RIZWFydGJlYXQnIHwgJ3Nlc3Npb25JZHMnPlxuICApOiBSZW1vdGVTZXJ2ZXIge1xuICAgIC8vIENoZWNrIGlmIGEgcmVtb3RlIHdpdGggdGhlIHNhbWUgbmFtZSBhbHJlYWR5IGV4aXN0c1xuICAgIGlmICh0aGlzLnJlbW90ZXNCeU5hbWUuaGFzKHJlbW90ZS5uYW1lKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBSZW1vdGUgd2l0aCBuYW1lICcke3JlbW90ZS5uYW1lfScgaXMgYWxyZWFkeSByZWdpc3RlcmVkYCk7XG4gICAgfVxuXG4gICAgY29uc3Qgbm93ID0gbmV3IERhdGUoKTtcbiAgICBjb25zdCByZWdpc3RlcmVkUmVtb3RlOiBSZW1vdGVTZXJ2ZXIgPSB7XG4gICAgICAuLi5yZW1vdGUsXG4gICAgICByZWdpc3RlcmVkQXQ6IG5vdyxcbiAgICAgIGxhc3RIZWFydGJlYXQ6IG5vdyxcbiAgICAgIHNlc3Npb25JZHM6IG5ldyBTZXQ8c3RyaW5nPigpLFxuICAgIH07XG5cbiAgICB0aGlzLnJlbW90ZXMuc2V0KHJlbW90ZS5pZCwgcmVnaXN0ZXJlZFJlbW90ZSk7XG4gICAgdGhpcy5yZW1vdGVzQnlOYW1lLnNldChyZW1vdGUubmFtZSwgcmVnaXN0ZXJlZFJlbW90ZSk7XG4gICAgbG9nZ2VyLmxvZyhjaGFsay5ncmVlbihgcmVtb3RlIHJlZ2lzdGVyZWQ6ICR7cmVtb3RlLm5hbWV9ICgke3JlbW90ZS5pZH0pIGZyb20gJHtyZW1vdGUudXJsfWApKTtcblxuICAgIC8vIEltbWVkaWF0ZWx5IGNoZWNrIGhlYWx0aCBvZiBuZXcgcmVtb3RlXG4gICAgdGhpcy5jaGVja1JlbW90ZUhlYWx0aChyZWdpc3RlcmVkUmVtb3RlKTtcblxuICAgIHJldHVybiByZWdpc3RlcmVkUmVtb3RlO1xuICB9XG5cbiAgdW5yZWdpc3RlcihyZW1vdGVJZDogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgY29uc3QgcmVtb3RlID0gdGhpcy5yZW1vdGVzLmdldChyZW1vdGVJZCk7XG4gICAgaWYgKHJlbW90ZSkge1xuICAgICAgbG9nZ2VyLmxvZyhjaGFsay55ZWxsb3coYHJlbW90ZSB1bnJlZ2lzdGVyZWQ6ICR7cmVtb3RlLm5hbWV9ICgke3JlbW90ZUlkfSlgKSk7XG5cbiAgICAgIC8vIENsZWFuIHVwIHNlc3Npb24gbWFwcGluZ3NcbiAgICAgIGZvciAoY29uc3Qgc2Vzc2lvbklkIG9mIHJlbW90ZS5zZXNzaW9uSWRzKSB7XG4gICAgICAgIHRoaXMuc2Vzc2lvblRvUmVtb3RlLmRlbGV0ZShzZXNzaW9uSWQpO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnJlbW90ZXNCeU5hbWUuZGVsZXRlKHJlbW90ZS5uYW1lKTtcbiAgICAgIHJldHVybiB0aGlzLnJlbW90ZXMuZGVsZXRlKHJlbW90ZUlkKTtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgZ2V0UmVtb3RlKHJlbW90ZUlkOiBzdHJpbmcpOiBSZW1vdGVTZXJ2ZXIgfCB1bmRlZmluZWQge1xuICAgIGNvbnN0IHJlbW90ZSA9IHRoaXMucmVtb3Rlcy5nZXQocmVtb3RlSWQpO1xuICAgIGlmICghcmVtb3RlKSB7XG4gICAgICBsb2dnZXIuZGVidWcoYHJlbW90ZSBub3QgZm91bmQ6ICR7cmVtb3RlSWR9YCk7XG4gICAgfVxuICAgIHJldHVybiByZW1vdGU7XG4gIH1cblxuICBnZXRSZW1vdGVCeVVybCh1cmw6IHN0cmluZyk6IFJlbW90ZVNlcnZlciB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIEFycmF5LmZyb20odGhpcy5yZW1vdGVzLnZhbHVlcygpKS5maW5kKChyKSA9PiByLnVybCA9PT0gdXJsKTtcbiAgfVxuXG4gIGdldFJlbW90ZXMoKTogUmVtb3RlU2VydmVyW10ge1xuICAgIHJldHVybiBBcnJheS5mcm9tKHRoaXMucmVtb3Rlcy52YWx1ZXMoKSk7XG4gIH1cblxuICBnZXRSZW1vdGVCeVNlc3Npb25JZChzZXNzaW9uSWQ6IHN0cmluZyk6IFJlbW90ZVNlcnZlciB8IHVuZGVmaW5lZCB7XG4gICAgY29uc3QgcmVtb3RlSWQgPSB0aGlzLnNlc3Npb25Ub1JlbW90ZS5nZXQoc2Vzc2lvbklkKTtcbiAgICByZXR1cm4gcmVtb3RlSWQgPyB0aGlzLnJlbW90ZXMuZ2V0KHJlbW90ZUlkKSA6IHVuZGVmaW5lZDtcbiAgfVxuXG4gIHVwZGF0ZVJlbW90ZVNlc3Npb25zKHJlbW90ZUlkOiBzdHJpbmcsIHNlc3Npb25JZHM6IHN0cmluZ1tdKTogdm9pZCB7XG4gICAgY29uc3QgcmVtb3RlID0gdGhpcy5yZW1vdGVzLmdldChyZW1vdGVJZCk7XG4gICAgaWYgKCFyZW1vdGUpIHtcbiAgICAgIGxvZ2dlci5kZWJ1ZyhgY2Fubm90IHVwZGF0ZSBzZXNzaW9uczogcmVtb3RlICR7cmVtb3RlSWR9IG5vdCBmb3VuZGApO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IG9sZENvdW50ID0gcmVtb3RlLnNlc3Npb25JZHMuc2l6ZTtcblxuICAgIC8vIFJlbW92ZSBvbGQgc2Vzc2lvbiBtYXBwaW5nc1xuICAgIGZvciAoY29uc3Qgb2xkU2Vzc2lvbklkIG9mIHJlbW90ZS5zZXNzaW9uSWRzKSB7XG4gICAgICB0aGlzLnNlc3Npb25Ub1JlbW90ZS5kZWxldGUob2xkU2Vzc2lvbklkKTtcbiAgICB9XG5cbiAgICAvLyBVcGRhdGUgd2l0aCBuZXcgc2Vzc2lvbnNcbiAgICByZW1vdGUuc2Vzc2lvbklkcyA9IG5ldyBTZXQoc2Vzc2lvbklkcyk7XG4gICAgZm9yIChjb25zdCBzZXNzaW9uSWQgb2Ygc2Vzc2lvbklkcykge1xuICAgICAgdGhpcy5zZXNzaW9uVG9SZW1vdGUuc2V0KHNlc3Npb25JZCwgcmVtb3RlSWQpO1xuICAgIH1cblxuICAgIGxvZ2dlci5kZWJ1ZyhgdXBkYXRlZCBzZXNzaW9ucyBmb3IgcmVtb3RlICR7cmVtb3RlLm5hbWV9YCwge1xuICAgICAgb2xkQ291bnQsXG4gICAgICBuZXdDb3VudDogc2Vzc2lvbklkcy5sZW5ndGgsXG4gICAgfSk7XG4gIH1cblxuICBhZGRTZXNzaW9uVG9SZW1vdGUocmVtb3RlSWQ6IHN0cmluZywgc2Vzc2lvbklkOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCByZW1vdGUgPSB0aGlzLnJlbW90ZXMuZ2V0KHJlbW90ZUlkKTtcbiAgICBpZiAoIXJlbW90ZSkge1xuICAgICAgbG9nZ2VyLndhcm4oYGNhbm5vdCBhZGQgc2Vzc2lvbiAke3Nlc3Npb25JZH06IHJlbW90ZSAke3JlbW90ZUlkfSBub3QgZm91bmRgKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICByZW1vdGUuc2Vzc2lvbklkcy5hZGQoc2Vzc2lvbklkKTtcbiAgICB0aGlzLnNlc3Npb25Ub1JlbW90ZS5zZXQoc2Vzc2lvbklkLCByZW1vdGVJZCk7XG4gICAgbG9nZ2VyLmRlYnVnKGBzZXNzaW9uICR7c2Vzc2lvbklkfSBhZGRlZCB0byByZW1vdGUgJHtyZW1vdGUubmFtZX1gKTtcbiAgfVxuXG4gIHJlbW92ZVNlc3Npb25Gcm9tUmVtb3RlKHNlc3Npb25JZDogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3QgcmVtb3RlSWQgPSB0aGlzLnNlc3Npb25Ub1JlbW90ZS5nZXQoc2Vzc2lvbklkKTtcbiAgICBpZiAoIXJlbW90ZUlkKSB7XG4gICAgICBsb2dnZXIuZGVidWcoYHNlc3Npb24gJHtzZXNzaW9uSWR9IG5vdCBtYXBwZWQgdG8gYW55IHJlbW90ZWApO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHJlbW90ZSA9IHRoaXMucmVtb3Rlcy5nZXQocmVtb3RlSWQpO1xuICAgIGlmIChyZW1vdGUpIHtcbiAgICAgIHJlbW90ZS5zZXNzaW9uSWRzLmRlbGV0ZShzZXNzaW9uSWQpO1xuICAgICAgbG9nZ2VyLmRlYnVnKGBzZXNzaW9uICR7c2Vzc2lvbklkfSByZW1vdmVkIGZyb20gcmVtb3RlICR7cmVtb3RlLm5hbWV9YCk7XG4gICAgfVxuXG4gICAgdGhpcy5zZXNzaW9uVG9SZW1vdGUuZGVsZXRlKHNlc3Npb25JZCk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGNoZWNrUmVtb3RlSGVhbHRoKHJlbW90ZTogUmVtb3RlU2VydmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8gU2tpcCBoZWFsdGggY2hlY2tzIGR1cmluZyBzaHV0ZG93blxuICAgIGlmIChpc1NodXR0aW5nRG93bigpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGNvbnRyb2xsZXIgPSBuZXcgQWJvcnRDb250cm9sbGVyKCk7XG4gICAgICBjb25zdCB0aW1lb3V0SWQgPSBzZXRUaW1lb3V0KCgpID0+IGNvbnRyb2xsZXIuYWJvcnQoKSwgdGhpcy5IRUFMVEhfQ0hFQ0tfVElNRU9VVCk7XG5cbiAgICAgIC8vIFVzZSB0aGUgdG9rZW4gcHJvdmlkZWQgYnkgdGhlIHJlbW90ZSBmb3IgYXV0aGVudGljYXRpb25cbiAgICAgIGNvbnN0IGhlYWRlcnM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgICAgIEF1dGhvcml6YXRpb246IGBCZWFyZXIgJHtyZW1vdGUudG9rZW59YCxcbiAgICAgIH07XG5cbiAgICAgIC8vIE9ubHkgY2hlY2sgaGVhbHRoIGVuZHBvaW50IC0gYWxsIHJlbW90ZXMgTVVTVCBoYXZlIGl0XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKGAke3JlbW90ZS51cmx9L2FwaS9oZWFsdGhgLCB7XG4gICAgICAgIGhlYWRlcnMsXG4gICAgICAgIHNpZ25hbDogY29udHJvbGxlci5zaWduYWwsXG4gICAgICB9KTtcblxuICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXRJZCk7XG5cbiAgICAgIGlmIChyZXNwb25zZS5vaykge1xuICAgICAgICByZW1vdGUubGFzdEhlYXJ0YmVhdCA9IG5ldyBEYXRlKCk7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhgaGVhbHRoIGNoZWNrIHBhc3NlZCBmb3IgJHtyZW1vdGUubmFtZX1gKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgSFRUUCAke3Jlc3BvbnNlLnN0YXR1c31gKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgLy8gRHVyaW5nIHNodXRkb3duLCBkb24ndCBsb2cgZXJyb3JzIG9yIHVucmVnaXN0ZXIgcmVtb3Rlc1xuICAgICAgaWYgKCFpc1NodXR0aW5nRG93bigpKSB7XG4gICAgICAgIGxvZ2dlci53YXJuKGByZW1vdGUgZmFpbGVkIGhlYWx0aCBjaGVjazogJHtyZW1vdGUubmFtZX0gKCR7cmVtb3RlLmlkfSlgLCBlcnJvcik7XG4gICAgICAgIC8vIFJlbW92ZSB0aGUgcmVtb3RlIGlmIGl0IGZhaWxzIGhlYWx0aCBjaGVja1xuICAgICAgICB0aGlzLnVucmVnaXN0ZXIocmVtb3RlLmlkKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHN0YXJ0SGVhbHRoQ2hlY2tlcigpIHtcbiAgICBsb2dnZXIuZGVidWcoJ3N0YXJ0aW5nIGhlYWx0aCBjaGVja2VyJyk7XG4gICAgdGhpcy5oZWFsdGhDaGVja0ludGVydmFsID0gc2V0SW50ZXJ2YWwoKCkgPT4ge1xuICAgICAgLy8gU2tpcCBoZWFsdGggY2hlY2tzIGR1cmluZyBzaHV0ZG93blxuICAgICAgaWYgKGlzU2h1dHRpbmdEb3duKCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICAvLyBDaGVjayBhbGwgcmVtb3RlcyBpbiBwYXJhbGxlbFxuICAgICAgY29uc3QgaGVhbHRoQ2hlY2tzID0gQXJyYXkuZnJvbSh0aGlzLnJlbW90ZXMudmFsdWVzKCkpLm1hcCgocmVtb3RlKSA9PlxuICAgICAgICB0aGlzLmNoZWNrUmVtb3RlSGVhbHRoKHJlbW90ZSlcbiAgICAgICk7XG5cbiAgICAgIFByb21pc2UuYWxsKGhlYWx0aENoZWNrcykuY2F0Y2goKGVycikgPT4ge1xuICAgICAgICBsb2dnZXIuZXJyb3IoJ2Vycm9yIGluIGhlYWx0aCBjaGVja3M6JywgZXJyKTtcbiAgICAgIH0pO1xuICAgIH0sIHRoaXMuSEVBTFRIX0NIRUNLX0lOVEVSVkFMKTtcbiAgfVxuXG4gIGRlc3Ryb3koKSB7XG4gICAgbG9nZ2VyLmxvZyhjaGFsay55ZWxsb3coJ2Rlc3Ryb3lpbmcgcmVtb3RlIHJlZ2lzdHJ5JykpO1xuICAgIGlmICh0aGlzLmhlYWx0aENoZWNrSW50ZXJ2YWwpIHtcbiAgICAgIGNsZWFySW50ZXJ2YWwodGhpcy5oZWFsdGhDaGVja0ludGVydmFsKTtcbiAgICAgIGxvZ2dlci5kZWJ1ZygnaGVhbHRoIGNoZWNrZXIgc3RvcHBlZCcpO1xuICAgIH1cbiAgfVxufVxuIl19