use std::any::Any;
use std::panic::AssertUnwindSafe;
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
use bytes::Bytes;
use foundation_netio::shared::http::SimpleHeaders;
use crate::shared::context::{Ctx, Spec};
use crate::shared::error::{ConnectError, ConnectResult};
use crate::shared::transport::{BoxFuture, ClientConn, HandlerConn};
pub struct UnaryCall {
pub headers: SimpleHeaders,
pub codec_name: String,
pub frame: Bytes,
}
pub struct UnaryReply {
pub headers: SimpleHeaders,
pub trailers: SimpleHeaders,
pub frame: Bytes,
}
pub struct StreamCall {
pub codec_name: String,
pub conn: Box<dyn HandlerConn>,
}
pub type UnaryFunc =
Arc<dyn Fn(Ctx, UnaryCall) -> BoxFuture<'static, ConnectResult<UnaryReply>> + Send + Sync>;
pub type StreamingHandlerFunc =
Arc<dyn Fn(Ctx, StreamCall) -> BoxFuture<'static, ConnectResult<()>> + Send + Sync>;
pub type StreamingClientFunc =
Arc<dyn Fn(Ctx, Spec) -> BoxFuture<'static, ConnectResult<Box<dyn ClientConn>>> + Send + Sync>;
pub trait Interceptor: Send + Sync + 'static {
fn wrap_unary(&self, next: UnaryFunc) -> UnaryFunc;
fn wrap_streaming_client(&self, next: StreamingClientFunc) -> StreamingClientFunc;
fn wrap_streaming_handler(&self, next: StreamingHandlerFunc) -> StreamingHandlerFunc;
}
pub struct InterceptorChain {
interceptors: Vec<Arc<dyn Interceptor>>,
}
impl InterceptorChain {
#[must_use]
pub fn new(interceptors: Vec<Arc<dyn Interceptor>>) -> Self {
Self { interceptors }
}
#[must_use]
pub fn wrap_unary(&self, next: UnaryFunc) -> UnaryFunc {
let mut func = next;
for interceptor in self.interceptors.iter().rev() {
func = interceptor.wrap_unary(func);
}
func
}
#[must_use]
pub fn wrap_streaming_handler(&self, next: StreamingHandlerFunc) -> StreamingHandlerFunc {
let mut func = next;
for interceptor in self.interceptors.iter().rev() {
func = interceptor.wrap_streaming_handler(func);
}
func
}
#[must_use]
pub fn wrap_streaming_client(&self, next: StreamingClientFunc) -> StreamingClientFunc {
let mut func = next;
for interceptor in self.interceptors.iter().rev() {
func = interceptor.wrap_streaming_client(func);
}
func
}
}
pub struct UnaryInterceptorFunc<F>(pub F);
impl<F> Interceptor for UnaryInterceptorFunc<F>
where
F: Fn(UnaryFunc) -> UnaryFunc + Send + Sync + 'static,
{
fn wrap_unary(&self, next: UnaryFunc) -> UnaryFunc {
(self.0)(next)
}
fn wrap_streaming_client(&self, next: StreamingClientFunc) -> StreamingClientFunc {
next
}
fn wrap_streaming_handler(&self, next: StreamingHandlerFunc) -> StreamingHandlerFunc {
next
}
}
pub type PanicPayload = Box<dyn Any + Send>;
pub struct RecoverInterceptor<F> {
handler: F,
}
impl<F> RecoverInterceptor<F>
where
F: Fn(&Ctx, &Spec, &SimpleHeaders, PanicPayload) -> ConnectError + Clone + Send + Sync + 'static,
{
pub fn new(handler: F) -> Self {
Self { handler }
}
}
impl<F> Interceptor for RecoverInterceptor<F>
where
F: Fn(&Ctx, &Spec, &SimpleHeaders, PanicPayload) -> ConnectError + Clone + Send + Sync + 'static,
{
fn wrap_unary(&self, next: UnaryFunc) -> UnaryFunc {
let handler = self.handler.clone();
Arc::new(move |ctx: Ctx, call: UnaryCall| {
let handler = handler.clone();
let next = next.clone();
let inner = next(ctx.clone(), call);
Box::pin(async move {
match (CatchUnwind { inner }).await {
Ok(result) => result,
Err(payload) => {
let spec = ctx.spec().clone();
let headers = (*ctx.request.headers).clone();
Err(handler(&ctx, &spec, &headers, payload).into())
}
}
})
})
}
fn wrap_streaming_client(&self, next: StreamingClientFunc) -> StreamingClientFunc {
next
}
fn wrap_streaming_handler(&self, next: StreamingHandlerFunc) -> StreamingHandlerFunc {
let handler = self.handler.clone();
Arc::new(move |ctx: Ctx, call: StreamCall| {
let handler = handler.clone();
let next = next.clone();
let inner = next(ctx.clone(), call);
Box::pin(async move {
match (CatchUnwind { inner }).await {
Ok(result) => result,
Err(payload) => {
let spec = ctx.spec().clone();
let headers = (*ctx.request.headers).clone();
Err(handler(&ctx, &spec, &headers, payload).into())
}
}
})
})
}
}
struct CatchUnwind<F> {
inner: F,
}
impl<F: std::future::Future> std::future::Future for CatchUnwind<F> {
type Output = std::thread::Result<F::Output>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let inner = unsafe { self.map_unchecked_mut(|s| &mut s.inner) };
match std::panic::catch_unwind(AssertUnwindSafe(|| inner.poll(cx))) {
Ok(Poll::Ready(v)) => Poll::Ready(Ok(v)),
Ok(Poll::Pending) => Poll::Pending,
Err(payload) => Poll::Ready(Err(payload)),
}
}
}