1
0
mirror of https://github.com/actix/examples synced 2025-01-23 14:24:35 +01:00
examples/basics/middleware/src/read_response_body.rs

125 lines
3.2 KiB
Rust
Raw Normal View History

2019-12-07 23:59:24 +06:00
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use std::task::{Context, Poll};
use actix_service::{Service, Transform};
use actix_web::body::{BodySize, MessageBody, ResponseBody};
2020-09-12 16:49:45 +01:00
use actix_web::web::{Bytes, BytesMut};
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error};
2019-12-07 23:59:24 +06:00
use futures::future::{ok, Ready};
pub struct Logging;
impl<S: 'static, B> Transform<S> for Logging
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
B: MessageBody + 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse<BodyLogger<B>>;
type Error = Error;
type InitError = ();
type Transform = LoggingMiddleware<S>;
2019-12-07 23:59:24 +06:00
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
2019-12-07 23:59:24 +06:00
ok(LoggingMiddleware { service })
}
}
pub struct LoggingMiddleware<S> {
service: S,
}
impl<S, B> Service for LoggingMiddleware<S>
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
B: MessageBody,
{
type Request = ServiceRequest;
type Response = ServiceResponse<BodyLogger<B>>;
type Error = Error;
type Future = WrapperStream<S, B>;
2019-12-07 23:59:24 +06:00
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
fn call(&mut self, req: ServiceRequest) -> Self::Future {
WrapperStream {
fut: self.service.call(req),
_t: PhantomData,
}
}
}
2019-12-07 23:59:24 +06:00
#[pin_project::pin_project]
pub struct WrapperStream<S, B>
where
B: MessageBody,
S: Service,
{
2019-12-07 23:59:24 +06:00
#[pin]
fut: S::Future,
_t: PhantomData<(B,)>,
}
impl<S, B> Future for WrapperStream<S, B>
where
B: MessageBody,
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
{
2019-12-07 23:59:24 +06:00
type Output = Result<ServiceResponse<BodyLogger<B>>, Error>;
2019-12-07 23:59:24 +06:00
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let res = futures::ready!(self.project().fut.poll(cx));
2019-12-07 23:59:24 +06:00
Poll::Ready(res.map(|res| {
res.map_body(move |_, body| {
ResponseBody::Body(BodyLogger {
body,
body_accum: BytesMut::new(),
})
})
2019-12-07 23:59:24 +06:00
}))
}
}
2020-09-12 16:49:45 +01:00
#[pin_project::pin_project(PinnedDrop)]
pub struct BodyLogger<B> {
2020-09-12 16:49:45 +01:00
#[pin]
body: ResponseBody<B>,
body_accum: BytesMut,
}
2020-09-12 16:49:45 +01:00
#[pin_project::pinned_drop]
impl<B> PinnedDrop for BodyLogger<B> {
fn drop(self: Pin<&mut Self>) {
println!("response body: {:?}", self.body_accum);
}
}
impl<B: MessageBody> MessageBody for BodyLogger<B> {
fn size(&self) -> BodySize {
self.body.size()
}
2020-09-12 16:49:45 +01:00
fn poll_next(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Result<Bytes, Error>>> {
let this = self.project();
match this.body.poll_next(cx) {
2019-12-07 23:59:24 +06:00
Poll::Ready(Some(Ok(chunk))) => {
2020-09-12 16:49:45 +01:00
this.body_accum.extend_from_slice(&chunk);
2019-12-07 23:59:24 +06:00
Poll::Ready(Some(Ok(chunk)))
}
2019-12-07 23:59:24 +06:00
Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e))),
Poll::Ready(None) => Poll::Ready(None),
Poll::Pending => Poll::Pending,
}
}
}