Skip to main content

Module callback

Module callback 

Source
Expand description

Middleware for observing both the request and response streams of a tower::Service via user-provided callback handlers.

A MakeCallbackHandler produces a pair of handlers per request: a RequestHandler (invoked as the request body is polled by the inner service) and a ResponseHandler (invoked when the response materializes and as its body is polled by the caller). The inner service’s request body is wrapped as a RequestBody, and the response body handed back to the caller is wrapped as a ResponseBody; both carry their respective handler along with the data.

Either side can be a no-op by using the unit type (), which has a blanket RequestHandler impl provided by this crate.

§Example

use http::request;
use http::response;
use sui_http::middleware::callback::CallbackLayer;
use sui_http::middleware::callback::MakeCallbackHandler;
use sui_http::middleware::callback::RequestHandler;
use sui_http::middleware::callback::ResponseHandler;

/// A handler that counts bytes observed on one side of the exchange.
#[derive(Default)]
struct ByteCounter {
    bytes: usize,
}

impl RequestHandler for ByteCounter {
    fn on_body_chunk<B: bytes::Buf>(&mut self, chunk: &B) {
        self.bytes += chunk.remaining();
    }
}

impl ResponseHandler for ByteCounter {
    fn on_response(&mut self, _parts: &response::Parts) {}
    fn on_service_error<E: std::fmt::Display + 'static>(&mut self, _error: &E) {}
    fn on_body_chunk<B: bytes::Buf>(&mut self, chunk: &B) {
        self.bytes += chunk.remaining();
    }
}

#[derive(Clone)]
struct MakeByteCounter;

impl MakeCallbackHandler for MakeByteCounter {
    type RequestHandler = ByteCounter;
    type ResponseHandler = ByteCounter;

    fn make_handler(
        &self,
        _request: &request::Parts,
    ) -> (Self::RequestHandler, Self::ResponseHandler) {
        (ByteCounter::default(), ByteCounter::default())
    }
}

let _layer = CallbackLayer::new(MakeByteCounter);

§Body type change

The wrapped Callback service hands the inner service a Request<RequestBody<B, M::RequestHandler>> rather than the original Request<B>. For body-polymorphic inner services (e.g. axum::Router or generic tower services), this is transparent.

Monomorphic inner services that require a specific body type — for example tonic::transport::Channel, which expects tonic::body::Body — must rebox the wrapped body at the call site:

let service = tower::ServiceBuilder::new()
    .layer(CallbackLayer::new(MakeByteCounter))
    .map_request(|req: tonic::Request<_>| req.map(tonic::body::Body::new))
    .service(tonic_service);

Structs§

Callback
Middleware that adds callbacks to a Service.
CallbackLayer
Layer that adds callbacks to a Service.
RequestBody
Request body wrapper for Callback.
ResponseBody
Response body wrapper for Callback.
ResponseFuture
Response future for Callback.

Traits§

MakeCallbackHandler
Factory for per-request callback handler pairs.
RequestHandler
Observes the request body as it is polled by the inner service.
ResponseHandler
Observes the response as seen by the caller: the response parts, the response body, and the service-level error that occurs if the inner service’s future resolves to Err before any response is produced.