refactor(backend): implement transaction mechanism and i18n errors for provider service
This commit completes phase 4 service layer extraction by introducing: 1. **Transaction mechanism with 2PC (Two-Phase Commit)**: - Introduced `run_transaction()` wrapper with snapshot-based rollback - Implemented `LiveSnapshot` enum to capture and restore live config files - Added `PostCommitAction` to separate config.json persistence from live file writes - Applied to critical operations: add, update, switch providers - Ensures atomicity: memory + config.json + live files stay consistent 2. **Internationalized error handling**: - Added `AppError::Localized` variant with key + zh + en messages - Implemented `AppError::localized()` helper function - Migrated 24 error sites to use i18n-ready errors - Enables frontend to display errors in user's preferred language 3. **Concurrency optimization**: - Fixed `get_custom_endpoints()` to use read lock instead of write lock - Ensured async IO operations (usage query) execute outside lock scope - Added defensive RAII lock management with explicit scope blocks 4. **Code organization improvements**: - Reduced commands/provider.rs from ~800 to ~320 lines (-60%) - Expanded services/provider.rs with transaction infrastructure - Added unit tests for validation and credential extraction - Documented legacy file cleanup logic with inline comments 5. **Backfill mechanism refinement**: - Ensured live config is synced back to memory before switching - Maintains SSOT (Single Source of Truth) architecture principle - Handles Codex dual-file (auth.json + config.toml) atomically Breaking changes: None (internal refactoring only) Performance: Improved read concurrency, no measurable overhead from snapshots Test coverage: Added validation tests, updated service layer tests
This commit is contained in:
@@ -46,6 +46,12 @@ pub enum AppError {
|
||||
McpValidation(String),
|
||||
#[error("{0}")]
|
||||
Message(String),
|
||||
#[error("{zh} ({en})")]
|
||||
Localized {
|
||||
key: &'static str,
|
||||
zh: String,
|
||||
en: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl AppError {
|
||||
@@ -69,6 +75,14 @@ impl AppError {
|
||||
source,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn localized(key: &'static str, zh: impl Into<String>, en: impl Into<String>) -> Self {
|
||||
Self::Localized {
|
||||
key,
|
||||
zh: zh.into(),
|
||||
en: en.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<PoisonError<T>> for AppError {
|
||||
|
||||
Reference in New Issue
Block a user