2023-05-09 20:15:37 +02:00
|
|
|
import type {
|
|
|
|
|
IAsyncIterator,
|
|
|
|
|
IDecodedMessage,
|
|
|
|
|
IDecoder,
|
|
|
|
|
IReceiver,
|
2023-08-16 20:18:13 +05:30
|
|
|
Unsubscribe
|
2023-05-09 20:15:37 +02:00
|
|
|
} from "@waku/interfaces";
|
|
|
|
|
|
2023-08-16 16:11:27 +05:30
|
|
|
/**
|
|
|
|
|
* Options for configuring the behavior of an iterator.
|
|
|
|
|
*
|
|
|
|
|
* @property timeoutMs - Optional timeout in milliseconds. If specified, the iterator will terminate after this time period.
|
|
|
|
|
* @property iteratorDelay - Optional delay in milliseconds between each iteration. Can be used to control the rate of iteration.
|
|
|
|
|
*/
|
2023-08-16 20:18:13 +05:30
|
|
|
export type IteratorOptions = {
|
2023-05-17 10:38:20 +02:00
|
|
|
timeoutMs?: number;
|
|
|
|
|
iteratorDelay?: number;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const FRAME_RATE = 60;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Function that transforms IReceiver subscription to iterable stream of data.
|
|
|
|
|
* @param receiver - object that allows to be subscribed to;
|
|
|
|
|
* @param decoder - parameter to be passed to receiver for subscription;
|
|
|
|
|
* @param options - options for receiver for subscription;
|
|
|
|
|
* @param iteratorOptions - optional configuration for iterator;
|
|
|
|
|
* @returns iterator and stop function to terminate it.
|
|
|
|
|
*/
|
2023-05-09 20:15:37 +02:00
|
|
|
export async function toAsyncIterator<T extends IDecodedMessage>(
|
|
|
|
|
receiver: IReceiver,
|
|
|
|
|
decoder: IDecoder<T> | IDecoder<T>[],
|
2023-08-16 20:18:13 +05:30
|
|
|
iteratorOptions?: IteratorOptions
|
2023-05-09 20:15:37 +02:00
|
|
|
): Promise<IAsyncIterator<T>> {
|
2023-05-17 10:38:20 +02:00
|
|
|
const iteratorDelay = iteratorOptions?.iteratorDelay ?? FRAME_RATE;
|
|
|
|
|
|
2023-05-09 20:15:37 +02:00
|
|
|
const messages: T[] = [];
|
|
|
|
|
|
|
|
|
|
let unsubscribe: undefined | Unsubscribe;
|
2023-09-07 13:15:49 +05:30
|
|
|
unsubscribe = await receiver.subscribe(decoder, (message: T) => {
|
|
|
|
|
messages.push(message);
|
|
|
|
|
});
|
2023-05-09 20:15:37 +02:00
|
|
|
|
2023-05-17 10:38:20 +02:00
|
|
|
const isWithTimeout = Number.isInteger(iteratorOptions?.timeoutMs);
|
|
|
|
|
const timeoutMs = iteratorOptions?.timeoutMs ?? 0;
|
|
|
|
|
const startTime = Date.now();
|
|
|
|
|
|
2023-05-09 20:15:37 +02:00
|
|
|
async function* iterator(): AsyncIterator<T> {
|
|
|
|
|
while (true) {
|
2023-05-17 10:38:20 +02:00
|
|
|
if (isWithTimeout && Date.now() - startTime >= timeoutMs) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await wait(iteratorDelay);
|
|
|
|
|
|
2023-05-09 20:15:37 +02:00
|
|
|
const message = messages.shift() as T;
|
|
|
|
|
|
|
|
|
|
if (!unsubscribe && messages.length === 0) {
|
|
|
|
|
return message;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!message && unsubscribe) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
yield message;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
iterator: iterator(),
|
|
|
|
|
async stop() {
|
|
|
|
|
if (unsubscribe) {
|
|
|
|
|
await unsubscribe();
|
|
|
|
|
unsubscribe = undefined;
|
|
|
|
|
}
|
2023-08-16 20:18:13 +05:30
|
|
|
}
|
2023-05-09 20:15:37 +02:00
|
|
|
};
|
|
|
|
|
}
|
2023-05-17 10:38:20 +02:00
|
|
|
|
|
|
|
|
function wait(ms: number): Promise<void> {
|
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
|
setTimeout(resolve, ms);
|
|
|
|
|
});
|
|
|
|
|
}
|