|
@@ -2,28 +2,45 @@ package ws
|
|
|
|
|
|
import (
|
|
import (
|
|
"errors"
|
|
"errors"
|
|
|
|
+ "eta/eta_api/utils"
|
|
"fmt"
|
|
"fmt"
|
|
"github.com/gorilla/websocket"
|
|
"github.com/gorilla/websocket"
|
|
"sync"
|
|
"sync"
|
|
"time"
|
|
"time"
|
|
)
|
|
)
|
|
|
|
|
|
|
|
+const (
|
|
|
|
+ defaultCheckInterval = 20 * time.Second // 检测间隔应小于心跳超时时间
|
|
|
|
+ connectionTimeout = 60 * time.Second // 客户端超时时间
|
|
|
|
+)
|
|
|
|
+
|
|
type ConnectionManager struct {
|
|
type ConnectionManager struct {
|
|
- Sessions sync.Map
|
|
|
|
- heartbeat *HeartbeatManager
|
|
|
|
|
|
+ Sessions sync.Map
|
|
|
|
+ ticker *time.Ticker
|
|
|
|
+ stopChan chan struct{}
|
|
}
|
|
}
|
|
|
|
|
|
var (
|
|
var (
|
|
- manager = &ConnectionManager{
|
|
|
|
- heartbeat: GetHeartbeatManager(),
|
|
|
|
- }
|
|
|
|
|
|
+ smOnce sync.Once
|
|
|
|
+ manager *ConnectionManager
|
|
)
|
|
)
|
|
|
|
|
|
|
|
+func GetInstance() *ConnectionManager {
|
|
|
|
+ smOnce.Do(func() {
|
|
|
|
+ if manager == nil {
|
|
|
|
+ manager = &ConnectionManager{
|
|
|
|
+ ticker: time.NewTicker(defaultCheckInterval),
|
|
|
|
+ stopChan: make(chan struct{}),
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ return manager
|
|
|
|
+}
|
|
func Manager() *ConnectionManager {
|
|
func Manager() *ConnectionManager {
|
|
return manager
|
|
return manager
|
|
}
|
|
}
|
|
|
|
|
|
-// 消息处理核心逻辑
|
|
|
|
|
|
+// HandleMessage 消息处理核心逻辑
|
|
func (manager *ConnectionManager) HandleMessage(userID int, sessionID string, message []byte) error {
|
|
func (manager *ConnectionManager) HandleMessage(userID int, sessionID string, message []byte) error {
|
|
if !Allow(userID, QA_LIMITER) {
|
|
if !Allow(userID, QA_LIMITER) {
|
|
return errors.New("您提问的太频繁了,请稍后再试")
|
|
return errors.New("您提问的太频繁了,请稍后再试")
|
|
@@ -36,40 +53,15 @@ func (manager *ConnectionManager) HandleMessage(userID int, sessionID string, me
|
|
// 处理业务逻辑
|
|
// 处理业务逻辑
|
|
session.History = append(session.History, string(message))
|
|
session.History = append(session.History, string(message))
|
|
response := "Processed: " + string(message)
|
|
response := "Processed: " + string(message)
|
|
-
|
|
|
|
// 更新最后活跃时间
|
|
// 更新最后活跃时间
|
|
session.LastActive = time.Now()
|
|
session.LastActive = time.Now()
|
|
-
|
|
|
|
// 发送响应
|
|
// 发送响应
|
|
return session.Conn.WriteMessage(websocket.TextMessage, []byte(response))
|
|
return session.Conn.WriteMessage(websocket.TextMessage, []byte(response))
|
|
}
|
|
}
|
|
|
|
|
|
-// 心跳管理
|
|
|
|
-func (manager *ConnectionManager) StartHeartbeat() {
|
|
|
|
- ticker := time.NewTicker(basePingInterval)
|
|
|
|
- defer ticker.Stop()
|
|
|
|
- for range ticker.C {
|
|
|
|
- manager.checkSessions()
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-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 true
|
|
|
|
- })
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
// AddSession Add 添加一个新的会话
|
|
// AddSession Add 添加一个新的会话
|
|
func (manager *ConnectionManager) AddSession(session *Session) {
|
|
func (manager *ConnectionManager) AddSession(session *Session) {
|
|
manager.Sessions.Store(session.Id, session)
|
|
manager.Sessions.Store(session.Id, session)
|
|
- manager.heartbeat.Register(session)
|
|
|
|
}
|
|
}
|
|
func (manager *ConnectionManager) GetSessionId(userId int, sessionId string) (sessionID string) {
|
|
func (manager *ConnectionManager) GetSessionId(userId int, sessionId string) (sessionID string) {
|
|
return fmt.Sprintf("%d_%s", userId, sessionId)
|
|
return fmt.Sprintf("%d_%s", userId, sessionId)
|
|
@@ -79,8 +71,7 @@ func (manager *ConnectionManager) GetSessionId(userId int, sessionId string) (se
|
|
func (manager *ConnectionManager) RemoveSession(sessionCode string) {
|
|
func (manager *ConnectionManager) RemoveSession(sessionCode string) {
|
|
if data, ok := manager.Sessions.LoadAndDelete(sessionCode); ok {
|
|
if data, ok := manager.Sessions.LoadAndDelete(sessionCode); ok {
|
|
session := data.(*Session)
|
|
session := data.(*Session)
|
|
- close(session.CloseChan)
|
|
|
|
- _ = session.Conn.Close()
|
|
|
|
|
|
+ session.Close()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -92,3 +83,63 @@ func (manager *ConnectionManager) GetSession(sessionCode string) (session *Sessi
|
|
}
|
|
}
|
|
return
|
|
return
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+// CheckAll 批量检测所有连接
|
|
|
|
+func (manager *ConnectionManager) CheckAll() {
|
|
|
|
+ manager.Sessions.Range(func(key, value interface{}) bool {
|
|
|
|
+ fmt.Printf("检测接接:%s", key)
|
|
|
|
+ session := value.(*Session)
|
|
|
|
+ if session.mu.TryRLock() {
|
|
|
|
+ defer session.mu.Unlock()
|
|
|
|
+ // 判断超时
|
|
|
|
+ if time.Since(session.LastActive) > connectionTimeout {
|
|
|
|
+ fmt.Printf("连接超时关闭: SessionID=%s, UserID=%s", session.Id, session.UserId)
|
|
|
|
+ utils.FileLog.Warn("连接超时关闭: SessionID=%s, UserID=%s", session.Id, session.UserId)
|
|
|
|
+ _ = session.Conn.Close()
|
|
|
|
+ session.Close()
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ // 发送心跳
|
|
|
|
+ go func(s *Session) {
|
|
|
|
+ err := s.Conn.WriteControl(websocket.PingMessage,
|
|
|
|
+ nil, time.Now().Add(5*time.Second))
|
|
|
|
+ fmt.Printf(s.Id)
|
|
|
|
+ if err != nil {
|
|
|
|
+ fmt.Printf("心跳发送失败: SessionID=%s, Error=%v", s.Id, err)
|
|
|
|
+ utils.FileLog.Warn("心跳发送失败: SessionID=%s, Error=%v",
|
|
|
|
+ s.Id, err)
|
|
|
|
+ _ = s.Conn.Close()
|
|
|
|
+ session.Close()
|
|
|
|
+ manager.Sessions.Delete(session.Id)
|
|
|
|
+ }
|
|
|
|
+ }(session)
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ return true
|
|
|
|
+ })
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Start 启动心跳检测
|
|
|
|
+func (manager *ConnectionManager) Start() {
|
|
|
|
+ defer manager.ticker.Stop()
|
|
|
|
+ for {
|
|
|
|
+ select {
|
|
|
|
+ case <-manager.ticker.C:
|
|
|
|
+ manager.CheckAll()
|
|
|
|
+ case <-manager.stopChan:
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Stop 停止心跳检测
|
|
|
|
+func (manager *ConnectionManager) Stop() {
|
|
|
|
+ close(manager.stopChan)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// UpdateActivity 跟新最近活跃时间
|
|
|
|
+func (manager *ConnectionManager) UpdateActivity(sessionID string) {
|
|
|
|
+ if session, ok := manager.Sessions.Load(sessionID); ok {
|
|
|
|
+ session.(*Session).LastActive = time.Now()
|
|
|
|
+ }
|
|
|
|
+}
|