1
0
mirror of https://github.com/actix/examples synced 2025-06-28 18:00:37 +02:00

Restructure folders (#411)

This commit is contained in:
Daniel T. Rodrigues
2021-02-25 21:57:58 -03:00
committed by GitHub
parent 9db98162b2
commit c3407627d0
334 changed files with 127 additions and 120 deletions

View File

@ -0,0 +1,45 @@
#![allow(clippy::type_complexity)]
use actix_service::Service;
use actix_web::{web, App, HttpServer};
use futures::future::FutureExt;
#[allow(dead_code)]
mod read_request_body;
#[allow(dead_code)]
mod read_response_body;
#[allow(dead_code)]
mod redirect;
#[allow(dead_code)]
mod simple;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
std::env::set_var("RUST_LOG", "actix_web=debug");
env_logger::init();
HttpServer::new(|| {
App::new()
.wrap(redirect::CheckLogin)
.wrap(read_request_body::Logging)
.wrap(read_response_body::Logging)
.wrap(simple::SayHi)
.wrap_fn(|req, srv| {
println!("Hi from start. You requested: {}", req.path());
srv.call(req).map(|res| {
println!("Hi from response");
res
})
})
.service(web::resource("/login").to(|| async {
"You are on /login. Go to src/redirect.rs to change this behavior."
}))
.service(web::resource("/").to(|| async {
"Hello, middleware! Check the console where the server is run."
}))
})
.bind("127.0.0.1:8080")?
.run()
.await
}

View File

@ -0,0 +1,72 @@
use std::cell::RefCell;
use std::pin::Pin;
use std::rc::Rc;
use std::task::{Context, Poll};
use actix_service::{Service, Transform};
use actix_web::web::BytesMut;
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error, HttpMessage};
use futures::future::{ok, Future, Ready};
use futures::stream::StreamExt;
pub struct Logging;
impl<S: 'static, B> Transform<S> for Logging
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = Error;
type InitError = ();
type Transform = LoggingMiddleware<S>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ok(LoggingMiddleware {
service: Rc::new(RefCell::new(service)),
})
}
}
pub struct LoggingMiddleware<S> {
// This is special: We need this to avoid lifetime issues.
service: Rc<RefCell<S>>,
}
impl<S, B> Service for LoggingMiddleware<S>
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>
+ 'static,
S::Future: 'static,
B: 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = Error;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
fn call(&mut self, mut req: ServiceRequest) -> Self::Future {
let mut svc = self.service.clone();
Box::pin(async move {
let mut body = BytesMut::new();
let mut stream = req.take_payload();
while let Some(chunk) = stream.next().await {
body.extend_from_slice(&chunk?);
}
println!("request body: {:?}", body);
let res = svc.call(req).await?;
println!("response: {:?}", res.headers());
Ok(res)
})
}
}

View File

@ -0,0 +1,124 @@
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};
use actix_web::web::{Bytes, BytesMut};
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error};
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>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
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>;
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,
}
}
}
#[pin_project::pin_project]
pub struct WrapperStream<S, B>
where
B: MessageBody,
S: Service,
{
#[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>,
{
type Output = Result<ServiceResponse<BodyLogger<B>>, Error>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let res = futures::ready!(self.project().fut.poll(cx));
Poll::Ready(res.map(|res| {
res.map_body(move |_, body| {
ResponseBody::Body(BodyLogger {
body,
body_accum: BytesMut::new(),
})
})
}))
}
}
#[pin_project::pin_project(PinnedDrop)]
pub struct BodyLogger<B> {
#[pin]
body: ResponseBody<B>,
body_accum: BytesMut,
}
#[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()
}
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) {
Poll::Ready(Some(Ok(chunk))) => {
this.body_accum.extend_from_slice(&chunk);
Poll::Ready(Some(Ok(chunk)))
}
Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e))),
Poll::Ready(None) => Poll::Ready(None),
Poll::Pending => Poll::Pending,
}
}
}

View File

@ -0,0 +1,65 @@
use std::task::{Context, Poll};
use actix_service::{Service, Transform};
use actix_web::dev::{ServiceRequest, ServiceResponse};
use actix_web::{http, Error, HttpResponse};
use futures::future::{ok, Either, Ready};
pub struct CheckLogin;
impl<S, B> Transform<S> for CheckLogin
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = Error;
type InitError = ();
type Transform = CheckLoginMiddleware<S>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ok(CheckLoginMiddleware { service })
}
}
pub struct CheckLoginMiddleware<S> {
service: S,
}
impl<S, B> Service for CheckLoginMiddleware<S>
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = Error;
type Future = Either<S::Future, Ready<Result<Self::Response, Self::Error>>>;
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 {
// We only need to hook into the `start` for this middleware.
let is_logged_in = false; // Change this to see the change in outcome in the browser
if is_logged_in {
Either::Left(self.service.call(req))
} else {
// Don't forward to /login if we are already on /login
if req.path() == "/login" {
Either::Left(self.service.call(req))
} else {
Either::Right(ok(req.into_response(
HttpResponse::Found()
.header(http::header::LOCATION, "/login")
.finish()
.into_body(),
)))
}
}
}
}

View File

@ -0,0 +1,67 @@
use std::pin::Pin;
use std::task::{Context, Poll};
use actix_service::{Service, Transform};
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error};
use futures::future::{ok, Ready};
use futures::Future;
// There are two steps in middleware processing.
// 1. Middleware initialization, middleware factory gets called with
// next service in chain as parameter.
// 2. Middleware's call method gets called with normal request.
pub struct SayHi;
// Middleware factory is `Transform` trait from actix-service crate
// `S` - type of the next service
// `B` - type of response's body
impl<S, B> Transform<S> for SayHi
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = Error;
type InitError = ();
type Transform = SayHiMiddleware<S>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ok(SayHiMiddleware { service })
}
}
pub struct SayHiMiddleware<S> {
service: S,
}
impl<S, B> Service for SayHiMiddleware<S>
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = Error;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;
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 {
println!("Hi from start. You requested: {}", req.path());
let fut = self.service.call(req);
Box::pin(async move {
let res = fut.await?;
println!("Hi from response");
Ok(res)
})
}
}