nanolith
Version:
Multi-threading in no time with seamless TypeScript support.
1 lines • 1.91 kB
JavaScript
import{randomUUID as v4}from"crypto";import{BroadcastChannel}from"worker_threads";import{isRawMessengerObject}from"./utilities.js";import{listenForStream,prepareWritableToPortStream}from"../streams/index.js";export class Messenger{#e=!1;#s;#t=[];#a=new Set;#r=v4();#n;#i={on:(e,s)=>{this.#a.add(s)},off:(e,s)=>{this.#a.delete(s)},postMessage:e=>{const s={type:"stream-message",sender:this.#r,data:e};this.#s.postMessage(s)}};#o=!1;get closed(){return this.#e}constructor(e){if(e&&"string"!=typeof e&&!isRawMessengerObject(e))throw new Error("Must either provide a string to create a new Messenger, or a MessengerRawData object.");e&&"string"!=typeof e?(this.#n=e.__messengerID,this.#s=new BroadcastChannel(e.__messengerID)):(this.#n="string"==typeof e?e:v4(),this.#s=new BroadcastChannel(this.#n)),this.#s.unref(),this.#c()}#c(){this.#s.onmessage=async e=>{const{data:s}=e;switch(s?.type){case"close":return this.close();case"stream-message":if(s.sender===this.#r)return;if("stream-ready-to-consume"!==s?.data?.type&&!this.#o)return;this.#a.forEach((e=>e(s.data)));break;case"message":if(s.sender===this.#r)return;await Promise.all(this.#t.map((e=>e(s.data))))}}}get ID(){return this.#n}get uniqueKey(){return this.#r}createStream(e){return prepareWritableToPortStream(this.#i,e??{})}onStream(e){return this.#o=!0,listenForStream(this.#i,e,1)}onMessage(e){return this.#t.push(e),()=>this.#l(e)}async waitForMessage(e){return new Promise((s=>{const t=async a=>{await e(a)&&(s(a),this.#l(t))};this.onMessage(t)}))}#l(e){const s=this.#t.indexOf(e);s<=-1||this.#t.splice(s,1)}sendMessage(e){const s={type:"message",sender:this.#r,data:e};this.#s.postMessage(s)}get raw(){return Object.freeze({__messengerID:this.#n})}setRef(e){if(e)return this.#s.ref();this.#s.unref()}close(){this.#e=!0,this.#s.close(),this.#t=[],this.#a.clear()}closeAll(){const e={sender:this.#r,type:"close"};this.#s.postMessage(e),this.close()}}