From 869f4cb67b5c9974939b691ffbc3937dea0aa34c Mon Sep 17 00:00:00 2001 From: James Brechtel Date: Thu, 11 Jun 2026 12:42:10 -0400 Subject: [PATCH] feat: add SSE event parsing for signal-cli --- noise-sse.el | 30 ++++++++++++++++++++++++++++++ test/noise-sse-test.el | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 noise-sse.el create mode 100644 test/noise-sse-test.el diff --git a/noise-sse.el b/noise-sse.el new file mode 100644 index 0000000..fd76c52 --- /dev/null +++ b/noise-sse.el @@ -0,0 +1,30 @@ +;;; noise-sse.el --- SSE client for signal-cli -*- lexical-binding: t; -*- + +;;; Commentary: + +;; Implements Server-Sent Events client for receiving real-time messages +;; from signal-cli daemon's /api/v1/events endpoint. + +;;; Code: + +(require 'url) +(require 'json) +(require 'cl-lib) + +(defun noise-sse--parse-event (event-string) + "Parse an SSE EVENT-STRING into a hash table. +Returns nil for empty or invalid events." + (when (and event-string (not (string-empty-p event-string))) + (let ((lines (split-string event-string "\n")) + (data-lines '())) + (dolist (line lines) + (when (string-prefix-p "data: " line) + (push (substring line 6) data-lines))) + (when data-lines + (let ((json-str (mapconcat #'identity (nreverse data-lines) ""))) + (condition-case nil + (json-parse-string json-str) + (error nil))))))) + +(provide 'noise-sse) +;;; noise-sse.el ends here diff --git a/test/noise-sse-test.el b/test/noise-sse-test.el new file mode 100644 index 0000000..ee054e1 --- /dev/null +++ b/test/noise-sse-test.el @@ -0,0 +1,33 @@ +;;; noise-sse-test.el --- Tests for SSE client -*- lexical-binding: t; -*- + +;;; Commentary: + +;; Tests for noise-sse.el SSE event parsing and connection management. + +;;; Code: + +(require 'ert) +(require 'noise-sse) + +(ert-deftest noise-sse--parse-event-basic () + "Parse a basic SSE event with data field." + (let ((event "data: {\"type\":\"message\",\"content\":\"hello\"}\n\n")) + (let ((result (noise-sse--parse-event event))) + (should (hash-table-p result)) + (should (equal (gethash "type" result) "message")) + (should (equal (gethash "content" result) "hello"))))) + +(ert-deftest noise-sse--parse-event-multiline () + "Parse SSE event with multiline data." + (let ((event "data: {\"type\":\"message\",\ndata: \"content\":\"hello\"}\n\n")) + (let ((result (noise-sse--parse-event event))) + (should (hash-table-p result)) + (should (equal (gethash "type" result) "message"))))) + +(ert-deftest noise-sse--parse-event-empty () + "Parse empty SSE event returns nil." + (let ((event "\n\n")) + (should (null (noise-sse--parse-event event))))) + +(provide 'noise-sse-test) +;;; noise-sse-test.el ends here