feat: aether-proxy 远程配置下发、连通性测试与 setup TUI

- 后端新增远程配置管理 API (PUT /config) 和连通性测试 API (POST /test)
- 前端新增远程配置编辑对话框和节点连通性测试按钮
- aether-proxy 支持通过心跳接收并热加载远程配置 (端口白名单、日志级别、心跳间隔、时间戳容差)
- aether-proxy 新增 TOML 配置文件支持和交互式 setup TUI
- aether-proxy 心跳 404 时自动重注册节点
- plain proxy 响应改为流式传输,减少内存缓冲
- 新增 remote_config 和 config_version 数据库字段及迁移
This commit is contained in:
fawney19
2026-02-07 19:20:09 +08:00
parent 3b8398b2e5
commit 31bc452374
18 changed files with 2771 additions and 113 deletions

View File

@@ -1,5 +1,12 @@
import apiClient from './client'
export interface ProxyNodeRemoteConfig {
allowed_ports?: number[]
log_level?: string
heartbeat_interval?: number
timestamp_tolerance?: number
}
export interface ProxyNode {
id: string
name: string
@@ -12,6 +19,9 @@ export interface ProxyNode {
proxy_url?: string
proxy_username?: string
proxy_password?: string // 脱敏后的密码
// 远程配置aether-proxy 节点)
remote_config: ProxyNodeRemoteConfig | null
config_version: number
registered_by: string | null
last_heartbeat_at: string | null
heartbeat_interval: number
@@ -45,6 +55,13 @@ export interface ManualProxyNodeUpdateRequest {
region?: string
}
export interface ProxyNodeTestResult {
success: boolean
latency_ms: number | null
exit_ip: string | null
error: string | null
}
export const proxyNodesApi = {
async listProxyNodes(params?: { status?: string; skip?: number; limit?: number }): Promise<ProxyNodeListResponse> {
const response = await apiClient.get<ProxyNodeListResponse>('/api/admin/proxy-nodes', { params })
@@ -65,4 +82,14 @@ export const proxyNodesApi = {
const response = await apiClient.delete<{ message: string; node_id: string; cleared_system_proxy: boolean }>(`/api/admin/proxy-nodes/${nodeId}`)
return response.data
},
async testNode(nodeId: string): Promise<ProxyNodeTestResult> {
const response = await apiClient.post<ProxyNodeTestResult>(`/api/admin/proxy-nodes/${nodeId}/test`)
return response.data
},
async updateNodeConfig(nodeId: string, data: ProxyNodeRemoteConfig): Promise<{ node_id: string; config_version: number; remote_config: ProxyNodeRemoteConfig; node: ProxyNode }> {
const response = await apiClient.put<{ node_id: string; config_version: number; remote_config: ProxyNodeRemoteConfig; node: ProxyNode }>(`/api/admin/proxy-nodes/${nodeId}/config`, data)
return response.data
},
}