nostr-sdk 0.45.0

A full-featured SDK for building high-performance and reliable nostr applications.
Documentation
use std::future::IntoFuture;
use std::time::Duration;

use nostr::message::ClientMessage;

use crate::error::Error;
use crate::future::BoxedFuture;
use crate::relay::Relay;

/// Send the client message
#[must_use = "Does nothing unless you await!"]
pub struct SendMessage<'relay, 'msg> {
    relay: &'relay Relay,
    msg: ClientMessage<'msg>,
    wait_until_sent: Option<Duration>,
}

impl<'relay, 'msg> SendMessage<'relay, 'msg> {
    pub(crate) fn new(relay: &'relay Relay, msg: ClientMessage<'msg>) -> Self {
        Self {
            relay,
            msg,
            wait_until_sent: None,
        }
    }

    #[inline]
    pub(crate) fn maybe_wait_until_sent(mut self, wait_until_sent: Option<Duration>) -> Self {
        self.wait_until_sent = wait_until_sent;
        self
    }

    /// Wait that message is sent
    #[inline]
    pub fn wait_until_sent(mut self, timeout: Duration) -> Self {
        self.wait_until_sent = Some(timeout);
        self
    }
}

impl<'relay, 'msg> IntoFuture for SendMessage<'relay, 'msg>
where
    'msg: 'relay,
{
    type Output = Result<(), Error>;
    type IntoFuture = BoxedFuture<'relay, Self::Output>;

    fn into_future(self) -> Self::IntoFuture {
        Box::pin(async move {
            self.relay
                .inner
                .send_msg(self.msg, self.wait_until_sent)
                .await
        })
    }
}

#[cfg(test)]
mod tests {
    use nostr::filter::Filter;
    use nostr::message::SubscriptionId;
    use nostr::types::RelayUrl;

    use super::*;
    use crate::error::ErrorKind;

    // At the moment, before consider a relay disconnected, are required at least 2 attempts and a success rate < 90%
    #[tokio::test]
    async fn test_send_message_to_non_connected_relay() {
        let url = RelayUrl::parse("ws://127.0.0.1:11123").unwrap();
        let relay: Relay = Relay::new(url);

        let msg = ClientMessage::req(SubscriptionId::generate(), Filter::new().limit(10));

        // First attempt
        let res = relay.try_connect().timeout(Duration::from_secs(1)).await;
        assert_eq!(res.unwrap_err().kind(), ErrorKind::Transport);

        // Relay is disconnected, but is required another attempt before consider it non-connected
        let res = relay.send_msg(msg.clone()).await;
        assert!(res.is_ok());

        // Second attempt
        let res = relay.try_connect().timeout(Duration::from_secs(1)).await;
        assert_eq!(res.unwrap_err().kind(), ErrorKind::Transport);

        // Relay is disconnected, we have a 2 attempts and success rate is < 90%
        let res = relay.send_msg(msg).await;
        let err = res.unwrap_err();
        assert_eq!(err.kind(), ErrorKind::State);
        assert_eq!(err.to_string(), "relay not connected");
    }
}