|
@@ -43,6 +43,7 @@ impl Default for Pool {
|
|
}
|
|
}
|
|
|
|
|
|
/// Return a subscription that will be removed when dropped
|
|
/// Return a subscription that will be removed when dropped
|
|
|
|
+#[derive(Debug)]
|
|
pub struct PoolSubscription {
|
|
pub struct PoolSubscription {
|
|
subscription_id: SubscriptionId,
|
|
subscription_id: SubscriptionId,
|
|
subscriptions: Subscriptions,
|
|
subscriptions: Subscriptions,
|
|
@@ -177,49 +178,221 @@ mod test {
|
|
use super::*;
|
|
use super::*;
|
|
use nostr_rs_memory::Memory;
|
|
use nostr_rs_memory::Memory;
|
|
use nostr_rs_relayer::Relayer;
|
|
use nostr_rs_relayer::Relayer;
|
|
|
|
+ use nostr_rs_types::{account::Account, types::Content};
|
|
use std::time::Duration;
|
|
use std::time::Duration;
|
|
use tokio::{net::TcpListener, task::JoinHandle, time::sleep};
|
|
use tokio::{net::TcpListener, task::JoinHandle, time::sleep};
|
|
|
|
|
|
- async fn dummy_server() -> (Url, JoinHandle<()>) {
|
|
|
|
- let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
|
|
|
|
|
|
+ async fn dummy_server(port: u16) -> (Url, JoinHandle<()>) {
|
|
|
|
+ let listener = TcpListener::bind(format!("127.0.0.1:{}", port))
|
|
|
|
+ .await
|
|
|
|
+ .unwrap();
|
|
let local_addr = listener.local_addr().expect("addr");
|
|
let local_addr = listener.local_addr().expect("addr");
|
|
|
|
|
|
let relayer = Relayer::new(Some(Memory::default()), None).expect("valid dummy server");
|
|
let relayer = Relayer::new(Some(Memory::default()), None).expect("valid dummy server");
|
|
let stopper = relayer.main(listener).expect("valid main loop");
|
|
let stopper = relayer.main(listener).expect("valid main loop");
|
|
(
|
|
(
|
|
- Url::parse(&format!("ws://{}", local_addr.to_string())).expect("valid url"),
|
|
|
|
|
|
+ Url::parse(&format!("ws://{}", local_addr)).expect("valid url"),
|
|
stopper,
|
|
stopper,
|
|
)
|
|
)
|
|
}
|
|
}
|
|
|
|
|
|
#[tokio::test]
|
|
#[tokio::test]
|
|
async fn droppable_subscription() {
|
|
async fn droppable_subscription() {
|
|
- let pool = Pool::default();
|
|
|
|
- let subscription = pool
|
|
|
|
|
|
+ let client_pool = Pool::default();
|
|
|
|
+ let subscription = client_pool
|
|
.subscribe(Default::default())
|
|
.subscribe(Default::default())
|
|
.await
|
|
.await
|
|
.expect("valid subscription");
|
|
.expect("valid subscription");
|
|
|
|
|
|
- assert_eq!(pool.active_subscriptions().await, 1);
|
|
|
|
|
|
+ assert_eq!(client_pool.active_subscriptions().await, 1);
|
|
drop(subscription);
|
|
drop(subscription);
|
|
sleep(Duration::from_millis(10)).await;
|
|
sleep(Duration::from_millis(10)).await;
|
|
- assert_eq!(pool.active_subscriptions().await, 0);
|
|
|
|
|
|
+ assert_eq!(client_pool.active_subscriptions().await, 0);
|
|
}
|
|
}
|
|
|
|
|
|
#[tokio::test]
|
|
#[tokio::test]
|
|
async fn connect_to_dummy_server() {
|
|
async fn connect_to_dummy_server() {
|
|
- let (addr, stopper) = dummy_server().await;
|
|
|
|
- let pool = Pool::new_with_clients(vec![addr]);
|
|
|
|
|
|
+ let (addr, stopper) = dummy_server(0).await;
|
|
|
|
+ let client_pool = Pool::new_with_clients(vec![addr]);
|
|
|
|
|
|
- assert_eq!(0, pool.check_active_connections().await);
|
|
|
|
|
|
+ assert_eq!(0, client_pool.check_active_connections().await);
|
|
|
|
|
|
- sleep(Duration::from_millis(1000)).await;
|
|
|
|
- assert_eq!(1, pool.check_active_connections().await);
|
|
|
|
|
|
+ sleep(Duration::from_millis(10)).await;
|
|
|
|
+ assert_eq!(1, client_pool.check_active_connections().await);
|
|
|
|
|
|
// stop dummy server
|
|
// stop dummy server
|
|
stopper.abort();
|
|
stopper.abort();
|
|
|
|
|
|
sleep(Duration::from_millis(100)).await;
|
|
sleep(Duration::from_millis(100)).await;
|
|
- assert_eq!(0, pool.check_active_connections().await);
|
|
|
|
|
|
+ assert_eq!(0, client_pool.check_active_connections().await);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #[tokio::test]
|
|
|
|
+ async fn two_clients_communication() {
|
|
|
|
+ let (addr, _) = dummy_server(0).await;
|
|
|
|
+ let mut client_pool1 = Pool::new_with_clients(vec![addr.clone()]);
|
|
|
|
+ let client_pool2 = Pool::new_with_clients(vec![addr]);
|
|
|
|
+
|
|
|
|
+ let _sub1 = client_pool1
|
|
|
|
+ .subscribe(Default::default())
|
|
|
|
+ .await
|
|
|
|
+ .expect("valid subscription");
|
|
|
|
+
|
|
|
|
+ sleep(Duration::from_millis(10)).await;
|
|
|
|
+
|
|
|
|
+ assert!(client_pool1
|
|
|
|
+ .try_recv()
|
|
|
|
+ .map(|(r, _)| r)
|
|
|
|
+ .expect("valid message")
|
|
|
|
+ .as_end_of_stored_events()
|
|
|
|
+ .is_some());
|
|
|
|
+ assert!(client_pool1.try_recv().is_none());
|
|
|
|
+
|
|
|
|
+ let account1 = Account::default();
|
|
|
|
+ let signed_content = account1
|
|
|
|
+ .sign_content(vec![], Content::ShortTextNote("test 0".to_owned()), None)
|
|
|
|
+ .expect("valid signed content");
|
|
|
|
+
|
|
|
|
+ client_pool2.post(signed_content.clone().into()).await;
|
|
|
|
+
|
|
|
|
+ sleep(Duration::from_millis(10)).await;
|
|
|
|
+
|
|
|
|
+ assert_eq!(
|
|
|
|
+ Some((signed_content.id, signed_content.signature)),
|
|
|
|
+ client_pool1
|
|
|
|
+ .try_recv()
|
|
|
|
+ .and_then(|(r, _)| r.as_event().cloned().map(|x| x.event))
|
|
|
|
+ .map(|x| (x.id, x.signature))
|
|
|
|
+ );
|
|
|
|
+ assert!(client_pool1.try_recv().is_none());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #[tokio::test]
|
|
|
|
+ async fn reconnect_and_resubscribe() {
|
|
|
|
+ let (addr, stopper) = dummy_server(0).await;
|
|
|
|
+ let mut client_pool1 = Pool::new_with_clients(vec![addr.clone()]);
|
|
|
|
+ let client_pool2 = Pool::new_with_clients(vec![addr.clone()]);
|
|
|
|
+
|
|
|
|
+ let _sub1 = client_pool1
|
|
|
|
+ .subscribe(Default::default())
|
|
|
|
+ .await
|
|
|
|
+ .expect("valid subscription");
|
|
|
|
+
|
|
|
|
+ sleep(Duration::from_millis(10)).await;
|
|
|
|
+
|
|
|
|
+ assert!(client_pool1
|
|
|
|
+ .try_recv()
|
|
|
|
+ .map(|(r, _)| r)
|
|
|
|
+ .expect("valid message")
|
|
|
|
+ .as_end_of_stored_events()
|
|
|
|
+ .is_some());
|
|
|
|
+ assert!(client_pool1.try_recv().is_none());
|
|
|
|
+
|
|
|
|
+ let account1 = Account::default();
|
|
|
|
+ let signed_content = account1
|
|
|
|
+ .sign_content(vec![], Content::ShortTextNote("test 1".to_owned()), None)
|
|
|
|
+ .expect("valid signed content");
|
|
|
|
+
|
|
|
|
+ client_pool2.post(signed_content.clone().into()).await;
|
|
|
|
+
|
|
|
|
+ sleep(Duration::from_millis(10)).await;
|
|
|
|
+
|
|
|
|
+ assert_eq!(
|
|
|
|
+ Some((signed_content.id, signed_content.signature)),
|
|
|
|
+ client_pool1
|
|
|
|
+ .try_recv()
|
|
|
|
+ .and_then(|(r, _)| r.as_event().cloned().map(|x| x.event))
|
|
|
|
+ .map(|x| (x.id, x.signature))
|
|
|
|
+ );
|
|
|
|
+ assert!(client_pool1.try_recv().is_none());
|
|
|
|
+
|
|
|
|
+ assert_eq!(1, client_pool1.check_active_connections().await);
|
|
|
|
+ assert_eq!(1, client_pool2.check_active_connections().await);
|
|
|
|
+
|
|
|
|
+ stopper.abort();
|
|
|
|
+
|
|
|
|
+ sleep(Duration::from_millis(10)).await;
|
|
|
|
+
|
|
|
|
+ assert_eq!(0, client_pool1.check_active_connections().await);
|
|
|
|
+ assert_eq!(0, client_pool2.check_active_connections().await);
|
|
|
|
+
|
|
|
|
+ let (_, stopper) = dummy_server(addr.port().expect("port")).await;
|
|
|
|
+
|
|
|
|
+ sleep(Duration::from_millis(2_000)).await;
|
|
|
|
+
|
|
|
|
+ assert_eq!(1, client_pool1.check_active_connections().await);
|
|
|
|
+ assert_eq!(1, client_pool2.check_active_connections().await);
|
|
|
|
+
|
|
|
|
+ let signed_content = account1
|
|
|
|
+ .sign_content(vec![], Content::ShortTextNote("test 1".to_owned()), None)
|
|
|
|
+ .expect("valid signed content");
|
|
|
|
+
|
|
|
|
+ client_pool2.post(signed_content.clone().into()).await;
|
|
|
|
+
|
|
|
|
+ sleep(Duration::from_millis(10)).await;
|
|
|
|
+
|
|
|
|
+ assert!(client_pool1
|
|
|
|
+ .try_recv()
|
|
|
|
+ .map(|(r, _)| r)
|
|
|
|
+ .expect("valid message")
|
|
|
|
+ .as_end_of_stored_events()
|
|
|
|
+ .is_some());
|
|
|
|
+ assert_eq!(
|
|
|
|
+ Some((signed_content.id, signed_content.signature)),
|
|
|
|
+ client_pool1
|
|
|
|
+ .try_recv()
|
|
|
|
+ .and_then(|(r, _)| r.as_event().cloned().map(|x| x.event))
|
|
|
|
+ .map(|x| (x.id, x.signature))
|
|
|
|
+ );
|
|
|
|
+ assert!(client_pool1.try_recv().is_none());
|
|
|
|
+
|
|
|
|
+ stopper.abort();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #[tokio::test]
|
|
|
|
+ async fn connect_multiple_servers() {
|
|
|
|
+ let (addr1, _) = dummy_server(0).await;
|
|
|
|
+ let (addr2, _) = dummy_server(0).await;
|
|
|
|
+ let mut client_pool1 = Pool::new_with_clients(vec![addr1.clone(), addr2]);
|
|
|
|
+ let client_pool2 = Pool::new_with_clients(vec![addr1]);
|
|
|
|
+
|
|
|
|
+ let _sub1 = client_pool1
|
|
|
|
+ .subscribe(Default::default())
|
|
|
|
+ .await
|
|
|
|
+ .expect("valid subscription");
|
|
|
|
+
|
|
|
|
+ sleep(Duration::from_millis(10)).await;
|
|
|
|
+
|
|
|
|
+ assert!(client_pool1
|
|
|
|
+ .try_recv()
|
|
|
|
+ .map(|(r, _)| r)
|
|
|
|
+ .expect("valid message")
|
|
|
|
+ .as_end_of_stored_events()
|
|
|
|
+ .is_some());
|
|
|
|
+
|
|
|
|
+ assert!(client_pool1
|
|
|
|
+ .try_recv()
|
|
|
|
+ .map(|(r, _)| r)
|
|
|
|
+ .expect("valid message")
|
|
|
|
+ .as_end_of_stored_events()
|
|
|
|
+ .is_some());
|
|
|
|
+
|
|
|
|
+ let account1 = Account::default();
|
|
|
|
+ let signed_content = account1
|
|
|
|
+ .sign_content(vec![], Content::ShortTextNote("test 0".to_owned()), None)
|
|
|
|
+ .expect("valid signed content");
|
|
|
|
+
|
|
|
|
+ client_pool2.post(signed_content.clone().into()).await;
|
|
|
|
+
|
|
|
|
+ sleep(Duration::from_millis(10)).await;
|
|
|
|
+
|
|
|
|
+ assert_eq!(
|
|
|
|
+ Some((signed_content.id, signed_content.signature)),
|
|
|
|
+ client_pool1
|
|
|
|
+ .try_recv()
|
|
|
|
+ .and_then(|(r, _)| r.as_event().cloned().map(|x| x.event))
|
|
|
|
+ .map(|x| (x.id, x.signature))
|
|
|
|
+ );
|
|
|
|
+ assert!(client_pool1.try_recv().is_none());
|
|
}
|
|
}
|
|
}
|
|
}
|