feat: add redis cache and fanout support
This commit is contained in:
@@ -205,6 +205,32 @@ func (s *Session) getSub(topic string) *Subscription {
|
||||
return s.subs[topic]
|
||||
}
|
||||
|
||||
func (s *Session) hasSub(topic string) bool {
|
||||
if s.multi != nil {
|
||||
return s.multi.hasSub(topic)
|
||||
}
|
||||
s.subsLock.RLock()
|
||||
defer s.subsLock.RUnlock()
|
||||
_, ok := s.subs[topic]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (s *Session) groupSubs() []string {
|
||||
if s.multi != nil {
|
||||
return s.multi.groupSubs()
|
||||
}
|
||||
s.subsLock.RLock()
|
||||
defer s.subsLock.RUnlock()
|
||||
|
||||
topics := make([]string, 0, len(s.subs))
|
||||
for topic := range s.subs {
|
||||
if len(topic) >= 3 && types.GetTopicCat(topic) == types.TopicCatGrp {
|
||||
topics = append(topics, topic)
|
||||
}
|
||||
}
|
||||
return topics
|
||||
}
|
||||
|
||||
func (s *Session) delSub(topic string) {
|
||||
if s.multi != nil {
|
||||
s.multi.delSub(topic)
|
||||
@@ -434,6 +460,11 @@ func (s *Session) purgeChannels() {
|
||||
// cleanUp is called when the session is terminated to perform resource cleanup.
|
||||
func (s *Session) cleanUp(expired bool) {
|
||||
atomic.StoreInt32(&s.terminating, 1)
|
||||
if !s.uid.IsZero() && s.tenantID.IsValid() {
|
||||
if err := store.MarkUserOffline(s.tenantID, s.uid, s.sid, currentNodeID()); err != nil {
|
||||
logs.Warn.Println("s.cleanUp: failed to mark user offline", s.uid, err, s.sid)
|
||||
}
|
||||
}
|
||||
s.purgeChannels()
|
||||
s.inflightReqs.Wait()
|
||||
s.inflightReqs = nil
|
||||
@@ -488,6 +519,16 @@ func (s *Session) dispatchRaw(raw []byte) {
|
||||
func (s *Session) dispatch(msg *ClientComMessage) {
|
||||
now := types.TimeNow()
|
||||
atomic.StoreInt64(&s.lastAction, now.UnixNano())
|
||||
if !s.uid.IsZero() && s.tenantID.IsValid() {
|
||||
if err := store.RefreshUserPresence(s.tenantID, s.uid, s.sid, currentNodeID()); err != nil {
|
||||
logs.Warn.Println("s.dispatch: failed to refresh user presence", s.uid, err, s.sid)
|
||||
}
|
||||
for _, topic := range s.groupSubs() {
|
||||
if err := store.MarkTopicMemberOnline(s.tenantID, topic, s.uid, currentNodeID()); err != nil {
|
||||
logs.Warn.Println("s.dispatch: failed to refresh group member presence", topic, s.uid, err, s.sid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This should be the first block here, before any other checks.
|
||||
var resp *ServerComMessage
|
||||
@@ -1200,6 +1241,9 @@ func (s *Session) onLogin(msgID string, timestamp time.Time, rec *auth.Rec, miss
|
||||
// Authenticate the session.
|
||||
s.uid = rec.Uid
|
||||
s.authLvl = rec.AuthLevel
|
||||
if err := store.MarkUserOnline(s.tenantID, s.uid, s.sid, currentNodeID(), s.platf, s.userAgent); err != nil {
|
||||
logs.Warn.Println("s.onLogin: failed to mark user online", s.uid, err, s.sid)
|
||||
}
|
||||
// Reset expiration time.
|
||||
rec.Lifetime = 0
|
||||
}
|
||||
@@ -1228,6 +1272,25 @@ func (s *Session) onLogin(msgID string, timestamp time.Time, rec *auth.Rec, miss
|
||||
return reply
|
||||
}
|
||||
|
||||
func currentNodeID() string {
|
||||
if globals.cluster != nil && globals.cluster.thisNodeName != "" {
|
||||
return globals.cluster.thisNodeName
|
||||
}
|
||||
return "local"
|
||||
}
|
||||
|
||||
func redisUserOnline(tenantID types.TenantID, uid types.Uid, fallback bool) bool {
|
||||
if !store.UserPresenceEnabled() || !tenantID.IsValid() || uid.IsZero() {
|
||||
return fallback
|
||||
}
|
||||
presence, err := store.GetUserPresence(tenantID, uid)
|
||||
if err != nil {
|
||||
logs.Warn.Printf("presence[%s]: failed to read redis presence: %v", uid.UserId(), err)
|
||||
return fallback
|
||||
}
|
||||
return presence.Online
|
||||
}
|
||||
|
||||
func (s *Session) get(msg *ClientComMessage) {
|
||||
// Expand topic name.
|
||||
var resp *ServerComMessage
|
||||
|
||||
Reference in New Issue
Block a user