|
@@ -1,12 +1,16 @@
|
|
use crate::{
|
|
use crate::{
|
|
connection::{ConnectionId, LocalConnection},
|
|
connection::{ConnectionId, LocalConnection},
|
|
- subscription::SubscriptionManager,
|
|
|
|
Connection, Error,
|
|
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, Url};
|
|
use nostr_rs_storage_base::Storage;
|
|
use nostr_rs_storage_base::Storage;
|
|
-use nostr_rs_types::{relayer, types::Event, Request, Response};
|
|
|
|
|
|
+use nostr_rs_subscription_manager::SubscriptionManager;
|
|
|
|
+use nostr_rs_types::{
|
|
|
|
+ relayer::{self, ROk, ROkStatus},
|
|
|
|
+ types::{Addr, Event, SubscriptionId},
|
|
|
|
+ Request, Response,
|
|
|
|
+};
|
|
use std::{
|
|
use std::{
|
|
collections::{HashMap, HashSet},
|
|
collections::{HashMap, HashSet},
|
|
ops::Deref,
|
|
ops::Deref,
|
|
@@ -21,6 +25,21 @@ use tokio::{
|
|
task::JoinHandle,
|
|
task::JoinHandle,
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+#[derive(Debug, Hash, Ord, PartialEq, PartialOrd, Eq, Clone)]
|
|
|
|
+pub struct RelayerSubscriptionId((SubscriptionId, ConnectionId));
|
|
|
|
+
|
|
|
|
+impl From<(SubscriptionId, ConnectionId)> for RelayerSubscriptionId {
|
|
|
|
+ fn from(value: (SubscriptionId, ConnectionId)) -> Self {
|
|
|
|
+ Self(value)
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl Default for RelayerSubscriptionId {
|
|
|
|
+ fn default() -> Self {
|
|
|
|
+ Self((SubscriptionId::empty(), ConnectionId::new_empty()))
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
/// Relayer struct
|
|
/// Relayer struct
|
|
///
|
|
///
|
|
pub struct Relayer<T: Storage + Send + Sync + 'static> {
|
|
pub struct Relayer<T: Storage + Send + Sync + 'static> {
|
|
@@ -30,7 +49,7 @@ pub struct Relayer<T: Storage + Send + Sync + 'static> {
|
|
/// 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>,
|
|
/// Subscription manager
|
|
/// Subscription manager
|
|
- subscriptions: Arc<SubscriptionManager>,
|
|
|
|
|
|
+ subscription_manager: Arc<SubscriptionManager<RelayerSubscriptionId, ()>>,
|
|
/// List of all active connections
|
|
/// List of all active connections
|
|
connections: RwLock<HashMap<ConnectionId, Connection>>,
|
|
connections: 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.
|
|
@@ -64,7 +83,7 @@ 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(),
|
|
|
|
|
|
+ subscription_manager: Default::default(),
|
|
send_to_relayer: sender.clone(),
|
|
send_to_relayer: sender.clone(),
|
|
relayer_receiver: Some(receiver),
|
|
relayer_receiver: Some(receiver),
|
|
connections: Default::default(),
|
|
connections: Default::default(),
|
|
@@ -76,9 +95,16 @@ impl<T: Storage + Send + Sync + 'static> Relayer<T> {
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// Connects to the relayer pool
|
|
|
|
+ pub async fn connect_to_relayer(&self, url: Url) -> Result<(), Error> {
|
|
|
|
+ let (client_pool, _) = self.client_pool.as_ref().ok_or(Error::NoClient)?;
|
|
|
|
+ let _ = client_pool.connect_to(url).await;
|
|
|
|
+ Ok(())
|
|
|
|
+ }
|
|
|
|
+
|
|
/// Total number of subscribers requests that actively listening for new events
|
|
/// Total number of subscribers requests that actively listening for new events
|
|
pub fn total_subscribers(&self) -> usize {
|
|
pub fn total_subscribers(&self) -> usize {
|
|
- self.subscriptions.total_subscribers()
|
|
|
|
|
|
+ self.subscription_manager.total_subscribers()
|
|
}
|
|
}
|
|
|
|
|
|
/// Splits the relayer object and extract their receiver.
|
|
/// Splits the relayer object and extract their receiver.
|
|
@@ -91,9 +117,12 @@ impl<T: Storage + Send + Sync + 'static> Relayer<T> {
|
|
///
|
|
///
|
|
/// This function consumes the object and takes the ownership. The returned
|
|
/// This function consumes the object and takes the ownership. The returned
|
|
/// JoinHandle() can be used to stop the main loop
|
|
/// JoinHandle() can be used to stop the main loop
|
|
- pub fn main(self, server: TcpListener) -> Result<JoinHandle<()>, Error> {
|
|
|
|
|
|
+ pub fn main(self, server: TcpListener) -> Result<(Arc<Self>, JoinHandle<()>), Error> {
|
|
let (this, mut receiver) = self.split()?;
|
|
let (this, mut receiver) = self.split()?;
|
|
- Ok(tokio::spawn(async move {
|
|
|
|
|
|
+ let _self = Arc::new(this);
|
|
|
|
+ let this = _self.clone();
|
|
|
|
+
|
|
|
|
+ let handle = tokio::spawn(async move {
|
|
loop {
|
|
loop {
|
|
tokio::select! {
|
|
tokio::select! {
|
|
Ok((stream, _)) = server.accept() => {
|
|
Ok((stream, _)) = server.accept() => {
|
|
@@ -103,12 +132,12 @@ impl<T: Storage + Send + Sync + 'static> Relayer<T> {
|
|
Some((conn_id, request)) = receiver.recv() => {
|
|
Some((conn_id, request)) = receiver.recv() => {
|
|
// receive messages from the connection pool
|
|
// receive messages from the connection pool
|
|
if conn_id.is_empty() {
|
|
if conn_id.is_empty() {
|
|
- // connection pool
|
|
|
|
|
|
+ // message received from client pool
|
|
if let Request::Event(event) = request {
|
|
if let Request::Event(event) = request {
|
|
|
|
+ let _ = this.broadcast(event.deref()).await;
|
|
if let Some(storage) = this.storage.as_ref() {
|
|
if let Some(storage) = this.storage.as_ref() {
|
|
let _ = storage.store_local_event(&event).await;
|
|
let _ = storage.store_local_event(&event).await;
|
|
}
|
|
}
|
|
- this.broadcast(event.deref()).await;
|
|
|
|
}
|
|
}
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
@@ -128,7 +157,9 @@ impl<T: Storage + Send + Sync + 'static> Relayer<T> {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- }))
|
|
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ Ok((_self, handle))
|
|
}
|
|
}
|
|
|
|
|
|
/// Handle the client pool
|
|
/// Handle the client pool
|
|
@@ -136,7 +167,7 @@ impl<T: Storage + Send + Sync + 'static> Relayer<T> {
|
|
/// Main loop to consume messages from the client pool and broadcast them to the local subscribers
|
|
/// Main loop to consume messages from the client pool and broadcast them to the local subscribers
|
|
fn handle_client_pool(
|
|
fn handle_client_pool(
|
|
client_pool: Pool,
|
|
client_pool: Pool,
|
|
- sender: Sender<(ConnectionId, Request)>,
|
|
|
|
|
|
+ send_message_to_relayer: Sender<(ConnectionId, Request)>,
|
|
) -> Result<(Pool, JoinHandle<()>), ClientError> {
|
|
) -> Result<(Pool, JoinHandle<()>), ClientError> {
|
|
let (mut receiver, client_pool) = client_pool.split()?;
|
|
let (mut receiver, client_pool) = client_pool.split()?;
|
|
|
|
|
|
@@ -145,12 +176,10 @@ impl<T: Storage + Send + Sync + 'static> Relayer<T> {
|
|
if let Some((response, _)) = receiver.recv().await {
|
|
if let Some((response, _)) = receiver.recv().await {
|
|
match response {
|
|
match response {
|
|
Response::Event(event) => {
|
|
Response::Event(event) => {
|
|
- let _ = sender
|
|
|
|
- .send((
|
|
|
|
- ConnectionId::new_empty(),
|
|
|
|
- Request::Event(event.event.into()),
|
|
|
|
- ))
|
|
|
|
- .await;
|
|
|
|
|
|
+ let _ = send_message_to_relayer.try_send((
|
|
|
|
+ ConnectionId::new_empty(),
|
|
|
|
+ Request::Event(event.event.into()),
|
|
|
|
+ ));
|
|
}
|
|
}
|
|
Response::EndOfStoredEvents(_) => {}
|
|
Response::EndOfStoredEvents(_) => {}
|
|
x => {
|
|
x => {
|
|
@@ -170,12 +199,33 @@ impl<T: Storage + Send + Sync + 'static> Relayer<T> {
|
|
}
|
|
}
|
|
|
|
|
|
/// Adds a new local connection to the list of active connections.
|
|
/// Adds a new local connection to the list of active connections.
|
|
- pub async fn create_new_local_connection(&self) -> LocalConnection {
|
|
|
|
|
|
+ pub async fn create_new_local_connection(self: &Arc<Self>) -> LocalConnection<T> {
|
|
let (conn, receiver) = Connection::new_local_connection();
|
|
let (conn, receiver) = Connection::new_local_connection();
|
|
let conn_id = conn.get_conn_id();
|
|
let conn_id = conn.get_conn_id();
|
|
self.connections.write().await.insert(conn_id, conn);
|
|
self.connections.write().await.insert(conn_id, conn);
|
|
|
|
|
|
- (conn_id, receiver, self.send_to_relayer.clone()).into()
|
|
|
|
|
|
+ (
|
|
|
|
+ conn_id,
|
|
|
|
+ receiver,
|
|
|
|
+ self.send_to_relayer.clone(),
|
|
|
|
+ self.clone(),
|
|
|
|
+ )
|
|
|
|
+ .into()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// Drops a connection from the list of active connections
|
|
|
|
+ ///
|
|
|
|
+ /// This function only works for local connections, normal connections can
|
|
|
|
+ /// be dropped on disconnection.
|
|
|
|
+ ///
|
|
|
|
+ /// This function could change in the future tu kick connections programmatically
|
|
|
|
+ pub fn drop_connection(self: &Arc<Self>, local_connection: &LocalConnection<T>) {
|
|
|
|
+ let id = local_connection.conn_id;
|
|
|
|
+ let this = self.clone();
|
|
|
|
+
|
|
|
|
+ tokio::spawn(async move {
|
|
|
|
+ this.connections.write().await.remove(&id);
|
|
|
|
+ });
|
|
}
|
|
}
|
|
|
|
|
|
/// Adds a new TpStream and adds it to the list of active connections.
|
|
/// Adds a new TpStream and adds it to the list of active connections.
|
|
@@ -200,32 +250,45 @@ impl<T: Storage + Send + Sync + 'static> Relayer<T> {
|
|
&self,
|
|
&self,
|
|
connection: &Connection,
|
|
connection: &Connection,
|
|
request: Request,
|
|
request: Request,
|
|
- ) -> Result<Option<Request>, Error> {
|
|
|
|
- match &request {
|
|
|
|
|
|
+ ) -> Result<(), Error> {
|
|
|
|
+ match request {
|
|
Request::Event(event) => {
|
|
Request::Event(event) => {
|
|
- if let Some(storage) = self.storage.as_ref() {
|
|
|
|
- let _ = storage.store(event).await;
|
|
|
|
- let _ = storage.store_local_event(event).await;
|
|
|
|
|
|
+ let event_id: Addr = event.id.clone().into();
|
|
|
|
+ if !self.broadcast(&event).await? {
|
|
|
|
+ connection.send(
|
|
|
|
+ ROk {
|
|
|
|
+ id: event_id,
|
|
|
|
+ status: ROkStatus::Duplicate,
|
|
|
|
+ }
|
|
|
|
+ .into(),
|
|
|
|
+ )?;
|
|
|
|
+ return Ok(());
|
|
}
|
|
}
|
|
|
|
|
|
- self.broadcast(event).await;
|
|
|
|
|
|
+ if let Some(storage) = self.storage.as_ref() {
|
|
|
|
+ let _ = storage.store_local_event(&event).await;
|
|
|
|
+ }
|
|
|
|
|
|
if let Some((client_pool, _)) = self.client_pool.as_ref() {
|
|
if let Some((client_pool, _)) = self.client_pool.as_ref() {
|
|
// pass the event to the pool of clients, so this relayer can relay
|
|
// pass the event to the pool of clients, so this relayer can relay
|
|
// their local events to the clients in the network of relayers
|
|
// their local events to the clients in the network of relayers
|
|
- let _ = client_pool.post(event.clone()).await;
|
|
|
|
|
|
+ let _ = client_pool.post(event).await;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ connection.send(
|
|
|
|
+ ROk {
|
|
|
|
+ id: event_id,
|
|
|
|
+ status: ROkStatus::Ok,
|
|
|
|
+ }
|
|
|
|
+ .into(),
|
|
|
|
+ )?;
|
|
}
|
|
}
|
|
Request::Request(request) => {
|
|
Request::Request(request) => {
|
|
let foreign_subscription = if let Some((client_pool, _)) = self.client_pool.as_ref()
|
|
let foreign_subscription = if let Some((client_pool, _)) = self.client_pool.as_ref()
|
|
{
|
|
{
|
|
// pass the subscription request to the pool of clients, so this relayer
|
|
// pass the subscription request to the pool of clients, so this relayer
|
|
// can relay any unknown event to the clients through their subscriptions
|
|
// can relay any unknown event to the clients through their subscriptions
|
|
- Some(
|
|
|
|
- client_pool
|
|
|
|
- .subscribe(request.filters.clone().into())
|
|
|
|
- .await?,
|
|
|
|
- )
|
|
|
|
|
|
+ Some(client_pool.subscribe(request.clone()).await)
|
|
} else {
|
|
} else {
|
|
None
|
|
None
|
|
};
|
|
};
|
|
@@ -260,11 +323,11 @@ impl<T: Storage + Send + Sync + 'static> Relayer<T> {
|
|
request.subscription_id.clone(),
|
|
request.subscription_id.clone(),
|
|
(
|
|
(
|
|
foreign_subscription,
|
|
foreign_subscription,
|
|
- self.subscriptions
|
|
|
|
|
|
+ self.subscription_manager
|
|
.subscribe(
|
|
.subscribe(
|
|
- connection.get_conn_id(),
|
|
|
|
- connection.get_sender(),
|
|
|
|
- request.clone(),
|
|
|
|
|
|
+ (request.subscription_id, connection.get_conn_id()).into(),
|
|
|
|
+ request.filters,
|
|
|
|
+ (),
|
|
)
|
|
)
|
|
.await,
|
|
.await,
|
|
),
|
|
),
|
|
@@ -272,21 +335,37 @@ impl<T: Storage + Send + Sync + 'static> Relayer<T> {
|
|
.await;
|
|
.await;
|
|
}
|
|
}
|
|
Request::Close(close) => {
|
|
Request::Close(close) => {
|
|
- connection.unsubscribe(close).await;
|
|
|
|
|
|
+ connection.unsubscribe(&close).await;
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
- Ok(Some(request))
|
|
|
|
|
|
+ Ok(())
|
|
}
|
|
}
|
|
|
|
|
|
#[inline]
|
|
#[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) -> Result<bool, Error> {
|
|
if let Some(storage) = self.storage.as_ref() {
|
|
if let Some(storage) = self.storage.as_ref() {
|
|
- let _ = storage.store(event).await;
|
|
|
|
|
|
+ if !storage.store(event).await? {
|
|
|
|
+ return Ok(false);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- self.subscriptions.broadcast(event.clone());
|
|
|
|
|
|
+ let connections = self.connections.read().await;
|
|
|
|
+ for RelayerSubscriptionId((sub_id, conn_id)) in
|
|
|
|
+ self.subscription_manager.get_subscribers(event).await
|
|
|
|
+ {
|
|
|
|
+ if let Some(connection) = connections.get(&conn_id) {
|
|
|
|
+ let _ = connection.send(
|
|
|
|
+ relayer::Event {
|
|
|
|
+ subscription_id: sub_id,
|
|
|
|
+ event: event.clone(),
|
|
|
|
+ }
|
|
|
|
+ .into(),
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ Ok(true)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -314,13 +393,24 @@ mod test {
|
|
|
|
|
|
let relayer =
|
|
let relayer =
|
|
Relayer::new(Some(Memory::default()), client_pool).expect("valid dummy server");
|
|
Relayer::new(Some(Memory::default()), client_pool).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)).expect("valid url"),
|
|
Url::parse(&format!("ws://{}", local_addr)).expect("valid url"),
|
|
stopper,
|
|
stopper,
|
|
)
|
|
)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ async fn dummy_server_with_relayer(
|
|
|
|
+ client_pool: Option<Pool>,
|
|
|
|
+ ) -> (Arc<Relayer<Memory>>, JoinHandle<()>) {
|
|
|
|
+ let listener = TcpListener::bind(format!("127.0.0.1:{}", 0)).await.unwrap();
|
|
|
|
+
|
|
|
|
+ let relayer =
|
|
|
|
+ Relayer::new(Some(Memory::default()), client_pool).expect("valid dummy server");
|
|
|
|
+ let (relayer, stopper) = relayer.main(listener).expect("valid main loop");
|
|
|
|
+ (relayer, stopper)
|
|
|
|
+ }
|
|
|
|
+
|
|
fn get_note_with_custom_tags(tags: Vec<Tag>) -> Event {
|
|
fn get_note_with_custom_tags(tags: Vec<Tag>) -> Event {
|
|
let account = Account::default();
|
|
let account = Account::default();
|
|
let content = Content::ShortTextNote("".to_owned());
|
|
let content = Content::ShortTextNote("".to_owned());
|
|
@@ -393,6 +483,18 @@ mod test {
|
|
let _ = relayer
|
|
let _ = relayer
|
|
.process_request_from_client(&connection, request)
|
|
.process_request_from_client(&connection, request)
|
|
.await;
|
|
.await;
|
|
|
|
+
|
|
|
|
+ // ev1
|
|
|
|
+ assert_eq!(
|
|
|
|
+ ROkStatus::Ok,
|
|
|
|
+ recv.try_recv()
|
|
|
|
+ .expect("valid")
|
|
|
|
+ .as_ok()
|
|
|
|
+ .cloned()
|
|
|
|
+ .unwrap()
|
|
|
|
+ .status,
|
|
|
|
+ );
|
|
|
|
+
|
|
// ev1
|
|
// ev1
|
|
assert_eq!(
|
|
assert_eq!(
|
|
note,
|
|
note,
|
|
@@ -475,7 +577,6 @@ mod test {
|
|
.expect("valid")
|
|
.expect("valid")
|
|
.as_event()
|
|
.as_event()
|
|
.expect("event")
|
|
.expect("event")
|
|
- .event
|
|
|
|
.id
|
|
.id
|
|
.to_string()
|
|
.to_string()
|
|
);
|
|
);
|
|
@@ -486,7 +587,6 @@ mod test {
|
|
.expect("valid")
|
|
.expect("valid")
|
|
.as_event()
|
|
.as_event()
|
|
.expect("event")
|
|
.expect("event")
|
|
- .event
|
|
|
|
.id
|
|
.id
|
|
.to_string()
|
|
.to_string()
|
|
);
|
|
);
|
|
@@ -497,7 +597,6 @@ mod test {
|
|
.expect("valid")
|
|
.expect("valid")
|
|
.as_event()
|
|
.as_event()
|
|
.expect("event")
|
|
.expect("event")
|
|
- .event
|
|
|
|
.id
|
|
.id
|
|
.to_string()
|
|
.to_string()
|
|
);
|
|
);
|
|
@@ -540,36 +639,43 @@ mod test {
|
|
}
|
|
}
|
|
]))
|
|
]))
|
|
.expect("valid object");
|
|
.expect("valid object");
|
|
- let relayer = Relayer::new(Some(get_db(false).await), None).expect("valid relayer");
|
|
|
|
- let (connection, mut recv) = Connection::new_local_connection();
|
|
|
|
|
|
+ let (relayer, _stopper) = dummy_server_with_relayer(None).await;
|
|
|
|
+ let mut receiver = relayer.create_new_local_connection().await;
|
|
|
|
+ let mut publisher = relayer.create_new_local_connection().await;
|
|
|
|
|
|
assert_eq!(relayer.total_subscribers(), 0);
|
|
assert_eq!(relayer.total_subscribers(), 0);
|
|
- let _ = relayer
|
|
|
|
- .process_request_from_client(&connection, request)
|
|
|
|
- .await;
|
|
|
|
|
|
|
|
- assert_eq!(relayer.total_subscribers(), 5);
|
|
|
|
|
|
+ receiver.send(request).await.expect("subscribe");
|
|
|
|
+
|
|
|
|
+ sleep(Duration::from_millis(10)).await;
|
|
|
|
+
|
|
|
|
+ assert_eq!(relayer.total_subscribers(), 1);
|
|
|
|
|
|
// eod
|
|
// eod
|
|
- assert!(recv
|
|
|
|
|
|
+ assert!(receiver
|
|
.try_recv()
|
|
.try_recv()
|
|
.expect("valid")
|
|
.expect("valid")
|
|
.as_end_of_stored_events()
|
|
.as_end_of_stored_events()
|
|
.is_some());
|
|
.is_some());
|
|
|
|
|
|
// It is empty
|
|
// It is empty
|
|
- assert!(recv.try_recv().is_err());
|
|
|
|
|
|
+ assert!(receiver.try_recv().is_none());
|
|
|
|
|
|
- relayer
|
|
|
|
- .process_request_from_client(&connection, get_note())
|
|
|
|
- .await
|
|
|
|
- .expect("process event");
|
|
|
|
|
|
+ publisher.send(get_note()).await.expect("valid send");
|
|
|
|
|
|
- sleep(Duration::from_millis(100)).await;
|
|
|
|
|
|
+ sleep(Duration::from_millis(10)).await;
|
|
|
|
+
|
|
|
|
+ // ok from posting
|
|
|
|
+ let msg = publisher.try_recv();
|
|
|
|
+ assert!(msg.is_some());
|
|
|
|
+ assert_eq!(
|
|
|
|
+ msg.expect("is ok").as_ok().expect("valid").id.to_hex(),
|
|
|
|
+ "e862fe23daf52ab09b36a37fa91ca3743e0c323e630e8627891212ca147c2da9".to_owned(),
|
|
|
|
+ );
|
|
|
|
|
|
// It is not empty
|
|
// It is not empty
|
|
- let msg = recv.try_recv();
|
|
|
|
- assert!(msg.is_ok());
|
|
|
|
|
|
+ let msg = receiver.try_recv();
|
|
|
|
+ assert!(msg.is_some());
|
|
assert_eq!(
|
|
assert_eq!(
|
|
msg.expect("is ok")
|
|
msg.expect("is ok")
|
|
.as_event()
|
|
.as_event()
|
|
@@ -580,12 +686,12 @@ mod test {
|
|
);
|
|
);
|
|
|
|
|
|
// it must be deliverd at most once
|
|
// it must be deliverd at most once
|
|
- assert!(recv.try_recv().is_err());
|
|
|
|
- assert_eq!(relayer.total_subscribers(), 5);
|
|
|
|
|
|
+ assert!(receiver.try_recv().is_none());
|
|
|
|
+ assert_eq!(relayer.total_subscribers(), 1);
|
|
|
|
|
|
// when client is dropped, the subscription is removed
|
|
// when client is dropped, the subscription is removed
|
|
// automatically
|
|
// automatically
|
|
- drop(connection);
|
|
|
|
|
|
+ drop(receiver);
|
|
|
|
|
|
sleep(Duration::from_millis(10)).await;
|
|
sleep(Duration::from_millis(10)).await;
|
|
|
|
|
|
@@ -624,36 +730,44 @@ mod test {
|
|
}
|
|
}
|
|
]))
|
|
]))
|
|
.expect("valid object");
|
|
.expect("valid object");
|
|
- let relayer = Relayer::new(Some(get_db(false).await), None).expect("valid relayer");
|
|
|
|
- let (connection, mut recv) = Connection::new_local_connection();
|
|
|
|
|
|
+
|
|
|
|
+ let (relayer, _stopper) = dummy_server_with_relayer(None).await;
|
|
|
|
+
|
|
|
|
+ let mut receiver = relayer.create_new_local_connection().await;
|
|
|
|
+ let mut publisher = relayer.create_new_local_connection().await;
|
|
|
|
|
|
assert_eq!(relayer.total_subscribers(), 0);
|
|
assert_eq!(relayer.total_subscribers(), 0);
|
|
- let _ = relayer
|
|
|
|
- .process_request_from_client(&connection, request)
|
|
|
|
- .await;
|
|
|
|
|
|
|
|
- assert_eq!(relayer.total_subscribers(), 5);
|
|
|
|
|
|
+ receiver.send(request).await.expect("subscribe");
|
|
|
|
+ sleep(Duration::from_millis(10)).await;
|
|
|
|
+
|
|
|
|
+ assert_eq!(relayer.total_subscribers(), 1);
|
|
|
|
|
|
// eod
|
|
// eod
|
|
- assert!(recv
|
|
|
|
|
|
+ assert!(receiver
|
|
.try_recv()
|
|
.try_recv()
|
|
.expect("valid")
|
|
.expect("valid")
|
|
.as_end_of_stored_events()
|
|
.as_end_of_stored_events()
|
|
.is_some());
|
|
.is_some());
|
|
|
|
|
|
// It is empty
|
|
// It is empty
|
|
- assert!(recv.try_recv().is_err());
|
|
|
|
|
|
+ assert!(receiver.try_recv().is_none());
|
|
|
|
|
|
- relayer
|
|
|
|
- .process_request_from_client(&connection, get_note())
|
|
|
|
- .await
|
|
|
|
- .expect("process event");
|
|
|
|
|
|
+ publisher.send(get_note()).await.expect("valid send");
|
|
|
|
|
|
sleep(Duration::from_millis(100)).await;
|
|
sleep(Duration::from_millis(100)).await;
|
|
|
|
|
|
|
|
+ // ok from posting
|
|
|
|
+ let msg = publisher.try_recv();
|
|
|
|
+ assert!(msg.is_some());
|
|
|
|
+ assert_eq!(
|
|
|
|
+ msg.expect("is ok").as_ok().expect("valid").id.to_hex(),
|
|
|
|
+ "e862fe23daf52ab09b36a37fa91ca3743e0c323e630e8627891212ca147c2da9".to_owned(),
|
|
|
|
+ );
|
|
|
|
+
|
|
// It is not empty
|
|
// It is not empty
|
|
- let msg = recv.try_recv();
|
|
|
|
- assert!(msg.is_ok());
|
|
|
|
|
|
+ let msg = receiver.try_recv();
|
|
|
|
+ assert!(msg.is_some());
|
|
assert_eq!(
|
|
assert_eq!(
|
|
msg.expect("is ok")
|
|
msg.expect("is ok")
|
|
.as_event()
|
|
.as_event()
|
|
@@ -664,12 +778,12 @@ mod test {
|
|
);
|
|
);
|
|
|
|
|
|
// it must be deliverd at most once
|
|
// it must be deliverd at most once
|
|
- assert!(recv.try_recv().is_err());
|
|
|
|
- assert_eq!(relayer.total_subscribers(), 5);
|
|
|
|
|
|
+ assert!(receiver.try_recv().is_none());
|
|
|
|
+ assert_eq!(relayer.total_subscribers(), 1);
|
|
|
|
|
|
// when client is dropped, the subscription is removed
|
|
// when client is dropped, the subscription is removed
|
|
// automatically
|
|
// automatically
|
|
- drop(connection);
|
|
|
|
|
|
+ drop(receiver);
|
|
|
|
|
|
sleep(Duration::from_millis(10)).await;
|
|
sleep(Duration::from_millis(10)).await;
|
|
|
|
|
|
@@ -687,50 +801,57 @@ mod test {
|
|
}]))
|
|
}]))
|
|
.expect("valid object");
|
|
.expect("valid object");
|
|
|
|
|
|
- let relayer = Relayer::new(Some(get_db(false).await), None).expect("valid relayer");
|
|
|
|
- let (publisher, _) = Connection::new_local_connection();
|
|
|
|
-
|
|
|
|
- let mut set1 = (0..1000)
|
|
|
|
- .map(|_| Connection::new_local_connection())
|
|
|
|
- .collect::<Vec<_>>();
|
|
|
|
-
|
|
|
|
- let mut set2 = (0..100)
|
|
|
|
- .map(|_| Connection::new_local_connection())
|
|
|
|
- .collect::<Vec<_>>();
|
|
|
|
|
|
+ let (relayer, _stopper) = dummy_server_with_relayer(None).await;
|
|
|
|
+ let mut publisher = relayer.create_new_local_connection().await;
|
|
|
|
|
|
- let subscribe1 = set1
|
|
|
|
- .iter()
|
|
|
|
- .map(|(connection, _)| relayer.process_request_from_client(connection, req1.clone()))
|
|
|
|
- .collect::<Vec<_>>();
|
|
|
|
|
|
+ let mut set1 = join_all(
|
|
|
|
+ (0..1000)
|
|
|
|
+ .map(|_| relayer.create_new_local_connection())
|
|
|
|
+ .collect::<Vec<_>>(),
|
|
|
|
+ )
|
|
|
|
+ .await;
|
|
|
|
|
|
- let subscribe2 = set2
|
|
|
|
- .iter()
|
|
|
|
- .map(|(connection, _)| relayer.process_request_from_client(connection, req2.clone()))
|
|
|
|
- .collect::<Vec<_>>();
|
|
|
|
|
|
+ let mut set2 = join_all(
|
|
|
|
+ (0..100)
|
|
|
|
+ .map(|_| relayer.create_new_local_connection())
|
|
|
|
+ .collect::<Vec<_>>(),
|
|
|
|
+ )
|
|
|
|
+ .await;
|
|
|
|
|
|
assert_eq!(relayer.total_subscribers(), 0);
|
|
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");
|
|
|
|
|
|
+ join_all(
|
|
|
|
+ set1.iter()
|
|
|
|
+ .map(|connection| connection.send(req1.clone()))
|
|
|
|
+ .collect::<Vec<_>>(),
|
|
|
|
+ )
|
|
|
|
+ .await
|
|
|
|
+ .into_iter()
|
|
|
|
+ .collect::<Result<Vec<_>, _>>()
|
|
|
|
+ .expect("subscribe all");
|
|
|
|
+
|
|
|
|
+ join_all(
|
|
|
|
+ set2.iter()
|
|
|
|
+ .map(|connection| connection.send(req2.clone()))
|
|
|
|
+ .collect::<Vec<_>>(),
|
|
|
|
+ )
|
|
|
|
+ .await
|
|
|
|
+ .into_iter()
|
|
|
|
+ .collect::<Result<Vec<_>, _>>()
|
|
|
|
+ .expect("subscribe all");
|
|
|
|
|
|
- for (_, recv) in set1.iter_mut() {
|
|
|
|
- assert!(recv
|
|
|
|
|
|
+ sleep(Duration::from_millis(10)).await;
|
|
|
|
+
|
|
|
|
+ for connection in set1.iter_mut() {
|
|
|
|
+ assert!(connection
|
|
.try_recv()
|
|
.try_recv()
|
|
.expect("end of stored events")
|
|
.expect("end of stored events")
|
|
.as_end_of_stored_events()
|
|
.as_end_of_stored_events()
|
|
.is_some());
|
|
.is_some());
|
|
}
|
|
}
|
|
|
|
|
|
- for (_, recv) in set2.iter_mut() {
|
|
|
|
- assert!(recv
|
|
|
|
|
|
+ for connection in set2.iter_mut() {
|
|
|
|
+ assert!(connection
|
|
.try_recv()
|
|
.try_recv()
|
|
.expect("end of stored events")
|
|
.expect("end of stored events")
|
|
.as_end_of_stored_events()
|
|
.as_end_of_stored_events()
|
|
@@ -739,21 +860,24 @@ mod test {
|
|
|
|
|
|
assert_eq!(relayer.total_subscribers(), 1100);
|
|
assert_eq!(relayer.total_subscribers(), 1100);
|
|
|
|
|
|
- relayer
|
|
|
|
- .process_request_from_client(&publisher, get_note())
|
|
|
|
- .await
|
|
|
|
- .expect("process event");
|
|
|
|
|
|
+ publisher.send(get_note()).await.expect("valid send");
|
|
|
|
|
|
sleep(Duration::from_millis(10)).await;
|
|
sleep(Duration::from_millis(10)).await;
|
|
|
|
|
|
- for (_, recv) in set1.iter_mut() {
|
|
|
|
- assert!(recv.try_recv().is_err());
|
|
|
|
|
|
+ let msg = publisher.try_recv();
|
|
|
|
+ assert!(msg.is_some());
|
|
|
|
+ assert_eq!(
|
|
|
|
+ msg.expect("is ok").as_ok().expect("valid").id.to_hex(),
|
|
|
|
+ "e862fe23daf52ab09b36a37fa91ca3743e0c323e630e8627891212ca147c2da9".to_owned(),
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ for connection in set1.iter_mut() {
|
|
|
|
+ assert!(connection.try_recv().is_none());
|
|
}
|
|
}
|
|
|
|
|
|
- for (_, recv) in set2.iter_mut() {
|
|
|
|
- let msg = recv.try_recv();
|
|
|
|
- println!("{:?}", msg);
|
|
|
|
- assert!(msg.is_ok());
|
|
|
|
|
|
+ for connection in set2.iter_mut() {
|
|
|
|
+ let msg = connection.try_recv();
|
|
|
|
+ assert!(msg.is_some());
|
|
let msg = msg.expect("msg");
|
|
let msg = msg.expect("msg");
|
|
|
|
|
|
assert_eq!(
|
|
assert_eq!(
|
|
@@ -761,7 +885,7 @@ mod test {
|
|
"1298169700973717".to_owned()
|
|
"1298169700973717".to_owned()
|
|
);
|
|
);
|
|
|
|
|
|
- assert!(recv.try_recv().is_err());
|
|
|
|
|
|
+ assert!(connection.try_recv().is_none());
|
|
}
|
|
}
|
|
|
|
|
|
drop(set1);
|
|
drop(set1);
|
|
@@ -776,40 +900,78 @@ mod test {
|
|
}
|
|
}
|
|
|
|
|
|
#[tokio::test]
|
|
#[tokio::test]
|
|
|
|
+ async fn posting_event_replies_ok() {
|
|
|
|
+ let relayer = Relayer::new(Some(get_db(false).await), None).expect("valid relayer");
|
|
|
|
+ let (connection, mut recv) = Connection::new_local_connection();
|
|
|
|
+
|
|
|
|
+ let note = get_note();
|
|
|
|
+ let note_id = note.as_event().map(|x| x.id.clone()).unwrap();
|
|
|
|
+
|
|
|
|
+ relayer
|
|
|
|
+ .process_request_from_client(&connection, note)
|
|
|
|
+ .await
|
|
|
|
+ .expect("process event");
|
|
|
|
+
|
|
|
|
+ sleep(Duration::from_millis(10)).await;
|
|
|
|
+
|
|
|
|
+ assert_eq!(
|
|
|
|
+ Some(
|
|
|
|
+ ROk {
|
|
|
|
+ id: note_id.into(),
|
|
|
|
+ status: ROkStatus::Ok,
|
|
|
|
+ }
|
|
|
|
+ .into()
|
|
|
|
+ ),
|
|
|
|
+ recv.try_recv().ok()
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #[tokio::test]
|
|
async fn subscribe_to_all() {
|
|
async fn subscribe_to_all() {
|
|
let request: Request =
|
|
let request: Request =
|
|
serde_json::from_value(json!(["REQ", "1298169700973717", {}])).expect("valid object");
|
|
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_local_connection();
|
|
|
|
|
|
+ let (relayer, _stopper) = dummy_server_with_relayer(None).await;
|
|
|
|
+
|
|
|
|
+ let mut local_connection_0 = relayer.create_new_local_connection().await;
|
|
|
|
+ let mut local_connection_1 = relayer.create_new_local_connection().await;
|
|
|
|
|
|
assert_eq!(relayer.total_subscribers(), 0);
|
|
assert_eq!(relayer.total_subscribers(), 0);
|
|
- let _ = relayer
|
|
|
|
- .process_request_from_client(&connection, request)
|
|
|
|
- .await;
|
|
|
|
|
|
+
|
|
|
|
+ local_connection_1.send(request).await.expect("valid send");
|
|
|
|
+
|
|
|
|
+ sleep(Duration::from_millis(10)).await;
|
|
|
|
|
|
assert_eq!(relayer.total_subscribers(), 1);
|
|
assert_eq!(relayer.total_subscribers(), 1);
|
|
|
|
|
|
// eod
|
|
// eod
|
|
- assert!(recv
|
|
|
|
|
|
+ assert!(local_connection_1
|
|
.try_recv()
|
|
.try_recv()
|
|
.expect("valid")
|
|
.expect("valid")
|
|
.as_end_of_stored_events()
|
|
.as_end_of_stored_events()
|
|
.is_some());
|
|
.is_some());
|
|
|
|
|
|
// It is empty
|
|
// It is empty
|
|
- assert!(recv.try_recv().is_err());
|
|
|
|
|
|
+ assert!(local_connection_1.try_recv().is_none());
|
|
|
|
|
|
- relayer
|
|
|
|
- .process_request_from_client(&connection, get_note())
|
|
|
|
|
|
+ local_connection_0
|
|
|
|
+ .send(get_note())
|
|
.await
|
|
.await
|
|
- .expect("process event");
|
|
|
|
|
|
+ .expect("valid send");
|
|
|
|
|
|
sleep(Duration::from_millis(10)).await;
|
|
sleep(Duration::from_millis(10)).await;
|
|
|
|
|
|
|
|
+ // ok from posting
|
|
|
|
+ let msg = local_connection_0.try_recv();
|
|
|
|
+ assert!(msg.is_some());
|
|
|
|
+ assert_eq!(
|
|
|
|
+ msg.expect("is ok").as_ok().expect("valid").id.to_hex(),
|
|
|
|
+ "e862fe23daf52ab09b36a37fa91ca3743e0c323e630e8627891212ca147c2da9".to_owned(),
|
|
|
|
+ );
|
|
|
|
+
|
|
// It is not empty
|
|
// It is not empty
|
|
- let msg = recv.try_recv();
|
|
|
|
- assert!(msg.is_ok());
|
|
|
|
|
|
+ let msg = local_connection_1.try_recv();
|
|
|
|
+ assert!(msg.is_some());
|
|
assert_eq!(
|
|
assert_eq!(
|
|
msg.expect("is ok")
|
|
msg.expect("is ok")
|
|
.as_event()
|
|
.as_event()
|
|
@@ -820,12 +982,12 @@ mod test {
|
|
);
|
|
);
|
|
|
|
|
|
// it must be deliverd at most once
|
|
// it must be deliverd at most once
|
|
- assert!(recv.try_recv().is_err());
|
|
|
|
|
|
+ assert!(local_connection_1.try_recv().is_none());
|
|
assert_eq!(relayer.total_subscribers(), 1);
|
|
assert_eq!(relayer.total_subscribers(), 1);
|
|
|
|
|
|
// when client is dropped, the subscription is removed
|
|
// when client is dropped, the subscription is removed
|
|
// automatically
|
|
// automatically
|
|
- drop(connection);
|
|
|
|
|
|
+ drop(local_connection_1);
|
|
|
|
|
|
sleep(Duration::from_millis(10)).await;
|
|
sleep(Duration::from_millis(10)).await;
|
|
|
|
|
|
@@ -837,24 +999,20 @@ mod test {
|
|
let (relayer1, _) = dummy_server(0, None).await;
|
|
let (relayer1, _) = dummy_server(0, None).await;
|
|
let (relayer2, _) = dummy_server(0, None).await;
|
|
let (relayer2, _) = dummy_server(0, None).await;
|
|
let (relayer3, _) = dummy_server(0, None).await;
|
|
let (relayer3, _) = dummy_server(0, None).await;
|
|
- let (main_relayer, _) = dummy_server(
|
|
|
|
- 0,
|
|
|
|
- Some(Pool::new_with_clients(vec![
|
|
|
|
- relayer1.clone(),
|
|
|
|
- relayer2.clone(),
|
|
|
|
- relayer3.clone(),
|
|
|
|
- ])),
|
|
|
|
- )
|
|
|
|
- .await;
|
|
|
|
|
|
|
|
- let mut reader_client =
|
|
|
|
- Pool::new_with_clients(vec![relayer1.clone(), relayer2.clone(), relayer3.clone()]);
|
|
|
|
- let main_client = Pool::new_with_clients(vec![main_relayer]);
|
|
|
|
|
|
+ let (pool, _in_scope) =
|
|
|
|
+ Pool::new_with_clients(vec![relayer1.clone(), relayer2.clone(), relayer3.clone()])
|
|
|
|
+ .expect("valid pool");
|
|
|
|
|
|
- let _sub = reader_client
|
|
|
|
- .subscribe(Default::default())
|
|
|
|
- .await
|
|
|
|
- .expect("valid subscription");
|
|
|
|
|
|
+ let (main_relayer, _) = dummy_server(0, Some(pool)).await;
|
|
|
|
+
|
|
|
|
+ let (mut reader_client, _reader_client_inscope) =
|
|
|
|
+ Pool::new_with_clients(vec![relayer1.clone(), relayer2.clone(), relayer3.clone()])
|
|
|
|
+ .expect("valid pool");
|
|
|
|
+ let (main_client, _main_client_inscope) =
|
|
|
|
+ Pool::new_with_clients(vec![main_relayer]).expect("valid pool");
|
|
|
|
+
|
|
|
|
+ let _sub = reader_client.subscribe(Default::default()).await;
|
|
|
|
|
|
sleep(Duration::from_millis(20)).await;
|
|
sleep(Duration::from_millis(20)).await;
|
|
|
|
|
|
@@ -894,19 +1052,19 @@ mod test {
|
|
assert_eq!(
|
|
assert_eq!(
|
|
responses
|
|
responses
|
|
.get(&relayer1.port().expect("port"))
|
|
.get(&relayer1.port().expect("port"))
|
|
- .map(|x| x.event.id.clone()),
|
|
|
|
|
|
+ .map(|x| x.id.clone()),
|
|
Some(signed_content.id.clone())
|
|
Some(signed_content.id.clone())
|
|
);
|
|
);
|
|
assert_eq!(
|
|
assert_eq!(
|
|
responses
|
|
responses
|
|
.get(&relayer2.port().expect("port"))
|
|
.get(&relayer2.port().expect("port"))
|
|
- .map(|x| x.event.id.clone()),
|
|
|
|
|
|
+ .map(|x| x.id.clone()),
|
|
Some(signed_content.id.clone())
|
|
Some(signed_content.id.clone())
|
|
);
|
|
);
|
|
assert_eq!(
|
|
assert_eq!(
|
|
responses
|
|
responses
|
|
.get(&relayer3.port().expect("port"))
|
|
.get(&relayer3.port().expect("port"))
|
|
- .map(|x| x.event.id.clone()),
|
|
|
|
|
|
+ .map(|x| x.id.clone()),
|
|
Some(signed_content.id)
|
|
Some(signed_content.id)
|
|
);
|
|
);
|
|
}
|
|
}
|
|
@@ -915,21 +1073,17 @@ mod test {
|
|
async fn relayer_with_client_pool() {
|
|
async fn relayer_with_client_pool() {
|
|
let (relayer1, _) = dummy_server(0, None).await;
|
|
let (relayer1, _) = dummy_server(0, None).await;
|
|
let (relayer2, _) = dummy_server(0, None).await;
|
|
let (relayer2, _) = dummy_server(0, None).await;
|
|
- let (main_relayer, _) = dummy_server(
|
|
|
|
- 0,
|
|
|
|
- Some(Pool::new_with_clients(vec![relayer1.clone(), relayer2])),
|
|
|
|
- )
|
|
|
|
- .await;
|
|
|
|
|
|
+ let (pool, _in_scope) =
|
|
|
|
+ Pool::new_with_clients(vec![relayer1.clone(), relayer2]).expect("valid pool");
|
|
|
|
+ let (main_relayer, _) = dummy_server(0, Some(pool)).await;
|
|
|
|
|
|
- let secondary_client = Pool::new_with_clients(vec![relayer1]);
|
|
|
|
|
|
+ let (secondary_client, _sc) = Pool::new_with_clients(vec![relayer1]).expect("valid client");
|
|
|
|
|
|
// Create a subscription in the main relayer, main_client is only
|
|
// Create a subscription in the main relayer, main_client is only
|
|
// connected to the main relayer
|
|
// connected to the main relayer
|
|
- let mut main_client = Pool::new_with_clients(vec![main_relayer]);
|
|
|
|
- let _sub = main_client
|
|
|
|
- .subscribe(Default::default())
|
|
|
|
- .await
|
|
|
|
- .expect("valid subscription");
|
|
|
|
|
|
+ let (mut main_client, _in_scope) =
|
|
|
|
+ Pool::new_with_clients(vec![main_relayer]).expect("valid client");
|
|
|
|
+ let _sub = main_client.subscribe(Default::default()).await;
|
|
|
|
|
|
sleep(Duration::from_millis(10)).await;
|
|
sleep(Duration::from_millis(10)).await;
|
|
assert!(main_client
|
|
assert!(main_client
|
|
@@ -942,7 +1096,7 @@ mod test {
|
|
|
|
|
|
let account1 = Account::default();
|
|
let account1 = Account::default();
|
|
let signed_content = account1
|
|
let signed_content = account1
|
|
- .sign_content(vec![], Content::ShortTextNote("test 0".to_owned()), None)
|
|
|
|
|
|
+ .sign_content(vec![], Content::ShortTextNote("test 01".to_owned()), None)
|
|
.expect("valid signed content");
|
|
.expect("valid signed content");
|
|
|
|
|
|
// account1 posts a new note into the relayer1, and the main relayer
|
|
// account1 posts a new note into the relayer1, and the main relayer
|
|
@@ -956,8 +1110,8 @@ mod test {
|
|
Some((signed_content.id, signed_content.signature)),
|
|
Some((signed_content.id, signed_content.signature)),
|
|
main_client
|
|
main_client
|
|
.try_recv()
|
|
.try_recv()
|
|
- .and_then(|(r, _)| r.as_event().cloned().map(|x| x.event))
|
|
|
|
- .map(|x| (x.id, x.signature))
|
|
|
|
|
|
+ .and_then(|(r, _)| r.as_event().cloned())
|
|
|
|
+ .map(|x| (x.id.clone(), x.signature.clone()))
|
|
);
|
|
);
|
|
assert!(main_client.try_recv().is_none());
|
|
assert!(main_client.try_recv().is_none());
|
|
}
|
|
}
|