150 lines
4.6 KiB
TypeScript
150 lines
4.6 KiB
TypeScript
/* eslint-disable react-hooks/exhaustive-deps */
|
||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||
import { differenceInSeconds, parseISO } from "date-fns";
|
||
import ky from "ky";
|
||
import { useEffect, useState } from "react";
|
||
import QRCode from "react-qr-code";
|
||
|
||
function MonitoringPage() {
|
||
const [sessions, setSessions] = useState<any>([]);
|
||
const [servers, setServers] = useState<any>([]);
|
||
|
||
async function getSessionServers() {
|
||
const response = await ky
|
||
.get(`${import.meta.env.VITE_COORD_URL}/session_servers`)
|
||
.json();
|
||
|
||
setServers(response);
|
||
|
||
setTimeout(() => {
|
||
getSessionServers();
|
||
}, 1000);
|
||
}
|
||
|
||
async function getActiveSessions() {
|
||
const response = await ky
|
||
.get(`${import.meta.env.VITE_COORD_URL}/active_sessions`)
|
||
.json();
|
||
|
||
setSessions(response);
|
||
|
||
setTimeout(() => {
|
||
getActiveSessions();
|
||
}, 1000);
|
||
}
|
||
|
||
async function endActiveSession(
|
||
location: string,
|
||
server: string,
|
||
uePort: number,
|
||
cirrusPort: number
|
||
) {
|
||
await ky
|
||
.get(
|
||
`${
|
||
import.meta.env.VITE_COORD_URL
|
||
}/end?location=${location}&server=${server}&uePort=${uePort}&cirrusPort=${cirrusPort}`
|
||
)
|
||
.json();
|
||
}
|
||
|
||
useEffect(() => {
|
||
getActiveSessions();
|
||
getSessionServers();
|
||
}, []);
|
||
|
||
return (
|
||
<div className="min-h-screen text-[#F2F2F2] p-4 gap-4 flex flex-col">
|
||
{servers.map((server: any) => (
|
||
<div key={server.id} className="p-4 bg-[#22222A]">
|
||
<div>
|
||
{differenceInSeconds(new Date(), parseISO(server.updatedAt)) >=
|
||
10 ? (
|
||
<p className="flex items-center gap-2">
|
||
<span className="h-2 w-2 rounded-full bg-red-500"></span>
|
||
<span>Не в сети</span>
|
||
</p>
|
||
) : (
|
||
<p className="flex items-center gap-2">
|
||
<span className="h-2 w-2 rounded-full bg-green-500"></span>
|
||
<span>В сети</span>
|
||
</p>
|
||
)}
|
||
</div>
|
||
<p>Локация: "{server.location}"</p>
|
||
<p>Имя сервера: "{server.name}"</p>
|
||
<p>Лимит процессов: {server.limit_process}</p>
|
||
<div>
|
||
<p>CPU: {server.cpu}</p>
|
||
<p>RAM: {server.ram}</p>
|
||
<p className="flex space-x-2">
|
||
<span>GPU: </span>
|
||
<span className="flex space-x-4">
|
||
{server.gpu?.map((item: any, index: number) => (
|
||
<span key={index}>
|
||
{item} {index === 2 && "°C"}
|
||
</span>
|
||
))}
|
||
</span>
|
||
</p>
|
||
</div>
|
||
</div>
|
||
))}
|
||
|
||
{sessions.map((session: any) => (
|
||
<div
|
||
key={session.id}
|
||
className="flex flex-wrap gap-4 justify-between items-center p-4 bg-[#22222A] rounded"
|
||
>
|
||
<div className="flex gap-4">
|
||
<div className="">
|
||
<QRCode
|
||
bgColor="#22222A"
|
||
fgColor="#F2F2F2"
|
||
size={128}
|
||
value={`https://stream.graff.tech/stream/?data=wss://${session.location}.sess.stream.graff.tech/${session.server}/${session.cirrusPort}/`}
|
||
viewBox={`0 0 128 128`}
|
||
/>
|
||
</div>
|
||
<div className="sm:text-base text-sm">
|
||
<p>Локация: "{session.location}"</p>
|
||
<p>Сервер: "{session.server}"</p>
|
||
<p>Сборка: "{session.title}"</p>
|
||
<p>Порт: {session.cirrusPort}</p>
|
||
<p>Пользователи: {session.connectedPlayersCount || 0}</p>
|
||
<p>
|
||
Время запуска: {new Date(session.createdAt).toLocaleString()}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="space-x-4">
|
||
<a
|
||
href={`https://stream.graff.tech/stream/${session.id}`}
|
||
target="_blank"
|
||
className="inline-block px-4 py-2 bg-blue-600 hover:bg-blue-500 transition-colors rounded"
|
||
>
|
||
Открыть в новом окне
|
||
</a>
|
||
<button
|
||
onClick={() =>
|
||
endActiveSession(
|
||
session.location,
|
||
session.server,
|
||
session.uePort,
|
||
session.cirrusPort
|
||
)
|
||
}
|
||
className="px-4 py-2 bg-red-600 hover:bg-red-500 transition-colors rounded"
|
||
>
|
||
Завершить сессию
|
||
</button>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export default MonitoringPage;
|