设置界面更新
This commit is contained in:
193
http/server.go
193
http/server.go
@@ -10,11 +10,12 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"dns-server/config"
|
||||
"dns-server/dns"
|
||||
"dns-server/logger"
|
||||
"dns-server/shield"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
// Server HTTP控制台服务器
|
||||
@@ -24,7 +25,7 @@ type Server struct {
|
||||
dnsServer *dns.Server
|
||||
shieldManager *shield.ShieldManager
|
||||
server *http.Server
|
||||
|
||||
|
||||
// WebSocket相关字段
|
||||
upgrader websocket.Upgrader
|
||||
clients map[*websocket.Conn]bool
|
||||
@@ -50,10 +51,10 @@ func NewServer(globalConfig *config.Config, dnsServer *dns.Server, shieldManager
|
||||
clients: make(map[*websocket.Conn]bool),
|
||||
broadcastChan: make(chan []byte, 100),
|
||||
}
|
||||
|
||||
|
||||
// 启动广播协程
|
||||
go server.startBroadcastLoop()
|
||||
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
@@ -73,6 +74,8 @@ func (s *Server) Start() error {
|
||||
// 添加统计相关接口
|
||||
mux.HandleFunc("/api/top-blocked", s.handleTopBlockedDomains)
|
||||
mux.HandleFunc("/api/top-resolved", s.handleTopResolvedDomains)
|
||||
mux.HandleFunc("/api/top-clients", s.handleTopClients)
|
||||
mux.HandleFunc("/api/top-domains", s.handleTopDomains)
|
||||
mux.HandleFunc("/api/recent-blocked", s.handleRecentBlockedDomains)
|
||||
mux.HandleFunc("/api/hourly-stats", s.handleHourlyStats)
|
||||
mux.HandleFunc("/api/daily-stats", s.handleDailyStats)
|
||||
@@ -131,27 +134,27 @@ func (s *Server) handleStats(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// 格式化平均响应时间为两位小数
|
||||
formattedResponseTime := float64(int(dnsStats.AvgResponseTime*100)) / 100
|
||||
|
||||
|
||||
// 构建响应数据,确保所有字段都反映服务器的真实状态
|
||||
stats := map[string]interface{}{
|
||||
"dns": map[string]interface{}{
|
||||
"Queries": dnsStats.Queries,
|
||||
"Blocked": dnsStats.Blocked,
|
||||
"Allowed": dnsStats.Allowed,
|
||||
"Errors": dnsStats.Errors,
|
||||
"LastQuery": dnsStats.LastQuery,
|
||||
"AvgResponseTime": formattedResponseTime,
|
||||
"Queries": dnsStats.Queries,
|
||||
"Blocked": dnsStats.Blocked,
|
||||
"Allowed": dnsStats.Allowed,
|
||||
"Errors": dnsStats.Errors,
|
||||
"LastQuery": dnsStats.LastQuery,
|
||||
"AvgResponseTime": formattedResponseTime,
|
||||
"TotalResponseTime": dnsStats.TotalResponseTime,
|
||||
"QueryTypes": dnsStats.QueryTypes,
|
||||
"SourceIPs": dnsStats.SourceIPs,
|
||||
"CpuUsage": dnsStats.CpuUsage,
|
||||
"QueryTypes": dnsStats.QueryTypes,
|
||||
"SourceIPs": dnsStats.SourceIPs,
|
||||
"CpuUsage": dnsStats.CpuUsage,
|
||||
},
|
||||
"shield": shieldStats,
|
||||
"topQueryType": topQueryType,
|
||||
"activeIPs": activeIPCount,
|
||||
"shield": shieldStats,
|
||||
"topQueryType": topQueryType,
|
||||
"activeIPs": activeIPCount,
|
||||
"avgResponseTime": formattedResponseTime,
|
||||
"cpuUsage": dnsStats.CpuUsage,
|
||||
"time": time.Now(),
|
||||
"cpuUsage": dnsStats.CpuUsage,
|
||||
"time": time.Now(),
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
@@ -197,25 +200,25 @@ func (s *Server) handleWebSocketStats(w http.ResponseWriter, r *http.Request) {
|
||||
case <-ticker.C:
|
||||
// 获取最新统计数据
|
||||
currentStats := s.buildStatsData()
|
||||
|
||||
|
||||
// 检查数据是否有变化
|
||||
if !s.areStatsEqual(lastStats, currentStats) {
|
||||
// 数据有变化,发送更新
|
||||
data, err := json.Marshal(map[string]interface{}{
|
||||
"type": "stats_update",
|
||||
"data": currentStats,
|
||||
"time": time.Now(),
|
||||
"type": "stats_update",
|
||||
"data": currentStats,
|
||||
"time": time.Now(),
|
||||
})
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("序列化统计数据失败: %v", err))
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
if err := conn.WriteMessage(websocket.TextMessage, data); err != nil {
|
||||
logger.Error(fmt.Sprintf("发送WebSocket消息失败: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// 更新最后发送的数据
|
||||
lastStats = currentStats
|
||||
}
|
||||
@@ -235,9 +238,9 @@ func (s *Server) handleWebSocketStats(w http.ResponseWriter, r *http.Request) {
|
||||
func (s *Server) sendInitialStats(conn *websocket.Conn) error {
|
||||
stats := s.buildStatsData()
|
||||
data, err := json.Marshal(map[string]interface{}{
|
||||
"type": "initial_data",
|
||||
"data": stats,
|
||||
"time": time.Now(),
|
||||
"type": "initial_data",
|
||||
"data": stats,
|
||||
"time": time.Now(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -267,25 +270,25 @@ func (s *Server) buildStatsData() map[string]interface{} {
|
||||
|
||||
// 格式化平均响应时间
|
||||
formattedResponseTime := float64(int(dnsStats.AvgResponseTime*100)) / 100
|
||||
|
||||
|
||||
return map[string]interface{}{
|
||||
"dns": map[string]interface{}{
|
||||
"Queries": dnsStats.Queries,
|
||||
"Blocked": dnsStats.Blocked,
|
||||
"Allowed": dnsStats.Allowed,
|
||||
"Errors": dnsStats.Errors,
|
||||
"LastQuery": dnsStats.LastQuery,
|
||||
"AvgResponseTime": formattedResponseTime,
|
||||
"Queries": dnsStats.Queries,
|
||||
"Blocked": dnsStats.Blocked,
|
||||
"Allowed": dnsStats.Allowed,
|
||||
"Errors": dnsStats.Errors,
|
||||
"LastQuery": dnsStats.LastQuery,
|
||||
"AvgResponseTime": formattedResponseTime,
|
||||
"TotalResponseTime": dnsStats.TotalResponseTime,
|
||||
"QueryTypes": dnsStats.QueryTypes,
|
||||
"SourceIPs": dnsStats.SourceIPs,
|
||||
"CpuUsage": dnsStats.CpuUsage,
|
||||
"QueryTypes": dnsStats.QueryTypes,
|
||||
"SourceIPs": dnsStats.SourceIPs,
|
||||
"CpuUsage": dnsStats.CpuUsage,
|
||||
},
|
||||
"shield": shieldStats,
|
||||
"topQueryType": topQueryType,
|
||||
"activeIPs": activeIPCount,
|
||||
"shield": shieldStats,
|
||||
"topQueryType": topQueryType,
|
||||
"activeIPs": activeIPCount,
|
||||
"avgResponseTime": formattedResponseTime,
|
||||
"cpuUsage": dnsStats.CpuUsage,
|
||||
"cpuUsage": dnsStats.CpuUsage,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,20 +297,20 @@ func (s *Server) areStatsEqual(stats1, stats2 map[string]interface{}) bool {
|
||||
if stats1 == nil || stats2 == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
// 只比较关键数值,避免频繁更新
|
||||
if dns1, ok1 := stats1["dns"].(map[string]interface{}); ok1 {
|
||||
if dns2, ok2 := stats2["dns"].(map[string]interface{}); ok2 {
|
||||
// 检查主要计数器
|
||||
if dns1["Queries"] != dns2["Queries"] ||
|
||||
dns1["Blocked"] != dns2["Blocked"] ||
|
||||
dns1["Allowed"] != dns2["Allowed"] ||
|
||||
dns1["Errors"] != dns2["Errors"] {
|
||||
dns1["Blocked"] != dns2["Blocked"] ||
|
||||
dns1["Allowed"] != dns2["Allowed"] ||
|
||||
dns1["Errors"] != dns2["Errors"] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -493,7 +496,7 @@ func (s *Server) handleQueryTypeStats(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// 获取DNS统计数据
|
||||
dnsStats := s.dnsServer.GetStats()
|
||||
|
||||
|
||||
// 转换为前端需要的格式
|
||||
result := make([]map[string]interface{}, 0, len(dnsStats.QueryTypes))
|
||||
for queryType, count := range dnsStats.QueryTypes {
|
||||
@@ -512,6 +515,74 @@ func (s *Server) handleQueryTypeStats(w http.ResponseWriter, r *http.Request) {
|
||||
json.NewEncoder(w).Encode(result)
|
||||
}
|
||||
|
||||
// handleTopClients 处理TOP客户端请求
|
||||
func (s *Server) handleTopClients(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
// 获取TOP客户端列表
|
||||
clients := s.dnsServer.GetTopClients(10)
|
||||
|
||||
// 转换为前端需要的格式
|
||||
result := make([]map[string]interface{}, len(clients))
|
||||
for i, client := range clients {
|
||||
result[i] = map[string]interface{}{
|
||||
"ip": client.IP,
|
||||
"count": client.Count,
|
||||
"lastSeen": client.LastSeen,
|
||||
}
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(result)
|
||||
}
|
||||
|
||||
// handleTopDomains 处理TOP域名请求
|
||||
func (s *Server) handleTopDomains(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
// 获取TOP被屏蔽域名
|
||||
blockedDomains := s.dnsServer.GetTopBlockedDomains(10)
|
||||
// 获取TOP已解析域名
|
||||
resolvedDomains := s.dnsServer.GetTopResolvedDomains(10)
|
||||
|
||||
// 合并并去重域名统计
|
||||
domainMap := make(map[string]int64)
|
||||
for _, domain := range blockedDomains {
|
||||
domainMap[domain.Domain] += domain.Count
|
||||
}
|
||||
for _, domain := range resolvedDomains {
|
||||
domainMap[domain.Domain] += domain.Count
|
||||
}
|
||||
|
||||
// 转换为切片并排序
|
||||
domainList := make([]map[string]interface{}, 0, len(domainMap))
|
||||
for domain, count := range domainMap {
|
||||
domainList = append(domainList, map[string]interface{}{
|
||||
"domain": domain,
|
||||
"count": count,
|
||||
})
|
||||
}
|
||||
|
||||
// 按计数降序排序
|
||||
sort.Slice(domainList, func(i, j int) bool {
|
||||
return domainList[i]["count"].(int64) > domainList[j]["count"].(int64)
|
||||
})
|
||||
|
||||
// 返回限制数量
|
||||
if len(domainList) > 10 {
|
||||
domainList = domainList[:10]
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(domainList)
|
||||
}
|
||||
|
||||
// handleShield 处理屏蔽规则管理请求
|
||||
func (s *Server) handleShield(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
@@ -820,25 +891,25 @@ func (s *Server) handleStatus(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
stats := s.dnsServer.GetStats()
|
||||
|
||||
|
||||
// 使用服务器的实际启动时间计算准确的运行时间
|
||||
serverStartTime := s.dnsServer.GetStartTime()
|
||||
uptime := time.Since(serverStartTime)
|
||||
|
||||
|
||||
// 构建包含所有真实服务器统计数据的响应
|
||||
status := map[string]interface{}{
|
||||
"status": "running",
|
||||
"queries": stats.Queries,
|
||||
"blocked": stats.Blocked,
|
||||
"allowed": stats.Allowed,
|
||||
"errors": stats.Errors,
|
||||
"lastQuery": stats.LastQuery,
|
||||
"status": "running",
|
||||
"queries": stats.Queries,
|
||||
"blocked": stats.Blocked,
|
||||
"allowed": stats.Allowed,
|
||||
"errors": stats.Errors,
|
||||
"lastQuery": stats.LastQuery,
|
||||
"avgResponseTime": stats.AvgResponseTime,
|
||||
"activeIPs": len(stats.SourceIPs),
|
||||
"startTime": serverStartTime,
|
||||
"uptime": uptime.Milliseconds(), // 转换为毫秒数,方便前端处理
|
||||
"cpuUsage": stats.CpuUsage,
|
||||
"timestamp": time.Now(),
|
||||
"activeIPs": len(stats.SourceIPs),
|
||||
"startTime": serverStartTime,
|
||||
"uptime": uptime.Milliseconds(), // 转换为毫秒数,方便前端处理
|
||||
"cpuUsage": stats.CpuUsage,
|
||||
"timestamp": time.Now(),
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
Reference in New Issue
Block a user