|
@@ -1,28 +1,18 @@
|
|
-use crate::{connection::ConnectionId, Connection, Error, Subscription};
|
|
|
|
|
|
+use crate::{connection::ConnectionId, subscription::SubscriptionManager, Connection, Error};
|
|
use futures_util::StreamExt;
|
|
use futures_util::StreamExt;
|
|
use nostr_rs_client::{Error as ClientError, Pool};
|
|
use nostr_rs_client::{Error as ClientError, Pool};
|
|
use nostr_rs_storage_base::Storage;
|
|
use nostr_rs_storage_base::Storage;
|
|
-use nostr_rs_types::{
|
|
|
|
- relayer,
|
|
|
|
- types::{Event, SubscriptionId},
|
|
|
|
- Request, Response,
|
|
|
|
-};
|
|
|
|
-use std::{collections::HashMap, ops::Deref};
|
|
|
|
|
|
+use nostr_rs_types::{relayer, types::Event, Request, Response};
|
|
|
|
+use std::{collections::HashMap, ops::Deref, sync::Arc};
|
|
use tokio::{
|
|
use tokio::{
|
|
net::{TcpListener, TcpStream},
|
|
net::{TcpListener, TcpStream},
|
|
- sync::{
|
|
|
|
- mpsc::{channel, Receiver, Sender},
|
|
|
|
- RwLockReadGuard,
|
|
|
|
- },
|
|
|
|
|
|
+ sync::mpsc::{channel, Receiver, Sender},
|
|
};
|
|
};
|
|
use tokio::{
|
|
use tokio::{
|
|
sync::{mpsc, RwLock},
|
|
sync::{mpsc, RwLock},
|
|
task::JoinHandle,
|
|
task::JoinHandle,
|
|
};
|
|
};
|
|
|
|
|
|
-type SubId = ConnectionId;
|
|
|
|
-type Subscriptions = HashMap<SubId, (SubscriptionId, Sender<Response>)>;
|
|
|
|
-
|
|
|
|
/// Relayer struct
|
|
/// Relayer struct
|
|
///
|
|
///
|
|
pub struct Relayer<T: Storage + Send + Sync + 'static> {
|
|
pub struct Relayer<T: Storage + Send + Sync + 'static> {
|
|
@@ -31,19 +21,8 @@ pub struct Relayer<T: Storage + Send + Sync + 'static> {
|
|
/// relayer just a dumb proxy (that can be useful for privacy) but it won't
|
|
/// relayer just a dumb proxy (that can be useful for privacy) but it won't
|
|
/// be able to perform any optimization like prefetching content while offline
|
|
/// be able to perform any optimization like prefetching content while offline
|
|
storage: Option<T>,
|
|
storage: Option<T>,
|
|
- /// Keeps a map between the internal subscription ID and the subscription
|
|
|
|
- /// type. One subscription ID may have multiple subscription types.
|
|
|
|
- ///
|
|
|
|
- /// Each connection keeps a list of the subscription ID provided by the user
|
|
|
|
- /// (String) and the internal, globally recognized subscription ID which is
|
|
|
|
- /// internal (SubId)
|
|
|
|
- subscriptions_ids_index: RwLock<HashMap<SubId, Vec<Subscription>>>,
|
|
|
|
- /// Each subscription type that is active has a list of subscriptions.
|
|
|
|
- ///
|
|
|
|
- /// A single REQ can be subscribed to multiple subscription types, specially
|
|
|
|
- /// when it is translated in OR filters. It is designed this way to allow a
|
|
|
|
- /// fast iteration and match quickly filters.
|
|
|
|
- subscriptions: RwLock<HashMap<Subscription, RwLock<Subscriptions>>>,
|
|
|
|
|
|
+ /// x
|
|
|
|
+ subscriptions: Arc<SubscriptionManager>,
|
|
clients: RwLock<HashMap<ConnectionId, Connection>>,
|
|
clients: RwLock<HashMap<ConnectionId, Connection>>,
|
|
/// This Sender can be used to send requests from anywhere to the relayer.
|
|
/// This Sender can be used to send requests from anywhere to the relayer.
|
|
send_to_relayer: Sender<(ConnectionId, Request)>,
|
|
send_to_relayer: Sender<(ConnectionId, Request)>,
|
|
@@ -76,10 +55,9 @@ impl<T: Storage + Send + Sync + 'static> Relayer<T> {
|
|
let (sender, receiver) = channel(100_000);
|
|
let (sender, receiver) = channel(100_000);
|
|
Ok(Self {
|
|
Ok(Self {
|
|
storage,
|
|
storage,
|
|
|
|
+ subscriptions: Default::default(),
|
|
send_to_relayer: sender.clone(),
|
|
send_to_relayer: sender.clone(),
|
|
relayer_receiver: Some(receiver),
|
|
relayer_receiver: Some(receiver),
|
|
- subscriptions: Default::default(),
|
|
|
|
- subscriptions_ids_index: Default::default(),
|
|
|
|
clients: Default::default(),
|
|
clients: Default::default(),
|
|
client_pool: if let Some(client_pool) = client_pool {
|
|
client_pool: if let Some(client_pool) = client_pool {
|
|
Some(Self::handle_client_pool(client_pool, sender)?)
|
|
Some(Self::handle_client_pool(client_pool, sender)?)
|
|
@@ -89,6 +67,11 @@ impl<T: Storage + Send + Sync + 'static> Relayer<T> {
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// Total number of subscribers requests that actively listening for new events
|
|
|
|
+ pub fn total_subscribers(&self) -> usize {
|
|
|
|
+ self.subscriptions.total_subscribers()
|
|
|
|
+ }
|
|
|
|
+
|
|
/// Splits the relayer object and extract their receiver.
|
|
/// Splits the relayer object and extract their receiver.
|
|
pub fn split(mut self) -> Result<(Self, Receiver<(ConnectionId, Request)>), Error> {
|
|
pub fn split(mut self) -> Result<(Self, Receiver<(ConnectionId, Request)>), Error> {
|
|
let receiver = self.relayer_receiver.take().ok_or(Error::AlreadySplitted)?;
|
|
let receiver = self.relayer_receiver.take().ok_or(Error::AlreadySplitted)?;
|
|
@@ -184,12 +167,13 @@ impl<T: Storage + Send + Sync + 'static> Relayer<T> {
|
|
let client =
|
|
let client =
|
|
Connection::new_connection(self.send_to_relayer.clone(), disconnection_notify, stream)
|
|
Connection::new_connection(self.send_to_relayer.clone(), disconnection_notify, stream)
|
|
.await?;
|
|
.await?;
|
|
- let id = client.conn_id;
|
|
|
|
|
|
+ let id = client.get_conn_id();
|
|
self.clients.write().await.insert(id, client);
|
|
self.clients.write().await.insert(id, client);
|
|
|
|
|
|
Ok(id)
|
|
Ok(id)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// Process a request from a connected client
|
|
async fn process_request_from_client(
|
|
async fn process_request_from_client(
|
|
&self,
|
|
&self,
|
|
connection: &Connection,
|
|
connection: &Connection,
|
|
@@ -217,37 +201,6 @@ impl<T: Storage + Send + Sync + 'static> Relayer<T> {
|
|
let _ = client_pool.subscribe(request.filters.clone().into()).await;
|
|
let _ = client_pool.subscribe(request.filters.clone().into()).await;
|
|
}
|
|
}
|
|
|
|
|
|
- // Create subscription
|
|
|
|
- let (sub_id, receiver) = connection
|
|
|
|
- .create_subscription(request.subscription_id.deref().to_owned())
|
|
|
|
- .await;
|
|
|
|
- let mut sub_index = self.subscriptions_ids_index.write().await;
|
|
|
|
- let mut subscriptions = self.subscriptions.write().await;
|
|
|
|
- if let Some(prev_subs) = sub_index.remove(&sub_id) {
|
|
|
|
- // remove any previous subscriptions
|
|
|
|
- for index in prev_subs.iter() {
|
|
|
|
- if let Some(subscriptions) = subscriptions.get_mut(index) {
|
|
|
|
- subscriptions.write().await.remove(&sub_id);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- let mut sub_index_values = vec![];
|
|
|
|
- for index in Subscription::from_filters(&request.filters).into_iter() {
|
|
|
|
- subscriptions
|
|
|
|
- .entry(index.clone())
|
|
|
|
- .or_insert_with(|| RwLock::new(HashMap::new()))
|
|
|
|
- .write()
|
|
|
|
- .await
|
|
|
|
- .insert(sub_id, (request.subscription_id.clone(), receiver.clone()));
|
|
|
|
- sub_index_values.push(index);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- sub_index.insert(sub_id, sub_index_values);
|
|
|
|
-
|
|
|
|
- drop(subscriptions);
|
|
|
|
- drop(sub_index);
|
|
|
|
-
|
|
|
|
if let Some(storage) = self.storage.as_ref() {
|
|
if let Some(storage) = self.storage.as_ref() {
|
|
// Sent all events that match the filter that are stored in our database
|
|
// Sent all events that match the filter that are stored in our database
|
|
for filter in request.filters.clone().into_iter() {
|
|
for filter in request.filters.clone().into_iter() {
|
|
@@ -267,19 +220,22 @@ impl<T: Storage + Send + Sync + 'static> Relayer<T> {
|
|
|
|
|
|
let _ = connection
|
|
let _ = connection
|
|
.send(relayer::EndOfStoredEvents(request.subscription_id.clone()).into());
|
|
.send(relayer::EndOfStoredEvents(request.subscription_id.clone()).into());
|
|
|
|
+
|
|
|
|
+ connection
|
|
|
|
+ .keep_track_subscription(
|
|
|
|
+ request.subscription_id.clone(),
|
|
|
|
+ self.subscriptions
|
|
|
|
+ .subscribe(
|
|
|
|
+ connection.get_conn_id(),
|
|
|
|
+ connection.get_sender(),
|
|
|
|
+ request.clone(),
|
|
|
|
+ )
|
|
|
|
+ .await,
|
|
|
|
+ )
|
|
|
|
+ .await;
|
|
}
|
|
}
|
|
- Request::Close(close) => {
|
|
|
|
- if let Some(id) = connection.get_subscription_id(&close.0).await {
|
|
|
|
- let mut subscriptions = self.subscriptions_ids_index.write().await;
|
|
|
|
- if let Some(indexes) = subscriptions.remove(&id) {
|
|
|
|
- let mut subscriptions = self.subscriptions.write().await;
|
|
|
|
- for index in indexes {
|
|
|
|
- if let Some(subscriptions) = subscriptions.get_mut(&index) {
|
|
|
|
- subscriptions.write().await.remove(&id);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ Request::Close(_close) => {
|
|
|
|
+ todo!()
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
@@ -287,43 +243,47 @@ impl<T: Storage + Send + Sync + 'static> Relayer<T> {
|
|
}
|
|
}
|
|
|
|
|
|
#[inline]
|
|
#[inline]
|
|
- fn broadcast_to_subscribers<'a>(
|
|
|
|
- subscriptions: RwLockReadGuard<'a, Subscriptions>,
|
|
|
|
- event: &Event,
|
|
|
|
- ) {
|
|
|
|
- for (_, receiver) in subscriptions.iter() {
|
|
|
|
- let _ = receiver.1.try_send(
|
|
|
|
- relayer::Event {
|
|
|
|
- subscription_id: receiver.0.clone(),
|
|
|
|
- event: event.clone(),
|
|
|
|
- }
|
|
|
|
- .into(),
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- #[inline]
|
|
|
|
/// Broadcast a given event to all local subscribers
|
|
/// Broadcast a given event to all local subscribers
|
|
pub async fn broadcast(&self, event: &Event) {
|
|
pub async fn broadcast(&self, event: &Event) {
|
|
if let Some(storage) = self.storage.as_ref() {
|
|
if let Some(storage) = self.storage.as_ref() {
|
|
let _ = storage.store(event).await;
|
|
let _ = storage.store(event).await;
|
|
}
|
|
}
|
|
- let subscriptions = self.subscriptions.read().await;
|
|
|
|
|
|
|
|
- for subscription_type in Subscription::from_event(event) {
|
|
|
|
- if let Some(subscribers) = subscriptions.get(&subscription_type) {
|
|
|
|
- Self::broadcast_to_subscribers(subscribers.read().await, event);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ self.subscriptions.broadcast(event.clone());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#[cfg(test)]
|
|
#[cfg(test)]
|
|
mod test {
|
|
mod test {
|
|
|
|
+ use std::time::Duration;
|
|
|
|
+
|
|
use super::*;
|
|
use super::*;
|
|
|
|
+ use futures::future::join_all;
|
|
use nostr_rs_memory::Memory;
|
|
use nostr_rs_memory::Memory;
|
|
use nostr_rs_types::Request;
|
|
use nostr_rs_types::Request;
|
|
use serde_json::json;
|
|
use serde_json::json;
|
|
|
|
+ use tokio::time::sleep;
|
|
|
|
+
|
|
|
|
+ fn get_note() -> Request {
|
|
|
|
+ serde_json::from_value(json!(
|
|
|
|
+ [
|
|
|
|
+ "EVENT",
|
|
|
|
+ {
|
|
|
|
+ "kind":1,
|
|
|
|
+ "content":"Pong",
|
|
|
|
+ "tags":[
|
|
|
|
+ ["e","9508850d7ddc8ef58c8b392236c49d472dc23fa11f4e73eb5475dfb099ddff42","","root"],
|
|
|
|
+ ["e","2e72250d80e9b3fd30230b3db3ed7d22f15d266ed345c36700b01ec153c9e28a","","reply"],
|
|
|
|
+ ["p","39a7d06e824c0c2523bedb93f0cef84245e4401fee03b6257a1c6dfd18b57efb"],
|
|
|
|
+ ["p","ee7202ad91459e013bfef263c59e47deb0163a5e7651b026673765488bfaf102"]
|
|
|
|
+ ],
|
|
|
|
+ "created_at":1681938616,
|
|
|
|
+ "pubkey":"a42007e33cfa25673b26f46f39df039aa6003258a68dc88f1f1e0447607aedb3",
|
|
|
|
+ "id":"e862fe23daf52ab09b36a37fa91ca3743e0c323e630e8627891212ca147c2da9",
|
|
|
|
+ "sig":"9036150a6c8a32933cffcc42aec4d2109a22e9f10d1c3860c0435a925e6386babb7df5c95fcf68c8ed6a9726a1f07225af663d0b068eb555014130aad21674fc",
|
|
|
|
+ }
|
|
|
|
+ ])).expect("value")
|
|
|
|
+ }
|
|
|
|
|
|
async fn get_db(prefill: bool) -> Memory {
|
|
async fn get_db(prefill: bool) -> Memory {
|
|
let db = Memory::default();
|
|
let db = Memory::default();
|
|
@@ -472,12 +432,110 @@ mod test {
|
|
|
|
|
|
#[tokio::test]
|
|
#[tokio::test]
|
|
async fn server_listener_real_time() {
|
|
async fn server_listener_real_time() {
|
|
- let request: Request = serde_json::from_str("[\"REQ\",\"1298169700973717\",{\"authors\":[\"39a7d06e824c0c2523bedb93f0cef84245e4401fee03b6257a1c6dfd18b57efb\"],\"since\":1681939304},{\"#p\":[\"39a7d06e824c0c2523bedb93f0cef84245e4401fee03b6257a1c6dfd18b57efb\"],\"kinds\":[1,3,6,7,9735],\"since\":1681939304},{\"#p\":[\"39a7d06e824c0c2523bedb93f0cef84245e4401fee03b6257a1c6dfd18b57efb\"],\"kinds\":[4]},{\"authors\":[\"39a7d06e824c0c2523bedb93f0cef84245e4401fee03b6257a1c6dfd18b57efb\"],\"kinds\":[4]},{\"#e\":[\"2e72250d80e9b3fd30230b3db3ed7d22f15d266ed345c36700b01ec153c9e28a\",\"a5e3369c43daf2675ecbce18831e5f4e07db0d4dde0ef4f5698e645e4c46eed1\"],\"kinds\":[1,6,7,9735]}]").expect("valid object");
|
|
|
|
|
|
+ let request: Request = serde_json::from_value(json!(
|
|
|
|
+ [
|
|
|
|
+ "REQ",
|
|
|
|
+ "1298169700973717",
|
|
|
|
+ {
|
|
|
|
+ "authors": ["39a7d06e824c0c2523bedb93f0cef84245e4401fee03b6257a1c6dfd18b57efb"],
|
|
|
|
+ "since":1681939304
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ "#p":["39a7d06e824c0c2523bedb93f0cef84245e4401fee03b6257a1c6dfd18b57efb"],
|
|
|
|
+ "kinds":[1,3,6,7,9735],
|
|
|
|
+ "since":1681939304
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ "#p":["39a7d06e824c0c2523bedb93f0cef84245e4401fee03b6257a1c6dfd18b57efb"],
|
|
|
|
+ "kinds":[4]
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ "authors":["39a7d06e824c0c2523bedb93f0cef84245e4401fee03b6257a1c6dfd18b57efb"],
|
|
|
|
+ "kinds":[4]
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ "#e":[
|
|
|
|
+ "2e72250d80e9b3fd30230b3db3ed7d22f15d266ed345c36700b01ec153c9e28a",
|
|
|
|
+ "a5e3369c43daf2675ecbce18831e5f4e07db0d4dde0ef4f5698e645e4c46eed1"
|
|
|
|
+ ],
|
|
|
|
+ "kinds":[1,6,7,9735]
|
|
|
|
+ }
|
|
|
|
+ ]))
|
|
|
|
+ .expect("valid object");
|
|
|
|
+ let relayer = Relayer::new(Some(get_db(false).await), None).expect("valid relayer");
|
|
|
|
+ let (connection, mut recv) = Connection::new_for_test();
|
|
|
|
+
|
|
|
|
+ assert_eq!(relayer.total_subscribers(), 0);
|
|
|
|
+ let _ = relayer
|
|
|
|
+ .process_request_from_client(&connection, request)
|
|
|
|
+ .await;
|
|
|
|
+
|
|
|
|
+ assert_eq!(relayer.total_subscribers(), 5);
|
|
|
|
+
|
|
|
|
+ // eod
|
|
|
|
+ assert!(recv
|
|
|
|
+ .try_recv()
|
|
|
|
+ .expect("valid")
|
|
|
|
+ .as_end_of_stored_events()
|
|
|
|
+ .is_some());
|
|
|
|
+
|
|
|
|
+ // It is empty
|
|
|
|
+ assert!(recv.try_recv().is_err());
|
|
|
|
+
|
|
|
|
+ relayer
|
|
|
|
+ .process_request_from_client(&connection, get_note())
|
|
|
|
+ .await
|
|
|
|
+ .expect("process event");
|
|
|
|
+
|
|
|
|
+ sleep(Duration::from_millis(100)).await;
|
|
|
|
+
|
|
|
|
+ // It is not empty
|
|
|
|
+ let msg = recv.try_recv();
|
|
|
|
+ assert!(msg.is_ok());
|
|
|
|
+ assert_eq!(
|
|
|
|
+ msg.expect("is ok")
|
|
|
|
+ .as_event()
|
|
|
|
+ .expect("valid")
|
|
|
|
+ .subscription_id
|
|
|
|
+ .to_string(),
|
|
|
|
+ "1298169700973717".to_owned()
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ // it must be deliverd at most once
|
|
|
|
+ assert!(recv.try_recv().is_err());
|
|
|
|
+ assert_eq!(relayer.total_subscribers(), 5);
|
|
|
|
+
|
|
|
|
+ // when client is dropped, the subscription is removed
|
|
|
|
+ // automatically
|
|
|
|
+ drop(connection);
|
|
|
|
+
|
|
|
|
+ sleep(Duration::from_millis(10)).await;
|
|
|
|
+
|
|
|
|
+ assert_eq!(relayer.total_subscribers(), 0);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #[tokio::test]
|
|
|
|
+ async fn subscribe_partial_key() {
|
|
|
|
+ let request: Request = serde_json::from_value(json!([
|
|
|
|
+ "REQ",
|
|
|
|
+ "1298169700973717",
|
|
|
|
+ {
|
|
|
|
+ "authors":["a42007e33c"],
|
|
|
|
+ "since":1681939304
|
|
|
|
+ }
|
|
|
|
+ ]))
|
|
|
|
+ .expect("valid object");
|
|
|
|
+
|
|
let relayer = Relayer::new(Some(get_db(false).await), None).expect("valid relayer");
|
|
let relayer = Relayer::new(Some(get_db(false).await), None).expect("valid relayer");
|
|
let (connection, mut recv) = Connection::new_for_test();
|
|
let (connection, mut recv) = Connection::new_for_test();
|
|
|
|
+
|
|
|
|
+ assert_eq!(relayer.total_subscribers(), 0);
|
|
let _ = relayer
|
|
let _ = relayer
|
|
.process_request_from_client(&connection, request)
|
|
.process_request_from_client(&connection, request)
|
|
.await;
|
|
.await;
|
|
|
|
+
|
|
|
|
+ assert_eq!(relayer.total_subscribers(), 1);
|
|
|
|
+
|
|
// eod
|
|
// eod
|
|
assert!(recv
|
|
assert!(recv
|
|
.try_recv()
|
|
.try_recv()
|
|
@@ -488,14 +546,190 @@ mod test {
|
|
// It is empty
|
|
// It is empty
|
|
assert!(recv.try_recv().is_err());
|
|
assert!(recv.try_recv().is_err());
|
|
|
|
|
|
- let new_event: Request = serde_json::from_str(r#"["EVENT", {"kind":1,"content":"Pong","tags":[["e","9508850d7ddc8ef58c8b392236c49d472dc23fa11f4e73eb5475dfb099ddff42","","root"],["e","2e72250d80e9b3fd30230b3db3ed7d22f15d266ed345c36700b01ec153c9e28a","","reply"],["p","39a7d06e824c0c2523bedb93f0cef84245e4401fee03b6257a1c6dfd18b57efb"],["p","ee7202ad91459e013bfef263c59e47deb0163a5e7651b026673765488bfaf102"]],"created_at":1681938616,"pubkey":"a42007e33cfa25673b26f46f39df039aa6003258a68dc88f1f1e0447607aedb3","id":"e862fe23daf52ab09b36a37fa91ca3743e0c323e630e8627891212ca147c2da9","sig":"9036150a6c8a32933cffcc42aec4d2109a22e9f10d1c3860c0435a925e6386babb7df5c95fcf68c8ed6a9726a1f07225af663d0b068eb555014130aad21674fc","meta":{"revision":0,"created":1681939266488,"version":0},"$loki":108}]"#).expect("value");
|
|
|
|
|
|
+ relayer
|
|
|
|
+ .process_request_from_client(&connection, get_note())
|
|
|
|
+ .await
|
|
|
|
+ .expect("process event");
|
|
|
|
+
|
|
|
|
+ sleep(Duration::from_millis(100)).await;
|
|
|
|
+
|
|
|
|
+ // It is not empty
|
|
|
|
+ let msg = recv.try_recv();
|
|
|
|
+ assert!(msg.is_ok());
|
|
|
|
+ assert_eq!(
|
|
|
|
+ msg.expect("is ok")
|
|
|
|
+ .as_event()
|
|
|
|
+ .expect("valid")
|
|
|
|
+ .subscription_id
|
|
|
|
+ .to_string(),
|
|
|
|
+ "1298169700973717".to_owned()
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ // it must be deliverd at most once
|
|
|
|
+ assert!(recv.try_recv().is_err());
|
|
|
|
+ assert_eq!(relayer.total_subscribers(), 1);
|
|
|
|
+
|
|
|
|
+ // when client is dropped, the subscription is removed
|
|
|
|
+ // automatically
|
|
|
|
+ drop(connection);
|
|
|
|
+
|
|
|
|
+ sleep(Duration::from_millis(10)).await;
|
|
|
|
+
|
|
|
|
+ assert_eq!(relayer.total_subscribers(), 0);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #[tokio::test]
|
|
|
|
+ async fn multiple_subcribers() {
|
|
|
|
+ let req1: Request = serde_json::from_value(json!(["REQ", "1298169700973717", {
|
|
|
|
+ "authors":["c42007e33c"],
|
|
|
|
+ }]))
|
|
|
|
+ .expect("valid object");
|
|
|
|
+ let req2: Request = serde_json::from_value(json!(["REQ", "1298169700973717", {
|
|
|
|
+ "authors":["a42007e33c"]
|
|
|
|
+ }]))
|
|
|
|
+ .expect("valid object");
|
|
|
|
+
|
|
|
|
+ let relayer = Relayer::new(Some(get_db(false).await), None).expect("valid relayer");
|
|
|
|
+ let (publisher, _) = Connection::new_for_test();
|
|
|
|
+
|
|
|
|
+ let mut set1 = (0..1000)
|
|
|
|
+ .map(|_| Connection::new_for_test())
|
|
|
|
+ .collect::<Vec<_>>();
|
|
|
|
+
|
|
|
|
+ let mut set2 = (0..100)
|
|
|
|
+ .map(|_| Connection::new_for_test())
|
|
|
|
+ .collect::<Vec<_>>();
|
|
|
|
+
|
|
|
|
+ let subscribe1 = set1
|
|
|
|
+ .iter()
|
|
|
|
+ .map(|(connection, _)| relayer.process_request_from_client(connection, req1.clone()))
|
|
|
|
+ .collect::<Vec<_>>();
|
|
|
|
+
|
|
|
|
+ let subscribe2 = set2
|
|
|
|
+ .iter()
|
|
|
|
+ .map(|(connection, _)| relayer.process_request_from_client(connection, req2.clone()))
|
|
|
|
+ .collect::<Vec<_>>();
|
|
|
|
+
|
|
|
|
+ assert_eq!(relayer.total_subscribers(), 0);
|
|
|
|
+
|
|
|
|
+ join_all(subscribe1)
|
|
|
|
+ .await
|
|
|
|
+ .into_iter()
|
|
|
|
+ .collect::<Result<Vec<_>, _>>()
|
|
|
|
+ .expect("valid calls");
|
|
|
|
+ join_all(subscribe2)
|
|
|
|
+ .await
|
|
|
|
+ .into_iter()
|
|
|
|
+ .collect::<Result<Vec<_>, _>>()
|
|
|
|
+ .expect("valid calls");
|
|
|
|
+
|
|
|
|
+ for (_, recv) in set1.iter_mut() {
|
|
|
|
+ assert!(recv
|
|
|
|
+ .try_recv()
|
|
|
|
+ .expect("end of stored events")
|
|
|
|
+ .as_end_of_stored_events()
|
|
|
|
+ .is_some());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (_, recv) in set2.iter_mut() {
|
|
|
|
+ assert!(recv
|
|
|
|
+ .try_recv()
|
|
|
|
+ .expect("end of stored events")
|
|
|
|
+ .as_end_of_stored_events()
|
|
|
|
+ .is_some());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ assert_eq!(relayer.total_subscribers(), 1100);
|
|
|
|
+
|
|
|
|
+ relayer
|
|
|
|
+ .process_request_from_client(&publisher, get_note())
|
|
|
|
+ .await
|
|
|
|
+ .expect("process event");
|
|
|
|
+
|
|
|
|
+ sleep(Duration::from_millis(10)).await;
|
|
|
|
+
|
|
|
|
+ for (_, recv) in set1.iter_mut() {
|
|
|
|
+ assert!(recv.try_recv().is_err());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (_, recv) in set2.iter_mut() {
|
|
|
|
+ let msg = recv.try_recv();
|
|
|
|
+ assert!(msg.is_ok());
|
|
|
|
+ let msg = msg.expect("msg");
|
|
|
|
+
|
|
|
|
+ assert_eq!(
|
|
|
|
+ msg.as_event().expect("valid").subscription_id.to_string(),
|
|
|
|
+ "1298169700973717".to_owned()
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ assert!(recv.try_recv().is_err());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ drop(set1);
|
|
|
|
+ sleep(Duration::from_millis(10)).await;
|
|
|
|
+ assert_eq!(relayer.total_subscribers(), 100);
|
|
|
|
+
|
|
|
|
+ drop(set2);
|
|
|
|
+ sleep(Duration::from_millis(10)).await;
|
|
|
|
+ assert_eq!(relayer.total_subscribers(), 0);
|
|
|
|
+
|
|
|
|
+ drop(relayer);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #[tokio::test]
|
|
|
|
+ async fn subscribe_to_all() {
|
|
|
|
+ let request: Request =
|
|
|
|
+ serde_json::from_value(json!(["REQ", "1298169700973717", {}])).expect("valid object");
|
|
|
|
+
|
|
|
|
+ let relayer = Relayer::new(Some(get_db(false).await), None).expect("valid relayer");
|
|
|
|
+ let (connection, mut recv) = Connection::new_for_test();
|
|
|
|
+
|
|
|
|
+ assert_eq!(relayer.total_subscribers(), 0);
|
|
|
|
+ let _ = relayer
|
|
|
|
+ .process_request_from_client(&connection, request)
|
|
|
|
+ .await;
|
|
|
|
+
|
|
|
|
+ assert_eq!(relayer.total_subscribers(), 1);
|
|
|
|
+
|
|
|
|
+ // eod
|
|
|
|
+ assert!(recv
|
|
|
|
+ .try_recv()
|
|
|
|
+ .expect("valid")
|
|
|
|
+ .as_end_of_stored_events()
|
|
|
|
+ .is_some());
|
|
|
|
+
|
|
|
|
+ // It is empty
|
|
|
|
+ assert!(recv.try_recv().is_err());
|
|
|
|
|
|
relayer
|
|
relayer
|
|
- .process_request_from_client(&connection, new_event)
|
|
|
|
|
|
+ .process_request_from_client(&connection, get_note())
|
|
.await
|
|
.await
|
|
.expect("process event");
|
|
.expect("process event");
|
|
|
|
|
|
|
|
+ sleep(Duration::from_millis(10)).await;
|
|
|
|
+
|
|
// It is not empty
|
|
// It is not empty
|
|
- assert!(recv.try_recv().is_ok());
|
|
|
|
|
|
+ let msg = recv.try_recv();
|
|
|
|
+ assert!(msg.is_ok());
|
|
|
|
+ assert_eq!(
|
|
|
|
+ msg.expect("is ok")
|
|
|
|
+ .as_event()
|
|
|
|
+ .expect("valid")
|
|
|
|
+ .subscription_id
|
|
|
|
+ .to_string(),
|
|
|
|
+ "1298169700973717".to_owned()
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ // it must be deliverd at most once
|
|
|
|
+ assert!(recv.try_recv().is_err());
|
|
|
|
+ assert_eq!(relayer.total_subscribers(), 1);
|
|
|
|
+
|
|
|
|
+ // when client is dropped, the subscription is removed
|
|
|
|
+ // automatically
|
|
|
|
+ drop(connection);
|
|
|
|
+
|
|
|
|
+ sleep(Duration::from_millis(10)).await;
|
|
|
|
+
|
|
|
|
+ assert_eq!(relayer.total_subscribers(), 0);
|
|
}
|
|
}
|
|
}
|
|
}
|