Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions backend/src/controllers/serverStatusController.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand Down Expand Up @@ -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'
});
}
};

6 changes: 5 additions & 1 deletion backend/src/routes/serverStatusRoutes.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import express from 'express';
import { getServerStatus, wakeUpServer } from '../controllers/serverStatusController';
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);

// Protected route - only authenticated admins can check RCON status
router.get('/rcon', authMiddleware, getRconStatus);

export default router;


Expand Down
40 changes: 40 additions & 0 deletions frontend/src/components/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ function Dashboard() {
const [invitationCode, setInvitationCode] = useState<string | null>(null);
const [isCopied, setIsCopied] = useState(false);
const [error, setError] = useState<string | null>(null);
const [rconConnected, setRconConnected] = useState<boolean>(true);

const invitationCodeRef = useRef<HTMLInputElement>(null);

Expand Down Expand Up @@ -69,14 +70,53 @@ function Dashboard() {
navigate("/admin/login");
}

// Function to fetch RCON status
const fetchRconStatus = async () => {
try {
const response = await apiJwt.get('/api/status/rcon');
setRconConnected(response.data.connected);
} catch (error) {
console.error('[Dashboard] Error fetching RCON status:', 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 (
<div className="container">
<TitleImage src="/dashboard.png" alt="Dashboard"/>

{/* Server Status Indicator */}
<div className="menu-dashboard">
<div className="item full" style={{
backgroundColor: rconConnected ? '#2d882d' : '#aa0000',
padding: '10px',
marginBottom: '10px'
}}>
<div className="title" style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
<span style={{ fontSize: '20px' }}>{rconConnected ? '🟩' : '🟥'}</span>
<span>{rconConnected ? 'Server is running' : 'Server is offline - Entries cannot be approved'}</span>
</div>
</div>
</div>

<UserTable />
<br />
<div className="menu-dashboard">
Expand Down