UNPKG

worker-channel

Version:

A modern zero-dependency Worker communication and orchestration library

386 lines (374 loc) 13.9 kB
function $parcel$exportWildcard(dest, source) { Object.keys(source).forEach(function(key) { if (key === 'default' || key === '__esModule' || dest.hasOwnProperty(key)) { return; } Object.defineProperty(dest, key, { enumerable: true, get: function get() { return source[key]; } }); }); return dest; } function $parcel$export(e, n, v, s) { Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true}); } $parcel$export(module.exports, "Channel", () => $53ffd25df6034fb9$export$cfdacaa37f9b4dd7); $parcel$export(module.exports, "WriteChannel", () => $53ffd25df6034fb9$export$78bfdaefc7563818); $parcel$export(module.exports, "ReadChannel", () => $53ffd25df6034fb9$export$1dad41a5cc16d28); $parcel$export(module.exports, "ReadWriteChannel", () => $53ffd25df6034fb9$export$88c66e79d857a104); /** @public @module main*/ var $9ba0f9a5c47c04f2$exports = {}; $parcel$export($9ba0f9a5c47c04f2$exports, "consumeStream", () => $9ba0f9a5c47c04f2$export$fefb0b1940ac6f37); $parcel$export($9ba0f9a5c47c04f2$exports, "consumeReader", () => $9ba0f9a5c47c04f2$export$a836a3368b19f4c8); $parcel$export($9ba0f9a5c47c04f2$exports, "SleepAbortError", () => $9ba0f9a5c47c04f2$export$d4d4d920633d6a7d); $parcel$export($9ba0f9a5c47c04f2$exports, "sleep", () => $9ba0f9a5c47c04f2$export$e772c8ff12451969); $parcel$export($9ba0f9a5c47c04f2$exports, "Deferred", () => $9ba0f9a5c47c04f2$export$85f6557964517f1a); $parcel$export($9ba0f9a5c47c04f2$exports, "isDefined", () => $9ba0f9a5c47c04f2$export$4e62c701997796c1); $parcel$export($9ba0f9a5c47c04f2$exports, "writerIsClosed", () => $9ba0f9a5c47c04f2$export$c8362a090f2ffd6); async function* $9ba0f9a5c47c04f2$export$fefb0b1940ac6f37(readable) { const reader = readable.getReader(); yield* $9ba0f9a5c47c04f2$export$a836a3368b19f4c8(reader); } async function* $9ba0f9a5c47c04f2$export$a836a3368b19f4c8(reader) { let done, value; do { ({ done: done , value: value } = await reader.read()); if (!done) yield value; }while (!done); } class $9ba0f9a5c47c04f2$export$d4d4d920633d6a7d extends Error { constructor(message = "Sleep Aborted."){ super(message); } } const $9ba0f9a5c47c04f2$export$e772c8ff12451969 = (ms, controller)=>new Promise((res, rej)=>{ const id = setTimeout(res, ms); controller?.signal.addEventListener("abort", ()=>{ clearTimeout(id); rej(new $9ba0f9a5c47c04f2$export$d4d4d920633d6a7d()); }); }); const $9ba0f9a5c47c04f2$export$85f6557964517f1a = ()=>{ let resolve; let reject; const promise = new Promise((res, rej)=>{ resolve = res; reject = rej; }); return { resolve: resolve, reject: reject, promise: promise }; }; function $9ba0f9a5c47c04f2$export$4e62c701997796c1(x) { return Boolean(x); } function $9ba0f9a5c47c04f2$export$c8362a090f2ffd6(writer) { return Promise.race([ $9ba0f9a5c47c04f2$export$e772c8ff12451969(0).then(()=>false), writer.closed.then(()=>true) ]); } var $faefaad95e5fcca0$exports = {}; class $53ffd25df6034fb9$export$cfdacaa37f9b4dd7 { /** Connect the readFrom or writeTo worker/port to either recieve from or send to to a different message port. * @param target The worker/port to send the `connection` change to. * @param action Whether you want to change the "writable" end or the "readable" end of the `target` * @param connection The connection that should now be written to or read from. */ connect(target, action, connection) { this._sendInternal(target, `worker-channel:${action}`, connection, [ connection ]); } /** @internal */ _sendInternal(target, type, data, transfers) { this[target]?.postMessage?.({ type: type, data: data }, transfers ?? []); } constructor({ controller: controller = new AbortController() , writeTo: writeTo = globalThis , readFrom: readFrom = globalThis } = {}){ this.controller = controller; // this.writeCommands = writeCommands; // this.readCommands = readCommands; this.writeTo = writeTo; this.readFrom = readFrom; this.listener = this.listener.bind(this); this.internalQueues = {}; this.start(); } /** @internal */ readWriteSetup() { this.transforms = new Map(); this.internalQueues.transform = new Proxy({}, { get: (_obj, command)=>{ if (this.transforms?.has(command) ?? false) { const stream = this.transforms?.get(command); if (stream) return stream; } const transformStream = new TransformStream(); this.transforms?.set(command, transformStream); return transformStream; } }); this.readSetup(); this.writeSetup(); } /** @internal */ readSetup() { this.readables = new Map(); this.internalQueues.read = new Proxy({}, { get: (_obj, command)=>{ if (this.readables?.has(command) ?? false) { const stream = this.readables?.get(command); if (stream) return stream; } const readableStream = (this.internalQueues?.transform?.[command]?.readable ?? new ReadableStream()).getReader(); this.readables?.set(command, readableStream); return readableStream; } }); } /** @internal */ writeSetup() { this.writables = new Map(); this.internalQueues.write = new Proxy({}, { get: (_obj, command)=>{ if (this.writables?.has(command) ?? false) { const stream = this.writables?.get(command); if (stream) return stream; } const stream = (this.internalQueues?.transform?.[command]?.writable ?? new WritableStream()).getWriter(); this.writables?.set(command, stream); return stream; } }); } /** Propagate close on all writers of channel * * @example * * ```ts * const writer = new WriteChannel(); * * // closes the "string" channel. * writer.close.writer.string(); * ``` */ close = { writer: new Proxy({}, { get: (_target, command)=>{ return ()=>{ (async ()=>{ const writer = this.writables?.get(command); this._sendInternal("writeTo", "worker-channel:close-writer", command); if (this.writeTo instanceof MessagePort) this.writeTo.close(); if (writer && await (0, $9ba0f9a5c47c04f2$export$c8362a090f2ffd6)(writer)) return; this.writables?.get(command)?.close(); })(); }; } }) }; /** Propagate cancel on all readers * * @example * * ```ts * const rChannel = new ReadChannel(); * * // cancels the "string" channel. * rChannel.cancel.reader.string(); * ``` */ cancel = { reader: new Proxy({}, { get: (_target, command)=>{ return ()=>{ this.readables?.get(command)?.releaseLock(); this._sendInternal("readFrom", "worker-channel:close-reader", command); if (this.readFrom instanceof MessagePort) this.readFrom.close(); }; } }) }; /** @internal */ _send(type, data, transfer) { return this.writeTo?.postMessage({ type: type, data: data }, transfer ?? []); } /** @internal */ async _read(type) { return (await this.internalQueues.read?.[type]?.read())?.value; } /** @internal */ async *_readAll(type) { const result = this.internalQueues.read?.[type]; if (!result) return; yield* (0, $9ba0f9a5c47c04f2$export$a836a3368b19f4c8)(result); } /** @internal */ async listen() { this.readFrom?.addEventListener?.("message", this.listener); } /** @internal */ async unlisten() { this.readFrom?.removeEventListener?.("message", this.listener); } /** @internal */ async listener(ev) { if (ev.data.type === "worker-channel:change-reader") { // sending inner listening channel this.unlisten(); this.readFrom = ev.data.data; ev.data.data.start(); this.listen(); return; } else if (ev.data.type === "worker-channel:change-writer") { // Sending inner posting channel. // this._send("acknowledge", true); this.writeTo = ev.data.data; return; } else if (ev.data.type === "worker-channel:close-writer") this.close.writer[ev.data.data](); else if (ev.data.type === "worker-channel:close-reader") this.cancel.reader[ev.data.data](); else // send data accordingi to type. this.internalQueues.write?.[ev.data.type]?.write(ev.data.data); } /** Starts the channel. Called automatically from the constructor, * but if you ever `.end()` the channel this will start it again. */ start() { this.controller?.signal.addEventListener("abort", ()=>{ return this.end(); }, { once: true }); } /** Ends the communication of the channel. * You can always restart the channel with `.start()`. */ end() { this.readFrom?.removeEventListener("message", this.listener); this.readables?.clear(); this.writables?.clear(); this.transforms?.clear(); } } class $53ffd25df6034fb9$export$78bfdaefc7563818 extends $53ffd25df6034fb9$export$cfdacaa37f9b4dd7 { start() { super.start(); this.writeSetup(); } /** Write to the channel. * * @example * An example worker script: * ```ts * // Setup the channel to be "string" (denoted by the type) with data of type string (denoted by data). * type MyMessage = {type: "string", data: string}; * const rwChannel = new ReadWriteChannel<MyMessage, MyMessage>(); * * // writes to the string channel: * rwChannel.write.string("foo"); * ``` */ write = new Proxy({}, { get: (_target, command)=>{ return (data, transfer)=>this._send(command, data, transfer); } }); } class $53ffd25df6034fb9$export$1dad41a5cc16d28 extends $53ffd25df6034fb9$export$cfdacaa37f9b4dd7 { start() { super.start(); this.listen(); this.readWriteSetup(); } /** Read from a channel. * * @example * An example worker script: * * ```ts * // Setup the channel to be "string" (denoted by the type) with data of type string (denoted by data). * type MessageType = {type: "string", data: string}; * const rChannel = new ReadChannel<MessageType>(); * * console.log(await rChannel.read.string()) * ``` */ read = new Proxy({}, { get: (_target, command)=>{ return ()=>this._read(command); } }); /** Read everything from a channel. * * @example * An example worker script: * * ```ts * * // Setup the channel to be "string" (denoted by the type) with data of type string (denoted by data). * type MessageType = {type: "string", data: string}; * const rChannel = new ReadChannel<MessageType>(); * * // Read everything from the "string" channel. * for await (const item of rChannel.readAll.string()) { * console.log(item); * } * ``` */ readAll = new Proxy({}, { get: (_target, command)=>{ return ()=>this._readAll(command); } }); } class $53ffd25df6034fb9$export$88c66e79d857a104 extends $53ffd25df6034fb9$export$cfdacaa37f9b4dd7 { start() { super.start(); this.listen(); this.readWriteSetup(); } /** Write to the channel. * * @example * ```ts * // Setup the channel to be "string" (denoted by the type) with data of type string (denoted by data). * type MyMessage = {type: "string", data: string}; * const rwChannel = new ReadWriteChannel<MyMessage, MyMessage>(); * * // writes to the string channel: * rwChannel.write.string("foo"); * ``` */ write = new Proxy({}, { get: (_target, command)=>{ return (data, transfer)=>this._send(command, data, transfer); } }); /** Read from the channel * * @example * ```ts * // Setup the channel to be "string" (denoted by the type) with data of type string (denoted by data). * type MyMessage = {type: "string", data: string}; * const rwChannel = new ReadWriteChannel<MyMessage, MyMessage>(); * * // Read data of type string from the "string" channel. * const str = await rwChannel.read.string(); * ``` */ read = new Proxy({}, { get: (_target, command)=>{ return ()=>this._read(command); } }); /** Read from the channel * * @example * ```ts * // Setup the channel to be "string" (denoted by the type) with data of type string (denoted by data). * type MyMessage = {type: "string", data: string}; * const rwChannel = new ReadWriteChannel<MyMessage, MyMessage>(); * * for await (const item of rwChannel.readAll.string()) { * console.log(item); * } * ``` */ readAll = new Proxy({}, { get: (_target, command)=>{ return ()=>this._readAll(command); } }); } $parcel$exportWildcard(module.exports, $9ba0f9a5c47c04f2$exports); $parcel$exportWildcard(module.exports, $faefaad95e5fcca0$exports); //# sourceMappingURL=index.cjs.map