use std::str::FromStr; use anyhow::bail; use axum::extract::FromRef; use base64::{engine, alphabet, Engine}; use ed25519_dalek::VerifyingKey; use sqlx::PgPool; use twilight_model::id::{marker::ApplicationMarker, Id}; pub mod database; pub mod discord; #[derive(Clone)] pub struct Config { pub discord_client_id: Id, discord_client_secret: String, discord_pub_key: VerifyingKey, pub database_url: String, pub listen_port: u16, } impl Config { pub fn configure() -> anyhow::Result { dotenvy::dotenv().ok(); let pub_key_bytes: Vec = hex::decode(std::env::var("DISCORD_PUB_KEY")?)?; let pub_key: [u8; 32] = match pub_key_bytes.try_into() { Ok(pk) => pk, Err(_) => bail!("Invalid discord public key"), }; Ok(Config { discord_client_id: Id::from_str(std::env::var("DISCORD_CLIENT_ID")?.as_str())?, discord_client_secret: std::env::var("DISCORD_CLIENT_SECRET")?, discord_pub_key: VerifyingKey::from_bytes(&pub_key)?, database_url: std::env::var("DATABASE_URL")?, listen_port: std::env::var("LISTEN_PORT")?.parse()?, }) } pub fn authorization(&self) -> String { let engine = engine::GeneralPurpose::new(&alphabet::STANDARD, engine::general_purpose::PAD); let auth = format!("{}:{}", self.discord_client_id, self.discord_client_secret); engine.encode(auth) } } #[derive(Clone)] pub struct AppState { pub config: Config, pub pg_pool: PgPool, } impl FromRef for PgPool { fn from_ref(app_state: &AppState) -> Self { app_state.pg_pool.clone() } } impl FromRef for VerifyingKey { fn from_ref(app_state: &AppState) -> Self { app_state.config.discord_pub_key } }