Files
Genarrative/server-rs/crates/api-server/src/state.rs

132 lines
3.9 KiB
Rust

use std::{error::Error, fmt};
use module_auth::{InMemoryPasswordUserStore, PasswordEntryService};
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<OssClient>,
password_entry_service: PasswordEntryService,
}
#[derive(Debug)]
pub enum AppStateInitError {
Jwt(JwtError),
RefreshCookie(RefreshCookieError),
Oss(OssError),
}
impl AppState {
pub fn new(config: AppConfig) -> Result<Self, AppStateInitError> {
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)?;
let password_entry_service =
PasswordEntryService::new(InMemoryPasswordUserStore::default());
Ok(Self {
config,
auth_jwt_config,
refresh_cookie_config,
oss_client,
password_entry_service,
})
}
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()
}
pub fn password_entry_service(&self) -> &PasswordEntryService {
&self.password_entry_service
}
}
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<JwtError> for AppStateInitError {
fn from(value: JwtError) -> Self {
Self::Jwt(value)
}
}
impl From<RefreshCookieError> for AppStateInitError {
fn from(value: RefreshCookieError) -> Self {
Self::RefreshCookie(value)
}
}
impl From<OssError> for AppStateInitError {
fn from(value: OssError) -> Self {
Self::Oss(value)
}
}
fn build_oss_client(config: &AppConfig) -> Result<Option<OssClient>, 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)))
}