Files
GoTunnel/web/src/api/index.ts
Flik 9f13b0d4e9
Some checks failed
Build Multi-Platform Binaries / build-binaries (amd64, darwin, server, false) (push) Has been cancelled
Build Multi-Platform Binaries / build-binaries (amd64, linux, client, true) (push) Has been cancelled
Build Multi-Platform Binaries / build-binaries (amd64, linux, server, true) (push) Has been cancelled
Build Multi-Platform Binaries / build-binaries (amd64, windows, client, true) (push) Has been cancelled
Build Multi-Platform Binaries / build-binaries (amd64, windows, server, true) (push) Has been cancelled
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, client, true) (push) Has been cancelled
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, server, true) (push) Has been cancelled
Build Multi-Platform Binaries / build-binaries (arm64, darwin, server, false) (push) Has been cancelled
Build Multi-Platform Binaries / build-binaries (arm64, linux, client, true) (push) Has been cancelled
Build Multi-Platform Binaries / build-binaries (arm64, linux, server, true) (push) Has been cancelled
Build Multi-Platform Binaries / build-binaries (arm64, windows, server, false) (push) Has been cancelled
Build Multi-Platform Binaries / build-frontend (push) Has been cancelled
feat(app): 添加服务端和客户端更新功能以及系统状态监控
- 在App.vue中新增服务端更新模态框和相关功能
- 添加applyServerUpdate API调用和更新确认对话框
- 实现客户端版本信息显示和更新检测功能
- 添加系统状态监控包括CPU、内存和磁盘使用情况
- 新增getClientSystemStats API接口获取客户端系统统计信息
- 更新go.mod和go.sum文件添加必要的依赖包
- 优化UI界面样式和交互体验
2026-01-22 21:32:03 +08:00

