refactor(backend): phase 1 - unified error handling with thiserror
Introduce AppError enum to replace Result<T, String> pattern across the codebase, improving error context preservation and type safety. ## Changes ### Core Infrastructure - Add src/error.rs with AppError enum using thiserror - Add thiserror dependency to Cargo.toml - Implement helper functions: io(), json(), toml() for ergonomic error creation - Implement From<PoisonError> for automatic lock error conversion - Implement From<AppError> for String to maintain Tauri command compatibility ### Module Migrations (60% complete) - config.rs: Full migration to AppError - read_json_file, write_json_file, atomic_write - archive_file, copy_file, delete_file - claude_mcp.rs: Full migration to AppError - get_mcp_status, read_mcp_json, upsert_mcp_server - delete_mcp_server, validate_command_in_path - set_mcp_servers_map - codex_config.rs: Full migration to AppError - write_codex_live_atomic with rollback support - read_and_validate_codex_config_text - validate_config_toml - app_config.rs: Partial migration - MultiAppConfig::load, MultiAppConfig::save - store.rs: Partial migration - AppState::save now returns Result<(), AppError> - commands.rs: Minimal changes - Use .map_err(Into::into) for compatibility - mcp.rs: Minimal changes - sync_enabled_to_claude uses Into::into conversion ### Documentation - Add docs/BACKEND_REFACTOR_PLAN.md with detailed refactoring roadmap ## Benefits - Type-safe error handling with preserved error chains - Better error messages with file paths and context - Reduced boilerplate code (118 Result<T, String> instances to migrate) - Automatic error conversion for seamless integration ## Testing - All existing tests pass (4/4) - Compilation successful with no warnings - Build time: 0.61s (no performance regression) ## Remaining Work - claude_plugin.rs (7 functions) - migration.rs, import_export.rs - Add unit tests for error.rs - Complete commands.rs migration after dependent modules Co-authored-by: Claude <claude@anthropic.com>
This commit is contained in:
84
src-tauri/src/error.rs
Normal file
84
src-tauri/src/error.rs
Normal file
@@ -0,0 +1,84 @@
|
||||
use std::path::Path;
|
||||
use std::sync::PoisonError;
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum AppError {
|
||||
#[error("配置错误: {0}")]
|
||||
Config(String),
|
||||
#[error("无效输入: {0}")]
|
||||
InvalidInput(String),
|
||||
#[error("IO 错误: {path}: {source}")]
|
||||
Io {
|
||||
path: String,
|
||||
#[source]
|
||||
source: std::io::Error,
|
||||
},
|
||||
#[error("{context}: {source}")]
|
||||
IoContext {
|
||||
context: String,
|
||||
#[source]
|
||||
source: std::io::Error,
|
||||
},
|
||||
#[error("JSON 解析错误: {path}: {source}")]
|
||||
Json {
|
||||
path: String,
|
||||
#[source]
|
||||
source: serde_json::Error,
|
||||
},
|
||||
#[error("JSON 序列化失败: {source}")]
|
||||
JsonSerialize {
|
||||
#[source]
|
||||
source: serde_json::Error,
|
||||
},
|
||||
#[error("TOML 解析错误: {path}: {source}")]
|
||||
Toml {
|
||||
path: String,
|
||||
#[source]
|
||||
source: toml::de::Error,
|
||||
},
|
||||
#[error("锁获取失败: {0}")]
|
||||
Lock(String),
|
||||
#[error("供应商不存在: {0}")]
|
||||
ProviderNotFound(String),
|
||||
#[error("MCP 校验失败: {0}")]
|
||||
McpValidation(String),
|
||||
#[error("{0}")]
|
||||
Message(String),
|
||||
}
|
||||
|
||||
impl AppError {
|
||||
pub fn io(path: impl AsRef<Path>, source: std::io::Error) -> Self {
|
||||
Self::Io {
|
||||
path: path.as_ref().display().to_string(),
|
||||
source,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn json(path: impl AsRef<Path>, source: serde_json::Error) -> Self {
|
||||
Self::Json {
|
||||
path: path.as_ref().display().to_string(),
|
||||
source,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toml(path: impl AsRef<Path>, source: toml::de::Error) -> Self {
|
||||
Self::Toml {
|
||||
path: path.as_ref().display().to_string(),
|
||||
source,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<PoisonError<T>> for AppError {
|
||||
fn from(err: PoisonError<T>) -> Self {
|
||||
Self::Lock(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AppError> for String {
|
||||
fn from(err: AppError) -> Self {
|
||||
err.to_string()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user