From 26e71bcaa818ea6545b3da409c0b4a84277e350c Mon Sep 17 00:00:00 2001 From: PxlLoewe <72106766+PxlLoewe@users.noreply.github.com> Date: Thu, 1 May 2025 21:48:25 -0700 Subject: [PATCH] implemented connectedDispatch record for dispatcher --- apps/dispatch-server/routes/dispatcher.ts | 16 +-- apps/dispatch-server/routes/router.ts | 2 + apps/dispatch-server/routes/status.ts | 22 ++++ .../socket-events/connect-dispatch.ts | 111 +++++++++++------- .../socket-events/connect-pilot.ts | 94 +++++++++++++++ .../app/dispatch/_components/left/Chat.tsx | 38 +++--- .../app/dispatch/_components/left/Report.tsx | 29 ++--- apps/dispatch/app/helpers/axios.ts | 13 ++ .../app/pilot/_components/navbar/Chat.tsx | 48 ++++---- .../app/pilot/_components/navbar/action.ts | 9 -- docker-compose.dev.yml | 2 +- grafana/grafana.db | Bin 1122304 -> 1122304 bytes packages/database/prisma/json/User.ts | 12 ++ .../prisma/schema/connectedAircraft.prisma | 2 +- .../database/prisma/schema/station.prisma | 2 +- packages/database/prisma/schema/user.prisma | 2 +- 16 files changed, 287 insertions(+), 115 deletions(-) create mode 100644 apps/dispatch-server/routes/status.ts create mode 100644 apps/dispatch-server/socket-events/connect-pilot.ts diff --git a/apps/dispatch-server/routes/dispatcher.ts b/apps/dispatch-server/routes/dispatcher.ts index 937d1bc4..b56eab9b 100644 --- a/apps/dispatch-server/routes/dispatcher.ts +++ b/apps/dispatch-server/routes/dispatcher.ts @@ -1,19 +1,15 @@ +import { prisma } from "@repo/db"; import { Router } from "express"; import { pubClient } from "modules/redis"; const router = Router(); router.get("/", async (req, res) => { - const keys = await pubClient.keys("Dispatcher:*"); - const user = await Promise.all( - keys.map(async (key) => { - const data = await pubClient.json.get(key); - return { - ...(typeof data === "object" && data !== null ? data : {}), - userId: key.split(":")[1], - }; - }), - ); + const user = await prisma.connectedDispatcher.findMany({ + where: { + logoutTime: null, + }, + }); res.json(user); }); diff --git a/apps/dispatch-server/routes/router.ts b/apps/dispatch-server/routes/router.ts index d5d83ffd..874ac22e 100644 --- a/apps/dispatch-server/routes/router.ts +++ b/apps/dispatch-server/routes/router.ts @@ -2,11 +2,13 @@ import { Router } from "express"; import livekitRouter from "./livekit"; import dispatcherRotuer from "./dispatcher"; import missionRouter from "./mission"; +import statusRouter from "./status"; const router = Router(); router.use("/livekit", livekitRouter); router.use("/dispatcher", dispatcherRotuer); router.use("/mission", missionRouter); +router.use("/status", statusRouter); export default router; diff --git a/apps/dispatch-server/routes/status.ts b/apps/dispatch-server/routes/status.ts new file mode 100644 index 00000000..b6beb8bc --- /dev/null +++ b/apps/dispatch-server/routes/status.ts @@ -0,0 +1,22 @@ +import { prisma } from "@repo/db"; +import { Router } from "express"; + +const router = Router(); + +router.get("/connected-users", async (req, res) => { + const connectedDispatcher = await prisma.connectedDispatcher.findMany({ + where: { + logoutTime: null, + }, + }); + + const connectedAircraft = await prisma.connectedAircraft.findMany({ + where: { + logoutTime: null, + }, + }); + + res.json([...connectedDispatcher, ...connectedAircraft]); +}); + +export default router; diff --git a/apps/dispatch-server/socket-events/connect-dispatch.ts b/apps/dispatch-server/socket-events/connect-dispatch.ts index 8c5b7b81..fb40f9e6 100644 --- a/apps/dispatch-server/socket-events/connect-dispatch.ts +++ b/apps/dispatch-server/socket-events/connect-dispatch.ts @@ -1,4 +1,4 @@ -import { prisma } from "@repo/db"; +import { getPublicUser, prisma } from "@repo/db"; import { pubClient } from "modules/redis"; import { Server, Socket } from "socket.io"; @@ -11,47 +11,76 @@ export const handleConnectDispatch = logoffTime: string; selectedZone: string; }) => { - const userId = socket.data.user.id; // User ID aus dem JWT-Token - console.log("User connected to dispatch server"); - const user = await prisma.user.findUnique({ - where: { - id: userId, - }, - }); - const connectedDispatcherEntry = await prisma.connectedDispatcher.create({ - data: { - publicUser: {}, - esimatedLogoutTime: logoffTime, - lastHeartbeat: new Date(), - userId: userId, - loginTime: new Date().toISOString(), - }, - }); - - socket.join("dispatchers"); // Dem Dispatcher-Raum beitreten - socket.join(`user:${userId}`); // Dem User-Raum beitreten - - /* const keys = await pubClient.keys("Dispatcher:*"); - await Promise.all( - keys.map(async (key) => { - return await pubClient.json.get(key); - }), - ); */ - io.to("dispatchers").emit("dispatcher-update"); - io.to("pilots").emit("dispatcher-update"); - - socket.on("disconnect", async () => { - console.log("Disconnected from dispatch server"); - await prisma.connectedDispatcher.update({ + try { + const userId = socket.data.user.id; // User ID aus dem JWT-Token + console.log("User connected to dispatch server"); + const user = await prisma.user.findUnique({ where: { - id: connectedDispatcherEntry.id, - }, - data: { - logoutTime: new Date().toISOString(), + id: userId, }, }); - }); - socket.on("reconnect", async () => { - console.log("Reconnected to dispatch server"); - }); + + if (!user) return Error("User not found"); + + let parsedLogoffDate = null; + if (logoffTime.length > 0) { + const now = new Date(); + const [hours, minutes] = logoffTime.split(":").map(Number); + if (!hours || !minutes) { + throw new Error("Invalid logoffTime format"); + } + parsedLogoffDate = new Date(now); + parsedLogoffDate.setHours(hours, minutes, 0, 0); + + // If the calculated time is earlier than now, add one day to make it tomorrow + if (parsedLogoffDate <= now) { + parsedLogoffDate.setDate(parsedLogoffDate.getDate() + 1); + } + + // If the calculated time is in the past, add one day to make it in the future + if (parsedLogoffDate <= now) { + parsedLogoffDate.setDate(parsedLogoffDate.getDate() + 1); + } + } + + const connectedDispatcherEntry = await prisma.connectedDispatcher.create({ + data: { + publicUser: getPublicUser(user) as any, + esimatedLogoutTime: parsedLogoffDate?.toISOString() || null, + lastHeartbeat: new Date().toISOString(), + userId: userId, + loginTime: new Date().toISOString(), + }, + }); + + socket.join("dispatchers"); // Dem Dispatcher-Raum beitreten + socket.join(`user:${userId}`); // Dem User-Raum beitreten + + /* const keys = await pubClient.keys("Dispatcher:*"); + await Promise.all( + keys.map(async (key) => { + return await pubClient.json.get(key); + }), + ); */ + io.to("dispatchers").emit("dispatcher-update"); + io.to("pilots").emit("dispatcher-update"); + + socket.on("disconnect", async () => { + console.log("Disconnected from dispatch server"); + await prisma.connectedDispatcher.update({ + where: { + id: connectedDispatcherEntry.id, + }, + data: { + logoutTime: new Date().toISOString(), + }, + }); + }); + socket.on("reconnect", async () => { + console.log("Reconnected to dispatch server"); + }); + } catch (error) { + console.error("Error connecting to dispatch server:", error); + console.log("Error connecting to dispatch server:", error); + } }; diff --git a/apps/dispatch-server/socket-events/connect-pilot.ts b/apps/dispatch-server/socket-events/connect-pilot.ts new file mode 100644 index 00000000..83b40869 --- /dev/null +++ b/apps/dispatch-server/socket-events/connect-pilot.ts @@ -0,0 +1,94 @@ +import { getPublicUser, prisma } from "@repo/db"; +import { Server, Socket } from "socket.io"; + +export const handleConnectDispatch = + (socket: Socket, io: Server) => + async ({ + logoffTime, + stationId, + }: { + logoffTime: string; + stationId: number; + }) => { + try { + const userId = socket.data.user.id; // User ID aus dem JWT-Token + console.log("User connected to dispatch server"); + const user = await prisma.user.findUnique({ + where: { + id: userId, + }, + }); + + if (!user) return Error("User not found"); + + let parsedLogoffDate = null; + if (logoffTime.length > 0) { + const now = new Date(); + const [hours, minutes] = logoffTime.split(":").map(Number); + if (!hours || !minutes) { + throw new Error("Invalid logoffTime format"); + } + parsedLogoffDate = new Date(now); + parsedLogoffDate.setHours(hours, minutes, 0, 0); + + // If the calculated time is earlier than now, add one day to make it tomorrow + if (parsedLogoffDate <= now) { + parsedLogoffDate.setDate(parsedLogoffDate.getDate() + 1); + } + } + + const connectedAircraftEntry = await prisma.connectedAircraft.create({ + data: { + publicUser: getPublicUser(user) as any, + esimatedLogoutTime: parsedLogoffDate?.toISOString() || null, + lastHeartbeat: new Date().toISOString(), + userId: userId, + loginTime: new Date().toISOString(), + stationId: stationId, + /* user: { connect: { id: userId } }, // Ensure the user relationship is set + station: { connect: { id: stationId } }, // Ensure the station relationship is set */ + }, + }); + + socket.join("dispatchers"); // Join the dispatchers room + socket.join(`user:${userId}`); // Join the user-specific room + socket.join(`station:${stationId}`); // Join the station-specific room + + io.to("dispatchers").emit("dispatcher-update"); + io.to("pilots").emit("dispatcher-update"); + + // Add a listener for station-specific events + socket.on(`station:${stationId}:event`, async (data) => { + console.log(`Received event for station ${stationId}:`, data); + // Handle station-specific logic here + io.to(`station:${stationId}`).emit("station-event-update", data); + }); + + socket.on("disconnect", async () => { + console.log("Disconnected from dispatch server"); + await prisma.connectedDispatcher.update({ + where: { + id: connectedAircraftEntry.id, + }, + data: { + logoutTime: new Date().toISOString(), + }, + }); + }); + + socket.on("reconnect", async () => { + console.log("Reconnected to dispatch server"); + await prisma.connectedDispatcher.update({ + where: { + id: connectedAircraftEntry.id, + }, + data: { + lastHeartbeat: new Date().toISOString(), + logoutTime: null, + }, + }); + }); + } catch (error) { + console.error("Error connecting to dispatch server:", error); + } + }; diff --git a/apps/dispatch/app/dispatch/_components/left/Chat.tsx b/apps/dispatch/app/dispatch/_components/left/Chat.tsx index 742dfc69..0b01c367 100644 --- a/apps/dispatch/app/dispatch/_components/left/Chat.tsx +++ b/apps/dispatch/app/dispatch/_components/left/Chat.tsx @@ -3,9 +3,9 @@ import { ChatBubbleIcon, PaperPlaneIcon } from "@radix-ui/react-icons"; import { useLeftMenuStore } from "_store/leftMenuStore"; import { useSession } from "next-auth/react"; import { Fragment, useEffect, useRef, useState } from "react"; -import { Dispatcher } from "dispatch/_components/navbar/_components/action"; import { cn } from "helpers/cn"; -import { getDispatcher } from "pilot/_components/navbar/action"; +import { getConenctedUsers } from "helpers/axios"; +import { asPublicUser, ConnectedAircraft, ConnectedDispatcher } from "@repo/db"; export const Chat = () => { const { @@ -24,7 +24,9 @@ export const Chat = () => { const session = useSession(); const [addTabValue, setAddTabValue] = useState(""); const [message, setMessage] = useState(""); - const [dispatcher, setDispatcher] = useState(null); + const [connectedUser, setConnectedUser] = useState< + (ConnectedAircraft | ConnectedDispatcher)[] | null + >(null); const timeout = useRef(null); useEffect(() => { @@ -33,24 +35,26 @@ export const Chat = () => { }, [session, setOwnId]); useEffect(() => { - const fetchDispatcher = async () => { - const data = await getDispatcher(); + const fetchConnectedUser = async () => { + const data = await getConenctedUsers(); if (data) { - const filteredDispatcher = data.filter((user) => { - return ( + const filteredConnectedUser = data.filter((user) => { + /* return ( user.userId !== session.data?.user.id && !Object.keys(chats).includes(user.userId) - ); + ); */ + + return true; }); - setDispatcher(filteredDispatcher); + setConnectedUser(filteredConnectedUser); } if (!addTabValue && data[0]) setAddTabValue(data[0].userId); }; timeout.current = setInterval(() => { - fetchDispatcher(); + fetchConnectedUser(); }, 1000); - fetchDispatcher(); + fetchConnectedUser(); return () => { if (timeout.current) { @@ -61,6 +65,8 @@ export const Chat = () => { }; }, [addTabValue, chats, session.data?.user.id]); + console.log("connectedUser", connectedUser); + return (
@@ -95,23 +101,23 @@ export const Chat = () => { value={addTabValue} onChange={(e) => setAddTabValue(e.target.value)} > - {!dispatcher?.length && ( + {!connectedUser?.length && ( )} - {dispatcher?.map((user) => ( + {connectedUser?.map((user) => ( ))}