|
@@ -1,28 +1,28 @@
|
|
|
package ws
|
|
|
|
|
|
import (
|
|
|
- "eta/eta_api/utils"
|
|
|
+ "errors"
|
|
|
"fmt"
|
|
|
"github.com/gorilla/websocket"
|
|
|
- "math/rand"
|
|
|
- "net"
|
|
|
+ "sync"
|
|
|
"time"
|
|
|
)
|
|
|
+
|
|
|
const (
|
|
|
- maxMessageSize = 1024 * 1024 // 1MB
|
|
|
+ maxMessageSize = 1024 * 1024 // 1MB
|
|
|
basePingInterval = 30 * time.Second
|
|
|
maxPingInterval = 120 * time.Second
|
|
|
minPingInterval = 15 * time.Second
|
|
|
)
|
|
|
+
|
|
|
type ConnectionManager struct {
|
|
|
- Sessions map[string]*Session
|
|
|
- heartbeat *HeartbeatManager
|
|
|
+ Sessions sync.Map
|
|
|
+ heartbeat *HeartbeatManager
|
|
|
}
|
|
|
|
|
|
var (
|
|
|
manager = &ConnectionManager{
|
|
|
- Sessions: make(map[string]*Session),
|
|
|
- heartbeat: NewHeartbeatManager(30 * time.Second),
|
|
|
+ heartbeat: GetHeartbeatManager(),
|
|
|
}
|
|
|
)
|
|
|
|
|
@@ -30,112 +30,71 @@ func Manager() *ConnectionManager {
|
|
|
return manager
|
|
|
}
|
|
|
|
|
|
-// Add 添加一个新的会话
|
|
|
-func (manager *ConnectionManager) Add(session *Session) {
|
|
|
- manager.Lock()
|
|
|
- defer manager.Unlock()
|
|
|
- manager.Sessions[manager.GetSessionId(session.UserId, session.SessionId)] = session
|
|
|
-}
|
|
|
-func (manager *ConnectionManager) GetSessionId(userId int, sessionId string) (sessionID string) {
|
|
|
- return fmt.Sprintf("%d_%s", userId, sessionId)
|
|
|
-}
|
|
|
+// 消息处理核心逻辑
|
|
|
+func (manager *ConnectionManager) HandleMessage(userID int, sessionID string, message []byte) error {
|
|
|
+ if !Allow(userID, QA_LIMITER) {
|
|
|
+ return errors.New("request too frequent")
|
|
|
+ }
|
|
|
+ session, exists := manager.GetSession(sessionID)
|
|
|
+ if !exists {
|
|
|
+ return errors.New("session not found")
|
|
|
+ }
|
|
|
|
|
|
-// Remove 移除一个会话
|
|
|
-func (manager *ConnectionManager) Remove(sessionCode string) {
|
|
|
- delete(manager.Sessions, sessionCode)
|
|
|
-}
|
|
|
+ // 处理业务逻辑
|
|
|
+ session.History = append(session.History, string(message))
|
|
|
+ response := "Processed: " + string(message)
|
|
|
|
|
|
-func (manager *ConnectionManager) Get(sessionID string) (session *Session, ok bool) {
|
|
|
- session, ok = manager.Sessions[sessionID]
|
|
|
- return
|
|
|
+ // 更新最后活跃时间
|
|
|
+ session.LastActive = time.Now()
|
|
|
+
|
|
|
+ // 发送响应
|
|
|
+ return session.Conn.WriteMessage(websocket.TextMessage, []byte(response))
|
|
|
}
|
|
|
-func (manager *ConnectionManager) HeartBeat(session *Session) {
|
|
|
- fmt.Println("执行心跳")
|
|
|
- if err := session.Conn.WriteMessage(websocket.PingMessage, nil); err != nil {
|
|
|
- err = session.Conn.Close()
|
|
|
- if err != nil {
|
|
|
- utils.FileLog.Error("关闭长连接失败: %v", err)
|
|
|
- return
|
|
|
- }
|
|
|
- delete(manager.Sessions, manager.GetSessionId(session.UserId, session.SessionId))
|
|
|
+
|
|
|
+// 心跳管理
|
|
|
+func (manager *ConnectionManager) StartHeartbeat() {
|
|
|
+ ticker := time.NewTicker(basePingInterval)
|
|
|
+ defer ticker.Stop()
|
|
|
+ for range ticker.C {
|
|
|
+ manager.checkSessions()
|
|
|
}
|
|
|
}
|
|
|
-func (manager *ConnectionManager) HandleWebSocketConnection(conn *websocket.Conn) {
|
|
|
- defer func() {
|
|
|
- if err := conn.Close(); err != nil {
|
|
|
- handleClose(err)
|
|
|
- }
|
|
|
- }()
|
|
|
- // 获取底层 TCP 连接并设置保活
|
|
|
- if tcpConn, ok := conn.NetConn().(*net.TCPConn); ok {
|
|
|
- _ = tcpConn.SetKeepAlive(true)
|
|
|
- _ = tcpConn.SetKeepAlivePeriod(90 * time.Second)
|
|
|
- utils.FileLog.Info("TCP KeepAlive 已启用")
|
|
|
- }
|
|
|
- // 初始化心跳间隔(基础值)
|
|
|
- baseInterval := 30 * time.Second
|
|
|
- adjustHeartbeatInterval(conn, baseInterval)
|
|
|
- // 设置心跳检测
|
|
|
- conn.SetPongHandler(func(string) error {
|
|
|
- err := conn.SetReadDeadline(time.Now().Add(60 * time.Second))
|
|
|
- if err != nil {
|
|
|
- utils.FileLog.Error("设置读取超时失败:WebSocket:", err)
|
|
|
+
|
|
|
+func (manager *ConnectionManager) checkSessions() {
|
|
|
+ manager.Sessions.Range(func(key, value interface{}) bool {
|
|
|
+ session := value.(*Session)
|
|
|
+ if time.Since(session.LastActive) > 2*basePingInterval {
|
|
|
+ session.Conn.Close()
|
|
|
+ manager.Sessions.Delete(key)
|
|
|
+ } else {
|
|
|
+ _ = session.Latency.SendPing(session.Conn)
|
|
|
}
|
|
|
- return nil
|
|
|
+ return true
|
|
|
})
|
|
|
- // 消息处理循环
|
|
|
- for {
|
|
|
- messageType, message, err := conn.ReadMessage()
|
|
|
- if err != nil {
|
|
|
- utils.FileLog.Error("Read error:", err)
|
|
|
- return
|
|
|
- }
|
|
|
- // 业务处理逻辑
|
|
|
- response := processMessage(message)
|
|
|
- // 返回响应
|
|
|
- if err = conn.WriteMessage(messageType, response); err != nil {
|
|
|
- utils.FileLog.Error("Write error:", err)
|
|
|
- return
|
|
|
- }
|
|
|
- }
|
|
|
}
|
|
|
-func handleClose(err error) {
|
|
|
- if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) {
|
|
|
- if wsErr, ok := err.(*websocket.CloseError); !ok {
|
|
|
- utils.FileLog.Error("未知错误 %s", err.Error())
|
|
|
- } else {
|
|
|
- switch wsErr.Code {
|
|
|
- case websocket.CloseNormalClosure:
|
|
|
- utils.FileLog.Info("正常关闭连接")
|
|
|
- default:
|
|
|
- utils.FileLog.Error("关闭代码:%d:%s", wsErr.Code, wsErr.Text)
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
- }
|
|
|
+// AddSession Add 添加一个新的会话
|
|
|
+func (manager *ConnectionManager) AddSession(session *Session) {
|
|
|
+ manager.Sessions.Store(session.ID, session)
|
|
|
+ manager.heartbeat.Register(session)
|
|
|
+}
|
|
|
+func (manager *ConnectionManager) GetSessionId(userId int, sessionId string) (sessionID string) {
|
|
|
+ return fmt.Sprintf("%d_%s", userId, sessionId)
|
|
|
}
|
|
|
|
|
|
-// 动态调整心跳间隔(需配合业务逻辑调用)
|
|
|
-func adjustHeartbeatInterval(conn *websocket.Conn, baseInterval time.Duration) {
|
|
|
- // 模拟网络延迟计算(实际应通过Ping-Pong测量)
|
|
|
- latency := time.Duration(rand.Intn(100)) * time.Millisecond
|
|
|
- newInterval := baseInterval + latency*2
|
|
|
-
|
|
|
- // 创建新的心跳定时器
|
|
|
- ticker := time.NewTicker(newInterval)
|
|
|
- defer ticker.Stop()
|
|
|
-
|
|
|
- go func() {
|
|
|
- for range ticker.C {
|
|
|
- if err := conn.WriteControl(websocket.PingMessage, nil, time.Now().Add(5*time.Second)); err != nil {
|
|
|
- utils.FileLog.Error("发送心跳包失败:", err)
|
|
|
- return
|
|
|
- }
|
|
|
- }
|
|
|
- }()
|
|
|
- utils.FileLog.Info("心跳间隔调整为: %v", newInterval)
|
|
|
+// RemoveSession Remove 移除一个会话
|
|
|
+func (manager *ConnectionManager) RemoveSession(sessionCode string) {
|
|
|
+ if data, ok := manager.Sessions.LoadAndDelete(sessionCode); ok {
|
|
|
+ session := data.(*Session)
|
|
|
+ close(session.CloseChan)
|
|
|
+ _ = session.Conn.Close()
|
|
|
+ }
|
|
|
}
|
|
|
-func processMessage(msg []byte) []byte {
|
|
|
- // 实现具体的业务逻辑
|
|
|
- return []byte("Received: " + string(msg))
|
|
|
+
|
|
|
+// GetSession 获取一个会话
|
|
|
+func (manager *ConnectionManager) GetSession(sessionCode string) (session *Session, ok bool) {
|
|
|
+ if data, ok := manager.Sessions.Load(sessionCode); ok {
|
|
|
+ session = data.(*Session)
|
|
|
+ }
|
|
|
+ return
|
|
|
}
|