From de27efd3ed678773213af8c215ea1bdfe2746e55 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 13:09:18 +0000 Subject: [PATCH 1/3] Initial plan From 29a60dcfce876d4442b09229395b7058bf0f37ae Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 13:13:41 +0000 Subject: [PATCH 2/3] Add RCON server status indicator to admin panel Co-authored-by: maxonary <62939182+maxonary@users.noreply.github.com> --- .../src/controllers/serverStatusController.ts | 27 +++++++++++ backend/src/routes/serverStatusRoutes.ts | 3 +- frontend/src/components/Dashboard.tsx | 45 ++++++++++++++++++- 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/backend/src/controllers/serverStatusController.ts b/backend/src/controllers/serverStatusController.ts index aa0969e..d062ef5 100644 --- a/backend/src/controllers/serverStatusController.ts +++ b/backend/src/controllers/serverStatusController.ts @@ -1,4 +1,5 @@ import { Request, Response } from 'express'; +import { connectRcon, disconnectRcon } from '../helpers/rconHelper'; const SLEEPING_SERVER_URL = process.env.SLEEPING_SERVER_URL || 'http://localhost:5000'; @@ -72,3 +73,29 @@ export const wakeUpServer = async (req: Request, res: Response) => { } }; +/** + * Get the RCON connection status + */ +export const getRconStatus = async (req: Request, res: Response) => { + try { + // Try to connect to RCON server + await connectRcon(); + + // If connection successful, disconnect and return success + disconnectRcon(); + + res.status(200).json({ + status: 'Running', + connected: true, + message: 'RCON server is connected' + }); + } catch (error) { + console.error('[RCON Status] RCON connection failed:', error instanceof Error ? error.message : error); + res.status(200).json({ + status: 'Offline', + connected: false, + message: 'RCON server is not connected - Entries cannot be approved' + }); + } +}; + diff --git a/backend/src/routes/serverStatusRoutes.ts b/backend/src/routes/serverStatusRoutes.ts index bdbae00..db3c157 100644 --- a/backend/src/routes/serverStatusRoutes.ts +++ b/backend/src/routes/serverStatusRoutes.ts @@ -1,11 +1,12 @@ import express from 'express'; -import { getServerStatus, wakeUpServer } from '../controllers/serverStatusController'; +import { getServerStatus, wakeUpServer, getRconStatus } from '../controllers/serverStatusController'; const router = express.Router(); // Public routes - anyone can check server status and wake up the server router.get('/', getServerStatus); router.post('/wakeup', wakeUpServer); +router.get('/rcon', getRconStatus); export default router; diff --git a/frontend/src/components/Dashboard.tsx b/frontend/src/components/Dashboard.tsx index 8e63f3e..0bdd5e9 100644 --- a/frontend/src/components/Dashboard.tsx +++ b/frontend/src/components/Dashboard.tsx @@ -4,7 +4,7 @@ import { useNavigate } from "react-router-dom"; import { copyToClipboard } from "../utils/clipboardUtils"; import UserTable from "./UserTable"; import Button from "./Button"; -import { apiJwt, setAuthToken } from "../api"; +import { apiJwt, setAuthToken, api } from "../api"; import "../styles/Minecraft.css"; import TitleImage from "./TitleImage"; @@ -36,6 +36,8 @@ function Dashboard() { const [invitationCode, setInvitationCode] = useState(null); const [isCopied, setIsCopied] = useState(false); const [error, setError] = useState(null); + const [rconStatus, setRconStatus] = useState(""); + const [rconConnected, setRconConnected] = useState(true); const invitationCodeRef = useRef(null); @@ -69,14 +71,55 @@ function Dashboard() { navigate("/admin/login"); } + // Function to fetch RCON status + const fetchRconStatus = async () => { + try { + const response = await api.get('/api/status/rcon'); + setRconStatus(response.data.status); + setRconConnected(response.data.connected); + } catch (error) { + console.error('[Dashboard] Error fetching RCON status:', error); + setRconStatus('Error'); + setRconConnected(false); + } + }; + useEffect(() => { const url = window.location.host; document.title = `Admin Dashboard - ${url}`; + + // Fetch RCON status immediately + fetchRconStatus(); + + // Set up polling to fetch status every 5 seconds + const statusInterval = setInterval(() => { + fetchRconStatus(); + }, 5000); // Poll every 5 seconds + + // Cleanup interval on unmount + return () => { + clearInterval(statusInterval); + }; }, []); return (
+ + {/* Server Status Indicator */} +
+
+
+ {rconConnected ? '🟩' : '🟥'} + {rconConnected ? 'Server is running' : 'Server is offline - Entries cannot be approved'} +
+
+
+
From 800b2c21b5206714a46c89646a907c9fa6a32e6d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 13:16:34 +0000 Subject: [PATCH 3/3] Address code review feedback: add auth and remove unused state Co-authored-by: maxonary <62939182+maxonary@users.noreply.github.com> --- backend/src/routes/serverStatusRoutes.ts | 5 ++++- frontend/src/components/Dashboard.tsx | 7 ++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/src/routes/serverStatusRoutes.ts b/backend/src/routes/serverStatusRoutes.ts index db3c157..f30dda0 100644 --- a/backend/src/routes/serverStatusRoutes.ts +++ b/backend/src/routes/serverStatusRoutes.ts @@ -1,12 +1,15 @@ import express from 'express'; import { getServerStatus, wakeUpServer, getRconStatus } from '../controllers/serverStatusController'; +import { authMiddleware } from '../middleware/authMiddleware'; const router = express.Router(); // Public routes - anyone can check server status and wake up the server router.get('/', getServerStatus); router.post('/wakeup', wakeUpServer); -router.get('/rcon', getRconStatus); + +// Protected route - only authenticated admins can check RCON status +router.get('/rcon', authMiddleware, getRconStatus); export default router; diff --git a/frontend/src/components/Dashboard.tsx b/frontend/src/components/Dashboard.tsx index 0bdd5e9..a52a574 100644 --- a/frontend/src/components/Dashboard.tsx +++ b/frontend/src/components/Dashboard.tsx @@ -4,7 +4,7 @@ import { useNavigate } from "react-router-dom"; import { copyToClipboard } from "../utils/clipboardUtils"; import UserTable from "./UserTable"; import Button from "./Button"; -import { apiJwt, setAuthToken, api } from "../api"; +import { apiJwt, setAuthToken } from "../api"; import "../styles/Minecraft.css"; import TitleImage from "./TitleImage"; @@ -36,7 +36,6 @@ function Dashboard() { const [invitationCode, setInvitationCode] = useState(null); const [isCopied, setIsCopied] = useState(false); const [error, setError] = useState(null); - const [rconStatus, setRconStatus] = useState(""); const [rconConnected, setRconConnected] = useState(true); const invitationCodeRef = useRef(null); @@ -74,12 +73,10 @@ function Dashboard() { // Function to fetch RCON status const fetchRconStatus = async () => { try { - const response = await api.get('/api/status/rcon'); - setRconStatus(response.data.status); + const response = await apiJwt.get('/api/status/rcon'); setRconConnected(response.data.connected); } catch (error) { console.error('[Dashboard] Error fetching RCON status:', error); - setRconStatus('Error'); setRconConnected(false); } };