package main import ( "encoding/json" "strconv" "time" "github.com/tinode/chat/server/logs" "github.com/tinode/chat/server/store" "github.com/tinode/chat/server/store/types" ) // dispatchIMGroupEvents delivers committed outbox events to online topic // sessions. Events remain pending when the hub is unavailable or its queue is // full, so the next successful group mutation retries them. func dispatchIMGroupEvents(tenantID types.TenantID) { if tenantID.IsZero() || globals.hub == nil || store.GroupBusiness == nil { return } now := time.Now().UTC().Round(time.Millisecond) events, err := store.GroupBusiness.ListPendingEvents(tenantID, 100, now) if err != nil { logs.Warn.Printf("group outbox: list tenant=%d: %v", tenantID, err) return } for _, event := range events { members, memberErr := store.Topics.GetUsers(tenantID, event.Topic, &types.QueryOpt{Limit: 1000}) if memberErr != nil { logs.Warn.Printf("group outbox: list members event=%s: %v", event.EventID, memberErr) return } for _, member := range members { uid := types.ParseUid(member.User) if uid.IsZero() { if decoded, parseErr := strconv.ParseInt(member.User, 10, 64); parseErr == nil && decoded > 0 { uid = store.EncodeUid(decoded) } } if uid.IsZero() || uid == event.ActorUserID { continue } if err = createIMSystemNotification(tenantID, uid, stableIMEventID(event.EventID, uid.UserId(), "notification"), event.EventType, "群聊动态", event.EventType, types.KVMap{"topic": event.Topic}); err != nil { logs.Warn.Printf("group outbox: create notification event=%s user=%s: %v", event.EventID, uid.UserId(), err) return } } payload := json.RawMessage(event.Payload) if len(payload) == 0 { payload = json.RawMessage(`{}`) } from := "" if !event.ActorUserID.IsZero() { from = event.ActorUserID.UserId() } message := &ServerComMessage{ TenantID: tenantID, RcptTo: event.Topic, AsUser: from, Timestamp: event.CreatedAt, Info: &MsgServerInfo{ Topic: event.Topic, From: from, What: "group", Event: event.EventType, Payload: payload, }, } select { case globals.hub.routeSrv <- message: if err = store.GroupBusiness.MarkEventDelivered(tenantID, event.EventID, now); err != nil { logs.Warn.Printf("group outbox: mark delivered event=%s: %v", event.EventID, err) return } default: logs.Warn.Printf("group outbox: hub queue full event=%s", event.EventID) return } } }