Utils/src/awaiter.ts

106 lines
2.7 KiB
TypeScript

import Observable, { ObserverCallback } from "./observable.js";
export type CheckFunction<T> = (val: T) => boolean;
export default class AwaitStore<T = any> {
private observable = new Observable<T>();
constructor(private _value: T) {
this.subscribe = this.subscribe.bind(this);
this.unsubscribe = this.unsubscribe.bind(this);
}
/**
* Get the current value
*/
get value() {
return this._value;
}
/**
* Set a new value and notify subscribers
* @param value Value to be set
*/
send(value: T) {
this._value = value;
this.observable.send(value);
}
/**
* Get the current value as well as all changes
* @param handler Handler called on change
*/
subscribe(handler: ObserverCallback<T>) {
handler(this._value);
return this.observable.subscribe(handler);
}
/**
* Unsubscribe from changes
* @param handler The handler to unsubscribe
*/
unsubscribe(handler: ObserverCallback<T>) {
this.observable.unsubscribe(handler);
}
/**
* Await a specific value and return.
*
* For example if val = true then this function would block until the value
* is actually true. If it is true, then the promise will resolve immediatly
*
* @param val Value to await
*/
awaitValue(
val: T | CheckFunction<T>
): PromiseLike<void> & {
catch: (cb: (err: any) => PromiseLike<void>) => PromiseLike<void>;
ignore: () => void;
} {
let ignore: () => void = () => undefined;
let prms = new Promise<void>((yes) => {
const cb = () => {
if (typeof val === "function") {
if ((val as CheckFunction<T>)(this._value)) {
yes();
this.unsubscribe(cb);
}
} else if (this._value === val) {
yes();
this.unsubscribe(cb);
}
};
this.subscribe(cb);
});
return {
then: prms.then.bind(prms),
catch: prms.catch.bind(prms),
ignore: () => ignore(),
};
}
/**
* Creates Public API with subscribe and unsubscribe
*
* @returns {object}
*/
getPublicApi() {
if (this.observable.closed) throw new Error("Observable is closed!");
return {
subscribe: (callback: ObserverCallback<T>) => this.subscribe(callback),
unsubscribe: (callback: ObserverCallback<T>) =>
this.unsubscribe(callback),
awaitValue: (value: T) => this.awaitValue(value),
};
}
/**
* Close this store. All subscribers will be unsubscribed and any further operations will fail
*/
close() {
this.observable.close();
}
}