2026-04-09 10:01:23 +08:00
|
|
|
package services
|
|
|
|
|
|
|
|
|
|
import "sync"
|
|
|
|
|
|
|
|
|
|
type WsConnectionManager struct {
|
|
|
|
|
mu sync.RWMutex
|
|
|
|
|
sessions map[string]*ClientSession
|
|
|
|
|
topics map[string]map[string]*ClientSession
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func newWsConnectionManager() *WsConnectionManager {
|
|
|
|
|
return &WsConnectionManager{
|
|
|
|
|
sessions: make(map[string]*ClientSession),
|
|
|
|
|
topics: make(map[string]map[string]*ClientSession),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (m *WsConnectionManager) Register(session *ClientSession, defaultTopics []string) int {
|
|
|
|
|
if session == nil {
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m.mu.Lock()
|
|
|
|
|
defer m.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
m.sessions[session.ID] = session
|
|
|
|
|
for _, topic := range defaultTopics {
|
|
|
|
|
m.subscribeLocked(session, topic)
|
|
|
|
|
}
|
|
|
|
|
return len(m.sessions)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (m *WsConnectionManager) Unregister(session *ClientSession) int {
|
|
|
|
|
if session == nil {
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m.mu.Lock()
|
|
|
|
|
defer m.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
delete(m.sessions, session.ID)
|
|
|
|
|
for topic := range session.Topics {
|
|
|
|
|
m.unsubscribeLocked(session, topic)
|
|
|
|
|
}
|
|
|
|
|
return len(m.sessions)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (m *WsConnectionManager) Subscribe(session *ClientSession, topics []string) []string {
|
|
|
|
|
if session == nil || len(topics) == 0 {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m.mu.Lock()
|
|
|
|
|
defer m.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
ret := make([]string, 0, len(topics))
|
|
|
|
|
for _, topic := range topics {
|
|
|
|
|
if _, exists := session.Topics[topic]; exists {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
m.subscribeLocked(session, topic)
|
|
|
|
|
ret = append(ret, topic)
|
|
|
|
|
}
|
|
|
|
|
return ret
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (m *WsConnectionManager) Unsubscribe(session *ClientSession, topics []string, keep map[string]struct{}) []string {
|
|
|
|
|
if session == nil || len(topics) == 0 {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m.mu.Lock()
|
|
|
|
|
defer m.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
ret := make([]string, 0, len(topics))
|
|
|
|
|
for _, topic := range topics {
|
|
|
|
|
if _, isDefault := keep[topic]; isDefault {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if _, exists := session.Topics[topic]; !exists {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
m.unsubscribeLocked(session, topic)
|
|
|
|
|
ret = append(ret, topic)
|
|
|
|
|
}
|
|
|
|
|
return ret
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (m *WsConnectionManager) FindByTopics(topics []string) []*ClientSession {
|
|
|
|
|
m.mu.RLock()
|
|
|
|
|
defer m.mu.RUnlock()
|
|
|
|
|
|
|
|
|
|
uniq := make(map[string]*ClientSession)
|
|
|
|
|
for _, topic := range topics {
|
|
|
|
|
for connID, session := range m.topics[topic] {
|
|
|
|
|
uniq[connID] = session
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret := make([]*ClientSession, 0, len(uniq))
|
|
|
|
|
for _, session := range uniq {
|
|
|
|
|
ret = append(ret, session)
|
|
|
|
|
}
|
|
|
|
|
return ret
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-14 20:28:48 +08:00
|
|
|
func (m *WsConnectionManager) HasTopic(topic string) bool {
|
|
|
|
|
m.mu.RLock()
|
|
|
|
|
defer m.mu.RUnlock()
|
|
|
|
|
|
|
|
|
|
sessions := m.topics[topic]
|
|
|
|
|
return len(sessions) > 0
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-09 10:01:23 +08:00
|
|
|
func (m *WsConnectionManager) subscribeLocked(session *ClientSession, topic string) {
|
|
|
|
|
if _, exists := session.Topics[topic]; exists {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if m.topics[topic] == nil {
|
|
|
|
|
m.topics[topic] = make(map[string]*ClientSession)
|
|
|
|
|
}
|
|
|
|
|
m.topics[topic][session.ID] = session
|
|
|
|
|
session.Topics[topic] = struct{}{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (m *WsConnectionManager) unsubscribeLocked(session *ClientSession, topic string) {
|
|
|
|
|
if sessions, ok := m.topics[topic]; ok {
|
|
|
|
|
delete(sessions, session.ID)
|
|
|
|
|
if len(sessions) == 0 {
|
|
|
|
|
delete(m.topics, topic)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
delete(session.Topics, topic)
|
|
|
|
|
}
|