sunbeam-g2v 0.4.0

Sunbeam Service Framework - A ConnectRPC-based framework for building microservices
//! Panic recovery middleware.

use std::{
    future::Future,
    pin::Pin,
    task::{Context, Poll},
};
use tower::{Layer, Service};

/// Panic recovery layer.
///
/// This middleware provides panic recovery for service handlers.
///
/// Note: This implementation does NOT actually catch panics from async code.
/// Panics in async Rust are not catchable with `catch_unwind`. For proper
/// panic handling on Tokio, use `tower_http::catch_panic::CatchPanicLayer` instead.
/// This middleware exists as a placeholder for future runtime-specific implementations.
#[derive(Debug, Clone)]
pub struct PanicRecoveryLayer;

impl<S> Layer<S> for PanicRecoveryLayer {
    type Service = PanicRecoveryService<S>;

    fn layer(&self, inner: S) -> Self::Service {
        PanicRecoveryService { inner }
    }
}

/// Panic recovery service.
#[derive(Debug, Clone)]
pub struct PanicRecoveryService<S> {
    inner: S,
}

impl<S, B> Service<http::Request<B>> for PanicRecoveryService<S>
where
    S: Service<http::Request<B>> + Send + 'static,
    S::Future: Send + 'static,
    S::Response: Send + 'static,
    S::Error: std::fmt::Debug + Send + 'static,
    B: Send + 'static,
{
    type Response = S::Response;
    type Error = S::Error;
    type Future =
        Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send + 'static>>;

    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        self.inner.poll_ready(cx)
    }

    fn call(&mut self, req: http::Request<B>) -> Self::Future {
        // Simply forward the call - panics will propagate through the future
        // In a Tokio-based application, use tower_http::catch_panic::CatchPanicLayer
        // which uses tokio::runtime::Handle to properly catch panics.
        Box::pin(self.inner.call(req))
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_panic_recovery_layer_creation() {
        let _ = PanicRecoveryLayer;
    }
}