pub(crate) mod dispatch;
pub(crate) mod erased;
use std::future::Future;
use std::sync::Arc;
use foundation_netio::shared::http::SimpleHeaders;
use std::any::Any;
use std::collections::HashMap;
use crate::shared::codec::ProcedureCodecs;
use crate::shared::compression::{CompressionRegistry, Compressor, SizeLimits};
use crate::shared::context::{Ctx, IdempotencyLevel, Spec, StreamType};
use crate::shared::error::{ConnectError, ConnectResult};
use crate::shared::interceptor::{
Interceptor, InterceptorChain, RecoverInterceptor, StreamingHandlerFunc, UnaryFunc,
};
use crate::shared::message::{Request, Response};
use crate::shared::protocol::{connect::ConnectHandler, grpc::GrpcHandler, grpc_web::GrpcWebHandler, ProtocolHandler};
use crate::shared::transport::DEFAULT_PIPE_DEPTH;
use erased::{
bidi_stream_handler, client_stream_handler, codec_meta, server_stream_handler, unary_handler,
ErasedStreamHandler, ErasedUnaryHandler, StreamHandlerImpl, UnaryHandlerImpl,
};
pub use dispatch::{
in_memory_body, CallHooks, CollectingSink, ConnectRpcHandler, DeadlineTimer, RequestBody,
ResponseSink,
};
pub use erased::RequestStream;
pub(crate) use erased::ProcedureMeta;
pub struct HandlerOptions {
pub interceptors: Vec<Arc<dyn Interceptor>>,
pub compression: Option<CompressionRegistry>,
pub limits: SizeLimits,
pub idempotency: IdempotencyLevel,
pub require_connect_protocol_header: bool,
pub pipe_depth: usize,
}
impl Default for HandlerOptions {
fn default() -> Self {
Self {
interceptors: Vec::new(),
compression: None,
limits: SizeLimits::default(),
idempotency: IdempotencyLevel::Unknown,
require_connect_protocol_header: false,
pipe_depth: DEFAULT_PIPE_DEPTH,
}
}
}
impl HandlerOptions {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn with_interceptors(mut self, interceptors: Vec<Arc<dyn Interceptor>>) -> Self {
self.interceptors = interceptors;
self
}
#[must_use]
pub fn with_read_max_bytes(mut self, n: usize) -> Self {
self.limits.read_max_bytes = n;
self
}
#[must_use]
pub fn with_send_max_bytes(mut self, n: usize) -> Self {
self.limits.send_max_bytes = n;
self
}
#[must_use]
pub fn with_idempotency(mut self, level: IdempotencyLevel) -> Self {
self.idempotency = level;
self
}
#[must_use]
pub fn with_require_connect_protocol_header(mut self, required: bool) -> Self {
self.require_connect_protocol_header = required;
self
}
#[must_use]
pub fn with_compression(mut self, _name: &str, compressor: Arc<dyn Compressor>) -> Self {
let mut registry = self.compression.take().unwrap_or_default();
registry.register(compressor);
self.compression = Some(registry);
self
}
#[must_use]
pub fn with_pipe_depth(mut self, n: usize) -> Self {
self.pipe_depth = n;
self
}
#[must_use]
pub fn with_recover<F>(mut self, handler: F) -> Self
where
F: Fn(&Ctx, &Spec, &SimpleHeaders, Box<dyn Any + Send>) -> ConnectError
+ Clone
+ Send
+ Sync
+ 'static,
{
self.interceptors
.push(Arc::new(RecoverInterceptor::new(handler)));
self
}
}
pub(crate) enum HandlerKind {
Unary(Arc<dyn ErasedUnaryHandler>),
ServerStream(Arc<dyn ErasedStreamHandler>),
ClientStream(Arc<dyn ErasedStreamHandler>),
BidiStream(Arc<dyn ErasedStreamHandler>),
}
pub(crate) struct HandlerEntry {
pub(crate) spec: Spec,
pub(crate) handler: HandlerKind,
pub(crate) options: HandlerOptions,
pub(crate) protocol_handlers: Vec<Box<dyn ProtocolHandler>>,
pub(crate) codec_meta: Arc<dyn ProcedureMeta>,
}
pub struct Router {
handlers: HashMap<String, HandlerEntry>,
compression: Arc<CompressionRegistry>,
global_options: Vec<Arc<dyn Interceptor>>,
}
impl Default for Router {
fn default() -> Self {
Self::new()
}
}
impl Router {
#[must_use]
pub fn new() -> Self {
Self {
handlers: HashMap::new(),
compression: Arc::new(CompressionRegistry::new()),
global_options: Vec::new(),
}
}
#[must_use]
pub fn with_compression(mut self, compression: Arc<CompressionRegistry>) -> Self {
self.compression = compression;
self
}
#[must_use]
pub fn with_global_interceptors(mut self, interceptors: Vec<Arc<dyn Interceptor>>) -> Self {
self.global_options = interceptors;
self
}
pub fn unary<Req, Res, F, Fut>(
&mut self,
procedure: &str,
codecs: ProcedureCodecs<Req, Res>,
handler: F,
options: HandlerOptions,
) where
Req: Send + 'static,
Res: Send + 'static,
F: Fn(Ctx, Request<Req>) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ConnectResult<Response<Res>>> + Send + 'static,
{
let codecs = Arc::new(codecs);
let inner = unary_handler(codecs.clone(), handler);
let func = self.compose_unary(&options, inner);
let entry = self.build_entry(
procedure,
StreamType::Unary,
HandlerKind::Unary(Arc::new(UnaryHandlerImpl::new(func))),
codec_meta(codecs),
options,
);
self.handlers.insert(procedure.to_string(), entry);
}
pub fn server_stream<Req, Res, S, F, Fut>(
&mut self,
procedure: &str,
codecs: ProcedureCodecs<Req, Res>,
handler: F,
options: HandlerOptions,
) where
Req: Send + 'static,
Res: Send + 'static,
S: futures::Stream<Item = ConnectResult<Res>> + Send + 'static,
F: Fn(Ctx, Request<Req>) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ConnectResult<S>> + Send + 'static,
{
let codecs = Arc::new(codecs);
let inner = server_stream_handler(codecs.clone(), handler);
let func = self.compose_streaming(&options, inner);
let entry = self.build_entry(
procedure,
StreamType::ServerStream,
HandlerKind::ServerStream(Arc::new(StreamHandlerImpl::new(func))),
codec_meta(codecs),
options,
);
self.handlers.insert(procedure.to_string(), entry);
}
pub fn client_stream<Req, Res, F, Fut>(
&mut self,
procedure: &str,
codecs: ProcedureCodecs<Req, Res>,
handler: F,
options: HandlerOptions,
) where
Req: Send + 'static,
Res: Send + 'static,
F: Fn(Ctx, RequestStream<Req>) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ConnectResult<Response<Res>>> + Send + 'static,
{
let codecs = Arc::new(codecs);
let inner = client_stream_handler(codecs.clone(), handler);
let func = self.compose_streaming(&options, inner);
let entry = self.build_entry(
procedure,
StreamType::ClientStream,
HandlerKind::ClientStream(Arc::new(StreamHandlerImpl::new(func))),
codec_meta(codecs),
options,
);
self.handlers.insert(procedure.to_string(), entry);
}
pub fn bidi_stream<Req, Res, S, F, Fut>(
&mut self,
procedure: &str,
codecs: ProcedureCodecs<Req, Res>,
handler: F,
options: HandlerOptions,
) where
Req: Send + 'static,
Res: Send + 'static,
S: futures::Stream<Item = ConnectResult<Res>> + Send + 'static,
F: Fn(Ctx, RequestStream<Req>) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ConnectResult<S>> + Send + 'static,
{
let codecs = Arc::new(codecs);
let inner = bidi_stream_handler(codecs.clone(), handler);
let func = self.compose_streaming(&options, inner);
let entry = self.build_entry(
procedure,
StreamType::BidiStream,
HandlerKind::BidiStream(Arc::new(StreamHandlerImpl::new(func))),
codec_meta(codecs),
options,
);
self.handlers.insert(procedure.to_string(), entry);
}
#[must_use]
pub fn into_handler(self) -> ConnectRpcHandler {
ConnectRpcHandler::new(self)
}
#[must_use]
pub fn len(&self) -> usize {
self.handlers.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.handlers.is_empty()
}
pub(crate) fn lookup(&self, path: &str) -> Option<&HandlerEntry> {
self.handlers.get(path)
}
pub(crate) fn global_compression(&self) -> &Arc<CompressionRegistry> {
&self.compression
}
fn compose_unary(&self, options: &HandlerOptions, inner: UnaryFunc) -> UnaryFunc {
InterceptorChain::new(self.merged_interceptors(options)).wrap_unary(inner)
}
fn compose_streaming(
&self,
options: &HandlerOptions,
inner: StreamingHandlerFunc,
) -> StreamingHandlerFunc {
InterceptorChain::new(self.merged_interceptors(options)).wrap_streaming_handler(inner)
}
fn merged_interceptors(&self, options: &HandlerOptions) -> Vec<Arc<dyn Interceptor>> {
let mut all = self.global_options.clone();
all.extend(options.interceptors.iter().cloned());
all
}
fn build_entry(
&self,
procedure: &str,
stream_type: StreamType,
handler: HandlerKind,
codec_meta: Arc<dyn ProcedureMeta>,
options: HandlerOptions,
) -> HandlerEntry {
HandlerEntry {
spec: Spec {
stream_type,
procedure: procedure.to_string(),
is_client: false,
idempotency: options.idempotency,
},
handler,
protocol_handlers: default_protocol_handlers(),
codec_meta,
options,
}
}
}
fn default_protocol_handlers() -> Vec<Box<dyn ProtocolHandler>> {
vec![
Box::new(ConnectHandler),
Box::new(GrpcHandler),
Box::new(GrpcWebHandler),
]
}