78 lines
2.1 KiB
TypeScript
78 lines
2.1 KiB
TypeScript
import { getJob, getReadInfo, refreshReadInfo } from "#lib/api/endpoints.js";
|
|
import type { ReadInfo } from "#lib/api/types.js";
|
|
import { accounts } from "#lib/stores/accounts.svelte.js";
|
|
|
|
const POLL_INTERVAL = 1000;
|
|
const POLL_MAX = 20;
|
|
|
|
export interface ReadEntry {
|
|
fetching: boolean;
|
|
info: ReadInfo;
|
|
}
|
|
|
|
function delay(ms: number): Promise<void> {
|
|
return new Promise((resolve) => {
|
|
setTimeout(resolve, ms);
|
|
});
|
|
}
|
|
|
|
async function waitForJob(jobId: number) {
|
|
for (let attempt = 0; attempt < POLL_MAX; attempt += 1) {
|
|
// biome-ignore lint/performance/noAwaitInLoops: polling waits between tries on purpose
|
|
await delay(POLL_INTERVAL);
|
|
const job = await getJob(jobId);
|
|
if (job.status !== "pending" && job.status !== "running") {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
function createReads() {
|
|
let entries = $state<Record<string, ReadEntry>>({});
|
|
const inflight = new Set<string>();
|
|
|
|
function key(chatId: number, messageId: number): string {
|
|
return `${accounts.selectedId}:${chatId}:${messageId}`;
|
|
}
|
|
|
|
async function load(entryKey: string, chatId: number, messageId: number) {
|
|
const info = await getReadInfo(chatId, messageId);
|
|
entries[entryKey] = { fetching: info.can_fetch, info };
|
|
if (!info.can_fetch) {
|
|
return;
|
|
}
|
|
try {
|
|
const { job_id } = await refreshReadInfo(chatId, messageId);
|
|
if (job_id !== null) {
|
|
await waitForJob(job_id);
|
|
}
|
|
entries[entryKey] = {
|
|
fetching: false,
|
|
info: await getReadInfo(chatId, messageId),
|
|
};
|
|
} finally {
|
|
entries[entryKey].fetching = false;
|
|
}
|
|
}
|
|
|
|
return {
|
|
get(chatId: number, messageId: number): ReadEntry | undefined {
|
|
return entries[key(chatId, messageId)];
|
|
},
|
|
open(chatId: number, messageId: number) {
|
|
const entryKey = key(chatId, messageId);
|
|
if (accounts.selectedId === null || inflight.has(entryKey)) {
|
|
return;
|
|
}
|
|
inflight.add(entryKey);
|
|
load(entryKey, chatId, messageId)
|
|
.catch(() => undefined)
|
|
.finally(() => {
|
|
inflight.delete(entryKey);
|
|
});
|
|
},
|
|
};
|
|
}
|
|
|
|
export const reads = createReads();
|