From 6bdf1afe9c91749a9feafddcdd04cf869d648f54 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Fri, 8 Nov 2024 17:26:44 +0100 Subject: [PATCH] controllers/user/update: Reduce `spawn_blocking()` scope The email sending code is still sync and needs to be in a `spawn_blocking()` block for now, but the rest of the `regenerate_token_and_send()` can be converted to use async database queries. --- src/controllers/user/resend.rs | 52 +++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/src/controllers/user/resend.rs b/src/controllers/user/resend.rs index 05529073aaf..7d3108eefb8 100644 --- a/src/controllers/user/resend.rs +++ b/src/controllers/user/resend.rs @@ -4,14 +4,15 @@ use crate::auth::AuthCheck; use crate::controllers::helpers::ok_true; use crate::models::Email; use crate::tasks::spawn_blocking; -use crate::util::errors::bad_request; use crate::util::errors::AppResult; +use crate::util::errors::{bad_request, BoxedAppError}; use axum::extract::Path; use axum::response::Response; use crates_io_database::schema::emails; use diesel::dsl::sql; use diesel::prelude::*; -use diesel_async::async_connection_wrapper::AsyncConnectionWrapper; +use diesel_async::scoped_futures::ScopedFutureExt; +use diesel_async::{AsyncConnection, RunQueryDsl}; use http::request::Parts; /// Handles `PUT /user/:user_id/resend` route @@ -22,35 +23,40 @@ pub async fn regenerate_token_and_send( ) -> AppResult { let mut conn = state.db_write().await?; let auth = AuthCheck::default().check(&req, &mut conn).await?; - spawn_blocking(move || { - let conn: &mut AsyncConnectionWrapper<_> = &mut conn.into(); - let user = auth.user(); - - // need to check if current user matches user to be updated - if user.id != param_user_id { - return Err(bad_request("current user does not match requested user")); - } + // need to check if current user matches user to be updated + if auth.user_id() != param_user_id { + return Err(bad_request("current user does not match requested user")); + } - conn.transaction(|conn| -> AppResult<_> { - let email: Email = diesel::update(Email::belonging_to(user)) + conn.transaction(|conn| { + async move { + let email: Email = diesel::update(Email::belonging_to(auth.user())) .set(emails::token.eq(sql("DEFAULT"))) .get_result(conn) + .await .optional()? .ok_or_else(|| bad_request("Email could not be found"))?; - let email1 = UserConfirmEmail { - user_name: &user.gh_login, - domain: &state.emails.domain, - token: email.token, - }; - - state.emails.send(&email.email, email1).map_err(Into::into) - })?; - - ok_true() + spawn_blocking(move || { + let email1 = UserConfirmEmail { + user_name: &auth.user().gh_login, + domain: &state.emails.domain, + token: email.token, + }; + + state + .emails + .send(&email.email, email1) + .map_err(BoxedAppError::from) + }) + .await + } + .scope_boxed() }) - .await + .await?; + + ok_true() } #[cfg(test)]