* @license MIT */ namespace Pterodactyl\Addons\AdvancedAdmin\Http\Controllers\Client; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Routing\Controller; use Illuminate\Support\Facades\DB; use Pterodactyl\Models\Server; class NetworkMetricsController extends Controller { /** GET /api/client/servers/{server}/addons/network/live */ public function live(Request $request, Server $server): JsonResponse { $this->requireAccess($request, $server); // Latest raw metric (most recent 30 seconds) $latest = DB::table('addon_network_metrics') ->where('server_id', $server->id) ->where('resolution', 'raw') ->where('recorded_at', '>=', now()->subSeconds(30)) ->orderByDesc('recorded_at') ->select('rx_bytes', 'tx_bytes', 'recorded_at') ->first(); return response()->json(['data' => $latest]); } /** GET /api/client/servers/{server}/addons/network/history */ public function history(Request $request, Server $server): JsonResponse { $this->requireAccess($request, $server); $resolution = $request->get('resolution', '5m'); abort_unless(in_array($resolution, ['raw', '5m', '1h', '1d'], true), 422, 'Invalid resolution.'); $hours = match ($resolution) { 'raw' => 1, '5m' => 24, '1h' => 168, '1d' => 8760, }; $metrics = DB::table('addon_network_metrics') ->where('server_id', $server->id) ->where('resolution', $resolution) ->where('recorded_at', '>=', now()->subHours($hours)) ->orderBy('recorded_at') ->select('rx_bytes', 'tx_bytes', 'recorded_at') ->get(); return response()->json(['data' => $metrics]); } /** GET /api/client/servers/{server}/addons/network/ports */ public function ports(Request $request, Server $server): JsonResponse { $this->requireAccess($request, $server); if (!config('advanced-admin.network.iptables_enabled')) { return response()->json(['data' => [], 'unavailable' => true, 'reason' => 'iptables collection not enabled']); } $ports = DB::table('addon_network_port_metrics') ->where('server_id', $server->id) ->where('resolution', '5m') ->where('recorded_at', '>=', now()->subHour()) ->groupBy('port', 'protocol') ->select('port', 'protocol', DB::raw('SUM(rx_bytes) as rx_bytes'), DB::raw('SUM(tx_bytes) as tx_bytes')) ->orderByDesc('rx_bytes') ->limit(50) ->get(); return response()->json(['data' => $ports]); } /** GET /api/client/servers/{server}/addons/network/flows */ public function flows(Request $request, Server $server): JsonResponse { $this->requireAccess($request, $server); $flows = DB::table('addon_network_flows') ->where(function ($q) use ($server) { $q->where('src_server_id', $server->id) ->orWhere('dst_server_id', $server->id); }) ->where('recorded_at', '>=', now()->subHours(24)) ->select('src_server_id', 'dst_server_id', DB::raw('SUM(bytes) as bytes'), DB::raw('SUM(packets) as packets')) ->groupBy('src_server_id', 'dst_server_id') ->orderByDesc('bytes') ->limit(50) ->get(); return response()->json(['data' => $flows]); } private function requireAccess(Request $request, Server $server): void { $user = $request->user(); abort_unless($user, 401); $isOwner = $server->owner_id === $user->id; $isAdmin = $user->root_admin; if (!$isOwner && !$isAdmin) { $subuser = $server->subusers()->where('user_id', $user->id)->first(); abort_unless($subuser, 403); } } }