64 lines
1.7 KiB
TypeScript
64 lines
1.7 KiB
TypeScript
type SyncTask = (dirPath: string, firstRun?: boolean) => Promise<void>;
|
|
|
|
export default class SyncScheduler {
|
|
private pending = new Map<string, boolean>();
|
|
private timers = new Map<string, NodeJS.Timeout>();
|
|
private flushing = false;
|
|
|
|
constructor(
|
|
private readonly task: SyncTask,
|
|
private readonly debounceMs: number
|
|
) {}
|
|
|
|
schedule(dirPath: string) {
|
|
const existing = this.timers.get(dirPath);
|
|
if (existing) clearTimeout(existing);
|
|
|
|
const timer = setTimeout(() => {
|
|
this.timers.delete(dirPath);
|
|
this.pending.set(dirPath, false);
|
|
void this.flush();
|
|
}, this.debounceMs);
|
|
|
|
this.timers.set(dirPath, timer);
|
|
}
|
|
|
|
enqueue(dirPath: string, firstRun?: boolean) {
|
|
const existing = this.timers.get(dirPath);
|
|
if (existing) {
|
|
clearTimeout(existing);
|
|
this.timers.delete(dirPath);
|
|
}
|
|
|
|
this.pending.set(dirPath, !!firstRun);
|
|
void this.flush();
|
|
}
|
|
|
|
private async flush() {
|
|
if (this.flushing) return;
|
|
|
|
this.flushing = true;
|
|
|
|
try {
|
|
while (this.pending.size > 0) {
|
|
const batch = [...this.pending.entries()];
|
|
this.pending.clear();
|
|
|
|
for (const [dirPath, firstRun] of batch) {
|
|
try {
|
|
await this.task(dirPath, firstRun);
|
|
} catch (error: any) {
|
|
console.log("ERROR:", error.message);
|
|
}
|
|
}
|
|
}
|
|
} finally {
|
|
this.flushing = false;
|
|
|
|
if (this.pending.size > 0) {
|
|
void this.flush();
|
|
}
|
|
}
|
|
}
|
|
}
|