import { NextRequest, NextResponse } from "next/server"; import { readFileSync, existsSync } from "fs"; import { auth } from "@/lib/auth"; import { memo } from "@/lib/cache"; export const dynamic = "force-dynamic"; const ANALYTICS_FILE = "/home/minecraft/server/analytics.jsonl"; type MetricEntry = { ts: string; tps: number; ramUsedMB: number; ramTotalMB: number; cpuPercent: number; playersOnline: number; players: string[]; }; function readWindow(hours: number): MetricEntry[] { const cutoff = new Date(Date.now() - hours * 60 * 60 * 1000).toISOString(); const raw = readFileSync(ANALYTICS_FILE, "utf8"); // Reverse scan: walk from the end, collect until we pass cutoff. const out: MetricEntry[] = []; let end = raw.length; while (end > 0) { const start = raw.lastIndexOf("\n", end - 1); const line = raw.slice(start + 1, end).trim(); end = start; if (!line) continue; try { const entry = JSON.parse(line) as MetricEntry; if (entry.ts < cutoff) break; // file is append-ordered by time out.push(entry); } catch {} } return out.reverse(); } export async function GET(req: NextRequest) { const session = await auth(); if (!session) { return NextResponse.json({ error: "Unauthorized" }, { status: 403 }); } const hours = Math.min( parseInt(req.nextUrl.searchParams.get("hours") || "6"), 48 ); if (!existsSync(ANALYTICS_FILE)) { return NextResponse.json([]); } try { const entries = memo(`analytics:${hours}`, 30_000, () => readWindow(hours)); return NextResponse.json(entries, { headers: { "Cache-Control": "private, max-age=30" }, }); } catch (e) { return NextResponse.json( { error: (e as Error).message }, { status: 500 } ); } }