mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-04 23:16:37 +08:00
[优化] 优化
This commit is contained in:
@@ -3,10 +3,8 @@ package frps
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -71,108 +69,6 @@ func (m *Manager) GetStatus() string {
|
|||||||
return m.status
|
return m.status
|
||||||
}
|
}
|
||||||
|
|
||||||
type frpsServerInfo struct {
|
|
||||||
Version string `json:"version"`
|
|
||||||
BindPort int `json:"bind_port"`
|
|
||||||
CurConns int `json:"cur_conns"`
|
|
||||||
ClientCounts int `json:"client_counts"`
|
|
||||||
ProxyTypeCount map[string]int `json:"proxy_type_count"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type frpsProxyInfo struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
ClientAddr string `json:"client_addr"`
|
|
||||||
LastStartTime string `json:"last_start_time"`
|
|
||||||
LastCloseTime string `json:"last_close_time"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type frpsProxiesResponse struct {
|
|
||||||
Proxies []frpsProxyInfo `json:"proxies"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Manager) fetchFrpsTelemetry() (connections int, proxyCount int, clientCount int, proxies []service.RelayProxyStat, err error) {
|
|
||||||
m.mu.RLock()
|
|
||||||
activeConfig := m.activeConfig
|
|
||||||
m.mu.RUnlock()
|
|
||||||
|
|
||||||
if activeConfig == nil {
|
|
||||||
return 0, 0, 0, nil, fmt.Errorf("activeConfig is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
dashboardPort := activeConfig.BindPort + 500
|
|
||||||
client := &http.Client{
|
|
||||||
Timeout: 2 * time.Second,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. Fetch serverinfo
|
|
||||||
infoURL := fmt.Sprintf("http://127.0.0.1:%d/api/serverinfo", dashboardPort)
|
|
||||||
req, err := http.NewRequest(http.MethodGet, infoURL, nil)
|
|
||||||
if err != nil {
|
|
||||||
return 0, 0, 0, nil, err
|
|
||||||
}
|
|
||||||
password := m.agentToken
|
|
||||||
if password == "" {
|
|
||||||
password = "admin"
|
|
||||||
}
|
|
||||||
req.SetBasicAuth("admin", password)
|
|
||||||
resp, err := client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return 0, 0, 0, nil, err
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
return 0, 0, 0, nil, fmt.Errorf("serverinfo returned status %d", resp.StatusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
var info frpsServerInfo
|
|
||||||
if err := json.NewDecoder(resp.Body).Decode(&info); err != nil {
|
|
||||||
return 0, 0, 0, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
connections = info.CurConns
|
|
||||||
clientCount = info.ClientCounts
|
|
||||||
|
|
||||||
totalProxies := 0
|
|
||||||
for _, count := range info.ProxyTypeCount {
|
|
||||||
totalProxies += count
|
|
||||||
}
|
|
||||||
proxyCount = totalProxies
|
|
||||||
|
|
||||||
// 2. Fetch HTTP proxies list
|
|
||||||
proxiesURL := fmt.Sprintf("http://127.0.0.1:%d/api/proxy/http", dashboardPort)
|
|
||||||
req2, err := http.NewRequest(http.MethodGet, proxiesURL, nil)
|
|
||||||
if err != nil {
|
|
||||||
return connections, proxyCount, clientCount, nil, nil
|
|
||||||
}
|
|
||||||
req2.SetBasicAuth("admin", password)
|
|
||||||
resp2, err := client.Do(req2)
|
|
||||||
if err != nil {
|
|
||||||
return connections, proxyCount, clientCount, nil, nil
|
|
||||||
}
|
|
||||||
defer resp2.Body.Close()
|
|
||||||
|
|
||||||
if resp2.StatusCode == http.StatusOK {
|
|
||||||
var listResp frpsProxiesResponse
|
|
||||||
if err := json.NewDecoder(resp2.Body).Decode(&listResp); err == nil {
|
|
||||||
for _, p := range listResp.Proxies {
|
|
||||||
proxies = append(proxies, service.RelayProxyStat{
|
|
||||||
Name: p.Name,
|
|
||||||
Type: p.Type,
|
|
||||||
Status: p.Status,
|
|
||||||
ClientAddr: p.ClientAddr,
|
|
||||||
LastStartTime: p.LastStartTime,
|
|
||||||
LastCloseTime: p.LastCloseTime,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return connections, proxyCount, clientCount, proxies, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Manager) GetRuntimeStatus() RuntimeStatus {
|
func (m *Manager) GetRuntimeStatus() RuntimeStatus {
|
||||||
m.mu.RLock()
|
m.mu.RLock()
|
||||||
status := m.status
|
status := m.status
|
||||||
@@ -180,29 +76,13 @@ func (m *Manager) GetRuntimeStatus() RuntimeStatus {
|
|||||||
cmd := m.cmd
|
cmd := m.cmd
|
||||||
m.mu.RUnlock()
|
m.mu.RUnlock()
|
||||||
|
|
||||||
connections := 0
|
|
||||||
proxyCount := 0
|
|
||||||
clientCount := 0
|
|
||||||
var proxies []service.RelayProxyStat
|
|
||||||
|
|
||||||
if cmd != nil && cmd.Process != nil && status == "healthy" {
|
|
||||||
if conns, pCount, cCount, pxs, err := m.fetchFrpsTelemetry(); err == nil {
|
|
||||||
connections = conns
|
|
||||||
proxyCount = pCount
|
|
||||||
clientCount = cCount
|
|
||||||
proxies = pxs
|
|
||||||
} else {
|
|
||||||
slog.Debug("failed to fetch frps telemetry", "error", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return RuntimeStatus{
|
return RuntimeStatus{
|
||||||
Status: status,
|
Status: status,
|
||||||
LastError: lastError,
|
LastError: lastError,
|
||||||
Connections: connections,
|
Connections: 0,
|
||||||
ProxyCount: proxyCount,
|
ProxyCount: 0,
|
||||||
ClientCount: clientCount,
|
ClientCount: 0,
|
||||||
Proxies: proxies,
|
Proxies: nil,
|
||||||
ProcessAlive: cmd != nil && cmd.Process != nil,
|
ProcessAlive: cmd != nil && cmd.Process != nil,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
@@ -152,20 +151,13 @@ func persistRelayHeartbeatObservability(nodeID string, payload RelayHeartbeatPay
|
|||||||
HealthEvents: payload.HealthEvents,
|
HealthEvents: payload.HealthEvents,
|
||||||
}, reportedAt)
|
}, reportedAt)
|
||||||
|
|
||||||
var proxiesJSON string
|
|
||||||
if len(payload.FrpsProxies) > 0 {
|
|
||||||
if data, err := json.Marshal(payload.FrpsProxies); err == nil {
|
|
||||||
proxiesJSON = string(data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
frpsObs := &model.NodeObservationFrps{
|
frpsObs := &model.NodeObservationFrps{
|
||||||
NodeID: nodeID,
|
NodeID: nodeID,
|
||||||
CapturedAt: reportedAt,
|
CapturedAt: reportedAt,
|
||||||
FrpsConnections: payload.FrpsConnCount,
|
FrpsConnections: 0,
|
||||||
FrpsProxyCount: payload.FrpsProxyCount,
|
FrpsProxyCount: 0,
|
||||||
FrpsClientCount: payload.FrpsClientCount,
|
FrpsClientCount: 0,
|
||||||
FrpsProxies: proxiesJSON,
|
FrpsProxies: "",
|
||||||
}
|
}
|
||||||
_ = frpsObs.Insert()
|
_ = frpsObs.Insert()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,7 +93,8 @@ func TestHeartbeatRelayPersistsRuntimeAndObservability(t *testing.T) {
|
|||||||
if observability.RelayDashboard == nil {
|
if observability.RelayDashboard == nil {
|
||||||
t.Fatal("expected relay dashboard snapshot")
|
t.Fatal("expected relay dashboard snapshot")
|
||||||
}
|
}
|
||||||
if observability.RelayDashboard.TotalConnections != 7 || observability.RelayDashboard.TotalProxies != 3 {
|
if observability.RelayDashboard.TotalConnections != 0 || observability.RelayDashboard.TotalProxies != 0 {
|
||||||
|
// Frps telemetry collection is disabled; dashboard values are always zero.
|
||||||
t.Fatalf("unexpected relay dashboard: %+v", observability.RelayDashboard)
|
t.Fatalf("unexpected relay dashboard: %+v", observability.RelayDashboard)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ const defaultValues: NodeEditorValues = {
|
|||||||
relay_client_access_addr: '',
|
relay_client_access_addr: '',
|
||||||
relay_agent_access_addr: '',
|
relay_agent_access_addr: '',
|
||||||
relay_client_proxy_url: '',
|
relay_client_proxy_url: '',
|
||||||
relay_web_server_enabled: false,
|
relay_web_server_enabled: true,
|
||||||
geo_manual_override: false,
|
geo_manual_override: false,
|
||||||
geo_region: '',
|
geo_region: '',
|
||||||
geo_name: '',
|
geo_name: '',
|
||||||
|
|||||||
@@ -461,53 +461,6 @@ export function RelayDetailPage({ node }: { node: NodeItem }) {
|
|||||||
|
|
||||||
{activeTab === 'dashboard' ? (
|
{activeTab === 'dashboard' ? (
|
||||||
<>
|
<>
|
||||||
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
|
|
||||||
<SummaryStat
|
|
||||||
label="运行诊断"
|
|
||||||
value={
|
|
||||||
activeHealthEvents.length
|
|
||||||
? `${activeHealthEvents.length} 个活动异常`
|
|
||||||
: '运行稳定'
|
|
||||||
}
|
|
||||||
hint={
|
|
||||||
latestHealthEvent
|
|
||||||
? `${getHealthEventLabel(latestHealthEvent)} · ${latestHealthEvent.message || '等待处理'}`
|
|
||||||
: '当前没有活动中的健康事件'
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<SummaryStat
|
|
||||||
label="中继代理总数"
|
|
||||||
value={
|
|
||||||
observability?.relay_dashboard
|
|
||||||
? `${observability.relay_dashboard.total_proxies}`
|
|
||||||
: '—'
|
|
||||||
}
|
|
||||||
hint={
|
|
||||||
observability?.relay_dashboard
|
|
||||||
? `${observability.relay_dashboard.online_proxies} 个在线,${observability.relay_dashboard.offline_proxies} 个离线`
|
|
||||||
: '暂无代理通道统计'
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<SummaryStat
|
|
||||||
label="活动并发连接数"
|
|
||||||
value={
|
|
||||||
observability?.relay_dashboard
|
|
||||||
? `${observability.relay_dashboard.total_connections}`
|
|
||||||
: '—'
|
|
||||||
}
|
|
||||||
hint="中继代理网络承载的当前活动连接总数"
|
|
||||||
/>
|
|
||||||
<SummaryStat
|
|
||||||
label="活动客户端"
|
|
||||||
value={
|
|
||||||
observability?.relay_dashboard
|
|
||||||
? `${observability.relay_dashboard.client_counts}`
|
|
||||||
: '—'
|
|
||||||
}
|
|
||||||
hint="已注册连接到该中继的主动客户端数量"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="grid gap-6 xl:grid-cols-3">
|
<div className="grid gap-6 xl:grid-cols-3">
|
||||||
<AppCard title="系统画像">
|
<AppCard title="系统画像">
|
||||||
{observabilityQuery.isLoading ? (
|
{observabilityQuery.isLoading ? (
|
||||||
@@ -780,65 +733,7 @@ export function RelayDetailPage({ node }: { node: NodeItem }) {
|
|||||||
</AppCard>
|
</AppCard>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid gap-6 xl:grid-cols-1">
|
|
||||||
<AppCard
|
|
||||||
title="隧道活跃通道状态"
|
|
||||||
description="展示中继节点上活跃并连接的 frps 网络隧道代理。"
|
|
||||||
>
|
|
||||||
{observability?.relay_dashboard?.proxies?.length ? (
|
|
||||||
<div className="overflow-x-auto">
|
|
||||||
<table className="w-full text-left text-sm text-[var(--foreground-secondary)]">
|
|
||||||
<thead className="border-b border-[var(--border-default)]">
|
|
||||||
<tr>
|
|
||||||
<th className="px-4 py-3 font-medium">
|
|
||||||
代理名称 (Proxy Name)
|
|
||||||
</th>
|
|
||||||
<th className="px-4 py-3 font-medium">代理类型</th>
|
|
||||||
<th className="px-4 py-3 font-medium">在线状态</th>
|
|
||||||
<th className="px-4 py-3 font-medium">
|
|
||||||
客户端接入地址
|
|
||||||
</th>
|
|
||||||
<th className="px-4 py-3 font-medium">
|
|
||||||
最近连接时间
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody className="divide-y divide-[var(--border-default)]">
|
|
||||||
{observability.relay_dashboard.proxies.map((proxy) => (
|
|
||||||
<tr key={proxy.name}>
|
|
||||||
<td className="px-4 py-3 font-medium text-[var(--foreground-primary)]">
|
|
||||||
{proxy.name}
|
|
||||||
</td>
|
|
||||||
<td className="px-4 py-3">{proxy.type}</td>
|
|
||||||
<td className="px-4 py-3">
|
|
||||||
<StatusBadge
|
|
||||||
label={
|
|
||||||
proxy.status === 'online' ? '在线' : '离线'
|
|
||||||
}
|
|
||||||
variant={
|
|
||||||
proxy.status === 'online' ? 'success' : 'info'
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
<td className="px-4 py-3">{proxy.client_addr}</td>
|
|
||||||
<td className="px-4 py-3">
|
|
||||||
{isMeaningfulTime(proxy.last_start_time)
|
|
||||||
? formatRelativeTime(proxy.last_start_time)
|
|
||||||
: '—'}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<EmptyState
|
|
||||||
title="暂无通道活动"
|
|
||||||
description="当前没有隧道客户端连接到该中继节点。"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</AppCard>
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user