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. - Callback
Layer Layerthat adds callbacks to aService.- Request
Body - Request body wrapper for
Callback. - Response
Body - Response body wrapper for
Callback. - Response
Future - Response future for
Callback.
Traits§
- Make
Callback Handler - Factory for per-request callback handler pairs.
- Request
Handler - Observes the request body as it is polled by the inner service.
- Response
Handler - 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
Errbefore any response is produced.