UNPKG

flipper-server-client

Version:

Lightweight abstraction to connect to Flipper Server and provide an API to interact with it

157 lines 6.9 kB
"use strict"; /** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @format */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createFlipperServerWithSocket = exports.createFlipperServer = exports.FlipperServerState = void 0; const eventemitter3_1 = __importDefault(require("eventemitter3")); const flipper_common_1 = require("flipper-common"); const reconnecting_websocket_1 = __importDefault(require("reconnecting-websocket")); const CONNECTION_TIMEOUT = 30 * 1000; const EXEC_TIMEOUT = 45 * 1000; var FlipperServerState; (function (FlipperServerState) { FlipperServerState[FlipperServerState["CONNECTING"] = 0] = "CONNECTING"; FlipperServerState[FlipperServerState["CONNECTED"] = 1] = "CONNECTED"; FlipperServerState[FlipperServerState["DISCONNECTED"] = 2] = "DISCONNECTED"; })(FlipperServerState || (exports.FlipperServerState = FlipperServerState = {})); function createFlipperServer(host, port, tokenProvider, onStateChange) { const URLProvider = () => { const token = tokenProvider(); return `ws://${host}:${port}?token=${token}`; }; const socket = new reconnecting_websocket_1.default(URLProvider); return createFlipperServerWithSocket(socket, port, onStateChange); } exports.createFlipperServer = createFlipperServer; function createFlipperServerWithSocket(socket, port, onStateChange) { onStateChange(FlipperServerState.CONNECTING); return new Promise((resolve, reject) => { let initialConnectionTimeout = setTimeout(() => { reject(new Error(`Failed to connect to the server in a timely manner. It may be unresponsive. Run the following from the terminal 'sudo kill -9 $(lsof -t -i :${port})' as to kill any existing running instance, if any.`)); }, CONNECTION_TIMEOUT); const eventEmitter = new eventemitter3_1.default(); const pendingRequests = new Map(); let requestId = 0; let connected = false; socket.addEventListener('open', () => { connected = true; onStateChange(FlipperServerState.CONNECTED); if (initialConnectionTimeout) { clearTimeout(initialConnectionTimeout); initialConnectionTimeout = undefined; resolve(flipperServer); } }); socket.addEventListener('close', () => { connected = false; onStateChange(FlipperServerState.DISCONNECTED); pendingRequests.forEach((r) => r.reject(new flipper_common_1.FlipperServerDisconnectedError('ws-close'))); pendingRequests.clear(); }); socket.addEventListener('message', ({ data }) => { try { const { event, payload } = JSON.parse(data.toString()); switch (event) { case 'exec-response': { const entry = pendingRequests.get(payload.id); if (!entry) { console.warn(`Unknown request id `, payload.id); } else { pendingRequests.delete(payload.id); clearTimeout(entry.timeout); entry.resolve(payload.data); } break; } case 'exec-response-error': { const entry = pendingRequests.get(payload.id); if (!entry) { console.warn(`flipper-server: Unknown request id `, payload.id); } else { pendingRequests.delete(payload.id); clearTimeout(entry.timeout); entry.reject(payload.data); } break; } case 'server-event': { eventEmitter.emit(payload.event, payload.data); break; } default: { console.warn('flipper-server: received unknown message type', data.toString()); } } } catch (e) { console.warn('flipper-server: failed to process message', data.toString()); } }); const commandOrOptionsIsOptions = (commandOrOptions) => typeof commandOrOptions === 'object'; const flipperServer = { async connect() { }, close() { }, exec(commandOrOptions, ...argsAmbiguous) { let timeout; let command; let args; if (commandOrOptionsIsOptions(commandOrOptions)) { timeout = commandOrOptions.timeout; command = argsAmbiguous[0]; args = argsAmbiguous.slice(1); } else { timeout = EXEC_TIMEOUT; command = commandOrOptions; args = argsAmbiguous; } if (connected) { const id = ++requestId; return new Promise((resolve, reject) => { pendingRequests.set(id, { resolve, reject, timeout: setInterval(() => { pendingRequests.delete(id); reject(new flipper_common_1.FlipperServerTimeoutError(`timeout for command '${command}'`)); }, timeout), }); const execMessage = { event: 'exec', payload: { id, command, args, }, }; socket.send(JSON.stringify(execMessage)); }); } else { throw new Error('Not connected to Flipper server'); } }, on(event, callback) { eventEmitter.on(event, callback); }, off(event, callback) { eventEmitter.off(event, callback); }, }; }); } exports.createFlipperServerWithSocket = createFlipperServerWithSocket; //# sourceMappingURL=FlipperServerClient.js.map