zwave-js
Version:
Z-Wave driver written entirely in JavaScript/TypeScript
93 lines • 3.16 kB
JavaScript
import { createDeferredPromise, } from "alcalzone-shared/deferred-promise";
import { SortedList } from "alcalzone-shared/sorted-list";
/**
* The transaction queue offers an async-iterable interface to a list of transactions.
*/
export class TransactionQueue {
constructor(options) {
this.name = options?.name ?? "unnamed";
this.mayStartNextTransaction = options?.mayStartNextTransaction
?? (() => true);
}
name;
mayStartNextTransaction;
transactions = new SortedList();
currentTransaction;
add(...items) {
this.transactions.add(...items);
this.trigger();
}
remove(...items) {
this.transactions.remove(...items);
this.trigger();
}
find(predicate) {
return this.transactions.find(predicate);
}
finalizeTransaction() {
this.currentTransaction = undefined;
}
get length() {
return this.transactions.length;
}
/** Causes the queue to re-evaluate whether the next transaction may be started */
trigger() {
while (this.transactions.length > 0 && this.listeners.length > 0) {
if (this.mayStartNextTransaction(this.transactions.peekStart())) {
const promise = this.listeners.shift();
const item = this.transactions.shift();
this.currentTransaction = item;
promise.resolve(item);
}
else {
break;
}
}
}
// A list of Promises that are waiting to be resolved
listeners = [];
// Whether the queue was ended
ended = false;
/** Ends the queue after it has been drained */
end() {
this.ended = true;
}
/** Ends the queue and discards all pending items */
abort() {
this.ended = true;
this.transactions.clear();
this.currentTransaction = undefined;
for (const p of this.listeners) {
p.resolve(undefined);
}
}
// Enable iterating the queue using for-await-of
[Symbol.asyncIterator]() {
return {
next: async () => {
let value;
if (this.transactions.length > 0
&& this.mayStartNextTransaction(this.transactions.peekStart())) {
// If the next transaction may be started, return it
value = this.transactions.shift();
}
else if (!this.ended) {
// Otherwise create a new promise and add it to the pending list
const promise = createDeferredPromise();
this.listeners.push(promise);
value = await promise;
}
this.currentTransaction = value;
if (value) {
// We have a value, return it
return { value, done: false };
}
else {
// No value means the queue was ended
return { value: undefined, done: true };
}
},
};
}
}
//# sourceMappingURL=Queue.js.map