lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README | LICENSE

commit e7817600be65afe420b9346ba2f8dfcd601b8131
parent 74d6515696249db9d51b61293c6f8832a543ed67
Author: triesap <tyson@radroots.org>
Date:   Fri, 12 Jun 2026 22:50:21 -0700

nostr_runtime: rename event callback sink

- rename the runtime event callback trait and in-memory helper from store to sink
- move the runtime module surface from store to sink without preserving old aliases
- update the nostrdb runtime adapter and tests to expose event-sink semantics
- verify the focused runtime lanes and workspace check under the new names

Diffstat:
Mcrates/nostr_ndb/README | 2+-
Mcrates/nostr_ndb/src/lib.rs | 2+-
Mcrates/nostr_ndb/src/runtime_adapter.rs | 32+++++++++++++++-----------------
Mcrates/nostr_runtime/README | 2+-
Mcrates/nostr_runtime/src/lib.rs | 4++--
Mcrates/nostr_runtime/src/runtime.rs | 26+++++++++++++-------------
Acrates/nostr_runtime/src/sink.rs | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dcrates/nostr_runtime/src/store.rs | 66------------------------------------------------------------------
8 files changed, 97 insertions(+), 101 deletions(-)

diff --git a/crates/nostr_ndb/README b/crates/nostr_ndb/README @@ -7,7 +7,7 @@ primitives for the `radroots` core libraries. * configuration, filter, ingest, query, and subscription types for nostrdb-backed workflows; - * runtime-adapter hooks that let higher layers drive a nostrdb event store; + * runtime-adapter hooks that let higher layers drive nostrdb as an event sink; * feature-gated support for the `nostrdb` crate, runtime glue, and gift-wrap handling; * a `std`-based integration crate with optional async runtime support. diff --git a/crates/nostr_ndb/src/lib.rs b/crates/nostr_ndb/src/lib.rs @@ -40,7 +40,7 @@ pub mod prelude { RadrootsNostrNdbNote, RadrootsNostrNdbProfile, RadrootsNostrNdbQuerySpec, }; #[cfg(all(feature = "ndb", feature = "runtime-adapter"))] - pub use crate::runtime_adapter::RadrootsNostrNdbEventStoreAdapter; + pub use crate::runtime_adapter::RadrootsNostrNdbEventSinkAdapter; #[cfg(all(feature = "ndb", feature = "rt"))] pub use crate::subscription::RadrootsNostrNdbSubscriptionStream; #[cfg(feature = "ndb")] diff --git a/crates/nostr_ndb/src/runtime_adapter.rs b/crates/nostr_ndb/src/runtime_adapter.rs @@ -1,11 +1,11 @@ use crate::ingest::RadrootsNostrNdbIngestSource; use crate::ndb::RadrootsNostrNdb; use radroots_nostr::prelude::RadrootsNostrEvent; -use radroots_nostr_runtime::prelude::RadrootsNostrEventStore; +use radroots_nostr_runtime::prelude::RadrootsNostrEventSink; use std::sync::Arc; #[derive(Clone)] -pub struct RadrootsNostrNdbEventStoreAdapter { +pub struct RadrootsNostrNdbEventSinkAdapter { ndb: RadrootsNostrNdb, source: RadrootsNostrNdbIngestSource, } @@ -14,7 +14,7 @@ fn ndb_error_to_string(source: crate::error::RadrootsNostrNdbError) -> String { source.to_string() } -impl RadrootsNostrNdbEventStoreAdapter { +impl RadrootsNostrNdbEventSinkAdapter { pub fn new(ndb: RadrootsNostrNdb) -> Self { Self { ndb, @@ -27,19 +27,19 @@ impl RadrootsNostrNdbEventStoreAdapter { self } - pub fn into_event_store(self) -> Arc<dyn RadrootsNostrEventStore> { + pub fn into_event_sink(self) -> Arc<dyn RadrootsNostrEventSink> { Arc::new(self) } } -impl RadrootsNostrEventStore for RadrootsNostrNdb { +impl RadrootsNostrEventSink for RadrootsNostrNdb { fn ingest_event(&self, event: &RadrootsNostrEvent) -> Result<(), String> { RadrootsNostrNdb::ingest_event(self, event, RadrootsNostrNdbIngestSource::client()) .map_err(ndb_error_to_string) } } -impl RadrootsNostrEventStore for RadrootsNostrNdbEventStoreAdapter { +impl RadrootsNostrEventSink for RadrootsNostrNdbEventSinkAdapter { fn ingest_event(&self, event: &RadrootsNostrEvent) -> Result<(), String> { self.ndb .ingest_event(event, self.source.clone()) @@ -60,7 +60,7 @@ mod tests { let db_dir = tmp_dir.path().join("ndb"); let config = RadrootsNostrNdbConfig::new(&db_dir); let ndb = RadrootsNostrNdb::open(config).expect("database should open"); - let adapter = RadrootsNostrNdbEventStoreAdapter::new(ndb); + let adapter = RadrootsNostrNdbEventSinkAdapter::new(ndb); let keys = RadrootsNostrKeys::generate(); let event = RadrootsNostrEventBuilder::text_note("hello from runtime adapter") @@ -73,40 +73,38 @@ mod tests { } #[test] - fn runtime_adapter_can_be_boxed_as_store_trait() { + fn runtime_adapter_can_be_boxed_as_sink_trait() { let tmp_dir = TempDir::new().expect("tempdir should open"); let db_dir = tmp_dir.path().join("ndb"); let config = RadrootsNostrNdbConfig::new(&db_dir); let ndb = RadrootsNostrNdb::open(config).expect("database should open"); - let store = RadrootsNostrNdbEventStoreAdapter::new(ndb) + let sink = RadrootsNostrNdbEventSinkAdapter::new(ndb) .with_source(RadrootsNostrNdbIngestSource::relay("wss://radroots.org")) - .into_event_store(); + .into_event_sink(); let keys = RadrootsNostrKeys::generate(); let event = RadrootsNostrEventBuilder::text_note("hello trait object") .sign_with_keys(&keys) .expect("event should sign"); - store - .ingest_event(&event) - .expect("boxed store should ingest event"); + sink.ingest_event(&event) + .expect("boxed sink should ingest event"); } #[test] - fn ndb_can_be_boxed_as_store_trait() { + fn ndb_can_be_boxed_as_sink_trait() { let tmp_dir = TempDir::new().expect("tempdir should open"); let db_dir = tmp_dir.path().join("ndb"); let config = RadrootsNostrNdbConfig::new(&db_dir); let ndb = RadrootsNostrNdb::open(config).expect("database should open"); - let store: Arc<dyn RadrootsNostrEventStore> = Arc::new(ndb.clone()); + let sink: Arc<dyn RadrootsNostrEventSink> = Arc::new(ndb.clone()); let keys = RadrootsNostrKeys::generate(); let event = RadrootsNostrEventBuilder::text_note("hello ndb trait object") .sign_with_keys(&keys) .expect("event should sign"); - store - .ingest_event(&event) + sink.ingest_event(&event) .expect("ndb trait object should ingest event"); } diff --git a/crates/nostr_runtime/README b/crates/nostr_runtime/README @@ -8,7 +8,7 @@ coordination for the `radroots` core libraries. * runtime builder, runtime events, and long-lived connection state types; * subscription specifications, policies, handles, and traffic-light status models; - * store abstractions and snapshot types used by higher-level network + * sink abstractions and snapshot types used by higher-level network orchestration; * feature-gated integration with client, runtime, and nostrdb adapter crates. diff --git a/crates/nostr_runtime/src/lib.rs b/crates/nostr_runtime/src/lib.rs @@ -9,14 +9,14 @@ pub mod types; #[cfg(all(feature = "nostr-client", feature = "rt"))] pub mod runtime; #[cfg(all(feature = "nostr-client", feature = "rt"))] -pub mod store; +pub mod sink; pub mod prelude { pub use crate::error::RadrootsNostrRuntimeError; #[cfg(all(feature = "nostr-client", feature = "rt"))] pub use crate::runtime::{RadrootsNostrRuntime, RadrootsNostrRuntimeBuilder}; #[cfg(all(feature = "nostr-client", feature = "rt"))] - pub use crate::store::{RadrootsNostrEventStore, RadrootsNostrInMemoryEventStore}; + pub use crate::sink::{RadrootsNostrEventSink, RadrootsNostrInMemoryEventSink}; pub use crate::types::{ RadrootsNostrConnectionSnapshot, RadrootsNostrRuntimeEvent, RadrootsNostrSubscriptionHandle, RadrootsNostrSubscriptionPolicy, diff --git a/crates/nostr_runtime/src/runtime.rs b/crates/nostr_runtime/src/runtime.rs @@ -1,5 +1,5 @@ use crate::error::RadrootsNostrRuntimeError; -use crate::store::RadrootsNostrEventStore; +use crate::sink::RadrootsNostrEventSink; use crate::types::{ RadrootsNostrConnectionSnapshot, RadrootsNostrRuntimeEvent, RadrootsNostrSubscriptionHandle, RadrootsNostrSubscriptionPolicy, RadrootsNostrSubscriptionSpec, RadrootsNostrTrafficLight, @@ -25,7 +25,7 @@ pub struct RadrootsNostrRuntimeBuilder { relays: Vec<String>, queue_capacity: usize, monitor_capacity: usize, - event_store: Option<Arc<dyn RadrootsNostrEventStore>>, + event_sink: Option<Arc<dyn RadrootsNostrEventSink>>, } impl RadrootsNostrRuntimeBuilder { @@ -38,7 +38,7 @@ impl RadrootsNostrRuntimeBuilder { relays: Vec::new(), queue_capacity: Self::DEFAULT_QUEUE_CAPACITY, monitor_capacity: Self::DEFAULT_MONITOR_CAPACITY, - event_store: None, + event_sink: None, } } @@ -67,8 +67,8 @@ impl RadrootsNostrRuntimeBuilder { self } - pub fn event_store(mut self, store: Arc<dyn RadrootsNostrEventStore>) -> Self { - self.event_store = Some(store); + pub fn event_sink(mut self, sink: Arc<dyn RadrootsNostrEventSink>) -> Self { + self.event_sink = Some(sink); self } @@ -102,7 +102,7 @@ impl RadrootsNostrRuntimeBuilder { started: AtomicBool::new(false), shutting_down: AtomicBool::new(false), next_subscription_id: AtomicU64::new(1), - event_store: self.event_store, + event_sink: self.event_sink, }); Ok(RadrootsNostrRuntime { inner }) @@ -132,7 +132,7 @@ struct RadrootsNostrRuntimeInner { started: AtomicBool, shutting_down: AtomicBool, next_subscription_id: AtomicU64, - event_store: Option<Arc<dyn RadrootsNostrEventStore>>, + event_sink: Option<Arc<dyn RadrootsNostrEventSink>>, } impl RadrootsNostrRuntime { @@ -413,8 +413,8 @@ fn spawn_subscription_worker( let kind = event.kind.as_u16(); since_unix = Some(event.created_at.as_secs().saturating_add(1)); - if let Some(store) = inner.event_store.as_ref() { - if let Err(message) = store.ingest_event(&event) { + if let Some(sink) = inner.event_sink.as_ref() { + if let Err(message) = sink.ingest_event(&event) { if let Ok(mut guard) = inner.last_error.lock() { *guard = Some(message.clone()); } @@ -458,7 +458,7 @@ fn spawn_subscription_worker( #[cfg(test)] mod tests { use super::*; - use crate::store::RadrootsNostrInMemoryEventStore; + use crate::sink::RadrootsNostrInMemoryEventSink; use alloc::sync::Arc; use radroots_nostr::prelude::RadrootsNostrFilter; @@ -519,12 +519,12 @@ mod tests { } #[test] - fn build_accepts_event_store() { - let store = Arc::new(RadrootsNostrInMemoryEventStore::new()); + fn build_accepts_event_sink() { + let sink = Arc::new(RadrootsNostrInMemoryEventSink::new()); let result = RadrootsNostrRuntimeBuilder::new() .keys(RadrootsNostrKeys::generate()) .add_relay("wss://relay.example.com") - .event_store(store) + .event_sink(sink) .build(); assert!(result.is_ok()); } diff --git a/crates/nostr_runtime/src/sink.rs b/crates/nostr_runtime/src/sink.rs @@ -0,0 +1,64 @@ +use alloc::string::ToString; +use alloc::vec::Vec; +use radroots_nostr::prelude::RadrootsNostrEvent; +use std::sync::Mutex; + +pub trait RadrootsNostrEventSink: Send + Sync { + fn ingest_event(&self, event: &RadrootsNostrEvent) -> Result<(), String>; +} + +#[derive(Default)] +pub struct RadrootsNostrInMemoryEventSink { + events: Mutex<Vec<RadrootsNostrEvent>>, +} + +impl RadrootsNostrInMemoryEventSink { + pub fn new() -> Self { + Self::default() + } + + pub fn events(&self) -> Vec<RadrootsNostrEvent> { + self.events + .lock() + .map(|guard| guard.clone()) + .unwrap_or_default() + } + + pub fn len(&self) -> usize { + self.events.lock().map(|guard| guard.len()).unwrap_or(0) + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } +} + +impl RadrootsNostrEventSink for RadrootsNostrInMemoryEventSink { + fn ingest_event(&self, event: &RadrootsNostrEvent) -> Result<(), String> { + self.events + .lock() + .map_err(|_| "in-memory sink lock poisoned".to_string()) + .map(|mut guard| { + guard.push(event.clone()); + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use radroots_nostr::prelude::{RadrootsNostrEventBuilder, RadrootsNostrKeys}; + + #[test] + fn in_memory_sink_tracks_events() { + let sink = RadrootsNostrInMemoryEventSink::new(); + let keys = RadrootsNostrKeys::generate(); + let event = RadrootsNostrEventBuilder::text_note("hello") + .sign_with_keys(&keys) + .expect("event should sign"); + + sink.ingest_event(&event).expect("event should be accepted"); + assert_eq!(sink.len(), 1); + assert!(!sink.is_empty()); + } +} diff --git a/crates/nostr_runtime/src/store.rs b/crates/nostr_runtime/src/store.rs @@ -1,66 +0,0 @@ -use alloc::string::ToString; -use alloc::vec::Vec; -use radroots_nostr::prelude::RadrootsNostrEvent; -use std::sync::Mutex; - -pub trait RadrootsNostrEventStore: Send + Sync { - fn ingest_event(&self, event: &RadrootsNostrEvent) -> Result<(), String>; -} - -#[derive(Default)] -pub struct RadrootsNostrInMemoryEventStore { - events: Mutex<Vec<RadrootsNostrEvent>>, -} - -impl RadrootsNostrInMemoryEventStore { - pub fn new() -> Self { - Self::default() - } - - pub fn events(&self) -> Vec<RadrootsNostrEvent> { - self.events - .lock() - .map(|guard| guard.clone()) - .unwrap_or_default() - } - - pub fn len(&self) -> usize { - self.events.lock().map(|guard| guard.len()).unwrap_or(0) - } - - pub fn is_empty(&self) -> bool { - self.len() == 0 - } -} - -impl RadrootsNostrEventStore for RadrootsNostrInMemoryEventStore { - fn ingest_event(&self, event: &RadrootsNostrEvent) -> Result<(), String> { - self.events - .lock() - .map_err(|_| "in-memory store lock poisoned".to_string()) - .map(|mut guard| { - guard.push(event.clone()); - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use radroots_nostr::prelude::{RadrootsNostrEventBuilder, RadrootsNostrKeys}; - - #[test] - fn in_memory_store_tracks_events() { - let store = RadrootsNostrInMemoryEventStore::new(); - let keys = RadrootsNostrKeys::generate(); - let event = RadrootsNostrEventBuilder::text_note("hello") - .sign_with_keys(&keys) - .expect("event should sign"); - - store - .ingest_event(&event) - .expect("event should be accepted"); - assert_eq!(store.len(), 1); - assert!(!store.is_empty()); - } -}