ente/web/packages/shared/utils/queueProcessor.ts
2024-07-02 10:55:57 +05:30

72 lines
2.0 KiB
TypeScript

import { ensure } from "@/utils/ensure";
import { CustomError } from "@ente/shared/error";
interface RequestQueueItem {
request: (canceller?: RequestCanceller) => Promise<any>;
successCallback: (response: any) => void;
failureCallback: (error: unknown) => void;
isCanceled: { status: boolean };
canceller: { exec: () => void };
}
export interface RequestCanceller {
exec: () => void;
}
export interface CancellationStatus {
status: boolean;
}
export default class QueueProcessor<T> {
private requestQueue: RequestQueueItem[] = [];
private isProcessingRequest = false;
public queueUpRequest(
request: (canceller?: RequestCanceller) => Promise<T>,
) {
const isCanceled: CancellationStatus = { status: false };
const canceller: RequestCanceller = {
exec: () => {
isCanceled.status = true;
},
};
const promise = new Promise<T>((resolve, reject) => {
this.requestQueue.push({
request,
successCallback: resolve,
failureCallback: reject,
isCanceled,
canceller,
});
this.processQueueIfNeeded();
});
return { promise, canceller };
}
private async processQueueIfNeeded() {
if (this.isProcessingRequest) return;
this.isProcessingRequest = true;
while (this.requestQueue.length > 0) {
const queueItem = ensure(this.requestQueue.shift());
let response = null;
if (queueItem.isCanceled.status) {
queueItem.failureCallback(Error(CustomError.REQUEST_CANCELLED));
} else {
try {
response = await queueItem.request(queueItem.canceller);
queueItem.successCallback(response);
} catch (e) {
queueItem.failureCallback(e);
}
}
}
this.isProcessingRequest = false;
}
}