aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTulir Asokan <tulir@maunium.net>2020-02-22 00:03:57 +0200
committerTulir Asokan <tulir@maunium.net>2020-02-22 00:03:57 +0200
commit442fdac4d5b949e556e94b0be53f2208709e8bf3 (patch)
treef63cb447525cdc15a4d733f857aefc82a0c9a7b7
parent032a83d70bec5b87605e04c755c678ec01a0de11 (diff)
Enable lazy loading of members
-rw-r--r--go.mod4
-rw-r--r--go.sum4
-rw-r--r--interface/matrix.go1
-rw-r--r--matrix/matrix.go15
-rw-r--r--matrix/rooms/room.go73
-rw-r--r--matrix/sync.go7
-rw-r--r--ui/member-list.go38
-rw-r--r--ui/view-main.go11
8 files changed, 104 insertions, 49 deletions
diff --git a/go.mod b/go.mod
index 78cea34..95bfaca 100644
--- a/go.mod
+++ b/go.mod
@@ -19,7 +19,7 @@ require (
golang.org/x/net v0.0.0-20200202094626-16171245cfb2
gopkg.in/toast.v1 v1.0.0-20180812000517-0a84660828b2
gopkg.in/yaml.v2 v2.2.8
- maunium.net/go/mautrix v0.1.0-alpha.3.0.20200220001222-8dc3dd5d538d
- maunium.net/go/mauview v0.0.0-20200220201003-92b19f8819b4
+ maunium.net/go/mautrix v0.1.0-alpha.3.0.20200221220303-b441ba9359cf
+ maunium.net/go/mauview v0.0.0-20200220222850-39f1414676d9
maunium.net/go/tcell v1.1.2-0.20200218183045-87c4a25c5b09
)
diff --git a/go.sum b/go.sum
index a13fd38..d7ca8f4 100644
--- a/go.sum
+++ b/go.sum
@@ -82,6 +82,8 @@ maunium.net/go/mautrix v0.1.0-alpha.3.0.20200219230859-de66c34ea5bc h1:1iMzqdMF4
maunium.net/go/mautrix v0.1.0-alpha.3.0.20200219230859-de66c34ea5bc/go.mod h1:g10T1fh2Q2HkJWycVs93eBXdWpqD67f1YVQhNxdIDr4=
maunium.net/go/mautrix v0.1.0-alpha.3.0.20200220001222-8dc3dd5d538d h1:doAHXnYCIgNy4qAgReZRRb3EaWR4D0w+Zs2y959Z8Uk=
maunium.net/go/mautrix v0.1.0-alpha.3.0.20200220001222-8dc3dd5d538d/go.mod h1:g10T1fh2Q2HkJWycVs93eBXdWpqD67f1YVQhNxdIDr4=
+maunium.net/go/mautrix v0.1.0-alpha.3.0.20200221220303-b441ba9359cf h1:ojEsISqRLmM9PRIJiVDTRHNmj5IZoXn3E64S+2uTJNw=
+maunium.net/go/mautrix v0.1.0-alpha.3.0.20200221220303-b441ba9359cf/go.mod h1:g10T1fh2Q2HkJWycVs93eBXdWpqD67f1YVQhNxdIDr4=
maunium.net/go/mauview v0.0.0-20200218183549-88ecb1321176 h1:KoTm7ASEzFIZ1SvPWuWYzpkeA+wiR1fuUu4l7TCHcE0=
maunium.net/go/mauview v0.0.0-20200218183549-88ecb1321176/go.mod h1:jwg3Ow7akzsCX3q38pZAfmEC5gGN8gXwMyyjy/yZVMg=
maunium.net/go/mauview v0.0.0-20200218231215-04d01c601d5b h1:Bfov5IkJQpkqDexiFioHIZpx4XL7AILDA1GwLVdqtBw=
@@ -92,5 +94,7 @@ maunium.net/go/mauview v0.0.0-20200219222453-b984e20438e6 h1:yYs5rsnDQrZie4eeWlc
maunium.net/go/mauview v0.0.0-20200219222453-b984e20438e6/go.mod h1:jwg3Ow7akzsCX3q38pZAfmEC5gGN8gXwMyyjy/yZVMg=
maunium.net/go/mauview v0.0.0-20200220201003-92b19f8819b4 h1:60G4iPYhO5Z4qkcniM+xPBeXNmuyD1tqXzj8ryeEdWY=
maunium.net/go/mauview v0.0.0-20200220201003-92b19f8819b4/go.mod h1:jwg3Ow7akzsCX3q38pZAfmEC5gGN8gXwMyyjy/yZVMg=
+maunium.net/go/mauview v0.0.0-20200220222850-39f1414676d9 h1:xwuAYvp2fdCNJHe4bj04BjKFRAX390gZUK21x6NoePM=
+maunium.net/go/mauview v0.0.0-20200220222850-39f1414676d9/go.mod h1:jwg3Ow7akzsCX3q38pZAfmEC5gGN8gXwMyyjy/yZVMg=
maunium.net/go/tcell v1.1.2-0.20200218183045-87c4a25c5b09 h1:hu+R+0nodoZPS19WGyYiw/d63+/NQS/R3Duw3d9HqAU=
maunium.net/go/tcell v1.1.2-0.20200218183045-87c4a25c5b09/go.mod h1:Ru7KmI5AU7xHUx6hGltgJvknrS+8jlGGMKK15pZuc9k=
diff --git a/interface/matrix.go b/interface/matrix.go
index af20509..0b1278d 100644
--- a/interface/matrix.go
+++ b/interface/matrix.go
@@ -43,6 +43,7 @@ type MatrixContainer interface {
LeaveRoom(roomID string) error
CreateRoom(req *mautrix.ReqCreateRoom) (*rooms.Room, error)
+ FetchMembers(room *rooms.Room) error
GetHistory(room *rooms.Room, limit int) ([]*event.Event, error)
GetEvent(room *rooms.Room, eventID string) (*event.Event, error)
GetRoom(roomID string) *rooms.Room
diff --git a/matrix/matrix.go b/matrix/matrix.go
index f0009bc..d3edde5 100644
--- a/matrix/matrix.go
+++ b/matrix/matrix.go
@@ -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 {
diff --git a/matrix/rooms/room.go b/matrix/rooms/room.go
index 4632730..9081ba5 100644
--- a/matrix/rooms/room.go
+++ b/matrix/rooms/room.go
@@ -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:
@@ -534,10 +519,6 @@ func (room *Room) updateNameCache() {
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
}
diff --git a/matrix/sync.go b/matrix/sync.go
index 622a235..564848b 100644
--- a/matrix/sync.go
+++ b/matrix/sync.go
@@ -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",
diff --git a/ui/member-list.go b/ui/member-list.go
index a96436d..b607a32 100644
--- a/ui/member-list.go
+++ b/ui/member-list.go
@@ -17,6 +17,7 @@
package ui
import (
+ "math"
"sort"
"strings"
@@ -40,6 +41,7 @@ func NewMemberList() *MemberList {
type memberListItem struct {
mautrix.Member
PowerLevel int
+ Sigil rune
UserID string
Color tcell.Color
}
@@ -64,11 +66,35 @@ func (rml roomMemberList) Swap(i, j int) {
func (ml *MemberList) Update(data map[string]*mautrix.Member, levels *mautrix.PowerLevels) *MemberList {
ml.list = make(roomMemberList, len(data))
i := 0
+ highestLevel := math.MinInt32
+ count := 0
+ for _, level := range levels.Users {
+ if level > highestLevel {
+ highestLevel = level
+ count = 1
+ } else if level == highestLevel {
+ count++
+ }
+ }
for userID, member := range data {
+ level := levels.GetUserLevel(userID)
+ sigil := ' '
+ if level == highestLevel && count == 1 {
+ sigil = '~'
+ } else if level > levels.StateDefault() {
+ sigil = '&'
+ } else if level >= levels.Ban() {
+ sigil = '@'
+ } else if level >= levels.Kick() || level >= levels.Redact() {
+ sigil = '%'
+ } else if level > levels.UsersDefault {
+ sigil = '+'
+ }
ml.list[i] = &memberListItem{
Member: *member,
UserID: userID,
- PowerLevel: levels.GetUserLevel(userID),
+ PowerLevel: level,
+ Sigil: sigil,
Color: widget.GetHashColor(userID),
}
i++
@@ -79,17 +105,21 @@ func (ml *MemberList) Update(data map[string]*mautrix.Member, levels *mautrix.Po
func (ml *MemberList) Draw(screen mauview.Screen) {
width, _ := screen.Size()
+ sigilStyle := tcell.StyleDefault.Background(tcell.ColorGreen).Foreground(tcell.ColorWhite)
for y, member := range ml.list {
+ if member.Sigil != ' ' {
+ screen.SetCell(0, y, sigilStyle, member.Sigil)
+ }
if member.Membership == "invite" {
- widget.WriteLineSimpleColor(screen, member.Displayname, 1, y, member.Color)
- screen.SetCell(0, y, tcell.StyleDefault, '(')
+ screen.SetCell(1, y, tcell.StyleDefault, '(')
if sw := runewidth.StringWidth(member.Displayname); sw < width-1 {
screen.SetCell(sw+1, y, tcell.StyleDefault, ')')
} else {
screen.SetCell(width-1, y, tcell.StyleDefault, ')')
}
+ widget.WriteLineSimpleColor(screen, member.Displayname, 2, y, member.Color)
} else {
- widget.WriteLineSimpleColor(screen, member.Displayname, 0, y, member.Color)
+ widget.WriteLineSimpleColor(screen, member.Displayname, 1, y, member.Color)
}
}
}
diff --git a/ui/view-main.go b/ui/view-main.go
index 507333a..30fa982 100644
--- a/ui/view-main.go
+++ b/ui/view-main.go
@@ -276,6 +276,17 @@ func (view *MainView) switchRoom(tag string, room *rooms.Room, lock bool) {
msgView.initialHistoryLoaded = true
go view.LoadHistory(room.ID)
}
+ if !room.MembersFetched {
+ go func() {
+ err := view.matrix.FetchMembers(room)
+ if err != nil {
+ debug.Print("Error fetching members:", err)
+ return
+ }
+ roomView.UpdateUserList()
+ view.parent.Render()
+ }()
+ }
}
func (view *MainView) addRoomPage(room *rooms.Room) *RoomView {