Selaa lähdekoodia

live monitoring

Leo dev 2 viikkoa sitten
vanhempi
commit
6b91411de5
4 muutettua tiedostoa jossa 159 lisäystä ja 30 poistoa
  1. 69 11
      src/app/api/servers/route.ts
  2. 43 11
      src/app/dashboard/page.tsx
  3. 45 6
      src/app/dashboard/server.tsx
  4. 2 2
      src/app/servers/Map.tsx

+ 69 - 11
src/app/api/servers/route.ts

@@ -4,7 +4,54 @@ import Server, { ServerAPI } from "@/types/server";
 import { HttpStatusCode } from "axios";
 import { validate } from "../auth/route";
 
+const useServer = (server: ServerAPI, index: number) => {
+  const ws = new WebSocket(`ws://${server.ip}:5273`);
+  ws.onmessage = (msg) => {
+    try {
+      if (deletes.has(index) || !currentServers[index]) {
+        ws.close();
+        return;
+      }
+      if (msg.data === "Success") {return}
+      const data = JSON.parse(msg.data);
+      
+      if (data.status) {
+        currentServers[index].status = data.status;
+      }
+      if (data.cpu) {
+        currentServers[index].cpu = data.cpu;
+      }
+      if (data.memory) {
+        currentServers[index].memory = data.memory;
+      }
+      if (data.disk) {
+        currentServers[index].storage = data.disk;
+      }
+      if (data.network) {
+        currentServers[index].network = data.network;
+      }
+    } catch (e) {
+      console.error("Error parsing WebSocket message:", e);
+    }
+  };
+  ws.onopen = () => ws.send("my-key");
+};
+
+const deletes = new Set<number>();
 export const servers = new Data<ServerAPI[]>("sentryx/servers.json", []);
