140 lines
4.7 KiB
TypeScript
140 lines
4.7 KiB
TypeScript
import { defineStore } from "pinia"
|
|
import type { MemberLight, Member } from "@shared/types/member"
|
|
import { getLightMembers, getFullMembers } from "@/api/member"
|
|
import { reactive, ref } from "vue"
|
|
import { resolve } from "path"
|
|
import { rejects } from "assert"
|
|
|
|
export const useMemberDirectory = defineStore('memberDirectory', () => {
|
|
const light = reactive<Record<number, MemberLight>>({});
|
|
const full = reactive<Record<number, Member>>({})
|
|
|
|
function getLight(id: number): Promise<MemberLight> {
|
|
if (light[id]) return Promise.resolve(light[id]);
|
|
|
|
if (!lightWaiters.has(id)) {
|
|
pendingLight.add(id);
|
|
lightWaiters.set(id, []);
|
|
}
|
|
|
|
scheduleBatch();
|
|
|
|
return new Promise<MemberLight>((resolve, reject) => {
|
|
lightWaiters.get(id)!.push({ resolve, reject })
|
|
})
|
|
}
|
|
|
|
function getFull(id: number): Promise<Member> {
|
|
if (full[id]) return Promise.resolve(full[id])
|
|
|
|
if (!fullWaiters.has(id)) {
|
|
pendingFull.add(id)
|
|
fullWaiters.set(id, [])
|
|
}
|
|
|
|
scheduleBatch()
|
|
|
|
return new Promise<Member>((resolve, reject) => {
|
|
fullWaiters.get(id)!.push({ resolve, reject })
|
|
})
|
|
}
|
|
|
|
function invalidateMember(id: number) {
|
|
delete light[id]
|
|
delete full[id]
|
|
}
|
|
|
|
//batching system
|
|
const pendingLight = new Set<number>()
|
|
const pendingFull = new Set<number>()
|
|
|
|
// promises
|
|
const lightWaiters = new Map<number, Array<{ resolve: (m: MemberLight) => void; reject: (e: any) => void }>>()
|
|
const fullWaiters = new Map<number, Array<{ resolve: (m: Member) => void; reject: (e: any) => void }>>()
|
|
|
|
let batchTimer: ReturnType<typeof setTimeout> | null = null;
|
|
|
|
function scheduleBatch() {
|
|
if (batchTimer) return
|
|
|
|
batchTimer = setTimeout(async () => {
|
|
batchTimer = null;
|
|
|
|
//Batch light
|
|
if (pendingLight.size > 0) {
|
|
const ids = Array.from(pendingLight);
|
|
pendingLight.clear();
|
|
|
|
try {
|
|
const res = await getLightMembers(ids);
|
|
for (const m of res) {
|
|
light[m.id] = m;
|
|
|
|
const waiters = lightWaiters.get(m.id);
|
|
if (waiters) {
|
|
for (const w of waiters) w.resolve(m)
|
|
lightWaiters.delete(m.id)
|
|
}
|
|
}
|
|
|
|
for (const id of ids) {
|
|
if (!light[id]) {
|
|
const waiters = lightWaiters.get(id);
|
|
if (waiters) {
|
|
for (const w of waiters) w.reject("Not found");
|
|
lightWaiters.delete(id);
|
|
}
|
|
}
|
|
}
|
|
} catch (error) {
|
|
for (const id of ids) {
|
|
const waiters = lightWaiters.get(id);
|
|
if (waiters) {
|
|
for (const w of waiters) w.reject(error);
|
|
lightWaiters.delete(id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//batch full
|
|
if (pendingFull.size > 0) {
|
|
const ids = Array.from(pendingFull);
|
|
pendingFull.clear();
|
|
|
|
try {
|
|
const res = await getFullMembers(ids);
|
|
for (const m of res) {
|
|
full[m.member_id] = m;
|
|
|
|
const waiters = fullWaiters.get(m.member_id);
|
|
if (waiters) {
|
|
for (const w of waiters) w.resolve(m)
|
|
fullWaiters.delete(m.member_id);
|
|
}
|
|
}
|
|
|
|
for (const id of ids) {
|
|
if (!light[id]) {
|
|
const waiters = fullWaiters.get(id);
|
|
if (waiters) {
|
|
for (const w of waiters) w.reject("Not found");
|
|
fullWaiters.delete(id);
|
|
}
|
|
}
|
|
}
|
|
} catch (error) {
|
|
for (const id of ids) {
|
|
const waiters = fullWaiters.get(id);
|
|
if (waiters) {
|
|
for (const w of waiters) w.reject(error);
|
|
fullWaiters.delete(id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
return { light, full, getLight, getFull, invalidateMember }
|
|
}) |