use std::{error::Error, fmt}; use platform_auth::{ JwtConfig, JwtError, RefreshCookieConfig, RefreshCookieError, RefreshCookieSameSite, }; use platform_oss::{OssClient, OssConfig, OssError}; use crate::config::AppConfig; // 当前阶段先保留最小共享状态壳,后续逐步接入配置、客户端与平台适配。 #[derive(Clone, Debug)] pub struct AppState { // 配置会在后续中间件、路由和平台适配接入时逐步消费。 #[allow(dead_code)] pub config: AppConfig, auth_jwt_config: JwtConfig, refresh_cookie_config: RefreshCookieConfig, oss_client: Option, } #[derive(Debug)] pub enum AppStateInitError { Jwt(JwtError), RefreshCookie(RefreshCookieError), Oss(OssError), } impl AppState { pub fn new(config: AppConfig) -> Result { let auth_jwt_config = JwtConfig::new( config.jwt_issuer.clone(), config.jwt_secret.clone(), config.jwt_access_token_ttl_seconds, )?; let refresh_cookie_same_site = RefreshCookieSameSite::parse(&config.refresh_cookie_same_site).ok_or( RefreshCookieError::InvalidConfig("refresh cookie SameSite 取值非法"), )?; let refresh_cookie_config = RefreshCookieConfig::new( config.refresh_cookie_name.clone(), config.refresh_cookie_path.clone(), config.refresh_cookie_secure, refresh_cookie_same_site, config.refresh_session_ttl_days, )?; let oss_client = build_oss_client(&config)?; Ok(Self { config, auth_jwt_config, refresh_cookie_config, oss_client, }) } pub fn auth_jwt_config(&self) -> &JwtConfig { &self.auth_jwt_config } pub fn refresh_cookie_config(&self) -> &RefreshCookieConfig { &self.refresh_cookie_config } pub fn oss_client(&self) -> Option<&OssClient> { self.oss_client.as_ref() } } impl fmt::Display for AppStateInitError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Jwt(error) => write!(f, "{error}"), Self::RefreshCookie(error) => write!(f, "{error}"), Self::Oss(error) => write!(f, "{error}"), } } } impl Error for AppStateInitError {} impl From for AppStateInitError { fn from(value: JwtError) -> Self { Self::Jwt(value) } } impl From for AppStateInitError { fn from(value: RefreshCookieError) -> Self { Self::RefreshCookie(value) } } impl From for AppStateInitError { fn from(value: OssError) -> Self { Self::Oss(value) } } fn build_oss_client(config: &AppConfig) -> Result, AppStateInitError> { let has_any_oss_field = config.oss_bucket.is_some() || config.oss_endpoint.is_some() || config.oss_access_key_id.is_some() || config.oss_access_key_secret.is_some() || config.oss_public_base_url.is_some(); if !has_any_oss_field { return Ok(None); } let oss_config = OssConfig::new( config.oss_bucket.clone().unwrap_or_default(), config.oss_endpoint.clone().unwrap_or_default(), config.oss_access_key_id.clone().unwrap_or_default(), config.oss_access_key_secret.clone().unwrap_or_default(), config.oss_public_base_url.clone(), config.oss_post_expire_seconds, config.oss_post_max_size_bytes, config.oss_success_action_status, )?; Ok(Some(OssClient::new(oss_config))) }