import os from "node:os"; import { Activity } from 'lucide-react'; import { hotelAlert, updateCatalog, updateNavigator, updateWordFilter, disconnectUser, alertUser, forwardUser, giveCredits, giveDuckets, giveDiamonds, giveBadge, setMotto, setRank, executeCommand, sendGift, } from "@/actions/commandocentrum"; import { DiagnosticRow, InfoItem, StatusCard, OnlineUsersWidget } from "@/components/admin/dashboard"; import { prisma } from "@/lib/prisma"; import { rcon } from "@/lib/services/rcon"; import { siteSettings } from "@/lib/services/site-settings"; export const dynamic = "force-dynamic"; function formatTimestamp(ts: number | null | undefined): string { if (!ts) return ""; return new Date(ts * 1000).toISOString().slice(0, 19).replace("T", " "); } function fromDate(d: Date | null | undefined): string { return d ? d.toISOString().slice(0, 19).replace("T", " ") : "—"; } function decodeStacktrace(raw: unknown): string { if (raw == null) return ""; try { if (typeof raw === "string") return raw; return Buffer.from(raw as Uint8Array).toString("utf8"); } catch { return ""; } } function mb(bytes: number): string { return `${Math.round(bytes / 1024 / 1024)} MB`; } function uptime(seconds: number): string { const d = Math.floor(seconds / 86400); const h = Math.floor((seconds % 86400) / 3600); const m = Math.floor((seconds % 3600) / 60); return d > 0 ? `${d}d ${h}h ${m}m` : h > 0 ? `${h}h ${m}m` : `${m}m`; } export default async function CommandoCentrum() { const [onlineCount, totalUsers, errors, dbOk, emulatorOnline, maintenance, activity] = await Promise.all([ prisma.user.count({ where: { online: "1" } }).catch(() => 0), prisma.user.count().catch(() => -1), prisma.emulatorErrors.findMany({ orderBy: { timestamp: "desc" }, take: 50 }).catch(() => []), prisma.websiteSetting .count() .then(() => true) .catch(() => false), rcon.send("ping", null).catch(() => false), siteSettings.getBool("maintenance_enabled", false), prisma.staffActivities .findMany({ orderBy: { createdAt: "desc" }, take: 12 }) .catch(() => [] as Awaited>), ]); const staffIds = Array.from(new Set(activity.map((a) => Number(a.userId)))).filter((n) => n > 0); let nameById = new Map(); if (staffIds.length) { const users = await prisma.user .findMany({ where: { id: { in: staffIds } }, select: { id: true, username: true } }) .catch(() => []); nameById = new Map(users.map((u) => [u.id, u.username])); } const appKeySet = !!process.env.APP_KEY; const smtpSet = !!process.env.SMTP_HOST; const rconSet = !!process.env.RCON_HOST; return (

Commandocentrum

Live hotel status, diagnostics and emulator control over RCON.

{/* ── Live status ────────────────────────────────────────── */}
= 0 ? `${totalUsers} accounts total` : "DB unavailable"} state="neutral" icon="👤" />
{/* ── Online users widget ───────────────────────────────── */}

Online Users

{/* ── Server info + diagnostics ──────────────────────────── */}

Server info

System diagnostics

Emulator controls

Update catalog

Reload catalog pages and items on the live server.

Update word filter

Reload the chat word filter from the database.

Update navigator

Reload navigator categories and room listings.

Hotel alert

Broadcast a message to every connected user.

{/* ── User RCON actions ──────────────────────────────────── */}

User actions (RCON)

Enter a User ID to perform actions on a specific user. Username required for disconnect.

Disconnect / Kick

Force disconnect a user.

Alert user

Send a popup alert to a user.

Forward to room

Teleport user to a room ID.

Give credits

Add credits to a user.

Give duckets

Add duckets to a user.

Give diamonds

Add diamonds to a user.

Give badge

Give a badge code (e.g. HOF1).

Set motto

Change user's motto (max 127 chars).

Set rank

Change user rank (0–10).

Execute command

Run a chat command as the user.

Send gift

Send a furniture item as gift.

{/* ── Staff activity ─────────────────────────────────────── */}

Recent staff activity

{activity.length === 0 ? (
No staff activity logged yet.
) : (
{activity.map((a) => ( ))}
When Staff Action Description
{fromDate(a.createdAt)} {nameById.get(Number(a.userId)) ?? `#${a.userId}`} {a.action} {a.description}
)}
{/* ── Emulator errors ────────────────────────────────────── */}

Recent emulator errors

{errors.length === 0 ? (
No emulator errors logged.
) : (
{errors.map((e) => { const trace = decodeStacktrace(e.stacktrace); return ( ); })}
When Type Version Stacktrace
{formatTimestamp(e.timestamp)} {e.type} {e.version}
                          {trace || "(empty)"}
                        
)}
); }