worker-channel
Version:
A modern zero-dependency Worker communication and orchestration library
386 lines (374 loc) • 13.9 kB
JavaScript
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