server: add client registry with dashboard support (#5115)

This commit is contained in:
fatedier
2026-01-08 20:07:14 +08:00
committed by GitHub
parent bc378bcbec
commit 36718d88e4
59 changed files with 4150 additions and 1837 deletions

View File

@@ -0,0 +1,10 @@
import { http } from './http'
import type { ClientInfoData } from '../types/client'
export const getClients = () => {
return http.get<ClientInfoData[]>('../api/clients')
}
export const getClient = (key: string) => {
return http.get<ClientInfoData>(`../api/clients/${key}`)
}

50
web/frps/src/api/http.ts Normal file
View File

@@ -0,0 +1,50 @@
// http.ts - Base HTTP client
class HTTPError extends Error {
status: number
statusText: string
constructor(status: number, statusText: string, message?: string) {
super(message || statusText)
this.status = status
this.statusText = statusText
}
}
async function request<T>(url: string, options: RequestInit = {}): Promise<T> {
const defaultOptions: RequestInit = {
credentials: 'include',
}
const response = await fetch(url, { ...defaultOptions, ...options })
if (!response.ok) {
throw new HTTPError(response.status, response.statusText, `HTTP ${response.status}`)
}
// Handle empty response (e.g. 204 No Content)
if (response.status === 204) {
return {} as T
}
return response.json()
}
export const http = {
get: <T>(url: string, options?: RequestInit) => request<T>(url, { ...options, method: 'GET' }),
post: <T>(url: string, body?: any, options?: RequestInit) =>
request<T>(url, {
...options,
method: 'POST',
headers: { 'Content-Type': 'application/json', ...options?.headers },
body: JSON.stringify(body)
}),
put: <T>(url: string, body?: any, options?: RequestInit) =>
request<T>(url, {
...options,
method: 'PUT',
headers: { 'Content-Type': 'application/json', ...options?.headers },
body: JSON.stringify(body)
}),
delete: <T>(url: string, options?: RequestInit) => request<T>(url, { ...options, method: 'DELETE' }),
}

18
web/frps/src/api/proxy.ts Normal file
View File

@@ -0,0 +1,18 @@
import { http } from './http'
import type { GetProxyResponse, ProxyStatsInfo, TrafficResponse } from '../types/proxy'
export const getProxiesByType = (type: string) => {
return http.get<GetProxyResponse>(`../api/proxy/${type}`)
}
export const getProxy = (type: string, name: string) => {
return http.get<ProxyStatsInfo>(`../api/proxy/${type}/${name}`)
}
export const getProxyTraffic = (name: string) => {
return http.get<TrafficResponse>(`../api/traffic/${name}`)
}
export const clearOfflineProxies = () => {
return http.delete('../api/proxies?status=offline')
}

View File

@@ -0,0 +1,6 @@
import { http } from './http'
import type { ServerInfo } from '../types/server'
export const getServerInfo = () => {
return http.get<ServerInfo>('../api/serverinfo')
}