aboutsummaryrefslogtreecommitdiff
path: root/matrix
diff options
context:
space:
mode:
Diffstat (limited to 'matrix')
-rw-r--r--matrix/matrix.go29
-rw-r--r--matrix/rooms/room.go108
-rw-r--r--matrix/rooms/roomcache.go32
3 files changed, 124 insertions, 45 deletions
diff --git a/matrix/matrix.go b/matrix/matrix.go
index de99801..8c19b24 100644
--- a/matrix/matrix.go
+++ b/matrix/matrix.go
@@ -221,7 +221,15 @@ func (c *Container) OnLogin() {
c.syncer.InitDoneCallback = func() {
debug.Print("Initial sync done")
c.config.AuthCache.InitialSyncDone = true
- c.config.SaveAuthCache()
+ debug.Print("Updating title caches")
+ for _, room := range c.config.Rooms.Map {
+ room.GetTitle()
+ }
+ debug.Print("Cleaning cached rooms from memory")
+ c.config.Rooms.ForceClean()
+ debug.Print("Saving all data")
+ c.config.SaveAll()
+ debug.Print("Adding rooms to UI")
c.ui.MainView().SetRooms(c.config.Rooms)
c.ui.Render()
}
@@ -294,17 +302,21 @@ func (c *Container) SendPreferencesToMatrix() {
// HandleMessage is the event handler for the m.room.message timeline event.
func (c *Container) HandleMessage(source EventSource, evt *mautrix.Event) {
- if source&EventSourceLeave != 0 || source&EventSourceState != 0 {
+ room := c.GetOrCreateRoom(evt.RoomID)
+ if source&EventSourceLeave != 0 {
+ room.HasLeft = true
+ return
+ } else if source&EventSourceState != 0 {
return
}
- room := c.GetOrCreateRoom(evt.RoomID)
err := c.history.Append(room, []*mautrix.Event{evt})
if err != nil {
debug.Printf("Failed to add event %s to history: %v", evt.ID, err)
}
- if !c.config.AuthCache.InitialSyncDone {
+ if !c.config.AuthCache.InitialSyncDone || !room.Loaded() {
+ room.LastReceivedMessage = time.Unix(evt.Timestamp/1000, evt.Timestamp%1000*1000)
return
}
@@ -327,7 +339,7 @@ func (c *Container) HandleMessage(source EventSource, evt *mautrix.Event) {
c.ui.Render()
}
} else {
- debug.Printf("Parsing event %s type %s %v from %s in %s failed (ParseEvent() returned nil).", evt.ID, evt.Type, evt.Content.Raw, evt.Sender, evt.RoomID)
+ debug.Printf("Parsing event %s type %s %v from %s in %s failed (ParseEvent() returned nil).", evt.ID, evt.Type.String(), evt.Content.Raw, evt.Sender, evt.RoomID)
}
}
@@ -335,6 +347,9 @@ func (c *Container) HandleMessage(source EventSource, evt *mautrix.Event) {
func (c *Container) HandleMembership(source EventSource, evt *mautrix.Event) {
isLeave := source&EventSourceLeave != 0
isTimeline := source&EventSourceTimeline != 0
+ if isLeave {
+ c.GetOrCreateRoom(evt.RoomID).HasLeft = true
+ }
isNonTimelineLeave := isLeave && !isTimeline
if !c.config.AuthCache.InitialSyncDone && isNonTimelineLeave {
return
@@ -437,7 +452,7 @@ func (c *Container) parseDirectChatInfo(evt *mautrix.Event) map[*rooms.Room]bool
continue
}
- room := c.GetRoom(roomID)
+ room := c.GetOrCreateRoom(roomID)
if room != nil && !room.HasLeft {
directChats[room] = true
}
@@ -473,7 +488,7 @@ func (c *Container) HandlePushRules(source EventSource, evt *mautrix.Event) {
// HandleTag is the event handler for the m.tag account data event.
func (c *Container) HandleTag(source EventSource, evt *mautrix.Event) {
- room := c.config.GetRoom(evt.RoomID)
+ room := c.GetOrCreateRoom(evt.RoomID)
newTags := make([]rooms.RoomTag, len(evt.Content.RoomTags))
index := 0
diff --git a/matrix/rooms/room.go b/matrix/rooms/room.go
index 87c3780..972a32a 100644
--- a/matrix/rooms/room.go
+++ b/matrix/rooms/room.go
@@ -115,6 +115,12 @@ type Room struct {
cache *RoomCache
// Lock for state and other room stuff.
lock sync.RWMutex
+ // Function to call when room state is unloaded.
+ onUnload func() bool
+ // Function to call when room state is loaded.
+ onLoad func() bool
+ // Whether or not the room state has changed
+ changed bool
// Room state cache linked list.
prev *Room
@@ -133,10 +139,13 @@ func (room *Room) Loaded() bool {
}
func (room *Room) Load() {
+ room.cache.TouchNode(room)
if room.Loaded() {
return
}
- room.cache.TouchNode(room)
+ if room.onLoad != nil && !room.onLoad() {
+ return
+ }
room.lock.Lock()
room.load()
room.lock.Unlock()
@@ -146,7 +155,7 @@ func (room *Room) load() {
if room.Loaded() {
return
}
- debug.Print("Loading state for room", room.ID)
+ debug.Print("Loading state for room", room.ID, "from disk")
room.state = make(map[mautrix.EventType]map[string]*mautrix.Event)
file, err := os.OpenFile(room.path, os.O_RDONLY, 0600)
if err != nil {
@@ -168,9 +177,17 @@ func (room *Room) load() {
if err = dec.Decode(&room.state); err != nil {
debug.Print("Failed to decode room state:", err)
}
+ room.changed = false
}
-func (room *Room) Unload() {
+func (room *Room) Touch() {
+ room.cache.TouchNode(room)
+}
+
+func (room *Room) Unload() bool {
+ if room.onUnload != nil && !room.onUnload() {
+ return false
+ }
debug.Print("Unloading", room.ID)
room.Save()
room.state = nil
@@ -179,14 +196,27 @@ func (room *Room) Unload() {
room.canonicalAliasCache = ""
room.firstMemberCache = nil
room.secondMemberCache = nil
+ return true
+}
+
+func (room *Room) SetOnUnload(fn func() bool) {
+ room.onUnload = fn
+}
+
+func (room *Room) SetOnLoad(fn func() bool) {
+ room.onLoad = fn
}
func (room *Room) Save() {
if !room.Loaded() {
- debug.Print("Failed to save room state: room not loaded")
+ debug.Print("Failed to save room", room.ID, "state: room not loaded")
+ return
+ }
+ if !room.changed {
+ debug.Print("Not saving", room.ID, "as state hasn't changed")
return
}
- debug.Print("Saving state for room", room.ID)
+ debug.Print("Saving state for room", room.ID, "to disk")
file, err := os.OpenFile(room.path, os.O_WRONLY|os.O_CREATE, 0600)
if err != nil {
debug.Print("Failed to open room state file for writing:", err)
@@ -298,40 +328,51 @@ func (room *Room) UpdateState(event *mautrix.Event) {
room.Load()
room.lock.Lock()
defer room.lock.Unlock()
+ room.changed = true
_, exists := room.state[event.Type]
if !exists {
room.state[event.Type] = make(map[string]*mautrix.Event)
}
switch event.Type {
case mautrix.StateRoomName:
- room.NameCache = ""
+ room.NameCache = event.Content.Name
+ room.nameCacheSource = ExplicitRoomName
case mautrix.StateCanonicalAlias:
if room.nameCacheSource <= CanonicalAliasRoomName {
- room.NameCache = ""
+ room.NameCache = event.Content.Alias
+ room.nameCacheSource = CanonicalAliasRoomName
}
- room.canonicalAliasCache = ""
+ room.canonicalAliasCache = event.Content.Alias
case mautrix.StateAliases:
if room.nameCacheSource <= AliasRoomName {
room.NameCache = ""
}
room.aliasesCache = nil
case mautrix.StateMember:
- room.memberCache = nil
- room.firstMemberCache = nil
- room.secondMemberCache = nil
+ if room.memberCache != nil {
+ userID := event.GetStateKey()
+ if event.Content.Membership == mautrix.MembershipLeave || event.Content.Membership == mautrix.MembershipBan {
+ delete(room.memberCache, userID)
+ } else if event.Content.Membership == mautrix.MembershipInvite || event.Content.Membership == mautrix.MembershipJoin {
+ member := room.eventToMember(userID, &event.Content)
+ existingMember, ok := room.memberCache[userID]
+ if ok {
+ *existingMember = *member
+ } else {
+ room.memberCache[userID] = member
+ room.updateNthMemberCache(userID, member)
+ }
+ }
+ }
if room.nameCacheSource <= MemberRoomName {
room.NameCache = ""
}
case mautrix.StateTopic:
- room.topicCache = ""
+ room.topicCache = event.Content.Topic
}
- stateKey := ""
- if event.StateKey != nil {
- stateKey = *event.StateKey
- }
if event.Type != mautrix.StateMember {
- debug.Printf("Updating state %s#%s for %s", event.Type, stateKey, room.ID)
+ debug.Printf("Updating state %s#%s for %s", event.Type.String(), event.GetStateKey(), room.ID)
}
if event.StateKey == nil {
@@ -477,6 +518,25 @@ func (room *Room) GetTitle() string {
return room.NameCache
}
+func (room *Room) eventToMember(userID string, content *mautrix.Content) *mautrix.Member {
+ member := &content.Member
+ member.Membership = content.Membership
+ if len(member.Displayname) == 0 {
+ member.Displayname = userID
+ }
+ return member
+}
+
+func (room *Room) updateNthMemberCache(userID string, member *mautrix.Member) {
+ if userID != room.SessionUserID {
+ if room.firstMemberCache == nil {
+ room.firstMemberCache = member
+ } else if room.secondMemberCache == nil {
+ room.secondMemberCache = member
+ }
+ }
+}
+
// createMemberCache caches all member events into a easily processable MXID -> *Member map.
func (room *Room) createMemberCache() map[string]*mautrix.Member {
if len(room.memberCache) > 0 {
@@ -489,20 +549,10 @@ func (room *Room) createMemberCache() map[string]*mautrix.Member {
room.secondMemberCache = nil
if events != nil {
for userID, event := range events {
- member := &event.Content.Member
- member.Membership = event.Content.Membership
- if len(member.Displayname) == 0 {
- member.Displayname = userID
- }
- if userID != room.SessionUserID {
- if room.firstMemberCache == nil {
- room.firstMemberCache = member
- } else if room.secondMemberCache == nil {
- room.secondMemberCache = member
- }
- }
+ member := room.eventToMember(userID, &event.Content)
if member.Membership == mautrix.MembershipJoin || member.Membership == mautrix.MembershipInvite {
cache[userID] = member
+ room.updateNthMemberCache(userID, member)
}
}
}
diff --git a/matrix/rooms/roomcache.go b/matrix/rooms/roomcache.go
index 03e3ad8..6fc400c 100644
--- a/matrix/rooms/roomcache.go
+++ b/matrix/rooms/roomcache.go
@@ -106,7 +106,7 @@ func (cache *RoomCache) LoadList() error {
func (cache *RoomCache) SaveLoadedRooms() {
cache.Lock()
defer cache.Unlock()
- cache.clean()
+ cache.clean(false)
for node := cache.head; node != nil; node = node.prev {
node.Save()
}
@@ -194,8 +194,7 @@ func (cache *RoomCache) GetOrCreate(roomID string) *Room {
func (cache *RoomCache) get(roomID string) *Room {
node, ok := cache.Map[roomID]
- if ok && node != nil && node.Loaded() {
- cache.touch(node)
+ if ok && node != nil {
return node
}
return nil
@@ -273,18 +272,29 @@ func (cache *RoomCache) llPush(node *Room) {
cache.tail = node
}
cache.size++
- cache.clean()
+ cache.clean(false)
+}
+
+func (cache *RoomCache) ForceClean() {
+ cache.Lock()
+ cache.clean(true)
+ cache.Unlock()
}
-func (cache *RoomCache) clean() {
+func (cache *RoomCache) clean(force bool) {
origSize := cache.size
maxTS := time.Now().Unix() - cache.maxAge
for cache.size > cache.maxSize {
- if cache.tail.touch > maxTS {
+ if cache.tail.touch > maxTS && !force {
break
}
- cache.tail.Unload()
- cache.llPop(cache.tail)
+ ok := cache.tail.Unload()
+ node := cache.tail
+ cache.llPop(node)
+ if !ok {
+ debug.Print("Unload returned false, pushing node back")
+ cache.llPush(node)
+ }
}
if cleaned := origSize - cache.size; cleaned > 0 {
debug.Print("Cleaned", cleaned, "rooms")
@@ -295,7 +305,11 @@ func (cache *RoomCache) Unload(node *Room) {
cache.Lock()
defer cache.Unlock()
cache.llPop(node)
- node.Unload()
+ ok := node.Unload()
+ if !ok {
+ debug.Print("Unload returned false, pushing node back")
+ cache.llPush(node)
+ }
}
func (cache *RoomCache) newRoom(roomID string) *Room {