Files
rdv/src/lib/trpc/routers/postdata.router.ts
bootunloader c1b5f28a60 fixed
2024-09-22 13:17:14 +03:00

229 lines
6.8 KiB
TypeScript

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<string, APISession>;
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,
};
}),
});