feat(#2569): matrix producer — sweep_unread pushes per-room todos instead of direct wakes

This commit is contained in:
damocles 2026-07-19 01:40:32 +02:00 committed by mara
commit 711e0ece2a
4 changed files with 125 additions and 71 deletions

View file

@ -34,15 +34,65 @@ use tokio::net::UnixStream;
/// Returns an error on socket connect failure, serialisation failure,
/// or I/O error writing to or reading from the socket.
pub async fn send_wake(socket: &Path, body: impl AsRef<str>) -> Result<()> {
use tokio::io::AsyncBufReadExt;
let payload = serde_json::json!({
"cmd": "wake",
"from": "matrix",
"body": body.as_ref(),
"transient": true,
});
let line = format!("{}\n", serde_json::to_string(&payload)?);
send_line(socket, &payload).await
}
/// Upsert a matrix-subsystem *todo* (loose-ends v2, #2569) on the
/// hyperhive control socket — the replacement for a direct wake. `key` is
/// the room id (the dedup key); hive-c0re coalesces a wake iff the todo is
/// new or its `summary` changed. Best-effort like [`send_wake`].
///
/// # Errors
///
/// Returns an error on socket connect failure, serialisation failure,
/// or I/O error writing to or reading from the socket.
pub async fn send_todo_upsert(socket: &Path, key: &str, summary: impl AsRef<str>) -> Result<()> {
let payload = serde_json::json!({
"cmd": "upsert_todo",
"subsystem": "matrix",
"key": key,
"summary": summary.as_ref(),
});
send_line(socket, &payload).await
}
/// Clear matrix-subsystem todos. `key = Some(room)` clears one room's
/// todo (it was read); `all = true` wipes the whole matrix set
/// (cancel-and-recreate on daemon restart). Best-effort.
///
/// # Errors
///
/// Returns an error on socket connect failure, serialisation failure,
/// or I/O error writing to or reading from the socket.
pub async fn send_todo_clear(socket: &Path, key: Option<&str>, all: bool) -> Result<()> {
let payload = serde_json::json!({
"cmd": "clear_todo",
"subsystem": "matrix",
"key": key,
"all": all,
});
send_line(socket, &payload).await
}
/// Write one JSON request line to the hyperhive control socket and drain
/// the response line (best-effort — the reply is not acted on, we just
/// read it so the server doesn't get ECONNRESET on its write-back).
/// Shared by [`send_wake`] and the todo senders.
///
/// # Errors
///
/// Returns an error on socket connect failure, serialisation failure,
/// or I/O error writing to or reading from the socket.
async fn send_line(socket: &Path, payload: &serde_json::Value) -> Result<()> {
use tokio::io::AsyncBufReadExt;
let line = format!("{}\n", serde_json::to_string(payload)?);
let stream = UnixStream::connect(socket)
.await
.with_context(|| format!("connect hyperhive socket {}", socket.display()))?;
@ -50,13 +100,11 @@ pub async fn send_wake(socket: &Path, body: impl AsRef<str>) -> Result<()> {
write
.write_all(line.as_bytes())
.await
.with_context(|| format!("write wake to {}", socket.display()))?;
.with_context(|| format!("write to {}", socket.display()))?;
write
.shutdown()
.await
.with_context(|| format!("shutdown write to {}", socket.display()))?;
// Drain the response line so the server doesn't get ECONNRESET on
// its write-back. We don't act on the response — best-effort wake.
let mut reader = tokio::io::BufReader::new(read);
let mut resp = String::new();
let _ = reader.read_line(&mut resp).await;