246 lines
8.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { get, post, put, del, getToken } from '../config/axios'
import type { ClientConfig, ClientStatus, ClientDetail, ServerStatus, PluginInfo, StorePluginInfo, PluginConfigResponse, JSPlugin, RuleSchemasMap, LogEntry, LogStreamOptions, ConfigField } from '../types'
// 重新导出 token 管理方法
export { getToken, setToken, removeToken } from '../config/axios'
// 认证 API
export const login = (username: string, password: string) =>
post<{ token: string }>('/auth/login', { username, password })
export const checkAuth = () => get('/auth/check')
// 服务器状态
export const getServerStatus = () => get<ServerStatus>('/status')
// 客户端管理
export const getClients = () => get<ClientStatus[]>('/clients')
export const getClient = (id: string) => get<ClientDetail>(`/client/${id}`)
export const addClient = (client: ClientConfig) => post('/clients', client)
export const updateClient = (id: string, client: ClientConfig) => put(`/client/${id}`, client)
export const deleteClient = (id: string) => del(`/client/${id}`)
export const reloadConfig = () => post('/config/reload')
// 客户端控制
export const pushConfigToClient = (id: string) => post(`/client/${id}/push`)
export const disconnectClient = (id: string) => post(`/client/${id}/disconnect`)
export const restartClient = (id: string) => post(`/client/${id}/restart`)
export const installPluginsToClient = (id: string, plugins: string[]) =>
post(`/client/${id}/install-plugins`, { plugins })
// 规则配置模式
export const getRuleSchemas = () => get<RuleSchemasMap>('/rule-schemas')
// 客户端插件控制(使用 pluginID
export const startClientPlugin = (clientId: string, pluginId: string, ruleName: string) =>
post(`/client/${clientId}/plugin/${pluginId}/start`, { rule_name: ruleName })
export const stopClientPlugin = (clientId: string, pluginId: string, ruleName: string) =>
post(`/client/${clientId}/plugin/${pluginId}/stop`, { rule_name: ruleName })
export const restartClientPlugin = (clientId: string, pluginId: string, ruleName: string) =>
post(`/client/${clientId}/plugin/${pluginId}/restart`, { rule_name: ruleName })
export const deleteClientPlugin = (clientId: string, pluginId: string) =>
post(`/client/${clientId}/plugin/${pluginId}/delete`)
export const updateClientPluginConfigWithRestart = (clientId: string, pluginId: string, ruleName: string, config: Record<string, string>, restart: boolean) =>
post(`/client/${clientId}/plugin/${pluginId}/config`, { rule_name: ruleName, config, restart })
// 插件管理
export const getPlugins = () => get<PluginInfo[]>('/plugins')
export const enablePlugin = (name: string) => post(`/plugin/${name}/enable`)
export const disablePlugin = (name: string) => post(`/plugin/${name}/disable`)
// 扩展商店
export const getStorePlugins = () => get<{ plugins: StorePluginInfo[] }>('/store/plugins')
export const installStorePlugin = (
pluginName: string,
downloadUrl: string,
signatureUrl: string,
clientId: string,
remotePort?: number,
version?: string,
configSchema?: ConfigField[],
authEnabled?: boolean,
authUsername?: string,
authPassword?: string
) =>
post('/store/install', {
plugin_name: pluginName,
version: version || '',
download_url: downloadUrl,
signature_url: signatureUrl,
client_id: clientId,
remote_port: remotePort || 0,
config_schema: configSchema || [],
auth_enabled: authEnabled || false,
auth_username: authUsername || '',
auth_password: authPassword || ''
})
// 客户端插件配置
export const getClientPluginConfig = (clientId: string, pluginName: string) =>
get<PluginConfigResponse>(`/client-plugin/${clientId}/${pluginName}/config`)
export const updateClientPluginConfig = (clientId: string, pluginName: string, config: Record<string, string>) =>
put(`/client-plugin/${clientId}/${pluginName}/config`, { config })
// JS 插件管理
export const getJSPlugins = () => get<JSPlugin[]>('/js-plugins')
export const createJSPlugin = (plugin: JSPlugin) => post('/js-plugins', plugin)
export const getJSPlugin = (name: string) => get<JSPlugin>(`/js-plugin/${name}`)
export const updateJSPlugin = (name: string, plugin: JSPlugin) => put(`/js-plugin/${name}`, plugin)
export const deleteJSPlugin = (name: string) => del(`/js-plugin/${name}`)
export const pushJSPluginToClient = (pluginName: string, clientId: string, remotePort?: number) =>
post(`/js-plugin/${pluginName}/push/${clientId}`, { remote_port: remotePort || 0 })
export const updateJSPluginConfig = (name: string, config: Record<string, string>) =>
put(`/js-plugin/${name}/config`, { config })
export const setJSPluginEnabled = (name: string, enabled: boolean) =>
post(`/js-plugin/${name}/${enabled ? 'enable' : 'disable'}`)
// 插件 API 代理(通过 pluginID 调用插件自定义 API
export const callPluginAPI = <T = any>(clientId: string, pluginId: string, method: string, route: string, body?: any) => {
const path = `/client/${clientId}/plugin-api/${pluginId}${route.startsWith('/') ? route : '/' + route}`
switch (method.toUpperCase()) {
case 'GET':
return get<T>(path)
case 'POST':
return post<T>(path, body)
case 'PUT':
return put<T>(path, body)
case 'DELETE':
return del<T>(path)
default:
return get<T>(path)
}
}
// 更新管理
export interface UpdateInfo {
available: boolean
current: string
latest: string
release_note: string
download_url: string
asset_name: string
asset_size: number
}
export interface VersionInfo {
version: string
git_commit: string
build_time: string
go_version: string
os: string
arch: string
}
export const getVersionInfo = () => get<VersionInfo>('/update/version')
export const checkServerUpdate = () => get<UpdateInfo>('/update/check/server')
export const checkClientUpdate = (os?: string, arch?: string) => {
const params = new URLSearchParams()
if (os) params.append('os', os)
if (arch) params.append('arch', arch)
const query = params.toString()
return get<UpdateInfo>(`/update/check/client${query ? '?' + query : ''}`)
}
export const applyServerUpdate = (downloadUrl: string, restart: boolean = true) =>
post('/update/apply/server', { download_url: downloadUrl, restart })
export const applyClientUpdate = (clientId: string, downloadUrl: string) =>
post('/update/apply/client', { client_id: clientId, download_url: downloadUrl })
// 日志流
export const createLogStream = (
clientId: string,
options: LogStreamOptions = {},
onLog: (entry: LogEntry) => void,
onError?: (error: Event) => void
): EventSource => {
const token = getToken()
const params = new URLSearchParams()
if (token) params.append('token', token)
if (options.lines !== undefined) params.append('lines', String(options.lines))
if (options.follow !== undefined) params.append('follow', String(options.follow))
if (options.level) params.append('level', options.level)
const url = `/api/client/${clientId}/logs?${params.toString()}`
const eventSource = new EventSource(url)
eventSource.addEventListener('log', (event) => {
try {
const entry = JSON.parse((event as MessageEvent).data) as LogEntry
onLog(entry)
} catch (e) {
console.error('Failed to parse log entry', e)
}
})
eventSource.addEventListener('heartbeat', () => {
// Keep-alive, no action needed
})
if (onError) {
eventSource.onerror = onError
}
return eventSource
}
// 流量统计
export interface TrafficStats {
traffic_24h: { inbound: number; outbound: number }
traffic_total: { inbound: number; outbound: number }
}
export interface TrafficRecord {
timestamp: number
inbound: number
outbound: number
}
export const getTrafficStats = () => get<TrafficStats>('/traffic/stats')
export const getTrafficHourly = () => get<{ records: TrafficRecord[] }>('/traffic/hourly')
// 客户端系统状态
export interface SystemStats {
cpu_usage: number
memory_total: number
memory_used: number
memory_usage: number
disk_total: number
disk_used: number
disk_usage: number
}
export const getClientSystemStats = (clientId: string) => get<SystemStats>(`/client/${clientId}/system-stats`)
// 服务器配置
export interface ServerConfigInfo {
bind_addr: string
bind_port: number
token: string
heartbeat_sec: number
heartbeat_timeout: number
}
export interface WebConfigInfo {
enabled: boolean
bind_port: number
username: string
password: string
}
export interface PluginStoreConfigInfo {
url: string
}
export interface ServerConfigResponse {
server: ServerConfigInfo
web: WebConfigInfo
plugin_store: PluginStoreConfigInfo
}
export interface UpdateServerConfigRequest {
server?: Partial<ServerConfigInfo>
web?: Partial<WebConfigInfo>
plugin_store?: Partial<PluginStoreConfigInfo>
}
export const getServerConfig = () => get<ServerConfigResponse>('/config')
export const updateServerConfig = (config: UpdateServerConfigRequest) => put('/config', config)