How to get a redis instance in a guard

49 views Asked by At

I need to get the managed redis client to create/check jwt tokens for an authentication middleware, but I am getting an error:

the trait bound `rocket::State<RedisRepo>: FromRequest<'_>` is not satisfied
the trait `FromRequest<'r>` is implemented for `&'r rocket::State<T>

first, I created a RedisRepo:

use std::env;
extern crate dotenv;
use dotenv::dotenv;
use rocket::{
    http::Status,
    request::{FromRequest, Outcome, Request},
};

use crate::error::common::CommonError;

extern crate redis;

pub fn create_redis_connection() -> redis::Client {
    dotenv().ok();

    let uri = match env::var("REDIS_URL") {
        Ok(v) => v.to_string(),
        Err(_) => format!("Error loading env variable"),
    };

    let client = redis::Client::open(uri);

    return client.ok().unwrap();
}

pub struct RedisRepo {
    pub client: redis::Client,
}

impl RedisRepo {
    pub fn init() -> Self {
        let client = create_redis_connection();

        RedisRepo { client }
    }
}

#[rocket::async_trait]
impl<'r> FromRequest<'r> for RedisRepo {
    type Error = CommonError;

    async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error> {
        let state = req.rocket().state::<RedisRepo>();

        if state.is_none() {
            return Outcome::Failure((
                Status::InternalServerError,
                CommonError {
                    description: "unable to get redis database".to_string(),
                },
            ));
        }

        Outcome::Success(*state.unwrap())
    }
}

then I added an authentication middleware:

use rocket::request::{self, FromRequest, Request};

use crate::{error::response::RequestError, repository::redis_repos::RedisRepo};

pub struct AuthContext {
    pub user_id: String,
}

#[rocket::async_trait]
impl<'r> FromRequest<'r> for AuthContext {
    type Error = RequestError;

    async fn from_request(req: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
        // get redis client
        let cache = req.guard::<rocket::State<RedisRepo>>().await;
        //              ^ error here : the trait bound `rocket::State<RedisRepo>:
        //              FromRequest<'_>` is not satisfied the trait `FromRequest<'r>` 
        //              is implemented for `&'r rocket::State<T>

        // TODO: get token from header

        // TODO: verify token

        // TODO: get user and check existing

        // TODO: get time and check that is not expiring

        request::Outcome::Success(AuthContext {
            // TODO: add user id
            user_id: "".to_string(),
        })
    }
}

and here is main.rs:

mod api;
mod controller;
mod error;
mod helpers;
mod middleware;
mod models;
mod repository;

#[macro_use]
extern crate rocket;

use api::{
    text_annotation_api::create_text_annotation,
    user_api::{create_user, get_user, update_user},
};
use repository::{mongodb_repos::MongoRepo, redis_repos::RedisRepo};

#[launch]
fn rocket() -> _ {
    let db = MongoRepo::init();
    let cache = RedisRepo::init();

    rocket::build()
        .manage(db)
        .manage(cache)
        .mount("/", routes![create_user, get_user, update_user])
}
0

There are 0 answers