/** * adminrpc HTTP REST client * * Calls the adminrpc HTTP server (default: http://adminrpc.admin.svc.cluster.local:9091) * which exposes the same session management and metrics APIs as the gRPC service. * * Usage: * import { listWorkspaceSessions, kickUser } from "@/lib/admin-rpc"; */ import { ADMIN_RPC_URL } from "./env"; // Default to k8s internal service address; override via ADMIN_RPC_URL env var const BASE_URL = ADMIN_RPC_URL || "http://adminrpc.admin.svc.cluster.local:9091"; async function rpc(path: string, options?: RequestInit): Promise { const url = `${BASE_URL}${path}`; const res = await fetch(url, { ...options, headers: { "Content-Type": "application/json", ...options?.headers, }, }); if (!res.ok) { const body = await res.text(); throw new Error(`adminrpc ${options?.method ?? "GET"} ${path} failed (${res.status}): ${body}`); } return res.json() as Promise; } // ─── Types ──────────────────────────────────────────────────────────────────── export interface UserSession { session_id: string; user_id: string; workspace_id: string; ip_address: string; user_agent: string; connected_at: string; last_heartbeat: string; } export interface SessionInfo { user_id: string; session_count: number; workspaces: string[]; latest_session: UserSession | null; } // ─── Sessions API ───────────────────────────────────────────────────────────── /** List all active sessions for a workspace. */ export async function listWorkspaceSessions(workspaceId: string): Promise { return rpc(`/api/admin/sessions/workspace/${encodeURIComponent(workspaceId)}`); } /** List all active sessions for a specific user. */ export async function listUserSessions(userId: string): Promise { return rpc(`/api/admin/sessions/user/${encodeURIComponent(userId)}`); } /** Get the online status of a specific user. */ export async function getUserStatus(userId: string): Promise<{ status: string }> { return rpc<{ status: string }>(`/api/admin/sessions/user/${encodeURIComponent(userId)}/status`); } /** Get detailed info for a user (session count, workspaces, latest session). */ export async function getUserInfo(userId: string): Promise { return rpc(`/api/admin/sessions/user/${encodeURIComponent(userId)}/info`); } /** List all online user IDs in a workspace. */ export async function getWorkspaceOnlineUsers(workspaceId: string): Promise<{ user_ids: string[] }> { return rpc<{ user_ids: string[] }>(`/api/admin/sessions/workspace/${encodeURIComponent(workspaceId)}/online-users`); } /** Check if a user is currently online. */ export async function isUserOnline(userId: string): Promise<{ online: boolean }> { return rpc<{ online: boolean }>(`/api/admin/sessions/user/${encodeURIComponent(userId)}/online`); } /** Kick all sessions for a user. Returns the number of sessions kicked. */ export async function kickUser(userId: string): Promise<{ kicked_count: number }> { return rpc<{ kicked_count: number }>("/api/admin/sessions/kick", { method: "POST", body: JSON.stringify({ user_id: userId }), }); } /** Kick all sessions for a user in a specific workspace. */ export async function kickUserFromWorkspace( userId: string, workspaceId: string ): Promise<{ kicked_count: number }> { return rpc<{ kicked_count: number }>("/api/admin/sessions/kick-workspace", { method: "POST", body: JSON.stringify({ user_id: userId, workspace_id: workspaceId }), }); } // ─── Metrics API ───────────────────────────────────────────────────────────── export interface InstanceMetrics { instance_id: string; timestamp_secs: number; http: Record; room: Record; } /** Get metrics across all app instances. */ export async function getMetrics(instanceFilter = ""): Promise { const qs = instanceFilter ? `?instance_filter=${encodeURIComponent(instanceFilter)}` : ""; return rpc(`/api/admin/metrics${qs}`); } /** Export all metrics as CSV string. */ export async function exportMetricsCsv(instanceFilter = ""): Promise { const qs = instanceFilter ? `?instance_filter=${encodeURIComponent(instanceFilter)}` : ""; const res = await fetch(`${BASE_URL}/api/admin/metrics/export${qs}`); if (!res.ok) { throw new Error(`adminrpc GET /metrics/export failed (${res.status})`); } return res.text(); } /** Get adminrpc health status. */ export async function adminRpcHealth(): Promise<{ ok: boolean }> { return rpc<{ ok: boolean }>("/health"); }