#[cfg(any(test, feature = "test-utils"))]
pub mod mock;
#[cfg(any(test, feature = "test-utils"))]
pub use mock::MockRelayPool;
use async_trait::async_trait;
use crate::core::error::{Error, Result};
use nostr_sdk::prelude::*;
use std::sync::Arc;
#[async_trait]
pub trait RelayPoolTrait: Send + Sync {
async fn connect(&self, relay_urls: &[String]) -> Result<()>;
async fn disconnect(&self) -> Result<()>;
async fn publish_event(&self, event: &Event) -> Result<EventId>;
async fn publish(&self, builder: EventBuilder) -> Result<EventId>;
async fn sign(&self, builder: EventBuilder) -> Result<Event>;
async fn signer(&self) -> Result<Arc<dyn NostrSigner>>;
fn notifications(&self) -> tokio::sync::broadcast::Receiver<RelayPoolNotification>;
async fn public_key(&self) -> Result<PublicKey>;
async fn subscribe(&self, filters: Vec<Filter>) -> Result<()>;
}
pub struct RelayPool {
client: Arc<Client>,
}
impl RelayPool {
pub async fn new<T>(signer: T) -> Result<Self>
where
T: IntoNostrSigner,
{
let client = Client::builder().signer(signer).build();
Ok(Self {
client: Arc::new(client),
})
}
pub async fn connect(&self, relay_urls: &[String]) -> Result<()> {
for url in relay_urls {
self.client
.add_relay(url)
.await
.map_err(|e| Error::Transport(e.to_string()))?;
}
self.client.connect().await;
Ok(())
}
pub async fn disconnect(&self) -> Result<()> {
self.client.disconnect().await;
Ok(())
}
pub async fn publish_event(&self, event: &Event) -> Result<EventId> {
let output = self
.client
.send_event(event)
.await
.map_err(|e| Error::Transport(e.to_string()))?;
Ok(output.val)
}
pub async fn publish(&self, builder: EventBuilder) -> Result<EventId> {
let output = self
.client
.send_event_builder(builder)
.await
.map_err(|e| Error::Transport(e.to_string()))?;
Ok(output.val)
}
pub async fn sign(&self, builder: EventBuilder) -> Result<Event> {
self.client
.sign_event_builder(builder)
.await
.map_err(|e| Error::Transport(e.to_string()))
}
pub fn client(&self) -> &Arc<Client> {
&self.client
}
pub fn notifications(&self) -> tokio::sync::broadcast::Receiver<RelayPoolNotification> {
self.client.notifications()
}
pub async fn public_key(&self) -> Result<PublicKey> {
let signer = self
.client
.signer()
.await
.map_err(|e| Error::Other(e.to_string()))?;
signer
.get_public_key()
.await
.map_err(|e| Error::Other(e.to_string()))
}
pub async fn subscribe(&self, filters: Vec<Filter>) -> Result<()> {
for filter in filters {
self.client
.subscribe(filter, None)
.await
.map_err(|e| Error::Transport(e.to_string()))?;
}
Ok(())
}
}
#[async_trait]
impl RelayPoolTrait for RelayPool {
async fn connect(&self, relay_urls: &[String]) -> Result<()> {
RelayPool::connect(self, relay_urls).await
}
async fn disconnect(&self) -> Result<()> {
RelayPool::disconnect(self).await
}
async fn publish_event(&self, event: &Event) -> Result<EventId> {
RelayPool::publish_event(self, event).await
}
async fn publish(&self, builder: EventBuilder) -> Result<EventId> {
RelayPool::publish(self, builder).await
}
async fn sign(&self, builder: EventBuilder) -> Result<Event> {
RelayPool::sign(self, builder).await
}
async fn signer(&self) -> Result<Arc<dyn NostrSigner>> {
self.client
.signer()
.await
.map_err(|e| Error::Other(e.to_string()))
}
fn notifications(&self) -> tokio::sync::broadcast::Receiver<RelayPoolNotification> {
RelayPool::notifications(self)
}
async fn public_key(&self) -> Result<PublicKey> {
RelayPool::public_key(self).await
}
async fn subscribe(&self, filters: Vec<Filter>) -> Result<()> {
RelayPool::subscribe(self, filters).await
}
}