迁移后端认证与拆分 Spacetime 客户端
This commit is contained in:
@@ -21,6 +21,7 @@ use platform_oss::{OssClient, OssConfig, OssError};
|
||||
use serde_json::Value;
|
||||
use spacetime_client::{SpacetimeClient, SpacetimeClientConfig, SpacetimeClientError};
|
||||
use time::OffsetDateTime;
|
||||
use tracing::{info, warn};
|
||||
|
||||
use crate::config::AppConfig;
|
||||
use crate::wechat_provider::{WechatProvider, build_wechat_provider};
|
||||
@@ -37,6 +38,7 @@ pub struct AppState {
|
||||
admin_runtime: Option<AdminRuntime>,
|
||||
refresh_cookie_config: RefreshCookieConfig,
|
||||
oss_client: Option<OssClient>,
|
||||
auth_store: InMemoryAuthStore,
|
||||
password_entry_service: PasswordEntryService,
|
||||
refresh_session_service: RefreshSessionService,
|
||||
auth_user_service: AuthUserService,
|
||||
@@ -86,6 +88,7 @@ pub struct AdminSession {
|
||||
pub enum AppStateInitError {
|
||||
Jwt(JwtError),
|
||||
RefreshCookie(RefreshCookieError),
|
||||
AuthStore(String),
|
||||
SmsProvider(SmsProviderError),
|
||||
Oss(OssError),
|
||||
Llm(LlmError),
|
||||
@@ -93,6 +96,15 @@ pub enum AppStateInitError {
|
||||
|
||||
impl AppState {
|
||||
pub fn new(config: AppConfig) -> Result<Self, AppStateInitError> {
|
||||
let auth_store = InMemoryAuthStore::from_persistence_path(config.auth_store_path.clone())
|
||||
.map_err(AppStateInitError::AuthStore)?;
|
||||
Self::new_with_auth_store(config, auth_store)
|
||||
}
|
||||
|
||||
fn new_with_auth_store(
|
||||
config: AppConfig,
|
||||
auth_store: InMemoryAuthStore,
|
||||
) -> Result<Self, AppStateInitError> {
|
||||
let auth_jwt_config = JwtConfig::new(
|
||||
config.jwt_issuer.clone(),
|
||||
config.jwt_secret.clone(),
|
||||
@@ -111,7 +123,6 @@ impl AppState {
|
||||
config.refresh_session_ttl_days,
|
||||
)?;
|
||||
let oss_client = build_oss_client(&config)?;
|
||||
let auth_store = InMemoryAuthStore::default();
|
||||
let sms_provider = SmsAuthProvider::new(SmsAuthConfig::new(
|
||||
SmsAuthProviderKind::parse(&config.sms_auth_provider).ok_or_else(|| {
|
||||
SmsProviderError::InvalidConfig("短信 provider 配置非法".to_string())
|
||||
@@ -141,7 +152,7 @@ impl AppState {
|
||||
let wechat_auth_service = WechatAuthService::new(auth_store.clone());
|
||||
let wechat_provider = build_wechat_provider(&config);
|
||||
let refresh_session_service =
|
||||
RefreshSessionService::new(auth_store, config.refresh_session_ttl_days);
|
||||
RefreshSessionService::new(auth_store.clone(), config.refresh_session_ttl_days);
|
||||
// AI 编排服务当前先挂接内存态 store,后续再按 task table / procedure 接到 SpacetimeDB 真相源。
|
||||
let ai_task_service = AiTaskService::new(InMemoryAiTaskStore::default());
|
||||
let spacetime_client = SpacetimeClient::new(SpacetimeClientConfig {
|
||||
@@ -158,6 +169,7 @@ impl AppState {
|
||||
admin_runtime,
|
||||
refresh_cookie_config,
|
||||
oss_client,
|
||||
auth_store,
|
||||
password_entry_service,
|
||||
refresh_session_service,
|
||||
auth_user_service,
|
||||
@@ -193,6 +205,49 @@ impl AppState {
|
||||
&self.password_entry_service
|
||||
}
|
||||
|
||||
pub async fn sync_auth_store_snapshot_to_spacetime(&self) -> Result<(), SpacetimeClientError> {
|
||||
let snapshot_json = self
|
||||
.auth_store
|
||||
.export_snapshot_json()
|
||||
.map_err(SpacetimeClientError::Runtime)?;
|
||||
let updated_at_micros = i64::try_from(
|
||||
OffsetDateTime::now_utc().unix_timestamp_nanos() / 1_000,
|
||||
)
|
||||
.map_err(|_| SpacetimeClientError::Runtime("认证快照更新时间超出 i64 范围".to_string()))?;
|
||||
self.spacetime_client
|
||||
.upsert_auth_store_snapshot(snapshot_json, updated_at_micros)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn try_restore_auth_store_from_spacetime(
|
||||
config: AppConfig,
|
||||
) -> Result<Self, AppStateInitError> {
|
||||
let spacetime_client = SpacetimeClient::new(SpacetimeClientConfig {
|
||||
server_url: config.spacetime_server_url.clone(),
|
||||
database: config.spacetime_database.clone(),
|
||||
token: config.spacetime_token.clone(),
|
||||
pool_size: config.spacetime_pool_size,
|
||||
});
|
||||
match spacetime_client.get_auth_store_snapshot().await {
|
||||
Ok(snapshot) => {
|
||||
if let Some(snapshot_json) = snapshot.snapshot_json {
|
||||
if !snapshot_json.trim().is_empty() {
|
||||
let auth_store = InMemoryAuthStore::from_snapshot_json(&snapshot_json)
|
||||
.map_err(AppStateInitError::AuthStore)?;
|
||||
info!("已从 SpacetimeDB 恢复认证快照");
|
||||
return Self::new_with_auth_store(config, auth_store);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(error) => {
|
||||
warn!(error = %error, "从 SpacetimeDB 恢复认证快照失败,回退到本地快照");
|
||||
}
|
||||
}
|
||||
|
||||
Self::new(config)
|
||||
}
|
||||
|
||||
pub fn refresh_session_service(&self) -> &RefreshSessionService {
|
||||
&self.refresh_session_service
|
||||
}
|
||||
@@ -392,6 +447,7 @@ impl fmt::Display for AppStateInitError {
|
||||
match self {
|
||||
Self::Jwt(error) => write!(f, "{error}"),
|
||||
Self::RefreshCookie(error) => write!(f, "{error}"),
|
||||
Self::AuthStore(error) => write!(f, "{error}"),
|
||||
Self::SmsProvider(error) => write!(f, "{error}"),
|
||||
Self::Oss(error) => write!(f, "{error}"),
|
||||
Self::Llm(error) => write!(f, "{error}"),
|
||||
|
||||
Reference in New Issue
Block a user