commit 0d7b012caf8dc87de5ca6a26f512031b1bd821b9
parent d9c2af4f22ff6b00875fe89f627b082250c02a34
Author: kernelkind <kernelkind@gmail.com>
Date: Mon, 2 Feb 2026 13:55:07 -0500
feat(outbox): add `OutboxSessionHandler`
Signed-off-by: kernelkind <kernelkind@gmail.com>
Diffstat:
3 files changed, 86 insertions(+), 1 deletion(-)
diff --git a/crates/enostr/src/relay/mod.rs b/crates/enostr/src/relay/mod.rs
@@ -22,7 +22,7 @@ pub use limits::{
};
pub use multicast::{MulticastRelay, MulticastRelayCache};
use nostrdb::Filter;
-pub use outbox::{OutboxPool, OutboxSession};
+pub use outbox::{OutboxPool, OutboxSession, OutboxSessionHandler};
pub use queue::QueuedTasks;
pub use subscription::{
FullModificationTask, ModifyFiltersTask, ModifyRelaysTask, ModifyTask, OutboxSubscriptions,
diff --git a/crates/enostr/src/relay/outbox/handler.rs b/crates/enostr/src/relay/outbox/handler.rs
@@ -0,0 +1,83 @@
+use hashbrown::HashSet;
+use nostrdb::{Filter, Note};
+
+use crate::relay::outbox::OutboxPool;
+use crate::relay::{NormRelayUrl, OutboxSubId, RelayId, RelayUrlPkgs};
+use crate::{relay::outbox::OutboxSession, Wakeup};
+
+/// OutboxSessionHandler is the RAII wrapper apps use to stage subscription
+/// updates; dropping it flushes the recorded operations into the OutboxPool.
+pub struct OutboxSessionHandler<'a, W>
+where
+ W: Wakeup,
+{
+ pub outbox: &'a mut OutboxPool,
+ pub(crate) session: OutboxSession,
+ pub(crate) wakeup: W,
+}
+
+impl<'a, W> Drop for OutboxSessionHandler<'a, W>
+where
+ W: Wakeup,
+{
+ fn drop(&mut self) {
+ let session = std::mem::take(&mut self.session);
+ self.outbox.ingest_session(session, &self.wakeup);
+ }
+}
+
+impl<'a, W> OutboxSessionHandler<'a, W>
+where
+ W: Wakeup,
+{
+ pub fn new(outbox: &'a mut OutboxPool, wakeup: W) -> Self {
+ Self {
+ outbox,
+ session: OutboxSession::default(),
+ wakeup,
+ }
+ }
+
+ pub fn subscribe(&mut self, filters: Vec<Filter>, urls: RelayUrlPkgs) -> OutboxSubId {
+ let new_id = self.outbox.registry.next();
+ self.session.subscribe(new_id, filters, urls);
+ new_id
+ }
+
+ pub fn oneshot(&mut self, filters: Vec<Filter>, urls: RelayUrlPkgs) {
+ let new_id = self.outbox.registry.next();
+ self.session.oneshot(new_id, filters, urls);
+ }
+
+ pub fn modify_filters(&mut self, id: OutboxSubId, filters: Vec<Filter>) {
+ self.session.new_filters(id, filters);
+ }
+
+ pub fn modify_relays(&mut self, id: OutboxSubId, relays: HashSet<NormRelayUrl>) {
+ self.session.new_relays(id, relays);
+ }
+
+ pub fn unsubscribe(&mut self, id: OutboxSubId) {
+ self.session.unsubscribe(id);
+ }
+
+ pub fn broadcast_note(&mut self, note: &Note, relays: Vec<RelayId>) {
+ self.outbox.broadcast_note(note, relays, &self.wakeup);
+ }
+
+ /// Eject the session from the handler.
+ /// This is only necessary between initialization of the app and the first frame
+ pub fn export(mut self) -> OutboxSession {
+ let session = std::mem::take(&mut self.session);
+ drop(self);
+ session
+ }
+
+ pub fn import(outbox: &'a mut OutboxPool, session: OutboxSession, wakeup: W) -> Self {
+ Self {
+ outbox,
+ session,
+ wakeup,
+ }
+ }
+}
diff --git a/crates/enostr/src/relay/outbox/mod.rs b/crates/enostr/src/relay/outbox/mod.rs
@@ -16,8 +16,10 @@ use crate::{
EventClientMessage, Wakeup, WebsocketConn,
};
+mod handler;
mod session;
+pub use handler::OutboxSessionHandler;
pub use session::OutboxSession;
const KEEPALIVE_PING_RATE: Duration = Duration::from_secs(45);