import { dbApiPostData } from "$lib/server/db/apipostdata.db"; import { dbApiUser } from "$lib/server/db/apiuser.db"; import { postDataToApi } from "$lib/server/postdata/post.handler"; import { getAllSessions } from "$lib/server/utils/session.service"; import { getULID } from "$lib/utils"; import { type APISession, type ServerError, zPostDataEntry, zPostDataFilters, zPostDataHistoryFilters, } from "$lib/utils/data.types"; import { createTRPCRouter, protectedProcedure } from "../t"; import { z } from "zod"; import { fetchDataForPosting, fetchPostDataHistory, updateBalanceOfPostUsers, } from "$lib/server/postdata/postdata.gen.controller"; import { redis } from "$lib/server/connectors/redis"; import { constants } from "$lib/utils/constants"; async function hasPostSession() { const out = await redis.get(constants.POST_SESSION_KEY); if (out === null) { await redis.set(constants.POST_SESSION_KEY, "1"); return false; } return out === "1"; } async function removePostSession() { await redis.del(constants.POST_SESSION_KEY); } const postDataCacheStore = { get: async (key: string) => { return JSON.parse((await redis.get(`pdcc:${key}`)) ?? "[]"); }, set: async (key: string, data: any) => { await redis.setex(`pdcc:${key}`, 60 * 60 * 1, JSON.stringify(data)); }, del: async (key: string) => { await redis.del(`pdcc:${key}`); }, }; export const postDataApiRouter = createTRPCRouter({ fetchPostDataHistory: protectedProcedure .input(zPostDataHistoryFilters) .mutation(async ({ input }) => { return await fetchPostDataHistory(input); }), hasPosted: protectedProcedure .input(zPostDataHistoryFilters) .query(async ({ input }) => { return { hasPosted: await dbApiPostData.doesPostHistoryDataExist( input.date, input.draw?.id ?? "", ), }; }), getPostDataForPreview: protectedProcedure .input(zPostDataFilters) .query(async ({ input }) => { const date = input.date; const cacheKey = getULID(); if (!input.draw) { return { ok: false, detail: "Draw is required", data: [], errors: undefined, key: cacheKey, }; } console.log("[+] Fetching the users with updated balances"); const balOut = await updateBalanceOfPostUsers( await dbApiUser.getAllPostUsersWithParentUsers(), ); if (!balOut.ok || !balOut.data) { return { ok: false, key: cacheKey, detail: balOut.detail, data: [], users: [], }; } const users = balOut.data; console.log(`[=] ${users.length} users found`); console.log(users); const result = await fetchDataForPosting(date, input, users); postDataCacheStore.set(cacheKey, result.data).catch(console.error); console.log("result.data.length = ", result.data.length); return { ...result, key: cacheKey }; }), post: protectedProcedure .input(z.object({ yes: zPostDataFilters, cachedDataKey: z.string() })) .mutation(async ({ input }) => { if (await hasPostSession()) { return { ok: false, detail: "Already posting data, please wait for the current session to finish", errors: [ { message: "Already posting data, please wait for the current session to finish", }, ] as ServerError, }; } const date = input.yes.date; const draw = input.yes.draw; if (!draw) { await removePostSession(); return { ok: false, detail: "Draw is required", errors: [{ message: "Draw is required" }] as ServerError, }; } const drawId = draw.id; console.log("[+] Fetching the users"); const users = await dbApiUser.getAllPostUsersWithParentUsers(); console.log(users); const balOut = await updateBalanceOfPostUsers(users); if (!balOut.ok || !balOut.data) { await removePostSession(); return { ok: false, detail: balOut.detail, data: [], users: [] }; } console.log(`[=] ${users} users found`); console.log(users); console.log("[+] Preparing the sessions for posting"); const sessions = await getAllSessions(); const userSessions = {} as Record; for (const each of sessions) { const targetUser = users.find( (u) => each.key.includes(u.id) || each.value.userId === u.userId, ); if (!targetUser) continue; userSessions[targetUser?.userId ?? ""] = each.value; } if (Object.keys(userSessions).length !== users.length) { await removePostSession(); return { ok: false, detail: `Some users don't have a session to post data with`, errors: [ { message: "Some users don't have a session to post data with" }, ], }; } let data: any[] = await postDataCacheStore.get(input.cachedDataKey); console.log("cached.data.length = ", data.length); if (data.length < 1) { console.log("No data found from preview, generating a list"); const _out = await fetchDataForPosting(date, input.yes, balOut.data); if (!_out.ok) { await removePostSession(); return _out; } data = _out.data; console.log("data.length = ", data.length); } if (data.length < 1) { await removePostSession(); return { ok: false, detail: "No data found to post for the selected date and draw", errors: [ { message: "No data found to post for the selected date and draw" }, ], }; } console.log(`[+] Posting ${data.length} entries to the API`); const res = await postDataToApi({ sessions: userSessions, data, users: users, draw: draw, }); console.timeEnd("Time taken to post data to the API"); if (!res.ok) { await removePostSession(); return { ok: false, detail: res.detail }; } console.log(`[+] Data posted to the API successfully`); await dbApiPostData.upsertData({ id: getULID(), drawId: +drawId.split(":")[1], bookDate: date, data, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), }); // Update the balance of the users after posting to the API await updateBalanceOfPostUsers(users); console.log("[+] Data saved to the database"); await postDataCacheStore.del(input.cachedDataKey); await removePostSession(); return { ok: true, detail: "Data successfully posted to API", errors: undefined, }; }), });