Phase 7b: broker broadcast + dashboard SSE message-flow tail; pkgs.git in module
This commit is contained in:
parent
46ff9c7aee
commit
9133d9e1a3
5 changed files with 133 additions and 6 deletions
|
|
@ -1,4 +1,5 @@
|
|||
//! Sqlite-backed message broker. Survives `hive-c0re` restart.
|
||||
//! Sqlite-backed message broker. Survives `hive-c0re` restart, and taps every
|
||||
//! send/recv onto a broadcast channel so the dashboard can stream it.
|
||||
|
||||
use std::path::Path;
|
||||
use std::sync::Mutex;
|
||||
|
|
@ -7,6 +8,8 @@ use std::time::{SystemTime, UNIX_EPOCH};
|
|||
use anyhow::{Context, Result};
|
||||
use hive_sh4re::Message;
|
||||
use rusqlite::{Connection, OptionalExtension, params};
|
||||
use serde::Serialize;
|
||||
use tokio::sync::broadcast;
|
||||
|
||||
const SCHEMA: &str = r"
|
||||
CREATE TABLE IF NOT EXISTS messages (
|
||||
|
|
@ -21,8 +24,30 @@ CREATE INDEX IF NOT EXISTS idx_messages_undelivered
|
|||
ON messages (recipient, id) WHERE delivered_at IS NULL;
|
||||
";
|
||||
|
||||
/// Capacity of the live event channel. Slow subscribers (e.g. an idle browser)
|
||||
/// may drop events past this; we send a `lagged` notice in their stream.
|
||||
const EVENT_CHANNEL: usize = 256;
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(rename_all = "snake_case", tag = "kind")]
|
||||
pub enum MessageEvent {
|
||||
Sent {
|
||||
from: String,
|
||||
to: String,
|
||||
body: String,
|
||||
at: i64,
|
||||
},
|
||||
Delivered {
|
||||
from: String,
|
||||
to: String,
|
||||
body: String,
|
||||
at: i64,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct Broker {
|
||||
conn: Mutex<Connection>,
|
||||
events: broadcast::Sender<MessageEvent>,
|
||||
}
|
||||
|
||||
impl Broker {
|
||||
|
|
@ -31,20 +56,33 @@ impl Broker {
|
|||
std::fs::create_dir_all(parent)
|
||||
.with_context(|| format!("create db parent {}", parent.display()))?;
|
||||
}
|
||||
let conn =
|
||||
Connection::open(path).with_context(|| format!("open broker db {}", path.display()))?;
|
||||
let conn = Connection::open(path)
|
||||
.with_context(|| format!("open broker db {}", path.display()))?;
|
||||
conn.execute_batch(SCHEMA).context("apply broker schema")?;
|
||||
let (events, _) = broadcast::channel(EVENT_CHANNEL);
|
||||
Ok(Self {
|
||||
conn: Mutex::new(conn),
|
||||
events,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn subscribe(&self) -> broadcast::Receiver<MessageEvent> {
|
||||
self.events.subscribe()
|
||||
}
|
||||
|
||||
pub fn send(&self, message: &Message) -> Result<()> {
|
||||
let conn = self.conn.lock().unwrap();
|
||||
conn.execute(
|
||||
"INSERT INTO messages (sender, recipient, body, sent_at) VALUES (?1, ?2, ?3, ?4)",
|
||||
params![message.from, message.to, message.body, now_unix()],
|
||||
)?;
|
||||
drop(conn);
|
||||
let _ = self.events.send(MessageEvent::Sent {
|
||||
from: message.from.clone(),
|
||||
to: message.to.clone(),
|
||||
body: message.body.clone(),
|
||||
at: now_unix(),
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -68,6 +106,13 @@ impl Broker {
|
|||
"UPDATE messages SET delivered_at = ?1 WHERE id = ?2",
|
||||
params![now_unix(), id],
|
||||
)?;
|
||||
drop(conn);
|
||||
let _ = self.events.send(MessageEvent::Delivered {
|
||||
from: from.clone(),
|
||||
to: to.clone(),
|
||||
body: body.clone(),
|
||||
at: now_unix(),
|
||||
});
|
||||
Ok(Some(Message { from, to, body }))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue