Skip to content

Commit

Permalink
Fix: Persist session data for reconnect
Browse files Browse the repository at this point in the history
When disconnecting from a session, we now keep the slots necessary for
reconnecting, and we persist those slots.

Previously all of the session's data was discarded after writing, so
if multiple accounts were disconnected but not at the same time, the
first session to be disconnected was forgotten.

Fixes #243.

Reported-by: formula-spectre <https://github.com/formula-spectre>
  • Loading branch information
alphapapa committed Oct 13, 2024
1 parent e78ad47 commit e7acf29
Showing 1 changed file with 27 additions and 8 deletions.
35 changes: 27 additions & 8 deletions ement.el
Original file line number Diff line number Diff line change
Expand Up @@ -350,9 +350,6 @@ in them won't work."
(interactive (list (if current-prefix-arg
(mapcar #'cdr ement-sessions)
(list (ement-complete-session)))))
(when ement-save-sessions
;; Write sessions before we remove them from the variable.
(ement--write-sessions ement-sessions))
(dolist (session sessions)
(let ((user-id (ement-user-id (ement-session-user session))))
(when-let ((process (map-elt ement-syncs session)))
Expand All @@ -362,11 +359,16 @@ in them won't work."
(delete-process process))
;; NOTE: I'd like to use `map-elt' here, but not until
;; <https://debbugs.gnu.org/cgi/bugreport.cgi?bug=47368> is fixed, I guess.
(setf (alist-get session ement-syncs nil nil #'equal) nil
(alist-get user-id ement-sessions nil 'remove #'equal) nil)))
(unless ement-sessions
;; HACK: If no sessions remain, clear the users table. It might be best
;; to store a per-session users table, but this is probably good enough.
(setf (alist-get session ement-syncs) nil
;; Set the session to an "emptied" one, which only retains slots needed to
;; reconnect.
(alist-get user-id ement-sessions nil nil #'equal) (ement--emptied session))))
(when ement-save-sessions
;; Write sessions now that we have emptied the session.
(ement--write-sessions ement-sessions))
(unless (cl-some #'ement-session-has-synced-p ement-sessions :key #'cdr)
;; HACK: If no connected sessions remain, clear the users table. It might be best to
;; store a per-session users table, but this is probably good enough.
(clrhash ement-users))
;; TODO: Should call this hook for each session with the session as argument.
(run-hooks 'ement-disconnect-hook)
Expand Down Expand Up @@ -873,6 +875,7 @@ Returns nil if unable to read `ement-sessions-file'."
:token token
:transaction-id transaction-id))))
(message "Ement: Writing sessions...")
;; TODO: Use `persist'.
(with-temp-file ement-sessions-file
(pcase-let* ((print-level nil)
(print-length nil)
Expand All @@ -885,6 +888,22 @@ Returns nil if unable to read `ement-sessions-file'."
;; Ensure permissions are safe.
(chmod ement-sessions-file #o600)))

(cl-defmethod ement--emptied ((session ement-session))
"Return a copy of SESSION with most slots nulled.
The copy only includes these slots: user, server, token, and
transaction-id. This is suitable for persisting upon disconnect
so the session can be reconnected, but allowing most data to be
garbage-collected."
(pcase-let* (((cl-struct ement-session user server token transaction-id) session)
((cl-struct ement-user (id user-id) username) user)
((cl-struct ement-server (name server-name) uri-prefix) server))
(make-ement-session :user (list :id user-id
:username username)
:server (list :name server-name
:uri-prefix uri-prefix)
:token token
:transaction-id transaction-id)))

(defun ement--kill-emacs-hook ()
"Function to be added to `kill-emacs-hook'.
Writes Ement session to disk when enabled."
Expand Down

0 comments on commit e7acf29

Please sign in to comment.