lib

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

commit c84fa324d929f8becb044766a1faf8b006cb181e
parent e1e9e41cd85d3b9329a5947bdeb1c999bb317b79
Author: triesap <tyson@radroots.org>
Date:   Thu, 19 Feb 2026 16:35:30 +0000

nostr-runtime: add subscription spec convenience builders


- add high-level constructors for text-note and kind-based subscription specs
- support author scoping and policy switching in fluent subscription spec builders
- preserve default stream timeout and reconnect settings across helper constructors
- add unit tests for subscription spec builder behavior and field updates

Diffstat:
Mnostr-runtime/src/types.rs | 107++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 106 insertions(+), 1 deletion(-)

diff --git a/nostr-runtime/src/types.rs b/nostr-runtime/src/types.rs @@ -1,6 +1,9 @@ use alloc::string::String; #[cfg(feature = "nostr-client")] -use radroots_nostr::prelude::RadrootsNostrFilter; +use radroots_nostr::prelude::{ + RadrootsNostrFilter, RadrootsNostrPublicKey, RadrootsNostrTimestamp, radroots_nostr_kind, + radroots_nostr_post_events_filter, +}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum RadrootsNostrSubscriptionPolicy { @@ -44,6 +47,43 @@ impl RadrootsNostrSubscriptionSpec { } } + pub fn with_policy(mut self, policy: RadrootsNostrSubscriptionPolicy) -> Self { + self.policy = policy; + self + } + + #[cfg(feature = "nostr-client")] + pub fn text_notes( + limit: Option<u16>, + since_unix: Option<u64>, + policy: RadrootsNostrSubscriptionPolicy, + ) -> Self { + Self::streaming(radroots_nostr_post_events_filter(limit, since_unix)).with_policy(policy) + } + + #[cfg(feature = "nostr-client")] + pub fn by_kind( + kind: u16, + limit: Option<u16>, + since_unix: Option<u64>, + policy: RadrootsNostrSubscriptionPolicy, + ) -> Self { + let mut filter = RadrootsNostrFilter::new().kind(radroots_nostr_kind(kind)); + if let Some(limit) = limit { + filter = filter.limit(limit.into()); + } + if let Some(since) = since_unix { + filter = filter.since(RadrootsNostrTimestamp::from(since)); + } + Self::streaming(filter).with_policy(policy) + } + + #[cfg(feature = "nostr-client")] + pub fn by_author(mut self, author: RadrootsNostrPublicKey) -> Self { + self.filter = self.filter.author(author); + self + } + pub fn named(mut self, name: impl Into<String>) -> Self { self.name = Some(name.into()); self @@ -60,6 +100,71 @@ impl RadrootsNostrSubscriptionSpec { } } +#[cfg(test)] +mod tests { + use super::*; + use radroots_nostr::prelude::RadrootsNostrKeys; + + #[test] + fn text_notes_constructor_sets_defaults() { + let spec = RadrootsNostrSubscriptionSpec::text_notes( + Some(5), + Some(10), + RadrootsNostrSubscriptionPolicy::Streaming, + ); + assert!(matches!( + spec.policy, + RadrootsNostrSubscriptionPolicy::Streaming + )); + assert_eq!( + spec.stream_timeout_secs, + RadrootsNostrSubscriptionSpec::DEFAULT_STREAM_TIMEOUT_SECS + ); + assert_eq!( + spec.reconnect_delay_millis, + RadrootsNostrSubscriptionSpec::DEFAULT_RECONNECT_DELAY_MILLIS + ); + } + + #[test] + fn by_kind_constructor_respects_policy() { + let spec = RadrootsNostrSubscriptionSpec::by_kind( + 30023, + None, + None, + RadrootsNostrSubscriptionPolicy::OneShotOnEose, + ); + assert!(matches!( + spec.policy, + RadrootsNostrSubscriptionPolicy::OneShotOnEose + )); + } + + #[test] + fn builder_methods_update_spec_fields() { + let keys = RadrootsNostrKeys::generate(); + let author = keys.public_key(); + let spec = RadrootsNostrSubscriptionSpec::text_notes( + None, + None, + RadrootsNostrSubscriptionPolicy::Streaming, + ) + .by_author(author) + .named("posts") + .stream_timeout_secs(12) + .reconnect_delay_millis(99) + .with_policy(RadrootsNostrSubscriptionPolicy::OneShotOnEose); + + assert_eq!(spec.name.as_deref(), Some("posts")); + assert_eq!(spec.stream_timeout_secs, 12); + assert_eq!(spec.reconnect_delay_millis, 99); + assert!(matches!( + spec.policy, + RadrootsNostrSubscriptionPolicy::OneShotOnEose + )); + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct RadrootsNostrSubscriptionHandle { pub id: String,