- Deleted contact router and its associated mail functionality. - Removed addEvent mutation from event_queue router. - Cleaned up fatture router by removing createClient and getListClienti procedures. - Commented out deletePrezziario mutation in prezziario router. - Removed unused procedures in servizio router, including getServizioOrdini and getPreOnboardData. - Cleaned up stats router by removing commented-out code. - Updated stripe router to restrict health check to admin users and changed several public procedures to protected. - Commented out sync router procedures and related types. - Removed unused client-related functions in fic controller. - Cleaned up servizio controller by removing getServizioOrdini and commented-out code. - Refactored auth service to inline pwResetTokenFromMailHandler logic. - Commented out deletePrezziario function in prezziario service. - Cleaned up zod types by commenting out unused types. - Commented out getMessagesArray function in kysely helper.
167 lines
4.2 KiB
TypeScript
167 lines
4.2 KiB
TypeScript
import { TRPCError, tracked } from "@trpc/server";
|
|
import { z } from "zod/v4";
|
|
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
|
|
import {
|
|
addTyping,
|
|
getCurrentlyTyping,
|
|
removeStaleTyping,
|
|
removeTyping,
|
|
} from "~/server/controllers/chat.controller";
|
|
import { db } from "~/server/db";
|
|
import { add } from "~/server/services/chat.service";
|
|
import { ee, type OnlineStatus } from "~/server/sse";
|
|
import { zChatId, zUserId } from "~/server/utils/zod_types";
|
|
import { getKeydbClient } from "~/utils/keydb";
|
|
//IDEA forse cambiare in semplice interval polling invece di sse
|
|
export const chatSSERouter = createTRPCRouter({
|
|
create: protectedProcedure
|
|
.input(z.object({ userId: zUserId }))
|
|
.mutation(async ({ input }) => {
|
|
const newChat = await add({
|
|
db,
|
|
userId: input.userId,
|
|
});
|
|
|
|
return newChat.chatid;
|
|
}),
|
|
|
|
enterChat: protectedProcedure
|
|
.input(z.object({ chatId: zChatId }))
|
|
.mutation(async ({ input, ctx }) => {
|
|
const chatKey = `chat:${input.chatId}:onlineUsers`;
|
|
const keydb = getKeydbClient();
|
|
|
|
if (!keydb) {
|
|
console.warn(
|
|
"KeyDB client is not initialized. Skipping online status.",
|
|
);
|
|
return [];
|
|
}
|
|
// Add the user to the Redis set
|
|
await keydb.sadd(
|
|
chatKey,
|
|
JSON.stringify({
|
|
isAdmin: ctx.session.isAdmin,
|
|
nome: ctx.session.nome,
|
|
userId: ctx.session.id,
|
|
}),
|
|
);
|
|
|
|
const onlineUsers = await keydb.smembers(chatKey);
|
|
const parsedUsers = onlineUsers.map(
|
|
(user) => JSON.parse(user) as OnlineStatus,
|
|
);
|
|
ee.emit("chatUpdates", input.chatId, {
|
|
data: parsedUsers,
|
|
eventType: "online",
|
|
});
|
|
return parsedUsers;
|
|
}),
|
|
|
|
leaveChat: protectedProcedure
|
|
.input(z.object({ chatId: zChatId }))
|
|
.mutation(async ({ input, ctx }) => {
|
|
const chatKey = `chat:${input.chatId}:onlineUsers`;
|
|
const keydb = getKeydbClient();
|
|
if (!keydb) {
|
|
console.warn(
|
|
"KeyDB client is not initialized. Skipping online status.",
|
|
);
|
|
return [];
|
|
}
|
|
// Remove the user from the Redis set
|
|
await keydb.srem(
|
|
chatKey,
|
|
JSON.stringify({
|
|
isAdmin: ctx.session.isAdmin,
|
|
nome: ctx.session.nome,
|
|
userId: ctx.session.id,
|
|
}),
|
|
);
|
|
|
|
const onlineUsers = await keydb.smembers(chatKey);
|
|
const parsedUsers = onlineUsers.map(
|
|
(user) => JSON.parse(user) as OnlineStatus,
|
|
);
|
|
ee.emit("chatUpdates", input.chatId, {
|
|
data: parsedUsers,
|
|
eventType: "online",
|
|
});
|
|
return parsedUsers;
|
|
}),
|
|
// list: publicProcedure.query(async () => {
|
|
// return await db
|
|
// .selectFrom("chats")
|
|
// .select([
|
|
// "chats.chatid",
|
|
// "chats.created_at",
|
|
// "chats.user_ref",
|
|
// getMessagesArray(),
|
|
// ])
|
|
// .innerJoin("users", "users.id", "chats.user_ref")
|
|
// .select(["users.username", "users.email", "users.nome"])
|
|
// .orderBy("chats.created_at", "desc")
|
|
// .execute();
|
|
// }),
|
|
|
|
onChatEvent: protectedProcedure
|
|
.input(
|
|
z.object({
|
|
chatId: zChatId,
|
|
}),
|
|
)
|
|
.subscription(async function* ({ input, signal }) {
|
|
try {
|
|
const iterable = ee.toIterable("chatUpdates", {
|
|
signal,
|
|
});
|
|
|
|
for await (const [chatId, data] of iterable) {
|
|
if (chatId === input.chatId) {
|
|
yield tracked(chatId, data);
|
|
}
|
|
}
|
|
} catch (e) {
|
|
if (e instanceof Error && e.name === "AbortError") return;
|
|
console.error("Error in onChatEvent subscription:", e);
|
|
}
|
|
}),
|
|
|
|
type: protectedProcedure
|
|
.input(
|
|
z.object({ chatId: zChatId, typing: z.boolean(), username: z.string() }),
|
|
)
|
|
.mutation(async ({ ctx, input }) => {
|
|
try {
|
|
await removeStaleTyping(input.chatId);
|
|
|
|
if (input.typing) {
|
|
// Add the user to the set
|
|
await addTyping({
|
|
chatId: input.chatId,
|
|
userId: ctx.session.id,
|
|
username: input.username,
|
|
});
|
|
} else {
|
|
await removeTyping({
|
|
chatId: input.chatId,
|
|
userId: ctx.session.id,
|
|
username: input.username,
|
|
});
|
|
}
|
|
|
|
ee.emit("chatUpdates", input.chatId, {
|
|
data: await getCurrentlyTyping(input.chatId),
|
|
eventType: "typing",
|
|
});
|
|
return true;
|
|
} catch (e) {
|
|
throw new TRPCError({
|
|
code: "INTERNAL_SERVER_ERROR",
|
|
message:
|
|
"An error occurred while processing the typing event: " +
|
|
(e as Error).message,
|
|
});
|
|
}
|
|
}),
|
|
});
|