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:
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