|
@@ -1,15 +1,21 @@
|
|
|
//! Code which enables sending messages between processes in the blocktree system.
|
|
|
+#![feature(type_alias_impl_trait)]
|
|
|
|
|
|
mod tls;
|
|
|
use tls::*;
|
|
|
mod callback_framed;
|
|
|
-use callback_framed::{CallbackFramed, DeserCallback};
|
|
|
+use callback_framed::CallbackFramed;
|
|
|
+pub use callback_framed::DeserCallback;
|
|
|
|
|
|
-use btlib::{bterr, crypto::Creds, error::BoxInIoErr, BlockPath, Result, Writecap};
|
|
|
-use btserde::{read_from, write_to};
|
|
|
+use btlib::{bterr, crypto::Creds, BlockPath, Result, Writecap};
|
|
|
+use btserde::write_to;
|
|
|
use bytes::{BufMut, BytesMut};
|
|
|
-use core::{future::Future, marker::Send, ops::DerefMut, pin::Pin};
|
|
|
-use futures::{sink::Send as SendFut, SinkExt, StreamExt};
|
|
|
+use core::{
|
|
|
+ future::{ready, Future, Ready},
|
|
|
+ marker::Send,
|
|
|
+ pin::Pin,
|
|
|
+};
|
|
|
+use futures::{FutureExt, SinkExt};
|
|
|
use log::error;
|
|
|
use quinn::{Connection, Endpoint, RecvStream, SendStream};
|
|
|
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
|
@@ -22,10 +28,11 @@ use std::{
|
|
|
sync::Arc,
|
|
|
};
|
|
|
use tokio::{
|
|
|
+ runtime::Handle,
|
|
|
select,
|
|
|
sync::{broadcast, Mutex},
|
|
|
};
|
|
|
-use tokio_util::codec::{Decoder, Encoder, Framed, FramedParts, FramedRead, FramedWrite};
|
|
|
+use tokio_util::codec::{Encoder, Framed, FramedParts};
|
|
|
|
|
|
/// Returns a [Receiver] bound to the given [IpAddr] which receives messages at the bind path of
|
|
|
/// the given [Writecap] of the given credentials. The returned type can be used to make
|
|
@@ -53,8 +60,7 @@ pub trait MsgCallback: Clone + Send + Sync + Unpin {
|
|
|
type Arg<'de>: CallMsg<'de>
|
|
|
where
|
|
|
Self: 'de;
|
|
|
- type Return;
|
|
|
- type CallFut<'de>: Future<Output = Self::Return> + Send
|
|
|
+ type CallFut<'de>: Future<Output = Result<()>> + Send
|
|
|
where
|
|
|
Self: 'de;
|
|
|
fn call<'de>(&'de self, arg: MsgReceived<Self::Arg<'de>>) -> Self::CallFut<'de>;
|
|
@@ -62,7 +68,6 @@ pub trait MsgCallback: Clone + Send + Sync + Unpin {
|
|
|
|
|
|
impl<T: MsgCallback> MsgCallback for &T {
|
|
|
type Arg<'de> = T::Arg<'de> where Self: 'de;
|
|
|
- type Return = T::Return;
|
|
|
type CallFut<'de> = T::CallFut<'de> where Self: 'de;
|
|
|
fn call<'de>(&'de self, arg: MsgReceived<Self::Arg<'de>>) -> Self::CallFut<'de> {
|
|
|
(*self).call(arg)
|
|
@@ -71,14 +76,11 @@ impl<T: MsgCallback> MsgCallback for &T {
|
|
|
|
|
|
/// Trait for messages which can be transmitted using the call method.
|
|
|
pub trait CallMsg<'de>: Serialize + Deserialize<'de> + Send + Sync {
|
|
|
- type Reply: Serialize + DeserializeOwned + Send;
|
|
|
+ type Reply<'r>: Serialize + Deserialize<'r> + Send;
|
|
|
}
|
|
|
|
|
|
-#[derive(Serialize, Deserialize)]
|
|
|
-pub enum NoReply {}
|
|
|
-
|
|
|
/// Trait for messages which can be transmitted using the send method.
|
|
|
-/// Types which implement this trait should specify [NoReply] as their reply type.
|
|
|
+/// Types which implement this trait should specify `()` as their reply type.
|
|
|
pub trait SendMsg<'de>: CallMsg<'de> {}
|
|
|
|
|
|
/// An address which identifies a block on the network. An instance of this struct can be
|
|
@@ -207,36 +209,79 @@ pub trait Receiver {
|
|
|
|
|
|
/// A type which can be used to transmit messages.
|
|
|
pub trait Transmitter {
|
|
|
- type SendFut<'s, T>: 's + Future<Output = Result<()>> + Send
|
|
|
+ type SendFut<'call, T>: 'call + Future<Output = Result<()>> + Send
|
|
|
where
|
|
|
- Self: 's,
|
|
|
- T: 's + Serialize + Send;
|
|
|
+ Self: 'call,
|
|
|
+ T: 'call + SendMsg<'call>;
|
|
|
|
|
|
/// Transmit a message to the connected [Receiver] without waiting for a reply.
|
|
|
- fn send<'de, T: 'de + SendMsg<'de>>(&'de mut self, msg: T) -> Self::SendFut<'de, T>;
|
|
|
+ fn send<'call, T: 'call + SendMsg<'call>>(&'call mut self, msg: T) -> Self::SendFut<'call, T>;
|
|
|
|
|
|
- type CallFut<'s, 'de, T>: 's + Future<Output = Result<T::Reply>> + Send
|
|
|
+ type CallFut<'call, T, F>: 'call + Future<Output = Result<F::Return>> + Send
|
|
|
where
|
|
|
- Self: 's,
|
|
|
- T: 's + CallMsg<'de>,
|
|
|
- T::Reply: 's;
|
|
|
+ Self: 'call,
|
|
|
+ T: 'call + CallMsg<'call>,
|
|
|
+ F: 'static + Send + Sync + DeserCallback;
|
|
|
|
|
|
- /// Transmit a message to the connected [Receiver] and wait for a reply.
|
|
|
- fn call<'s, 'de, T>(&'s mut self, msg: T) -> Self::CallFut<'s, 'de, T>
|
|
|
+ /// Transmit a message to the connected [Receiver], waits for a reply, then calls the given
|
|
|
+ /// [DeserCallback] with the deserialized reply.
|
|
|
+ fn call<'call, T, F>(&'call mut self, msg: T, callback: F) -> Self::CallFut<'call, T, F>
|
|
|
where
|
|
|
- T: 's + CallMsg<'de>,
|
|
|
- T::Reply: 's;
|
|
|
-
|
|
|
- type FinishFut: Future<Output = Result<()>> + Send;
|
|
|
-
|
|
|
- /// Finish any ongoing transmissions and close the connection to the [Receiver].
|
|
|
- fn finish(self) -> Self::FinishFut;
|
|
|
+ T: 'call + CallMsg<'call>,
|
|
|
+ F: 'static + Send + Sync + DeserCallback;
|
|
|
+
|
|
|
+ /// Transmits a message to the connected [Reciever], waits for a reply, then passes back the
|
|
|
+ /// the reply to the caller.
|
|
|
+ fn call_through<'call, T>(
|
|
|
+ &'call mut self,
|
|
|
+ msg: T,
|
|
|
+ ) -> Self::CallFut<'call, T, Passthrough<T::Reply<'call>>>
|
|
|
+ where
|
|
|
+ T: 'call + CallMsg<'call>,
|
|
|
+ T::Reply<'call>: 'static + Send + Sync + DeserializeOwned,
|
|
|
+ {
|
|
|
+ self.call(msg, Passthrough::new())
|
|
|
+ }
|
|
|
|
|
|
/// Returns the address that this instance is transmitting to.
|
|
|
fn addr(&self) -> &Arc<BlockAddr>;
|
|
|
}
|
|
|
|
|
|
+pub struct Passthrough<T> {
|
|
|
+ phantom: PhantomData<T>,
|
|
|
+}
|
|
|
+
|
|
|
+impl<T> Passthrough<T> {
|
|
|
+ pub fn new() -> Self {
|
|
|
+ Self {
|
|
|
+ phantom: PhantomData,
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<T> Default for Passthrough<T> {
|
|
|
+ fn default() -> Self {
|
|
|
+ Self::new()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<T> Clone for Passthrough<T> {
|
|
|
+ fn clone(&self) -> Self {
|
|
|
+ Self::new()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<T: 'static + Send + DeserializeOwned> DeserCallback for Passthrough<T> {
|
|
|
+ type Arg<'de> = T;
|
|
|
+ type Return = T;
|
|
|
+ type CallFut<'de> = Ready<T>;
|
|
|
+ fn call<'de>(&'de mut self, arg: Self::Arg<'de>) -> Self::CallFut<'de> {
|
|
|
+ ready(arg)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/// Encodes messages using [btserde].
|
|
|
+#[derive(Debug)]
|
|
|
struct MsgEncoder;
|
|
|
|
|
|
impl MsgEncoder {
|
|
@@ -263,73 +308,26 @@ impl<T: Serialize> Encoder<T> for MsgEncoder {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/// Decodes messages using [btserde].
|
|
|
-struct MsgDecoder<T>(PhantomData<T>);
|
|
|
-
|
|
|
-impl<T> MsgDecoder<T> {
|
|
|
- fn new() -> Self {
|
|
|
- Self(PhantomData)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-impl<T: DeserializeOwned> Decoder for MsgDecoder<T> {
|
|
|
- type Item = T;
|
|
|
- type Error = btlib::Error;
|
|
|
-
|
|
|
- fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>> {
|
|
|
- let mut slice: &[u8] = src.as_ref();
|
|
|
- let payload_len: u64 = match read_from(&mut slice) {
|
|
|
- Ok(payload_len) => payload_len,
|
|
|
- Err(err) => {
|
|
|
- return match err {
|
|
|
- btserde::Error::Eof => Ok(None),
|
|
|
- btserde::Error::Io(ref io_err) => match io_err.kind() {
|
|
|
- std::io::ErrorKind::UnexpectedEof => Ok(None),
|
|
|
- _ => Err(err.into()),
|
|
|
- },
|
|
|
- _ => Err(err.into()),
|
|
|
- }
|
|
|
- }
|
|
|
- };
|
|
|
- let payload_len: usize = payload_len.try_into().box_err()?;
|
|
|
- if slice.len() < payload_len {
|
|
|
- src.reserve(payload_len - slice.len());
|
|
|
- return Ok(None);
|
|
|
- }
|
|
|
- let msg = read_from(&mut slice)?;
|
|
|
- // Consume all the bytes that have been read out of the buffer.
|
|
|
- let _ = src.split_to(std::mem::size_of::<u64>() + payload_len);
|
|
|
- Ok(Some(msg))
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-type SharedFrameParts = Arc<Mutex<Option<FramedParts<SendStream, MsgEncoder>>>>;
|
|
|
+type FramedMsg = Framed<SendStream, MsgEncoder>;
|
|
|
+type ArcMutex<T> = Arc<Mutex<T>>;
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
pub struct Replier {
|
|
|
- parts: SharedFrameParts,
|
|
|
+ stream: ArcMutex<FramedMsg>,
|
|
|
}
|
|
|
|
|
|
impl Replier {
|
|
|
- fn new(send_stream: SendStream) -> Self {
|
|
|
- let parts = FramedParts::new::<()>(send_stream, MsgEncoder::new());
|
|
|
- let parts = Arc::new(Mutex::new(Some(parts)));
|
|
|
- Self { parts }
|
|
|
+ fn new(stream: ArcMutex<FramedMsg>) -> Self {
|
|
|
+ Self { stream }
|
|
|
}
|
|
|
|
|
|
- pub async fn reply<T: Serialize + Send>(self, reply: T) -> Result<()> {
|
|
|
- let parts = self.parts;
|
|
|
- let mut guard = parts.lock().await;
|
|
|
- // We must ensure the parts are put back before we leave this block.
|
|
|
- let parts = guard.take().unwrap();
|
|
|
- let mut stream = Framed::from_parts(parts);
|
|
|
- let result = stream.send(reply).await;
|
|
|
- *guard = Some(stream.into_parts());
|
|
|
- result
|
|
|
+ pub async fn reply<T: Serialize + Send>(&mut self, reply: T) -> Result<()> {
|
|
|
+ let mut guard = self.stream.lock().await;
|
|
|
+ guard.send(reply).await?;
|
|
|
+ Ok(())
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-#[derive(Clone)]
|
|
|
struct MsgRecvdCallback<F> {
|
|
|
path: Arc<BlockPath>,
|
|
|
replier: Replier,
|
|
@@ -337,10 +335,10 @@ struct MsgRecvdCallback<F> {
|
|
|
}
|
|
|
|
|
|
impl<F: MsgCallback> MsgRecvdCallback<F> {
|
|
|
- fn new(path: Arc<BlockPath>, replier: Replier, inner: F) -> Self {
|
|
|
+ fn new(path: Arc<BlockPath>, framed_msg: ArcMutex<FramedMsg>, inner: F) -> Self {
|
|
|
Self {
|
|
|
path,
|
|
|
- replier,
|
|
|
+ replier: Replier::new(framed_msg),
|
|
|
inner,
|
|
|
}
|
|
|
}
|
|
@@ -348,9 +346,9 @@ impl<F: MsgCallback> MsgRecvdCallback<F> {
|
|
|
|
|
|
impl<F: MsgCallback> DeserCallback for MsgRecvdCallback<F> {
|
|
|
type Arg<'de> = Envelope<F::Arg<'de>> where Self: 'de;
|
|
|
- type Return = F::Return;
|
|
|
- type CallFut<'s> = F::CallFut<'s> where F: 's;
|
|
|
- fn call<'de>(&'de self, arg: Envelope<F::Arg<'de>>) -> Self::CallFut<'de> {
|
|
|
+ type Return = Result<()>;
|
|
|
+ type CallFut<'de> = F::CallFut<'de> where F: 'de, Self: 'de;
|
|
|
+ fn call<'de>(&'de mut self, arg: Envelope<F::Arg<'de>>) -> Self::CallFut<'de> {
|
|
|
let replier = match arg.kind {
|
|
|
MsgKind::Call => Some(self.replier.clone()),
|
|
|
MsgKind::Send => None,
|
|
@@ -440,11 +438,13 @@ impl QuicReceiver {
|
|
|
let connection = unwrap_or_continue!(connecting.await, |err| error!(
|
|
|
"error accepting QUIC connection: {err}"
|
|
|
));
|
|
|
- tokio::spawn(Self::handle_connection(
|
|
|
- connection,
|
|
|
- callback.clone(),
|
|
|
- stop_rx.resubscribe(),
|
|
|
- ));
|
|
|
+ let callback = callback.clone();
|
|
|
+ let stop_rx = stop_rx.resubscribe();
|
|
|
+ // spawn_blocking is used to allow the user supplied callback to to block without
|
|
|
+ // disrupting the main thread pool.
|
|
|
+ tokio::task::spawn_blocking(move || {
|
|
|
+ Handle::current().block_on(Self::handle_connection(connection, callback, stop_rx))
|
|
|
+ });
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -457,17 +457,39 @@ impl QuicReceiver {
|
|
|
Self::client_path(connection.peer_identity()),
|
|
|
|err| error!("failed to get client path from peer identity: {err}")
|
|
|
);
|
|
|
- let (send_stream, recv_stream) = unwrap_or_return!(
|
|
|
- connection.accept_bi().await,
|
|
|
- |err| error!("error accepting receive stream: {err}")
|
|
|
- );
|
|
|
- let replier = Replier::new(send_stream);
|
|
|
- let callback = MsgRecvdCallback::new(client_path, replier, callback);
|
|
|
- let mut msg_stream = CallbackFramed::new(recv_stream);
|
|
|
+ let mut frame_parts_opt: Option<FramedParts<SendStream, MsgEncoder>> = None;
|
|
|
loop {
|
|
|
- let decode_result = await_or_stop!(msg_stream.next(callback.clone()), stop_rx.recv());
|
|
|
- if let Err(ref err) = decode_result {
|
|
|
- error!("msg_stream produced an error: {err}");
|
|
|
+ let result = await_or_stop!(connection.accept_bi().map(Some), stop_rx.recv());
|
|
|
+ let (send_stream, recv_stream) =
|
|
|
+ unwrap_or_continue!(result, |err| error!("error accepting stream: {err}"));
|
|
|
+ let frame_parts = match frame_parts_opt {
|
|
|
+ Some(mut frame_parts) => {
|
|
|
+ frame_parts.io = send_stream;
|
|
|
+ frame_parts
|
|
|
+ }
|
|
|
+ None => FramedParts::new::<<<F as MsgCallback>::Arg<'_> as CallMsg>::Reply<'_>>(
|
|
|
+ send_stream,
|
|
|
+ MsgEncoder::new(),
|
|
|
+ ),
|
|
|
+ };
|
|
|
+ let framed_msg = Arc::new(Mutex::new(FramedMsg::from_parts(frame_parts)));
|
|
|
+ let callback =
|
|
|
+ MsgRecvdCallback::new(client_path.clone(), framed_msg.clone(), callback.clone());
|
|
|
+ let mut msg_stream = CallbackFramed::new(recv_stream);
|
|
|
+ let result = msg_stream
|
|
|
+ .next(callback)
|
|
|
+ .await
|
|
|
+ .ok_or_else(|| bterr!("client closed stream before sending a message"));
|
|
|
+ let msg_framed = Arc::try_unwrap(framed_msg).unwrap();
|
|
|
+ let msg_framed = msg_framed.into_inner();
|
|
|
+ frame_parts_opt = Some(msg_framed.into_parts());
|
|
|
+ match unwrap_or_continue!(result) {
|
|
|
+ Err(err) => error!("msg_stream produced an error: {err}"),
|
|
|
+ Ok(result) => {
|
|
|
+ if let Err(err) = result {
|
|
|
+ error!("callback returned an error: {err}");
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -510,10 +532,23 @@ impl Receiver for QuicReceiver {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+macro_rules! cleanup_on_err {
|
|
|
+ ($result:expr, $guard:ident, $parts:ident) => {
|
|
|
+ match $result {
|
|
|
+ Ok(value) => value,
|
|
|
+ Err(err) => {
|
|
|
+ *$guard = Some($parts);
|
|
|
+ return Err(err.into());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
struct QuicTransmitter {
|
|
|
addr: Arc<BlockAddr>,
|
|
|
- sink: FramedWrite<SendStream, MsgEncoder>,
|
|
|
- recv_stream: Mutex<RecvStream>,
|
|
|
+ connection: Connection,
|
|
|
+ send_parts: Mutex<Option<FramedParts<SendStream, MsgEncoder>>>,
|
|
|
+ recv_buf: Mutex<Option<BytesMut>>,
|
|
|
}
|
|
|
|
|
|
impl QuicTransmitter {
|
|
@@ -530,59 +565,78 @@ impl QuicTransmitter {
|
|
|
"UNIMPORTANT",
|
|
|
)?;
|
|
|
let connection = connecting.await?;
|
|
|
- let (send_stream, recv_stream) = connection.open_bi().await?;
|
|
|
- let sink = FramedWrite::new(send_stream, MsgEncoder::new());
|
|
|
+ let send_parts = Mutex::new(None);
|
|
|
+ let recv_buf = Mutex::new(Some(BytesMut::new()));
|
|
|
Ok(Self {
|
|
|
addr,
|
|
|
- sink,
|
|
|
- recv_stream: Mutex::new(recv_stream),
|
|
|
+ connection,
|
|
|
+ send_parts,
|
|
|
+ recv_buf,
|
|
|
})
|
|
|
}
|
|
|
+
|
|
|
+ async fn transmit<T: Serialize>(&mut self, envelope: Envelope<T>) -> Result<RecvStream> {
|
|
|
+ let mut guard = self.send_parts.lock().await;
|
|
|
+ let (send_stream, recv_stream) = self.connection.open_bi().await?;
|
|
|
+ let parts = match guard.take() {
|
|
|
+ Some(mut parts) => {
|
|
|
+ parts.io = send_stream;
|
|
|
+ parts
|
|
|
+ }
|
|
|
+ None => FramedParts::new::<Envelope<T>>(send_stream, MsgEncoder::new()),
|
|
|
+ };
|
|
|
+ let mut sink = Framed::from_parts(parts);
|
|
|
+ let result = sink.send(envelope).await;
|
|
|
+ let parts = sink.into_parts();
|
|
|
+ cleanup_on_err!(result, guard, parts);
|
|
|
+ *guard = Some(parts);
|
|
|
+ Ok(recv_stream)
|
|
|
+ }
|
|
|
+
|
|
|
+ async fn call<'ser, T, F>(&'ser mut self, msg: T, callback: F) -> Result<F::Return>
|
|
|
+ where
|
|
|
+ T: 'ser + CallMsg<'ser>,
|
|
|
+ F: 'static + Send + Sync + DeserCallback,
|
|
|
+ {
|
|
|
+ let recv_stream = self.transmit(Envelope::call(msg)).await?;
|
|
|
+ let mut guard = self.recv_buf.lock().await;
|
|
|
+ let buffer = guard.take().unwrap();
|
|
|
+ let mut callback_framed = CallbackFramed::from_parts(recv_stream, buffer);
|
|
|
+ let result = callback_framed
|
|
|
+ .next(callback)
|
|
|
+ .await
|
|
|
+ .ok_or_else(|| bterr!("server hung up before sending reply"));
|
|
|
+ let (_, buffer) = callback_framed.into_parts();
|
|
|
+ let output = cleanup_on_err!(result, guard, buffer);
|
|
|
+ *guard = Some(buffer);
|
|
|
+ output
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-/// TODO: Once the "Permit impl Trait in type aliases"
|
|
|
-/// https://github.com/rust-lang/rust/issues/63063
|
|
|
-/// feature lands the future types in this implementation should be rewritten to
|
|
|
-/// use it.
|
|
|
impl Transmitter for QuicTransmitter {
|
|
|
fn addr(&self) -> &Arc<BlockAddr> {
|
|
|
&self.addr
|
|
|
}
|
|
|
|
|
|
- type SendFut<'s, T> = SendFut<'s, FramedWrite<SendStream, MsgEncoder>, Envelope<T>>
|
|
|
- where T: 's + Serialize + Send;
|
|
|
-
|
|
|
- fn send<'de, T: 'de + SendMsg<'de>>(&'de mut self, msg: T) -> Self::SendFut<'de, T> {
|
|
|
- self.sink.send(Envelope::send(msg))
|
|
|
- }
|
|
|
-
|
|
|
- type FinishFut = Pin<Box<dyn Future<Output = Result<()>> + Send>>;
|
|
|
+ type SendFut<'ser, T> = impl 'ser + Future<Output = Result<()>> + Send
|
|
|
+ where T: 'ser + SendMsg<'ser>;
|
|
|
|
|
|
- fn finish(mut self) -> Self::FinishFut {
|
|
|
- Box::pin(async move {
|
|
|
- let steam: &mut SendStream = self.sink.get_mut();
|
|
|
- steam.finish().await.map_err(|err| bterr!(err))
|
|
|
- })
|
|
|
+ fn send<'ser, 'r, T: 'ser + SendMsg<'ser>>(&'ser mut self, msg: T) -> Self::SendFut<'ser, T> {
|
|
|
+ self.transmit(Envelope::send(msg))
|
|
|
+ .map(|result| result.map(|_| ()))
|
|
|
}
|
|
|
|
|
|
- type CallFut<'s, 'de, T> = Pin<Box<dyn 's + Future<Output = Result<T::Reply>> + Send>>
|
|
|
+ type CallFut<'ser, T, F> = impl 'ser + Future<Output = Result<F::Return>> + Send
|
|
|
where
|
|
|
- T: 's + CallMsg<'de>,
|
|
|
- T::Reply: 's;
|
|
|
+ Self: 'ser,
|
|
|
+ T: 'ser + CallMsg<'ser>,
|
|
|
+ F: 'static + Send + Sync + DeserCallback;
|
|
|
|
|
|
- fn call<'s, 'de, T>(&'s mut self, msg: T) -> Self::CallFut<'s, 'de, T>
|
|
|
+ fn call<'ser, T, F>(&'ser mut self, msg: T, callback: F) -> Self::CallFut<'ser, T, F>
|
|
|
where
|
|
|
- T: 's + CallMsg<'de>,
|
|
|
- T::Reply: 's,
|
|
|
+ T: 'ser + CallMsg<'ser>,
|
|
|
+ F: 'static + Send + Sync + DeserCallback,
|
|
|
{
|
|
|
- Box::pin(async move {
|
|
|
- self.sink.send(Envelope::call(msg)).await?;
|
|
|
- let mut guard = self.recv_stream.lock().await;
|
|
|
- let mut source = FramedRead::new(guard.deref_mut(), MsgDecoder::<T::Reply>::new());
|
|
|
- source
|
|
|
- .next()
|
|
|
- .await
|
|
|
- .ok_or_else(|| bterr!("server hung up before sending reply"))?
|
|
|
- })
|
|
|
+ self.call(msg, callback)
|
|
|
}
|
|
|
}
|