+export var currentServers: Server[] = servers.data.map(
+    (s) =>
+      ({
+        ...s,
+        status: "offline",
+        cpu: 0,
+        memory: 0,
+        storage: 0,
+        network: 0,
+      } as Server)
+  );
+
+servers.data.map(useServer);
 
 export async function GET(request: Request) {
   const { searchParams } = new URL(request.url);
@@ -17,17 +64,6 @@ export async function GET(request: Request) {
       { status: HttpStatusCode.Unauthorized }
     );
 
-  const currentServers = servers.data.map(
-    (s) =>
-      ({
-        ...s,
-        status: "online",
-        cpu: 20,
-        memory: 70,
-        storage: 40,
-        network: 30,
-      } as Server)
-  );
 
   if (query) {
     let tokens = (query || "").toLocaleLowerCase().split(" ");
@@ -76,6 +112,25 @@ export async function POST(request: Request) {
     location: body.location,
   });
 
+  currentServers.push({
+    name: body.name,
+    ip: body.ip,
+    coordinates: body.coordinates,
+    location: body.location,
+    status: "offline",
+    cpu: 0,
+    memory: 0,
+    storage: 0,
+    network: 0,
+  });
+
+  useServer({
+    name: body.name,
+    ip: body.ip,
+    coordinates: body.coordinates,
+    location: body.location,
+  }, servers.data.length - 1);
+
   servers.write();
 
   return NextResponse.json({
@@ -105,6 +160,9 @@ export async function DELETE(request: Request) {
     );
 
   servers.data.splice(parseInt(index), 1);
+  currentServers.splice(parseInt(index), 1);
+
+  deletes.add(parseInt(index));
 
   servers.write();
 

+ 43 - 11
src/app/dashboard/page.tsx

@@ -3,11 +3,11 @@
 import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
 import { Label } from "@/components/ui/label";
 import { cn } from "@/lib/utils";
-import { CircleCheckBig, Cpu, MemoryStick, TriangleAlert } from "lucide-react";
+import { CircleCheckBig, Cpu, HardDrive, MemoryStick, Network, TriangleAlert } from "lucide-react";
 import { ChartAreaGradient } from "./chart";
 import { Progress } from "@/components/ui/progress";
 import getSession from "@/hooks/getSession";
-import ServerComponent from "./server";
+import ServerComponent, { ByteUnit, UsageBar } from "./server";
 import { Input } from "@/components/ui/input";
 import { Button } from "@/components/ui/button";
 import { useEffect, useState } from "react";
@@ -90,7 +90,7 @@ export default function Dashboard() {
     network: 0,
   });
 
-  useEffect(() => {
+  const getServers = () => {
     if (!session) return;
 
     session.getServers().then((servers) => {
@@ -107,9 +107,21 @@ export default function Dashboard() {
         cpu: average(servers, (s) => s.cpu),
         memory: average(servers, (s) => s.memory),
         storage: average(servers, (s) => s.storage),
-        network: average(servers, (s) => s.network),
-      });
-    });
+        network: servers.reduce((sum, s) => sum + s.network, 0),
+      });``
+    }).catch((e) => {
+      console.error("Error fetching servers:", e);
+    })
+  };
+
+  useEffect(() => {
+    const interval = setInterval(() => {
+      console.log("Refreshing servers data...");
+      getServers();
+    }, 3000);
+
+    // Cleanup on unmount
+    return () => clearInterval(interval);
   }, [session]);
 
   useEffect(() => {
@@ -171,11 +183,31 @@ export default function Dashboard() {
           <CardHeader>
             <CardTitle>System Overview</CardTitle>
           </CardHeader>
-          <CardContent className="flex flex-col gap-6 w-full md:w-96">
-            <Summary value={serverData.cpu}>Average CPU</Summary>
-            <Summary value={serverData.memory}>Average Memory</Summary>
-            <Summary value={serverData.storage}>Storage</Summary>
-            <Summary value={serverData.network}>Average Network</Summary>
+          <CardContent className="flex flex-col gap-4 w-full md:w-96">
+            <UsageBar
+              value={serverData.cpu}
+              Icon={Cpu}
+              text="CPU"
+              color="var(--chart-2)"
+            />
+            <UsageBar
+              value={serverData.memory}
+              Icon={MemoryStick}
+              text="Memory"
+              color="var(--chart-1)"
+            />
+            <UsageBar
+              value={serverData.storage}
+              Icon={HardDrive}
+              text="Storage"
+              color="var(--chart-5)"
+            />
+            <ByteUnit
+              value={serverData.network}
+              Icon={Network}
+              text="Network"
+              color="var(--chart-3)"
+            />
           </CardContent>
         </Card>
       </div>

+ 45 - 6
src/app/dashboard/server.tsx

@@ -64,6 +64,43 @@ export function UsageBar({
   );
 }
 
+function formatBytes(bytes: number, decimals = 2): string {
+  if (bytes === 0) return "0 Bytes";
+
+  const k = 1024;
+  const dm = decimals < 0 ? 0 : decimals;
+
+  const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
+  const i = Math.floor(Math.log(bytes) / Math.log(k));
+
+  const size = parseFloat((bytes / Math.pow(k, i)).toFixed(dm));
+
+  return `${size} ${sizes[i]}`;
+}
+
+export function ByteUnit({
+  value,
+  Icon,
+  text,
+  color,
+}: {
+  value: number;
+  Icon: React.ElementType;
+  text: string;
+  color: string;
+}) {
+  return (
+    <div className="flex flex-col gap-2 w-full">
+      <div className="justify-between flex">
+        <Label className="text-md flex justify-center">
+          <Icon size={16} color={color} /> {text}
+        </Label>
+        <Label className="text-md">{formatBytes(value)}</Label>
+      </div>
+    </div>
+  )
+}
+
 export default function ServerComponent({
   server,
   index,
@@ -127,12 +164,14 @@ export default function ServerComponent({
                 text="Storage"
                 color="var(--chart-5)"
               />
-              <UsageBar
-                value={server.network}
-                Icon={Network}
-                text="Network"
-                color="var(--chart-3)"
-              />
+              <div className="flex flex-col gap-2 w-full">
+                <div className="justify-between flex">
+                  <Label className="text-md flex justify-center">
+                    <Network size={16} color="var(--chart-3)" /> Network
+                  </Label>
+                  <Label className="text-md">{formatBytes(server.network)}</Label>
+                </div>
+              </div>
             </CardContent>
           </Card>
         </ContextMenuTrigger>

+ 2 - 2
src/app/servers/Map.tsx

@@ -10,7 +10,7 @@ import {
   SheetTitle,
   SheetTrigger,
 } from "@/components/ui/sheet";
-import ServerComponent, { UsageBar } from "../dashboard/server";
+import ServerComponent, { ByteUnit, UsageBar } from "../dashboard/server";
 import {
   Cpu,
   HardDrive,
@@ -117,7 +117,7 @@ export default function Map({ servers }: { servers: Server[] }) {
                 text="Storage"
                 color="var(--chart-5)"
               />
-              <UsageBar
+              <ByteUnit
                 value={sheet.network}
                 Icon={Network}
                 text="Network"