UNPKG

@signalapp/mock-server

Version:
119 lines (118 loc) 3.95 kB
"use strict"; // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Service = void 0; const assert_1 = __importDefault(require("assert")); const debug_1 = __importDefault(require("debug")); const compiled_1 = require("../../../protos/compiled"); const debug = (0, debug_1.default)('mock:ws:service'); const WSMessage = compiled_1.signalservice.WebSocketMessage; class Service { ws; requests = new Map(); lastSentId = 0n; constructor(ws) { this.ws = ws; this.ws = ws; // eslint-disable-next-line @typescript-eslint/no-misused-promises this.ws.on('message', async (message) => { try { await this.onMessage(message); } catch (error) { (0, assert_1.default)(error instanceof Error); debug('onMessage error', error.stack); } }); this.ws.once('close', () => { this.onClose(); }); } async send(verb, path, options) { const id = this.lastSentId++; const packet = WSMessage.encode({ type: WSMessage.Type.REQUEST, request: { headers: options.headers ?? null, body: options.body ?? null, verb, path, id, }, response: null, }); this.ws.send(packet); return new Promise((resolve) => this.requests.set(id, resolve)); } async onMessage(raw) { if (!(raw instanceof Uint8Array)) { throw new Error('Unexpected input'); } // @ts-expect-error -- Can't refine to Uint8Array<ArrayBuffer> const message = WSMessage.decode(raw); if (message.type === WSMessage.Type.RESPONSE) { const response = message.response; if (!response) { throw new Error('Expected response in message'); } const id = response.id ?? 0n; const resolve = this.requests.get(id); if (!resolve) { throw new Error(`Unexpected response: ${id}`); } resolve(response); } else if (message.type === WSMessage.Type.REQUEST) { const request = message.request; if (!request) { throw new Error('Expected request in message'); } let response; try { response = await this.handleRequest(request); } catch (error) { (0, assert_1.default)(error instanceof Error); console.error('handleRequest error', error.stack); response = { id: request.id, status: 500, message: null, headers: null, body: Buffer.from(JSON.stringify({ error: error.stack, })), }; } // Keepalive responses const packet = WSMessage.encode({ type: WSMessage.Type.RESPONSE, request: null, response: { ...response, id: request.id, }, }); this.ws.send(packet); } else { debug('unsupported message', message); } } onClose() { for (const [id, resolve] of this.requests.entries()) { resolve({ id, status: 500, message: 'WebSocket is gone', headers: null, body: null, }); } } } exports.Service = Service;