Next.js 16 + Tailwind v4 + shadcn v4 dashboard for managing a modded Forge 1.20.1 server. Includes server controls, player management, mod manager with Modrinth search and dependency resolution, world backups, snapshots, analytics, logs, and chat bridge. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
50 lines
1.4 KiB
TypeScript
50 lines
1.4 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import { status } from "minecraft-server-util";
|
|
import { execSync } from "child_process";
|
|
import { MC_SERVER_IP, MC_SERVER_PORT } from "@/lib/constants";
|
|
import { sendCommand } from "@/lib/rcon";
|
|
|
|
export const dynamic = "force-dynamic";
|
|
|
|
export async function GET() {
|
|
// Tier 1: MC protocol ping (fastest, gives player/version info)
|
|
try {
|
|
const result = await status(MC_SERVER_IP, MC_SERVER_PORT, {
|
|
timeout: 5000,
|
|
});
|
|
return NextResponse.json({
|
|
online: true,
|
|
players: { online: result.players.online, max: result.players.max },
|
|
version: result.version.name,
|
|
motd: result.motd.clean,
|
|
});
|
|
} catch {}
|
|
|
|
// Tier 2: RCON (server is online but protocol ping failed)
|
|
try {
|
|
const response = await sendCommand("list");
|
|
const match = response.match(/There are (\d+) of a max of (\d+) players/);
|
|
return NextResponse.json({
|
|
online: true,
|
|
players: {
|
|
online: match ? parseInt(match[1], 10) : 0,
|
|
max: match ? parseInt(match[2], 10) : 20,
|
|
},
|
|
});
|
|
} catch {}
|
|
|
|
// Tier 3: systemctl (process alive but not yet accepting connections)
|
|
let starting = false;
|
|
try {
|
|
const out = execSync("systemctl is-active minecraft.service", {
|
|
encoding: "utf8",
|
|
}).trim();
|
|
starting = out === "active" || out === "activating";
|
|
} catch {}
|
|
|
|
return NextResponse.json({
|
|
online: false,
|
|
starting,
|
|
players: { online: 0, max: 0 },
|
|
});
|
|
}
|