@thi.ng/csp
Version:
Primitives & operators for Communicating Sequential Processes based on async/await and async iterables
97 lines (96 loc) • 2.23 kB
JavaScript
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
};