148 lines
3.3 KiB
Go
148 lines
3.3 KiB
Go
package main
|
||
|
||
import (
|
||
"fmt"
|
||
"net"
|
||
"sync"
|
||
"time"
|
||
)
|
||
|
||
// 客户端信息结构
|
||
type ClientInfo struct {
|
||
IP string // IP地址
|
||
Port string // 端口
|
||
LastSeen time.Time // 最后活跃时间
|
||
IsConnected bool // 是否当前连接
|
||
}
|
||
|
||
// 客户端列表(使用互斥锁保护的映射)
|
||
var (
|
||
clientsMutex sync.Mutex
|
||
clients = make(map[string]*ClientInfo)
|
||
)
|
||
|
||
// addClient 添加客户端
|
||
func addClient(addr string) {
|
||
clientsMutex.Lock()
|
||
defer clientsMutex.Unlock()
|
||
|
||
host, port, err := net.SplitHostPort(addr)
|
||
if err != nil {
|
||
Logger.Printf("解析客户端地址失败 %s: %v", addr, err)
|
||
host = addr
|
||
port = "unknown"
|
||
}
|
||
|
||
clients[addr] = &ClientInfo{
|
||
IP: host,
|
||
Port: port,
|
||
LastSeen: time.Now(),
|
||
IsConnected: true,
|
||
}
|
||
|
||
Logger.Printf("添加新客户端: %s", addr)
|
||
}
|
||
|
||
// updateClientLastSeen 更新客户端最后活跃时间
|
||
func updateClientLastSeen(addr string) {
|
||
clientsMutex.Lock()
|
||
defer clientsMutex.Unlock()
|
||
|
||
if client, exists := clients[addr]; exists {
|
||
client.LastSeen = time.Now()
|
||
}
|
||
}
|
||
|
||
// removeClient 移除客户端(标记断开)
|
||
func removeClient(addr string) {
|
||
clientsMutex.Lock()
|
||
defer clientsMutex.Unlock()
|
||
|
||
if client, exists := clients[addr]; exists {
|
||
client.IsConnected = false
|
||
Logger.Printf("客户端断开连接: %s", addr)
|
||
}
|
||
}
|
||
|
||
// getAllClients 获取所有客户端信息
|
||
func getAllClients() []map[string]interface{} {
|
||
clientsMutex.Lock()
|
||
defer clientsMutex.Unlock()
|
||
|
||
now := time.Now()
|
||
result := make([]map[string]interface{}, 0, len(clients))
|
||
|
||
for addr, client := range clients {
|
||
lastSeenDuration := now.Sub(client.LastSeen)
|
||
|
||
// 清理24小时前的记录
|
||
if lastSeenDuration > 24*time.Hour {
|
||
delete(clients, addr)
|
||
continue
|
||
}
|
||
|
||
// 连接状态判断:当前连接且2小时内活跃为在线
|
||
isOnline := client.IsConnected && lastSeenDuration < 2*time.Hour
|
||
var connectionStatus string
|
||
if isOnline {
|
||
connectionStatus = "保持连接"
|
||
} else if client.IsConnected {
|
||
connectionStatus = "连接超时"
|
||
} else {
|
||
connectionStatus = "已断开"
|
||
}
|
||
|
||
result = append(result, map[string]interface{}{
|
||
"address": addr,
|
||
"ip": client.IP,
|
||
"port": client.Port,
|
||
"lastSeen": client.LastSeen,
|
||
"isOnline": isOnline,
|
||
"connectionStatus": connectionStatus,
|
||
"lastSeenFormatted": formatDuration(lastSeenDuration),
|
||
})
|
||
}
|
||
|
||
return result
|
||
}
|
||
|
||
// formatDuration 格式化持续时间为友好的字符串
|
||
func formatDuration(d time.Duration) string {
|
||
if d < time.Minute {
|
||
return "刚刚"
|
||
} else if d < time.Hour {
|
||
return fmt.Sprintf("%d分钟前", int(d.Minutes()))
|
||
} else if d < 24*time.Hour {
|
||
hours := int(d.Hours())
|
||
minutes := int(d.Minutes()) % 60
|
||
if minutes == 0 {
|
||
return fmt.Sprintf("%d小时前", hours)
|
||
} else {
|
||
return fmt.Sprintf("%d小时%d分钟前", hours, minutes)
|
||
}
|
||
} else {
|
||
return fmt.Sprintf("%d天前", int(d.Hours()/24))
|
||
}
|
||
}
|
||
|
||
// startClientCleanup 启动清理过期客户端的goroutine
|
||
func startClientCleanup() {
|
||
go func() {
|
||
for {
|
||
time.Sleep(1 * time.Hour) // 每小时检查一次
|
||
|
||
clientsMutex.Lock()
|
||
now := time.Now()
|
||
|
||
for addr, client := range clients {
|
||
if now.Sub(client.LastSeen) > 24*time.Hour {
|
||
delete(clients, addr)
|
||
Logger.Printf("移除过期客户端: %s", addr)
|
||
}
|
||
}
|
||
|
||
clientsMutex.Unlock()
|
||
}
|
||
}()
|
||
}
|