pub mod monitor;
use futures::future::BoxFuture;
use std::{
error::Error,
fmt,
future::Future,
pin::Pin,
sync::Arc,
task::{Context, Poll, ready},
};
use tokio_util::sync::ReusableBoxFuture;
use crate::{
RemoteSend, chmux, codec, exec,
rch::{SendingError, SendingErrorKind, base, mpsc, oneshot},
};
pub use remoc_macro::remote;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum CallError {
Dropped,
RemoteSend(base::SendErrorKind),
RemoteReceive(base::RecvError),
RemoteConnect(chmux::ConnectError),
RemoteListen(chmux::ListenerError),
RemoteForward,
}
impl fmt::Display for CallError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Dropped => write!(f, "processing request failed"),
Self::RemoteSend(err) => write!(f, "send error: {err}"),
Self::RemoteReceive(err) => write!(f, "receive error: {err}"),
Self::RemoteConnect(err) => write!(f, "connect error: {err}"),
Self::RemoteListen(err) => write!(f, "listen error: {err}"),
Self::RemoteForward => write!(f, "forwarding error"),
}
}
}
impl Error for CallError {}
impl<T> From<mpsc::SendError<T>> for CallError {
fn from(err: mpsc::SendError<T>) -> Self {
match err {
mpsc::SendError::Closed(_) => Self::Dropped,
mpsc::SendError::RemoteSend(err) => Self::RemoteSend(err),
mpsc::SendError::RemoteConnect(err) => Self::RemoteConnect(err),
mpsc::SendError::RemoteListen(err) => Self::RemoteListen(err),
mpsc::SendError::RemoteForward => Self::RemoteForward,
}
}
}
impl From<oneshot::RecvError> for CallError {
fn from(err: oneshot::RecvError) -> Self {
match err {
oneshot::RecvError::Closed => Self::Dropped,
oneshot::RecvError::RemoteReceive(err) => Self::RemoteReceive(err),
oneshot::RecvError::RemoteConnect(err) => Self::RemoteConnect(err),
oneshot::RecvError::RemoteListen(err) => Self::RemoteListen(err),
}
}
}
#[doc(hidden)]
pub trait ReqEnum {
fn trait_name() -> &'static str;
fn method_name(&self) -> &'static str;
}
#[derive(Serialize, Deserialize)]
pub enum Req<Value, Ref, RefMut> {
Value(Value),
Ref(Ref),
RefMut(RefMut),
}
impl<Value, Ref, RefMut> Req<Value, Ref, RefMut>
where
Value: ReqEnum,
Ref: ReqEnum,
RefMut: ReqEnum,
{
pub fn trait_name() -> &'static str {
let trait_name = Value::trait_name();
assert_eq!(trait_name, Ref::trait_name());
assert_eq!(trait_name, RefMut::trait_name());
trait_name
}
pub fn method_name(&self) -> &'static str {
match self {
Self::Value(req) => req.method_name(),
Self::Ref(req) => req.method_name(),
Self::RefMut(req) => req.method_name(),
}
}
}
pub trait Client {
fn capacity(&self) -> usize;
fn closed(&self) -> Closed;
fn is_closed(&self) -> bool;
fn max_request_size(&self) -> usize;
fn set_max_request_size(&mut self, max_request_size: usize);
fn max_reply_size(&self) -> usize;
fn set_max_reply_size(&mut self, max_reply_size: usize);
}
pub struct Closed(ReusableBoxFuture<'static, ()>);
impl fmt::Debug for Closed {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("Closed").finish()
}
}
impl Closed {
#[doc(hidden)]
pub fn new(fut: impl Future<Output = ()> + Send + 'static) -> Self {
Self(ReusableBoxFuture::new(fut))
}
}
impl Future for Closed {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
self.as_mut().0.poll_unpin(cx)
}
}
pub trait MonitorableClient {
type Value: ReqEnum;
type Ref: ReqEnum;
type RefMut: ReqEnum;
fn set_monitor(&mut self, monitor: impl ClientMonitor<Self::Value, Self::Ref, Self::RefMut> + 'static);
}
pub trait ClientMonitor<Value, Ref, RefMut>: Send + Sync
where
Value: ReqEnum,
Ref: ReqEnum,
RefMut: ReqEnum,
{
fn pre_call<'a>(&'a self, req: &'a Req<Value, Ref, RefMut>) -> BoxFuture<'a, CallDecision>;
}
pub enum CallDecision {
Pass,
Guard(Box<dyn CallGuard>),
Drop,
}
impl fmt::Debug for CallDecision {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Pass => write!(f, "Pass"),
Self::Guard(_) => write!(f, "Guard"),
Self::Drop => write!(f, "Drop"),
}
}
}
pub trait CallGuard: Send {
fn failed(&mut self) {}
fn reply_failed(&mut self, err: &oneshot::RecvError) {
let _ = err;
}
}
pub struct ChainedMonitor<A, B>(pub A, pub B);
impl<A, B, Value, Ref, RefMut> ClientMonitor<Value, Ref, RefMut> for ChainedMonitor<A, B>
where
A: ClientMonitor<Value, Ref, RefMut>,
B: ClientMonitor<Value, Ref, RefMut>,
Value: ReqEnum,
Ref: ReqEnum,
RefMut: ReqEnum,
{
fn pre_call<'a>(&'a self, req: &'a Req<Value, Ref, RefMut>) -> BoxFuture<'a, CallDecision> {
let pre_call_0 = self.0.pre_call(req);
let pre_call_1 = self.1.pre_call(req);
async move {
let guard_0 = match pre_call_0.await {
CallDecision::Pass => None,
CallDecision::Guard(guard) => Some(guard),
CallDecision::Drop => return CallDecision::Drop,
};
let guard_1 = match pre_call_1.await {
CallDecision::Pass => None,
CallDecision::Guard(guard) => Some(guard),
CallDecision::Drop => return CallDecision::Drop,
};
match (guard_0, guard_1) {
(None, None) => CallDecision::Pass,
(Some(guard0), None) => CallDecision::Guard(guard0),
(None, Some(guard1)) => CallDecision::Guard(guard1),
(Some(guard0), Some(guard1)) => CallDecision::Guard(Box::new(ChainedCallGuard(guard1, guard0))),
}
}
.boxed()
}
}
struct ChainedCallGuard(Box<dyn CallGuard>, Box<dyn CallGuard>);
impl CallGuard for ChainedCallGuard {
fn failed(&mut self) {
self.0.failed();
self.1.failed();
}
fn reply_failed(&mut self, err: &oneshot::RecvError) {
self.0.reply_failed(err);
self.1.reply_failed(err);
}
}
pub trait ServerBase {
type Client: Client;
}
pub trait Server<Target, Codec>: ServerBase
where
Self: Sized,
{
fn new(target: Target, request_buffer: usize) -> (Self, Self::Client);
fn serve(self) -> impl Future<Output = (Option<Target>, Result<(), ServeError>)>;
}
pub trait ServerRef<'target, Target, Codec>: ServerBase
where
Self: Sized,
{
fn new(target: &'target Target, request_buffer: usize) -> (Self, Self::Client);
fn serve(self) -> impl Future<Output = Result<(), ServeError>>;
}
pub trait ServerRefMut<'target, Target, Codec>: ServerBase
where
Self: Sized,
{
fn new(target: &'target mut Target, request_buffer: usize) -> (Self, Self::Client);
fn serve(self) -> impl Future<Output = Result<(), ServeError>>;
}
pub trait ServerShared<Target, Codec>: ServerBase
where
Self: Sized,
Self::Client: Clone,
{
fn new(target: Arc<Target>, request_buffer: usize) -> (Self, Self::Client);
fn serve(self, spawn: bool) -> impl Future<Output = Result<(), ServeError>>;
}
pub trait ServerSharedMut<Target, Codec>: ServerBase
where
Self: Sized,
{
fn new(target: Arc<LocalRwLock<Target>>, request_buffer: usize) -> (Self, Self::Client);
fn serve(self, spawn: bool) -> impl Future<Output = Result<(), ServeError>>;
}
pub trait ReqReceiver<Codec>: ServerBase
where
Self: Sized,
{
type Value: ReqEnum;
type Ref: ReqEnum;
type RefMut: ReqEnum;
fn new(request_buffer: usize) -> (Self, Self::Client);
#[allow(clippy::type_complexity)]
fn recv(
&mut self,
) -> impl Future<Output = Result<Option<Req<Self::Value, Self::Ref, Self::RefMut>>, mpsc::RecvError>> + Send;
fn close(&mut self);
fn into_stream(self) -> ReqReceiverStream<Self, Codec>
where
Self: Send + 'static,
Codec: 'static,
{
ReqReceiverStream::new(self)
}
}
pub struct ReqReceiverStream<R, Codec>
where
R: ReqReceiver<Codec> + Send + 'static,
Codec: 'static,
{
#[allow(clippy::type_complexity)]
inner: ReusableBoxFuture<'static, (Result<Option<Req<R::Value, R::Ref, R::RefMut>>, mpsc::RecvError>, R)>,
close: bool,
}
impl<R, Codec> fmt::Debug for ReqReceiverStream<R, Codec>
where
R: ReqReceiver<Codec> + Send + 'static,
Codec: 'static,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("ReqReceiverStream").finish()
}
}
impl<R, Codec> ReqReceiverStream<R, Codec>
where
R: ReqReceiver<Codec> + Send + 'static,
Codec: 'static,
{
pub fn new(req_rx: R) -> Self {
Self { inner: ReusableBoxFuture::new(Self::make_future(req_rx, false)), close: false }
}
pub fn close(&mut self) {
self.close = true;
}
#[allow(clippy::type_complexity)]
async fn make_future(
mut req_rx: R, close: bool,
) -> (Result<Option<Req<R::Value, R::Ref, R::RefMut>>, mpsc::RecvError>, R) {
if close {
req_rx.close();
}
let result = req_rx.recv().await;
(result, req_rx)
}
}
impl<R, Codec> Stream for ReqReceiverStream<R, Codec>
where
R: ReqReceiver<Codec> + Send + 'static,
Codec: 'static,
{
type Item = Result<Req<R::Value, R::Ref, R::RefMut>, mpsc::RecvError>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
let (result, req_rx) = ready!(self.inner.poll(cx));
let close = self.close;
self.inner.set(Self::make_future(req_rx, close));
Poll::Ready(result.transpose())
}
}
impl<R, Codec> Unpin for ReqReceiverStream<R, Codec> where R: ReqReceiver<Codec> + Send + 'static {}
pub trait MonitorableServer {
type Value: ReqEnum;
type Ref: ReqEnum;
type RefMut: ReqEnum;
fn set_monitor(&mut self, monitor: impl ServerMonitor<Self::Value, Self::Ref, Self::RefMut> + 'static);
}
pub trait ServerMonitor<Value, Ref, RefMut>: Send
where
Value: ReqEnum,
Ref: ReqEnum,
RefMut: ReqEnum,
{
fn pre_dispatch<'a>(
&'a mut self, req: &'a Result<Option<Req<Value, Ref, RefMut>>, mpsc::RecvError>,
) -> BoxFuture<'a, DispatchDecision>;
}
pub trait MonitorableReqReceiver {
type Value: ReqEnum;
type Ref: ReqEnum;
type RefMut: ReqEnum;
fn set_monitor(&mut self, monitor: impl ReqReceiverMonitor<Self::Value, Self::Ref, Self::RefMut> + 'static);
}
pub trait ReqReceiverMonitor<Value, Ref, RefMut>: Send
where
Value: ReqEnum,
Ref: ReqEnum,
RefMut: ReqEnum,
{
fn pre_recv<'a>(
&'a mut self, req: &'a Result<Option<Req<Value, Ref, RefMut>>, mpsc::RecvError>,
) -> BoxFuture<'a, RecvDecision>;
}
impl<A, B, Value, Ref, RefMut> ReqReceiverMonitor<Value, Ref, RefMut> for ChainedMonitor<A, B>
where
A: ReqReceiverMonitor<Value, Ref, RefMut>,
B: ReqReceiverMonitor<Value, Ref, RefMut>,
Value: ReqEnum,
Ref: ReqEnum,
RefMut: ReqEnum,
{
fn pre_recv<'a>(
&'a mut self, req: &'a Result<Option<Req<Value, Ref, RefMut>>, mpsc::RecvError>,
) -> BoxFuture<'a, RecvDecision> {
let pre_recv_0 = self.0.pre_recv(req);
let pre_recv_1 = self.1.pre_recv(req);
async move {
match pre_recv_0.await {
RecvDecision::Pass => (),
RecvDecision::Drop => return RecvDecision::Drop,
}
pre_recv_1.await
}
.boxed()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RecvDecision {
Pass,
Drop,
}
impl<A, B, Value, Ref, RefMut> ServerMonitor<Value, Ref, RefMut> for ChainedMonitor<A, B>
where
A: ServerMonitor<Value, Ref, RefMut>,
B: ServerMonitor<Value, Ref, RefMut>,
Value: ReqEnum,
Ref: ReqEnum,
RefMut: ReqEnum,
{
fn pre_dispatch<'a>(
&'a mut self, req: &'a Result<Option<Req<Value, Ref, RefMut>>, mpsc::RecvError>,
) -> BoxFuture<'a, DispatchDecision> {
let pre_dispatch_0 = self.0.pre_dispatch(req);
let pre_dispatch_1 = self.1.pre_dispatch(req);
async move {
let guard_0 = match pre_dispatch_0.await {
DispatchDecision::Pass => None,
DispatchDecision::Guard(guard) => Some(guard),
DispatchDecision::Drop => return DispatchDecision::Drop,
DispatchDecision::Error(err) => return DispatchDecision::Error(err),
};
let guard_1 = match pre_dispatch_1.await {
DispatchDecision::Pass => None,
DispatchDecision::Guard(guard) => Some(guard),
DispatchDecision::Drop => return DispatchDecision::Drop,
DispatchDecision::Error(err) => return DispatchDecision::Error(err),
};
match (guard_0, guard_1) {
(None, None) => DispatchDecision::Pass,
(Some(guard0), None) => DispatchDecision::Guard(guard0),
(None, Some(guard1)) => DispatchDecision::Guard(guard1),
(Some(guard0), Some(guard1)) => {
DispatchDecision::Guard(Box::new(ChainedDispatchGuard(guard1, guard0)))
}
}
}
.boxed()
}
}
struct ChainedDispatchGuard(Box<dyn DispatchGuard>, Box<dyn DispatchGuard>);
impl DispatchGuard for ChainedDispatchGuard {
fn failed(&mut self) {
self.0.failed();
self.1.failed();
}
}
pub trait DispatchGuard: Send {
fn failed(&mut self) {}
}
pub enum DispatchDecision {
Pass,
Guard(Box<dyn DispatchGuard>),
Drop,
Error(Box<dyn Error + Send>),
}
impl fmt::Debug for DispatchDecision {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Pass => write!(f, "Pass"),
Self::Guard(_) => write!(f, "Guard"),
Self::Drop => write!(f, "Drop"),
Self::Error(err) => f.debug_tuple("Error").field(err).finish(),
}
}
}
#[macro_export]
#[doc(hidden)]
macro_rules! server_monitor_pre_dispatch {
($monitor:expr, $req:expr) => {
match $monitor.pre_dispatch(&$req).await {
::remoc::rtc::DispatchDecision::Pass => ::std::boxed::Box::new(::remoc::rtc::DefaultGuard),
::remoc::rtc::DispatchDecision::Guard(guard) => guard,
::remoc::rtc::DispatchDecision::Drop => {
match &$req {
Ok(None) => (),
Err(err) if err.is_final() => (),
_ => continue,
}
::std::boxed::Box::new(::remoc::rtc::DefaultGuard)
}
::remoc::rtc::DispatchDecision::Error(err) => return Err(::remoc::rtc::ServeError::Monitor(err)),
}
};
($monitor:expr, $req:expr, $target:expr) => {
match $monitor.pre_dispatch(&$req).await {
::remoc::rtc::DispatchDecision::Pass => ::std::boxed::Box::new(::remoc::rtc::DefaultGuard),
::remoc::rtc::DispatchDecision::Guard(guard) => guard,
::remoc::rtc::DispatchDecision::Drop => {
match &$req {
Ok(None) => (),
Err(err) if err.is_final() => (),
_ => continue,
}
::std::boxed::Box::new(::remoc::rtc::DefaultGuard)
}
::remoc::rtc::DispatchDecision::Error(err) => {
return (Some($target), Err(::remoc::rtc::ServeError::Monitor(err)))
}
}
};
}
#[doc(hidden)]
pub use crate::server_monitor_pre_dispatch;
#[macro_export]
#[doc(hidden)]
macro_rules! req_receiver_monitor_pre_recv {
($monitor:expr, $req:expr) => {
match $monitor.pre_recv(&$req).await {
::remoc::rtc::RecvDecision::Pass => (),
::remoc::rtc::RecvDecision::Drop => match &$req {
Ok(None) => (),
Err(err) if err.is_final() => (),
_ => continue,
},
}
};
}
#[doc(hidden)]
pub use crate::req_receiver_monitor_pre_recv;
#[doc(hidden)]
#[derive(Debug, Default)]
pub struct DefaultMonitor;
impl<Value, Ref, RefMut> ClientMonitor<Value, Ref, RefMut> for DefaultMonitor
where
Value: ReqEnum,
Ref: ReqEnum,
RefMut: ReqEnum,
{
fn pre_call<'a>(&self, req: &'a Req<Value, Ref, RefMut>) -> BoxFuture<'a, CallDecision> {
let _ = req;
std::future::ready(CallDecision::Pass).boxed()
}
}
impl<Value, Ref, RefMut> ServerMonitor<Value, Ref, RefMut> for DefaultMonitor
where
Value: ReqEnum,
Ref: ReqEnum,
RefMut: ReqEnum,
{
fn pre_dispatch<'a>(
&mut self, req: &'a Result<Option<Req<Value, Ref, RefMut>>, mpsc::RecvError>,
) -> BoxFuture<'a, DispatchDecision> {
let _ = req;
std::future::ready(DispatchDecision::Pass).boxed()
}
}
impl<Value, Ref, RefMut> ReqReceiverMonitor<Value, Ref, RefMut> for DefaultMonitor
where
Value: ReqEnum,
Ref: ReqEnum,
RefMut: ReqEnum,
{
fn pre_recv<'a>(
&mut self, req: &'a Result<Option<Req<Value, Ref, RefMut>>, mpsc::RecvError>,
) -> BoxFuture<'a, RecvDecision> {
let _ = req;
std::future::ready(RecvDecision::Pass).boxed()
}
}
#[doc(hidden)]
pub fn default_client_monitor<Value, Ref, RefMut>() -> Arc<dyn ClientMonitor<Value, Ref, RefMut>>
where
Value: ReqEnum,
Ref: ReqEnum,
RefMut: ReqEnum,
{
Arc::new(DefaultMonitor)
}
#[doc(hidden)]
#[derive(Debug, Default)]
pub struct DefaultGuard;
impl CallGuard for DefaultGuard {}
impl DispatchGuard for DefaultGuard {}
#[derive(Debug)]
pub enum ServeError {
ReqReceive(mpsc::RecvError),
ReplySend(SendingErrorKind),
Monitor(Box<dyn Error + Send>),
}
impl From<mpsc::RecvError> for ServeError {
fn from(err: mpsc::RecvError) -> Self {
Self::ReqReceive(err)
}
}
impl<T> From<SendingError<T>> for ServeError {
fn from(err: SendingError<T>) -> Self {
Self::ReplySend(err.kind())
}
}
impl From<SendingErrorKind> for ServeError {
fn from(err: SendingErrorKind) -> Self {
Self::ReplySend(err)
}
}
impl fmt::Display for ServeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::ReqReceive(err) => write!(f, "failed to receive RTC request: {err}"),
Self::ReplySend(err) => write!(f, "failed to send reply to RTC request: {err}"),
Self::Monitor(err) => write!(f, "failed by server monitor: {err}"),
}
}
}
impl Error for ServeError {}
#[doc(hidden)]
pub use crate::exec::task::spawn;
#[doc(hidden)]
pub use serde::{Deserialize, Serialize};
#[doc(hidden)]
pub use tokio::select;
#[doc(hidden)]
pub use tokio::sync::RwLock as LocalRwLock;
#[doc(hidden)]
pub use tokio::sync::broadcast as local_broadcast;
#[doc(hidden)]
pub use tokio::sync::mpsc as local_mpsc;
#[doc(hidden)]
pub type ReplyErrorSender = tokio::sync::mpsc::Sender<SendingErrorKind>;
#[doc(hidden)]
pub use futures::future::FutureExt;
#[doc(hidden)]
pub use futures::stream::Stream;
#[doc(hidden)]
pub use futures::stream::StreamExt;
#[doc(hidden)]
pub use tracing::Instrument;
#[doc(hidden)]
pub fn reply_error_channel() -> (ReplyErrorSender, tokio::sync::mpsc::Receiver<SendingErrorKind>) {
tokio::sync::mpsc::channel(16)
}
#[doc(hidden)]
pub fn empty_client_drop_tx() -> local_broadcast::Sender<()> {
local_broadcast::channel(1).0
}
#[doc(hidden)]
pub const fn missing_max_reply_size() -> usize {
usize::MAX
}
#[doc(hidden)]
pub async fn send_reply<T, E, Codec>(
reply_tx: oneshot::Sender<Result<T, E>, Codec>, err_tx: &ReplyErrorSender,
mut dispatch_guard: Box<dyn DispatchGuard>, result: Result<T, E>,
) where
T: RemoteSend,
E: RemoteSend,
Codec: codec::Codec,
{
if result.is_err() {
dispatch_guard.failed();
}
let Ok(sending) = reply_tx.send(result) else { return };
let err_tx = err_tx.clone();
exec::spawn(
async move {
if let Err(err) = sending.await {
let kind = err.kind();
match &kind {
SendingErrorKind::Send(base::SendErrorKind::Send(_)) => return,
SendingErrorKind::Dropped => return,
_ => (),
}
let _ = err_tx.send(kind).await;
}
drop(dispatch_guard);
}
.in_current_span(),
);
}
#[doc(hidden)]
pub mod serde_max_reply_size {
use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub fn serialize<S>(max_reply_size: &usize, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let max_reply_size = u64::try_from(*max_reply_size).unwrap_or(u64::MAX);
max_reply_size.serialize(serializer)
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<usize, D::Error>
where
D: Deserializer<'de>,
{
let max_reply_size = u64::deserialize(deserializer)?;
Ok(usize::try_from(max_reply_size).unwrap_or(usize::MAX))
}
}