//! `IoHandler` middlewares use crate::calls::Metadata; use crate::types::{Call, Output, Request, Response}; use futures_util::future::Either; use std::future::Future; use std::pin::Pin; /// RPC middleware pub trait Middleware: Send + Sync + 'static { /// A returned request future. type Future: Future> + Send + 'static; /// A returned call future. type CallFuture: Future> + Send + 'static; /// Method invoked on each request. /// Allows you to either respond directly (without executing RPC call) /// or do any additional work before and/or after processing the request. fn on_request(&self, request: Request, meta: M, next: F) -> Either where F: Fn(Request, M) -> X + Send + Sync, X: Future> + Send + 'static, { Either::Right(next(request, meta)) } /// Method invoked on each call inside a request. /// /// Allows you to either handle the call directly (without executing RPC call). fn on_call(&self, call: Call, meta: M, next: F) -> Either where F: Fn(Call, M) -> X + Send + Sync, X: Future> + Send + 'static, { Either::Right(next(call, meta)) } } /// Dummy future used as a noop result of middleware. pub type NoopFuture = Pin> + Send>>; /// Dummy future used as a noop call result of middleware. pub type NoopCallFuture = Pin> + Send>>; /// No-op middleware implementation #[derive(Clone, Debug, Default)] pub struct Noop; impl Middleware for Noop { type Future = NoopFuture; type CallFuture = NoopCallFuture; } impl, B: Middleware> Middleware for (A, B) { type Future = Either; type CallFuture = Either; fn on_request(&self, request: Request, meta: M, process: F) -> Either where F: Fn(Request, M) -> X + Send + Sync, X: Future> + Send + 'static, { repack(self.0.on_request(request, meta, |request, meta| { self.1.on_request(request, meta, &process) })) } fn on_call(&self, call: Call, meta: M, process: F) -> Either where F: Fn(Call, M) -> X + Send + Sync, X: Future> + Send + 'static, { repack( self.0 .on_call(call, meta, |call, meta| self.1.on_call(call, meta, &process)), ) } } impl, B: Middleware, C: Middleware> Middleware for (A, B, C) { type Future = Either>; type CallFuture = Either>; fn on_request(&self, request: Request, meta: M, process: F) -> Either where F: Fn(Request, M) -> X + Send + Sync, X: Future> + Send + 'static, { repack(self.0.on_request(request, meta, |request, meta| { repack(self.1.on_request(request, meta, |request, meta| { self.2.on_request(request, meta, &process) })) })) } fn on_call(&self, call: Call, meta: M, process: F) -> Either where F: Fn(Call, M) -> X + Send + Sync, X: Future> + Send + 'static, { repack(self.0.on_call(call, meta, |call, meta| { repack( self.1 .on_call(call, meta, |call, meta| self.2.on_call(call, meta, &process)), ) })) } } impl, B: Middleware, C: Middleware, D: Middleware> Middleware for (A, B, C, D) { type Future = Either>>; type CallFuture = Either>>; fn on_request(&self, request: Request, meta: M, process: F) -> Either where F: Fn(Request, M) -> X + Send + Sync, X: Future> + Send + 'static, { repack(self.0.on_request(request, meta, |request, meta| { repack(self.1.on_request(request, meta, |request, meta| { repack(self.2.on_request(request, meta, |request, meta| { self.3.on_request(request, meta, &process) })) })) })) } fn on_call(&self, call: Call, meta: M, process: F) -> Either where F: Fn(Call, M) -> X + Send + Sync, X: Future> + Send + 'static, { repack(self.0.on_call(call, meta, |call, meta| { repack(self.1.on_call(call, meta, |call, meta| { repack( self.2 .on_call(call, meta, |call, meta| self.3.on_call(call, meta, &process)), ) })) })) } } #[inline(always)] fn repack(result: Either>) -> Either, X> { match result { Either::Left(a) => Either::Left(Either::Left(a)), Either::Right(Either::Left(b)) => Either::Left(Either::Right(b)), Either::Right(Either::Right(x)) => Either::Right(x), } }