feat: integrate SSE with message reception pipeline
This commit is contained in:
+25
-41
@@ -2,31 +2,22 @@
|
|||||||
|
|
||||||
;;; Commentary:
|
;;; Commentary:
|
||||||
|
|
||||||
;; Fetches new envelopes from signal-cli via the receive JSON-RPC method
|
;; Fetches new envelopes from signal-cli via SSE or JSON-RPC
|
||||||
;; and stores them in the local database: incoming messages, messages
|
;; and stores them in the local database: incoming messages, messages
|
||||||
;; sent from other linked devices (sync), delivery/read receipts, and
|
;; sent from other linked devices (sync), delivery/read receipts, and
|
||||||
;; typing indicators. `noise-receive-start-polling' polls on a timer.
|
;; typing indicators. `noise-receive-start-sse' connects to the SSE
|
||||||
|
;; endpoint for real-time message reception.
|
||||||
|
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
|
||||||
(require 'noise-rpc)
|
(require 'noise-rpc)
|
||||||
(require 'noise-db)
|
(require 'noise-db)
|
||||||
(require 'noise-conversation)
|
(require 'noise-conversation)
|
||||||
|
(require 'noise-sse)
|
||||||
(require 'cl-lib)
|
(require 'cl-lib)
|
||||||
|
|
||||||
(declare-function noise-chat-list--render "noise-chat-list")
|
(declare-function noise-chat-list--render "noise-chat-list")
|
||||||
|
|
||||||
(defcustom noise-receive-interval 5
|
|
||||||
"Seconds between automatic polls of signal-cli for new messages."
|
|
||||||
:type 'integer
|
|
||||||
:group 'noise)
|
|
||||||
|
|
||||||
(defvar noise-receive--timer nil
|
|
||||||
"Active polling timer, or nil.")
|
|
||||||
|
|
||||||
(defvar noise-receive--last-poll-error nil
|
|
||||||
"Last error message shown by the poller, to avoid repeating it.")
|
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun noise-receive ()
|
(defun noise-receive ()
|
||||||
"Fetch and store new envelopes from signal-cli.
|
"Fetch and store new envelopes from signal-cli.
|
||||||
@@ -53,38 +44,31 @@ Returns the number of new messages stored."
|
|||||||
(message "Received %d new message%s" new (if (= new 1) "" "s")))
|
(message "Received %d new message%s" new (if (= new 1) "" "s")))
|
||||||
new))
|
new))
|
||||||
|
|
||||||
|
(defun noise-receive--handle-sse-event (event)
|
||||||
|
"Handle an SSE EVENT from signal-cli.
|
||||||
|
Processes the envelope and updates UI."
|
||||||
|
(noise-db-init)
|
||||||
|
(when-let ((envelope (noise-receive--field event "envelope")))
|
||||||
|
(when-let ((conv-id (noise-receive--process-envelope envelope)))
|
||||||
|
(noise-conversation-refresh-for conv-id)
|
||||||
|
(when-let ((buf (get-buffer "*signal*")))
|
||||||
|
(with-current-buffer buf
|
||||||
|
(noise-chat-list--render))))))
|
||||||
|
|
||||||
|
;; Override the default handler in noise-sse
|
||||||
|
(setq noise-sse--handle-event #'noise-receive--handle-sse-event)
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun noise-receive-start-polling ()
|
(defun noise-receive-start-sse ()
|
||||||
"Start polling signal-cli for new messages every `noise-receive-interval'."
|
"Start receiving messages via SSE."
|
||||||
(interactive)
|
(interactive)
|
||||||
(noise-receive-stop-polling)
|
(noise-sse-connect))
|
||||||
(setq noise-receive--timer
|
|
||||||
(run-with-timer 0 noise-receive-interval #'noise-receive--poll)))
|
|
||||||
|
|
||||||
(defun noise-receive-stop-polling ()
|
;;;###autoload
|
||||||
"Stop the message polling timer."
|
(defun noise-receive-stop-sse ()
|
||||||
|
"Stop receiving messages via SSE."
|
||||||
(interactive)
|
(interactive)
|
||||||
(when noise-receive--timer
|
(noise-sse-disconnect))
|
||||||
(cancel-timer noise-receive--timer)
|
|
||||||
(setq noise-receive--timer nil)))
|
|
||||||
|
|
||||||
(defun noise-receive--poll ()
|
|
||||||
"Poll for messages.
|
|
||||||
Errors are shown in the echo area once per distinct error rather than
|
|
||||||
on every poll, and never abort the timer."
|
|
||||||
(condition-case err
|
|
||||||
(progn
|
|
||||||
(noise-receive)
|
|
||||||
(setq noise-receive--last-poll-error nil))
|
|
||||||
(error
|
|
||||||
(let ((text (error-message-string err)))
|
|
||||||
(unless (equal text noise-receive--last-poll-error)
|
|
||||||
(setq noise-receive--last-poll-error text)
|
|
||||||
(message "Noise: receiving failed: %s%s"
|
|
||||||
text
|
|
||||||
(if (string-match-p "account parameter" text)
|
|
||||||
" — set `noise-account' or run M-x noise-select-account"
|
|
||||||
"")))))))
|
|
||||||
|
|
||||||
;;; Envelope processing
|
;;; Envelope processing
|
||||||
|
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
;;; noise-receive-poll-test.el --- Tests for the receive poller -*- lexical-binding: t; -*-
|
|
||||||
|
|
||||||
(require 'ert)
|
|
||||||
(require 'noise-receive)
|
|
||||||
|
|
||||||
(ert-deftest noise-receive--poll-surfaces-error-once ()
|
|
||||||
"A failing poll messages the user once, not on every retry."
|
|
||||||
(let ((noise-receive--last-poll-error nil)
|
|
||||||
(messages nil))
|
|
||||||
(cl-letf (((symbol-function 'noise-receive)
|
|
||||||
(lambda ()
|
|
||||||
(signal 'noise-rpc-error
|
|
||||||
'("signal-cli error -32602: Method requires valid account parameter"))))
|
|
||||||
((symbol-function 'message)
|
|
||||||
(lambda (fmt &rest args)
|
|
||||||
(push (apply #'format fmt args) messages))))
|
|
||||||
(noise-receive--poll)
|
|
||||||
(noise-receive--poll))
|
|
||||||
(should (= 1 (length messages)))
|
|
||||||
(should (string-match-p "account parameter" (car messages)))
|
|
||||||
;; the hint points at the fix
|
|
||||||
(should (string-match-p "noise-select-account" (car messages)))))
|
|
||||||
|
|
||||||
(ert-deftest noise-receive--poll-recovers-and-resets ()
|
|
||||||
"After a successful poll, a recurring error is shown again."
|
|
||||||
(let ((noise-receive--last-poll-error nil)
|
|
||||||
(messages nil)
|
|
||||||
(fail t))
|
|
||||||
(cl-letf (((symbol-function 'noise-receive)
|
|
||||||
(lambda ()
|
|
||||||
(when fail
|
|
||||||
(signal 'noise-rpc-error '("connection refused")))
|
|
||||||
0))
|
|
||||||
((symbol-function 'message)
|
|
||||||
(lambda (fmt &rest args)
|
|
||||||
(push (apply #'format fmt args) messages))))
|
|
||||||
(noise-receive--poll) ; error -> message
|
|
||||||
(setq fail nil)
|
|
||||||
(noise-receive--poll) ; success -> resets
|
|
||||||
(setq fail t)
|
|
||||||
(noise-receive--poll)) ; error again -> message again
|
|
||||||
(should (= 2 (length messages)))))
|
|
||||||
Reference in New Issue
Block a user