Enable lazy loading of members

This commit is contained in:
Tulir Asokan
2020-02-22 00:03:57 +02:00
parent 032a83d70b
commit 442fdac4d5
8 changed files with 104 additions and 49 deletions

View File

@ -834,6 +834,18 @@ func (c *Container) LeaveRoom(roomID string) error {
return nil
}
func (c *Container) FetchMembers(room *rooms.Room) error {
members, err := c.client.Members(room.ID, mautrix.ReqMembers{At: room.LastPrevBatch})
if err != nil {
return err
}
for _, evt := range members.Chunk {
room.UpdateState(evt)
}
room.MembersFetched = true
return nil
}
// GetHistory fetches room history.
func (c *Container) GetHistory(room *rooms.Room, limit int) ([]*event.Event, error) {
events, err := c.history.Load(room, limit)
@ -849,6 +861,9 @@ func (c *Container) GetHistory(room *rooms.Room, limit int) ([]*event.Event, err
return nil, err
}
debug.Printf("Loaded %d events for %s from server from %s to %s", len(resp.Chunk), room.ID, resp.Start, resp.End)
for _, evt := range resp.State {
room.UpdateState(evt)
}
room.PrevBatch = resp.End
c.config.Rooms.Put(room)
if len(resp.Chunk) == 0 {

View File

@ -21,7 +21,6 @@ import (
"encoding/gob"
"fmt"
"os"
"sort"
"time"
sync "github.com/sasha-s/go-deadlock"
@ -41,7 +40,6 @@ type RoomNameSource int
const (
UnknownRoomName RoomNameSource = iota
MemberRoomName
AliasRoomName
CanonicalAliasRoomName
ExplicitRoomName
)
@ -71,6 +69,8 @@ type Room struct {
// The first batch of events that has been fetched for this room.
// Used for fetching additional history.
PrevBatch string
// The last_batch field from the most recent sync. Used for fetching member lists.
LastPrevBatch string
// The MXID of the user whose session this room was created for.
SessionUserID string
SessionMember *mautrix.Member
@ -88,6 +88,10 @@ type Room struct {
// Timestamp of previously received actual message.
LastReceivedMessage time.Time
// The lazy loading summary for this room.
Summary mautrix.LazyLoadSummary
// Whether or not the members for this room have been fetched from the server.
MembersFetched bool
// Room state cache.
state map[mautrix.EventType]map[string]*mautrix.Event
// MXID -> Member cache calculated from membership events.
@ -106,8 +110,6 @@ type Room struct {
topicCache string
// The canonical alias of the room. Directly fetched from the m.room.canonical_alias state event.
CanonicalAliasCache string
// The list of aliases. Directly fetched from the m.room.aliases state event.
aliasesCache []string
// Whether or not the room has been tombstoned.
replacedCache bool
// The room ID that replaced this room.
@ -199,13 +201,13 @@ func (room *Room) Unload() bool {
debug.Print("Unloading", room.ID)
room.Save()
room.state = nil
room.aliasesCache = nil
room.topicCache = ""
room.CanonicalAliasCache = ""
room.firstMemberCache = nil
room.secondMemberCache = nil
room.memberCache = nil
room.exMemberCache = nil
room.replacedByCache = nil
if room.postUnload != nil {
room.postUnload()
}
@ -343,6 +345,21 @@ func (room *Room) Tags() []RoomTag {
return room.RawTags
}
func (room *Room) UpdateSummary(summary mautrix.LazyLoadSummary) {
if summary.JoinedMemberCount != nil {
room.Summary.JoinedMemberCount = summary.JoinedMemberCount
}
if summary.InvitedMemberCount != nil {
room.Summary.InvitedMemberCount = summary.InvitedMemberCount
}
if summary.Heroes != nil {
room.Summary.Heroes = summary.Heroes
}
if room.nameCacheSource <= MemberRoomName {
room.NameCache = ""
}
}
// UpdateState updates the room's current state with the given Event. This will clobber events based
// on the type/state_key combination.
func (room *Room) UpdateState(event *mautrix.Event) {
@ -367,11 +384,6 @@ func (room *Room) UpdateState(event *mautrix.Event) {
room.nameCacheSource = CanonicalAliasRoomName
}
room.CanonicalAliasCache = event.Content.Alias
case mautrix.StateAliases:
if room.nameCacheSource <= AliasRoomName {
room.NameCache = ""
}
room.aliasesCache = nil
case mautrix.StateMember:
if room.nameCacheSource <= MemberRoomName {
room.NameCache = ""
@ -395,7 +407,7 @@ func (room *Room) updateMemberState(event *mautrix.Event) {
}
if room.memberCache != nil {
member := room.eventToMember(userID, &event.Content)
if event.Content.Membership.IsInviteOrJoin() {
if member.Membership.IsInviteOrJoin() {
existingMember, ok := room.memberCache[userID]
if ok {
*existingMember = *member
@ -458,20 +470,6 @@ func (room *Room) GetCanonicalAlias() string {
return room.CanonicalAliasCache
}
// GetAliases returns the list of aliases that point to this room.
func (room *Room) GetAliases() []string {
if room.aliasesCache == nil {
room.lock.RLock()
aliasEvents := room.getStateEvents(mautrix.StateAliases)
room.aliasesCache = []string{}
for _, event := range aliasEvents {
room.aliasesCache = append(room.aliasesCache, event.Content.Aliases...)
}
room.lock.RUnlock()
}
return room.aliasesCache
}
// updateNameFromNameEvent updates the room display name to be the name set in the name event.
func (room *Room) updateNameFromNameEvent() {
nameEvt := room.GetStateEvent(mautrix.StateRoomName, "")
@ -480,19 +478,6 @@ func (room *Room) updateNameFromNameEvent() {
}
}
// updateNameFromAliases updates the room display name to be the first room alias it finds.
//
// Deprecated: the Client-Server API recommends against using non-canonical aliases as display name.
func (room *Room) updateNameFromAliases() {
// TODO the spec says clients should not use m.room.aliases for room names.
// However, Riot also uses m.room.aliases, so this is here now.
aliases := room.GetAliases()
if len(aliases) > 0 {
sort.Sort(sort.StringSlice(aliases))
room.NameCache = aliases[0]
}
}
// updateNameFromMembers updates the room display name based on the members in this room.
//
// The room name depends on the number of users:
@ -533,10 +518,6 @@ func (room *Room) updateNameCache() {
room.NameCache = room.GetCanonicalAlias()
room.nameCacheSource = CanonicalAliasRoomName
}
if len(room.NameCache) == 0 {
room.updateNameFromAliases()
room.nameCacheSource = AliasRoomName
}
if len(room.NameCache) == 0 {
room.updateNameFromMembers()
room.nameCacheSource = MemberRoomName
@ -616,10 +597,16 @@ func (room *Room) createMemberCache() map[string]*mautrix.Member {
}
}
}
if len(room.Summary.Heroes) > 1 {
room.firstMemberCache, _ = cache[room.Summary.Heroes[0]]
}
if len(room.Summary.Heroes) > 2 {
room.secondMemberCache, _ = cache[room.Summary.Heroes[1]]
}
room.lock.RUnlock()
room.lock.Lock()
room.memberCache = cache
room.exMemberCache = cache
room.exMemberCache = exCache
room.lock.Unlock()
return cache
}

View File

@ -112,6 +112,7 @@ func (s *GomuksSyncer) ProcessResponse(res *mautrix.RespSync, since string) (err
for roomID, roomData := range res.Rooms.Join {
room := s.Session.GetRoom(roomID)
room.UpdateSummary(roomData.Summary)
s.processSyncEvents(room, roomData.State.Events, EventSourceJoin|EventSourceState)
s.processSyncEvents(room, roomData.Timeline.Events, EventSourceJoin|EventSourceTimeline)
s.processSyncEvents(room, roomData.Ephemeral.Events, EventSourceJoin|EventSourceEphemeral)
@ -120,22 +121,26 @@ func (s *GomuksSyncer) ProcessResponse(res *mautrix.RespSync, since string) (err
if len(room.PrevBatch) == 0 {
room.PrevBatch = roomData.Timeline.PrevBatch
}
room.LastPrevBatch = roomData.Timeline.PrevBatch
}
for roomID, roomData := range res.Rooms.Invite {
room := s.Session.GetRoom(roomID)
room.UpdateSummary(roomData.Summary)
s.processSyncEvents(room, roomData.State.Events, EventSourceInvite|EventSourceState)
}
for roomID, roomData := range res.Rooms.Leave {
room := s.Session.GetRoom(roomID)
room.HasLeft = true
room.UpdateSummary(roomData.Summary)
s.processSyncEvents(room, roomData.State.Events, EventSourceLeave|EventSourceState)
s.processSyncEvents(room, roomData.Timeline.Events, EventSourceLeave|EventSourceTimeline)
if len(room.PrevBatch) == 0 {
room.PrevBatch = roomData.Timeline.PrevBatch
}
room.LastPrevBatch = roomData.Timeline.PrevBatch
}
if since == "" && s.InitDoneCallback != nil {
@ -207,6 +212,7 @@ func (s *GomuksSyncer) GetFilterJSON(userID string) json.RawMessage {
Room: mautrix.RoomFilter{
IncludeLeave: false,
State: mautrix.FilterPart{
LazyLoadMembers: true,
Types: []string{
"m.room.member",
"m.room.name",
@ -218,6 +224,7 @@ func (s *GomuksSyncer) GetFilterJSON(userID string) json.RawMessage {
},
},
Timeline: mautrix.FilterPart{
LazyLoadMembers: true,
Types: []string{
"m.room.message",
"m.room.redaction",