import { useState, useEffect, useRef } from 'react'; import { Server } from '../types'; import ping from './utils/jsping'; interface ServerWidgetProps { config: { serverWidget: { enabled: boolean; pingFrequency: number; servers: Server[]; }; }; } const STATUS_COLORS: Record = { online: 'bg-green-400 text-green-400', offline: 'bg-red-400 text-red-400', }; const getStatusColor = (status: string): string => STATUS_COLORS[status] ?? 'bg-slate-400 text-slate-400'; const ServerWidget: React.FC = ({ config }) => { const [serverStatus, setServerStatus] = useState>({}); const serversRef = useRef(config.serverWidget.servers); serversRef.current = config.serverWidget.servers; const serversSignature = JSON.stringify(config.serverWidget.servers.map(s => [s.id, s.address])); useEffect(() => { if (!config.serverWidget.enabled || serversRef.current.length === 0) return; let timer: ReturnType | undefined; let controller: AbortController | undefined; let cancelled = false; const frequency = Math.min(60, Math.max(5, config.serverWidget.pingFrequency || 15)) * 1000; setServerStatus(Object.fromEntries(serversRef.current.map(server => [server.id, 'pending']))); const pingServers = async () => { if (cancelled || document.visibilityState !== 'visible') return; const cycle = new AbortController(); controller = cycle; const servers = serversRef.current; const statuses: Record = {}; let next = 0; await Promise.all(Array.from({ length: Math.min(4, servers.length) }, async () => { while (next < servers.length && !cycle.signal.aborted) { const server = servers[next++]; try { await ping(server.address, 1, cycle.signal); statuses[server.id] = 'online'; } catch { statuses[server.id] = 'offline'; } } })); if (cancelled || cycle.signal.aborted) return; setServerStatus(previous => servers.every(server => previous[server.id] === statuses[server.id]) ? previous : statuses); timer = setTimeout(() => void pingServers(), frequency); }; const onVisibilityChange = () => { clearTimeout(timer); controller?.abort(); if (document.visibilityState === 'visible') void pingServers(); }; void pingServers(); document.addEventListener('visibilitychange', onVisibilityChange); return () => { cancelled = true; clearTimeout(timer); controller?.abort(); document.removeEventListener('visibilitychange', onVisibilityChange); }; }, [ config.serverWidget.enabled, config.serverWidget.pingFrequency, serversSignature, ]); if (!config.serverWidget.enabled) { return null; } return (
{config.serverWidget.servers.map((server) => (
{server.name}
))}
); }; export default ServerWidget;