phonograph/interim-server/src/app_state.rs

84 lines
2.2 KiB
Rust
Raw Normal View History

2025-05-02 23:48:54 -07:00
use std::sync::Arc;
use anyhow::Result;
use axum::{
extract::{FromRef, FromRequestParts},
http::request::Parts,
};
2025-08-04 13:59:42 -07:00
use interim_models::client::AppDbClient;
2025-05-02 23:48:54 -07:00
use oauth2::basic::BasicClient;
2025-08-04 13:59:42 -07:00
use sqlx::postgres::PgPoolOptions;
2025-05-02 23:48:54 -07:00
2025-05-26 22:08:21 -07:00
use crate::{
app_error::AppError, auth, base_pooler::BasePooler, sessions::PgStore, settings::Settings,
};
2025-05-02 23:48:54 -07:00
/// Global app configuration
pub struct App {
2025-05-26 22:08:21 -07:00
pub app_db: sqlx::PgPool,
pub base_pooler: BasePooler,
2025-05-02 23:48:54 -07:00
pub oauth_client: BasicClient,
pub reqwest_client: reqwest::Client,
pub session_store: PgStore,
pub settings: Settings,
}
impl App {
/// Initialize global application functions based on config values
pub async fn from_settings(settings: Settings) -> Result<Self> {
2025-05-26 22:08:21 -07:00
let app_db = PgPoolOptions::new()
.max_connections(settings.app_db_max_connections)
.connect(&settings.database_url)
.await?;
2025-05-02 23:48:54 -07:00
2025-05-26 22:08:21 -07:00
let session_store = PgStore::new(app_db.clone());
2025-05-02 23:48:54 -07:00
let reqwest_client = reqwest::ClientBuilder::new().https_only(true).build()?;
let oauth_client = auth::new_oauth_client(&settings)?;
2025-05-26 22:08:21 -07:00
let base_pooler = BasePooler::new_with_app_db(app_db.clone());
2025-05-02 23:48:54 -07:00
Ok(Self {
2025-05-26 22:08:21 -07:00
app_db,
base_pooler,
2025-05-02 23:48:54 -07:00
oauth_client,
reqwest_client,
session_store,
settings,
})
}
}
/// Global app configuration, arced for relatively inexpensive clones
pub type AppState = Arc<App>;
/// State extractor for shared reqwest client
#[derive(Clone)]
pub struct ReqwestClient(pub reqwest::Client);
impl<S> FromRef<S> for ReqwestClient
where
S: Into<AppState> + Clone,
{
fn from_ref(state: &S) -> Self {
ReqwestClient(Into::<AppState>::into(state.clone()).reqwest_client.clone())
}
}
2025-05-13 00:02:33 -07:00
/// Extractor to automatically obtain a Deadpool Diesel connection
2025-08-04 13:59:42 -07:00
pub struct AppDbConn(pub AppDbClient);
2025-05-13 00:02:33 -07:00
2025-05-26 22:08:21 -07:00
impl<S> FromRequestParts<S> for AppDbConn
2025-05-13 00:02:33 -07:00
where
S: Into<AppState> + Clone + Sync,
{
type Rejection = AppError;
async fn from_request_parts(_: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
let conn = Into::<AppState>::into(state.clone())
2025-05-26 22:08:21 -07:00
.app_db
.acquire()
2025-05-13 00:02:33 -07:00
.await?;
2025-08-04 13:59:42 -07:00
Ok(Self(AppDbClient::from_pool_conn(conn)))
2025-05-13 00:02:33 -07:00
}
}