UNPKG

@phnq/message

Version:

Asynchronous, incremental messaging client and server

110 lines (109 loc) 4.42 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.LocalPubSubTransport = void 0; const MessageTransport_1 = require("../MessageTransport"); const serialize_1 = require("../serialize"); class LocalPubSubTransport { constructor(options) { this.subIds = []; this.subjectById = new Map(); this.options = options; this.subIds = options.subscriptions.map(sub => PubSub.instance.subscribe(sub, (message) => { if (this.receiveHandler) { this.receiveHandler(message); } })); } send(message) { return __awaiter(this, void 0, void 0, function* () { const publishSubject = this.options.publishSubject; let subject; if (message.t === MessageTransport_1.MessageType.End) { subject = this.subjectById.get(message.c); } else { subject = typeof publishSubject === 'string' ? publishSubject : publishSubject(message); } if (subject === undefined) { throw new Error('Could not get subject'); } if (message.t === MessageTransport_1.MessageType.End) { this.subjectById.delete(message.c); } else { this.subjectById.set(message.c, subject); } const subCount = PubSub.instance.publish(subject, message); if (subCount === 0) { throw new Error(`No subscribers for subject: ${subject}`); } return undefined; }); } onReceive(receive) { this.receiveHandler = receive; } close() { return __awaiter(this, void 0, void 0, function* () { for (const subId of this.subIds) { PubSub.instance.unsubscribe(subId); } this.subIds = []; }); } } exports.LocalPubSubTransport = LocalPubSubTransport; class PubSub { constructor() { this.subIdIter = (function* subIdGen() { let i = 0; while (true) { i += 1; yield i; } })(); this.subscriptions = {}; } publish(subject, message) { var _a; const subs = (_a = this.subscriptions[subject]) !== null && _a !== void 0 ? _a : []; for (const sub of subs) { /** * This MessageTransport doesn't strictly require any marshalling or unmarshalling since the messages * are sent synchronously within the same process. However, we still annotate and deannotate the message, * effectively cloning it. The benefits are: * - It ensures that the original message is not mutated by the subscriber. * - It ensures compatibility with other transports. */ const clonedMessage = (0, serialize_1.deannotate)((0, serialize_1.annotate)(message)); sub.handler(clonedMessage); } return subs.length; } subscribe(subject, callback) { var _a; const subs = (_a = this.subscriptions[subject]) !== null && _a !== void 0 ? _a : []; const subId = this.subIdIter.next().value; subs.push({ subId, handler: callback }); this.subscriptions[subject] = subs; return subId; } unsubscribe(subId) { for (const subject in this.subscriptions) { this.subscriptions[subject] = this.subscriptions[subject].filter(sub => sub.subId !== subId); if (this.subscriptions[subject].length === 0) { delete this.subscriptions[subject]; } } } } PubSub.instance = new PubSub();