Skip to content

Instantly share code, notes, and snippets.

@rhzs
Last active September 6, 2020 11:03
Show Gist options
  • Save rhzs/9c9cff8a8bed07c927e2a5a8df6c36e4 to your computer and use it in GitHub Desktop.
Save rhzs/9c9cff8a8bed07c927e2a5a8df6c36e4 to your computer and use it in GitHub Desktop.
Actix User Middleware with lifetime
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://postgres@127.0.0.1:5432/telemed-test");
let pool = web::Data::new(db_pool);
App::new()
.app_data(pool.clone())
}
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