diff --git a/clientapi/routing/presence.go b/clientapi/routing/presence.go index 07d690bdb..09f8372da 100644 --- a/clientapi/routing/presence.go +++ b/clientapi/routing/presence.go @@ -124,10 +124,11 @@ func GetPresence( } lastActiveTS := gomatrixserverlib.Timestamp(lastActive) + currentlyActive := time.Since(lastActiveTS.Time()).Minutes() < 5 return util.JSONResponse{ Code: http.StatusOK, JSON: types.PresenceClientResponse{ - CurrentlyActive: time.Since(lastActiveTS.Time()).Minutes() < 5, + CurrentlyActive: ¤tlyActive, LastActiveAgo: time.Since(lastActiveTS.Time()).Milliseconds(), Presence: presence.Header.Get("presence"), StatusMsg: &statusMsg, diff --git a/syncapi/streams/stream_presence.go b/syncapi/streams/stream_presence.go index 864492e5e..8af23803f 100644 --- a/syncapi/streams/stream_presence.go +++ b/syncapi/streams/stream_presence.go @@ -18,6 +18,7 @@ import ( "context" "database/sql" "encoding/json" + "sync" "time" "github.com/matrix-org/dendrite/syncapi/types" @@ -26,6 +27,7 @@ import ( type PresenceStreamProvider struct { StreamProvider + cache sync.Map } func (p *PresenceStreamProvider) Setup() { @@ -64,6 +66,7 @@ func (p *PresenceStreamProvider) IncrementalSync( rooms, err := p.DB.AllJoinedUsersInRooms(ctx) if err != nil { req.Log.WithError(err).Error("unable to query joined users") + return from } sharedUsers := map[string]bool{ @@ -88,11 +91,11 @@ func (p *PresenceStreamProvider) IncrementalSync( } presences[roomUsers[i]], err = p.DB.GetPresence(ctx, roomUsers[i]) if err != nil { - req.Log.WithError(err).Error("unable to query presence for user") + req.Log.WithError(err).Warn("unable to query presence for user") if err == sql.ErrNoRows { continue } - return to + return from } } } @@ -104,8 +107,24 @@ func (p *PresenceStreamProvider) IncrementalSync( if !sharedUsers[presence.UserID] { continue } + pres, ok := p.cache.Load(req.Device.UserID + presence.UserID) + if ok { + // skip already sent presence + prevPresence := pres.(*types.Presence) + currentlyActive := time.Since(prevPresence.LastActiveTS.Time()).Minutes() < 5 + samePresence := prevPresence.ClientFields.Presence == presence.ClientFields.Presence && + prevPresence.ClientFields.StatusMsg == presence.ClientFields.StatusMsg + skip := currentlyActive && samePresence && req.Device.UserID != presence.UserID + if skip { + req.Log.Debugf("Skipping presence, no change (%s)", presence.UserID) + continue + } + } presence.ClientFields.LastActiveAgo = time.Since(presence.LastActiveTS.Time()).Milliseconds() - presence.ClientFields.CurrentlyActive = time.Since(presence.LastActiveTS.Time()).Minutes() < 5 + currentlyActive := time.Since(presence.LastActiveTS.Time()).Minutes() < 5 + if presence.ClientFields.Presence == "online" { + presence.ClientFields.CurrentlyActive = ¤tlyActive + } content, err := json.Marshal(presence.ClientFields) if err != nil { @@ -120,6 +139,7 @@ func (p *PresenceStreamProvider) IncrementalSync( if presence.StreamPos > lastPos { lastPos = presence.StreamPos } + p.cache.Store(req.Device.UserID+presence.UserID, presence) } return lastPos diff --git a/syncapi/types/types.go b/syncapi/types/types.go index 93256d398..af0e6e969 100644 --- a/syncapi/types/types.go +++ b/syncapi/types/types.go @@ -522,7 +522,7 @@ type Presence struct { } type PresenceClientResponse struct { - CurrentlyActive bool `json:"currently_active"` + CurrentlyActive *bool `json:"currently_active,omitempty"` LastActiveAgo int64 `json:"last_active_ago,omitempty"` Presence string `json:"presence"` StatusMsg *string `json:"status_msg,omitempty"`