0

我初始化了一个 Mutex< Pool<Postgres>>实例并将其传递给实例上的管理方法Rocket,以便访问我的控制器上的数据库。我通常做的是:

// this is purely for example
#[get("/foo/bar")]
pub async fn controller<'a>(
    // ... others ...
    db_pool: &State<Mutex<PgPool>>,
    // ... others ...
) {
    // ... do other things ...
    let query_r = sqlx::query("SELECT * FROM users WHERE id=$1")
        .bind(&id)
        .fetch_optional(&mut db_pool.inner().lock().await.acquire().await.unwrap()) // i reach `inner` of state, then `lock` the mutex, lastly `acquire` a pool connection
        .await; // type is Result<Option<PgRow>> i suppose, rust-analyzer is not very good at inferring it
    // ... do other things ...
}

这很酷,但这是我的问题:我写了一个结构如下......

pub struct User {
    id: usize,
    username: String,
    email: String,
}

...而且我实际上想将它用作请求保护,以便客户端在没有提供正确凭据的情况下无法访问控制器。

Rocket 的官方指南告诉实现FromRequest特征,以便可以将其解析为警卫。

但是,为了初始化一个User实例,我需要在这个FromRequest特征中获取一个PoolConnection。我已经深入研究了 Rocket 的 API 文档,似乎FromRequest 上的请求参数有一个名为 Rocket 的方法它返回一个实例,并且通过它,我可以访问 stateRocket<Orbit>

但是,问题是state方法返回&Mutex<Pool<Postgres>>,这是一个不可变的引用,所以我不能用它对数据库做任何操作。

我已经走了这么远,想问是否有人知道Mutex<Pool<Postgres>>无需参考即可访问的方法。

提前致谢。

我走了多远

下面是我如何实现FromRequest

pub struct User {
    id: usize,
    username: String,
    email: String,
}

#[derive(Debug)]
pub enum UserError {
    TokenError(TokenError),
    MissingToken,
    DatabasePoolError,
}

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

    async fn from_request(request: &'r rocket::Request<'_>) -> request::Outcome<Self, Self::Error> {
        let encrypted_token_o = request.headers().get_one("Authorization");

        match encrypted_token_o {
            Some(encrypted_token) => {
                let claims_r = Claims::try_from(encrypted_token.to_owned());

                match claims_r {
                    Ok(claims) => {
                        let db_pool_o = request.rocket().state::<Mutex<PgPool>>();

                        match db_pool_o {
                            Some(db_pool) => {
                                let id = 0; // a test id
                                let query_r = sqlx::query(
                                    "SELECT id, username, email FROM users WHERE id=$1",
                                )
                                .bind(&id)
                                .fetch_optional(
                                    // ERROR: no method named `inner` found for reference `&rocket::futures::lock::Mutex<Pool<Postgres>>` in the current scope
                                    &mut db_pool.inner().lock().await.acquire().await.unwrap(),
                                )
                                .await;
                                todo!()
                            }
                            None => request::Outcome::Failure((
                                http::Status::InternalServerError,
                                UserError::DatabasePoolError,
                            )),
                        }
                    }
                    Err(e) => request::Outcome::Failure((
                        http::Status::InternalServerError,
                        UserError::TokenError(e),
                    )),
                }
            }
            None => request::Outcome::Failure((http::Status::BadRequest, UserError::MissingToken)),
        }
    }
}

环境

  • 锈病 1.55.0
  • 火箭 0.5.0-rc.1 具有功能defaultjson
  • sqlx 0.5.7 的特性runtime-tokio-native-tls,all-typespostgresmigrate
4

0 回答 0