lib

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

commit 8b84f42e87ab4bf2f66932d634769a874526a8b3
parent 0de0fabe00914ad201b6a0b84f82ff0f39fe81e0
Author: triesap <tyson@radroots.org>
Date:   Mon,  6 Oct 2025 13:25:39 +0100

net-core: add async and blocking APIs for publishing replies in `radroots-nostr` client

Diffstat:
Mcrates/events-codec/src/job/error.rs | 2+-
Mcrates/net-core/Cargo.toml | 26+++++++++++++-------------
Mcrates/net-core/src/builder.rs | 13++++---------
Mcrates/net-core/src/nostr_client/posts.rs | 65++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
4 files changed, 78 insertions(+), 28 deletions(-)

diff --git a/crates/events-codec/src/job/error.rs b/crates/events-codec/src/job/error.rs @@ -4,7 +4,7 @@ use core::fmt; pub enum JobParseError { MissingTag(&'static str), InvalidTag(&'static str), - InvalidNumber(&'static str, std::num::ParseIntError), + InvalidNumber(&'static str, core::num::ParseIntError), NonWholeSats(&'static str), AmountOverflow(&'static str), MissingChainTag(&'static str), diff --git a/crates/net-core/Cargo.toml b/crates/net-core/Cargo.toml @@ -9,19 +9,20 @@ license.workspace = true [features] default = ["std"] std = [] -rt = ["dep:tokio"] +rt = ["std", "dep:tokio"] nostr-client = [ - "dep:radroots-events", - "radroots-events/serde", - "dep:nostr", - "dep:nostr-sdk", - "dep:secrecy", - "dep:hex", - "dep:tempfile", - "dep:serde_json" + "std", + "dep:radroots-events", + "radroots-events/serde", + "dep:nostr", + "dep:nostr-sdk", + "dep:secrecy", + "dep:hex", + "dep:tempfile", + "dep:serde_json" ] -directories = ["dep:directories"] -fs-persistence = [] +directories = ["std", "dep:directories"] +fs-persistence = ["std"] [dependencies] radroots-events = { workspace = true, optional = true, default-features = true, features = ["std", "serde", "typeshare"] } @@ -38,4 +39,4 @@ thiserror = { workspace = true } tokio = { workspace = true, optional = true, features = ["rt-multi-thread"] } tracing = { workspace = true } tracing-subscriber = { workspace = true, features = ["fmt", "env-filter"] } -tracing-appender = { workspace = true } -\ No newline at end of file +tracing-appender = { workspace = true } diff --git a/crates/net-core/src/builder.rs b/crates/net-core/src/builder.rs @@ -32,19 +32,14 @@ impl NetBuilder { self } - #[allow(unreachable_code)] pub fn build(self) -> Result<NetHandle> { - let net = Net::new(self.config.clone()); + let mut _net = Net::new(self.config.clone()); #[cfg(feature = "rt")] - { - let mut net = net; - if self.manage_runtime { - net.init_managed_runtime(None)?; - } - return Ok(NetHandle::from_inner(net)); + if self.manage_runtime { + _net.init_managed_runtime(None)?; } - Ok(NetHandle::from_inner(net)) + Ok(NetHandle::from_inner(_net)) } } diff --git a/crates/net-core/src/nostr_client/posts.rs b/crates/net-core/src/nostr_client/posts.rs @@ -4,13 +4,14 @@ use crate::error::{NetError, Result}; use radroots_events::post::models::{RadrootsPost, RadrootsPostEventMetadata}; use super::manager::NostrClientManager; +use nostr_sdk::prelude::*; impl NostrClientManager { pub async fn publish_text_note(&self, content: String) -> Result<String> { let out = self .inner .client - .send_event_builder(nostr_sdk::prelude::EventBuilder::text_note(content)) + .send_event_builder(EventBuilder::text_note(content)) .await .map_err(|e| NetError::Msg(e.to_string()))?; Ok(out.val.to_string()) @@ -22,16 +23,70 @@ impl NostrClientManager { rt.block_on(async move { this.publish_text_note(content).await }) } + pub async fn publish_reply_to_event( + &self, + parent_event_id_hex: String, + parent_author_hex: String, + content: String, + root_event_id_hex: Option<String>, + ) -> Result<String> { + let parent_id = + EventId::from_hex(&parent_event_id_hex).map_err(|_| NetError::InvalidHex32)?; + let parent_pubkey = + PublicKey::from_hex(&parent_author_hex).map_err(|_| NetError::InvalidHex32)?; + + let mut tags: Vec<Tag> = Vec::new(); + + if let Some(root_hex) = root_event_id_hex { + if !root_hex.is_empty() { + if let Ok(root_id) = EventId::from_hex(&root_hex) { + tags.push(Tag::event(root_id)); + } + } + } + + tags.push(Tag::event(parent_id)); + tags.push(Tag::public_key(parent_pubkey)); + + let builder = EventBuilder::text_note(content).tags(tags); + let out = self + .inner + .client + .send_event_builder(builder) + .await + .map_err(|e| NetError::Msg(e.to_string()))?; + + Ok(out.val.to_string()) + } + + pub fn publish_reply_to_event_blocking( + &self, + parent_event_id_hex: String, + parent_author_hex: String, + content: String, + root_event_id_hex: Option<String>, + ) -> Result<String> { + let rt = self.inner.rt.clone(); + let this = self.clone(); + rt.block_on(async move { + this.publish_reply_to_event( + parent_event_id_hex, + parent_author_hex, + content, + root_event_id_hex, + ) + .await + }) + } + pub async fn fetch_text_notes( &self, limit: u16, since_unix: Option<u64>, ) -> Result<Vec<RadrootsPostEventMetadata>> { - let mut filter = nostr_sdk::prelude::Filter::new() - .kind(nostr_sdk::prelude::Kind::TextNote) - .limit(limit.into()); + let mut filter = Filter::new().kind(Kind::TextNote).limit(limit.into()); if let Some(s) = since_unix { - filter = filter.since(nostr_sdk::prelude::Timestamp::from(s)); + filter = filter.since(Timestamp::from(s)); } let events = self .inner