Last active
September 6, 2020 11:03
-
-
Save rhzs/9c9cff8a8bed07c927e2a5a8df6c36e4 to your computer and use it in GitHub Desktop.
Actix User Middleware with lifetime
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use actix_http::Error; | |
use actix_service::ServiceFactory; | |
use actix_web::{dev, web, App}; | |
use sqlx::{AnyPool}; | |
pub fn create_app( | |
data: &Data, | |
) -> App< | |
impl ServiceFactory< | |
Config = (), | |
Request = dev::ServiceRequest, | |
Response = dev::ServiceResponse<actix_http::body::Body>, | |
Error = Error, | |
InitError = (), | |
>, | |
actix_http::body::Body, | |
> { | |
let db_pool = AnyPool::connect("postgres://[email protected]:5432/telemed-test"); | |
let pool = web::Data::new(db_pool); | |
App::new() | |
.app_data(pool.clone()) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::pin::Pin; | |
use std::task::{Context, Poll}; | |
use actix_service::{Service, Transform}; | |
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, web, Error}; | |
use futures::future::{ok, Ready}; | |
use futures::{Future, TryFutureExt}; | |
use crate::error::ResponseError; | |
use actix_web::web::Query; | |
use sqlx::AnyPool; | |
use std::cell::RefCell; | |
use std::rc::Rc; | |
#[derive(Clone)] | |
pub enum User { | |
Internal, | |
Public, | |
} | |
impl<S: 'static, B> Transform<S> for User | |
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 Transform = UserMiddleware<S>; | |
type InitError = (); | |
type Future = Ready<Result<Self::Transform, Self::InitError>>; | |
fn new_transform(&self, service: S) -> Self::Future { | |
ok(UserMiddleware { | |
service: Rc::new(RefCell::new(service)), | |
}) | |
} | |
} | |
pub struct UserMiddleware<S> { | |
service: Rc<RefCell<S>>, | |
} | |
impl<S, B> Service for UserMiddleware<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 pool: Option<&web::Data<AnyPool>> = req.app_data(); // COMPILE ERROR: --- borrow of `req` occurs here | |
if pool.is_none() { | |
return Box::pin(async { | |
Err(ResponseError::from(crate::error::Error::Internal( | |
"invalid database pool connection".to_string(), | |
)) | |
.into()) | |
}); | |
} | |
let pool = pool.unwrap(); | |
let user = User::find_by_auth_token(pool, "my user token"); // COMPILE ERROR, due to `req` usage in line 61. | |
let mut svc = self.service.clone(); | |
Box::pin(async move { | |
let res = svc.call(req).await?; | |
Ok(res) | |
}) // This line: COMPILE ERROR: | |
// borrow might be used here, when `user` is dropped and runs the destructor for type `impl futures::Future` | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment