use std::future::IntoFuture;
use std::time::Duration;
use crate::error::Error;
use crate::future::BoxedFuture;
use crate::policy::AdmitStatus;
use crate::relay::{Relay, RelayStatus};
use crate::transport::websocket::{WebSocketSink, WebSocketStream};
#[must_use = "Does nothing unless you await!"]
pub struct TryConnect<'relay> {
relay: &'relay Relay,
timeout: Duration,
}
impl<'relay> TryConnect<'relay> {
#[inline]
pub(crate) fn new(relay: &'relay Relay) -> Self {
Self {
relay,
timeout: Duration::from_secs(15),
}
}
#[inline]
pub fn timeout(mut self, timeout: Duration) -> Self {
self.timeout = timeout;
self
}
}
impl<'relay> IntoFuture for TryConnect<'relay> {
type Output = Result<(), Error>;
type IntoFuture = BoxedFuture<'relay, Self::Output>;
fn into_future(self) -> Self::IntoFuture {
Box::pin(async move {
let status: RelayStatus = self.relay.status();
if status.is_shutdown() {
return Err(Error::shutdown());
}
if status.is_banned() {
return Err(Error::banned());
}
if !status.can_connect() {
return Ok(());
}
if let AdmitStatus::Rejected { reason } =
self.relay.inner.check_connection_policy().await?
{
self.relay.inner.set_status(RelayStatus::Terminated, false);
return Err(Error::connection_rejected(reason));
}
let stream: (WebSocketSink, WebSocketStream) = self
.relay
.inner
._try_connect(self.timeout, RelayStatus::Terminated)
.await?;
self.relay.inner.spawn_connection_task(Some(stream));
Ok(())
})
}
}
#[cfg(test)]
mod tests {
use async_utility::time;
use nostr::types::RelayUrl;
use super::*;
use crate::error::ErrorKind;
use crate::local_relay::*;
#[tokio::test]
async fn test_try_connect() {
let mock = MockRelay::run().await.unwrap();
let url = mock.url().await;
let relay: Relay = Relay::new(url);
assert_eq!(relay.status(), RelayStatus::Initialized);
relay
.try_connect()
.timeout(Duration::from_millis(500))
.await
.unwrap();
assert_eq!(relay.status(), RelayStatus::Connected);
time::sleep(Duration::from_millis(500)).await;
assert!(relay.inner.is_running());
}
#[tokio::test]
async fn test_try_connect_to_unreachable_relay() {
let url = RelayUrl::parse("wss://127.0.0.1:666").unwrap();
let relay: Relay = Relay::new(url);
assert_eq!(relay.status(), RelayStatus::Initialized);
let res = relay.try_connect().timeout(Duration::from_secs(2)).await;
assert_eq!(res.unwrap_err().kind(), ErrorKind::Transport);
assert_eq!(relay.status(), RelayStatus::Terminated);
assert!(!relay.inner.is_running());
}
}