live monitoring
This commit is contained in:
@@ -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
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user