WIP: Fix: (ement-room--user-display-name) Cache other name types

WIP: This may currently cause some displaynames to not be shown
correctly when loading older messages, so not merging yet.  This gets
complicated...

When a room has many events (e.g. over 1,000), searching the events
for "displayname" events can take a long time.  If we only cache
displaynames from such events, then users without an explicitly set
displayname will cause this search to happen every time this function
is called, e.g. every time a message from such a user is formatted.

So rather than only caching a name from a "displayname" event, we
cache whatever we calculate, and we clear that cache whenever a new
"displayname" event is handled
This commit is contained in:
Adam Porter 2021-08-10 07:51:21 -05:00
parent 836d8a222b
commit af2eee6f97
2 changed files with 37 additions and 14 deletions

View file

@ -71,6 +71,10 @@ Used by `ement-room-send-message'.")
"Hook run in compose buffers when created. "Hook run in compose buffers when created.
Used to, e.g. call `ement-room-compose-org'.") Used to, e.g. call `ement-room-compose-org'.")
(defvar ement-room-in-retro-callback nil
;; TODO: Use this in more event handlers.
"Non-nil when `ement-room-retro-callback' is running.")
(declare-function ement-view-room "ement.el") (declare-function ement-view-room "ement.el")
(declare-function ement-room-list "ement-room-list.el") (declare-function ement-room-list "ement-room-list.el")
(declare-function ement-notify-switch-to-mentions-buffer "ement-notify") (declare-function ement-notify-switch-to-mentions-buffer "ement-notify")
@ -1107,7 +1111,8 @@ reaction string, e.g. \"👍\"."
(declare-function ement--make-event "ement.el") (declare-function ement--make-event "ement.el")
(defun ement-room-retro-callback (room data) (defun ement-room-retro-callback (room data)
"Push new DATA to ROOM on SESSION and add events to room buffer." "Push new DATA to ROOM on SESSION and add events to room buffer."
(pcase-let* (((cl-struct ement-room local) room) (pcase-let* ((ement-room-in-retro-callback t)
((cl-struct ement-room local) room)
((map _start end chunk state) data) ((map _start end chunk state) data)
((map buffer) local) ((map buffer) local)
(num-events (length chunk)) (num-events (length chunk))
@ -1150,6 +1155,7 @@ reaction string, e.g. \"👍\"."
(when-let ((buffer-window (get-buffer-window buffer))) (when-let ((buffer-window (get-buffer-window buffer)))
(select-window buffer-window)) (select-window buffer-window))
;; FIXME: Use retro-loading in event handlers, or in --handle-events, anyway. ;; FIXME: Use retro-loading in event handlers, or in --handle-events, anyway.
(ement-room--handle-events state)
(ement-room--handle-events chunk) (ement-room--handle-events chunk)
(setf (ement-room-prev-batch room) end (setf (ement-room-prev-batch room) end
ement-room-retro-loading nil))))) ement-room-retro-loading nil)))))
@ -1395,17 +1401,28 @@ data slot."
(equal "join" (alist-get 'membership (ement-event-content event))) (equal "join" (alist-get 'membership (ement-event-content event)))
(equal user (ement-event-sender event)) (equal user (ement-event-sender event))
(alist-get 'displayname (ement-event-content event))))) (alist-get 'displayname (ement-event-content event)))))
(if-let* ((displayname (or (cl-loop for event in (ement-room-timeline room) ;; FIXME: As the number of events in a room increases, so does the time it takes
when (join-displayname-event-p event) ;; to search them here. In case a room has many events (like over a thousand),
return (alist-get 'displayname (ement-event-content event))) ;; it can get slow when loading earlier events. Not sure how to fix this.
(cl-loop for event in (ement-room-state room) (let* ((name-event (or (cl-loop for event in (ement-room-timeline room)
when (join-displayname-event-p event) when (join-displayname-event-p event)
return (alist-get 'displayname (ement-event-content event))))) return event)
(calculated-name displayname)) (cl-loop for event in (ement-room-state room)
(puthash room calculated-name (ement-user-room-display-names user)) when (join-displayname-event-p event)
;; No membership state event: use pre-calculated displayname or ID. return event)))
(or (ement-user-displayname user) (name-from-event (when name-event
(ement-user-id user)))))) (alist-get 'displayname (ement-event-content name-event))))
(calculated-name (or name-from-event
;; No membership state event: use pre-calculated displayname or ID.
(ement-user-displayname user)
(ement-user-id user))))
(when name-event
;; We also have to save the latest displayname event so we know whether a newly received displayname
;; event is actually newer, so we know whether to recalculate the cached name in the future.
(setf (ement-user-displayname-event user) name-event))
;; NOTE: When a user changes display name, the cached value in that room
;; needs to be cleared so this function will calculate a new value.
(puthash room calculated-name (ement-user-room-display-names user))))))
(defun ement-room--event-data (id) (defun ement-room--event-data (id)
"Return event struct for event ID in current buffer." "Return event struct for event ID in current buffer."
@ -1532,6 +1549,12 @@ function to `ement-room-event-fns', which see."
(ewoc-set-hf ement-ewoc "" footer)))) (ewoc-set-hf ement-ewoc "" footer))))
(ement-room-defevent "m.room.member" (ement-room-defevent "m.room.member"
(when (alist-get 'displayname (ement-event-content event))
(unless (ement-user-displayname-event (ement-event-sender event))
;; User had no previously seen displayname event: clear cached
;; displayname to cause it to be recalculated.
;; FIXME: Pass room and session to function instead of getting from room buffer.
(puthash ement-room nil (ement-user-room-display-names (ement-event-sender event)))))
(with-silent-modifications (with-silent-modifications
(ement-room--insert-event event))) (ement-room--insert-event event)))

View file

@ -39,8 +39,8 @@
(cl-defstruct ement-user (cl-defstruct ement-user
id displayname account-data room-display-names id displayname account-data room-display-names
color color
username ;; NOTE: Not exactly according to spec, I guess, but useful for now. username ;; NOTE: Not exactly according to spec, I guess, but useful for now.
) displayname-event)
(cl-defstruct ement-event (cl-defstruct ement-event
id sender content origin-server-ts type unsigned id sender content origin-server-ts type unsigned