UNPKG

@thi.ng/csp

Version:

Primitives & operators for Communicating Sequential Processes based on async/await and async iterables

97 lines (96 loc) 2.23 kB
import { illegalArity } from "@thi.ng/errors/illegal-arity"; import { Channel } from "./channel.js"; import { Mult } from "./mult.js"; function pubsub(...args) { return new PubSub(...args); } class PubSub { src; fn; topics; constructor(...args) { switch (args.length) { case 2: this.src = args[0]; this.fn = args[1]; break; case 1: this.src = new Channel(); this.fn = args[0]; break; default: illegalArity(args.length); } this.topics = {}; this.process(); } writable() { return this.src.writable(); } write(val) { return this.src.write(val); } close() { return this.src.close(); } closed() { return this.src.closed(); } /** * Creates a new topic subscription channel and returns it. Each topic is * managed by its own {@link Mult} and can have arbitrary number of * subscribers. * * @param id - topic id */ subscribeTopic(id) { let topic = this.topics[id]; if (!topic) { this.topics[id] = topic = new Mult(`${this.src.id}-${id}`); } return topic.subscribe(); } /** * Attempts to remove a subscription channel for given topic `id`. Returns * true if successful. If `close` is true (default), the given channel will * also be closed (only if unsubscription was successful). * * @remarks * See {@link Mult.subscribe} for reverse op. * * @param id * @param ch * @param close */ unsubscribeTopic(id, ch, close = true) { const topic = this.topics[id]; return topic?.unsubscribe(ch, close) ?? false; } /** * Removes all child subscription channels for given topic `id` and if * `close` is true (default) also closes them. * * @param close */ unsubscribeAll(id, close = true) { const topic = this.topics[id]; topic?.unsubscribeAll(close); } async process() { let x; while ((x = await this.src.read()) !== void 0) { const id = this.fn(x); let topic = this.topics[id]; topic && await topic.write(x); x = null; } for (let t of Object.values(this.topics)) { t.close(); } this.topics = {}; } } export { PubSub, pubsub };