use thiserror::Error; /// 应用错误类型 #[derive(Error, Debug, Clone)] pub enum AppError { /// 配置错误 #[error("{0}")] Config(String), /// 文件操作错误 #[error("{0}")] File(String), /// 格式不支持错误 #[error("{0}")] UnsupportedFormat(String), /// 解析错误 #[error("{0}")] Parse(String), /// MinerU错误 #[error("{0}")] MinerU(String), /// MarkItDown错误 #[error("{0}")] MarkItDown(String), /// OSS操作错误 #[error("{0}")] Oss(String), /// 数据库错误 #[error("{0}")] Database(String), /// 网络错误 #[error("{0}")] Network(String), /// 任务错误 #[error("{0}")] Task(String), /// 内部错误 #[error("{0}")] Internal(String), /// 超时错误 #[error("{0}")] Timeout(String), /// 验证错误 #[error("{0}")] Validation(String), /// 环境错误 #[error("{0}")] Environment(String), /// 虚拟环境路径错误 #[error("{0}")] VirtualEnvironmentPath(String), /// 权限错误 #[error("{0}")] Permission(String), /// 路径错误 #[error("{0}")] Path(String), /// 队列错误 #[error("{0}")] Queue(String), /// 处理错误 #[error("{0}")] Processing(String), } impl AppError { // =========================================== // 工厂方法 - 创建带国际化消息的错误 // =========================================== /// 创建配置错误 pub fn config_error(detail: impl Into) -> Self { Self::Config(t!("errors.document_parser.config", detail = detail.into()).to_string()) } /// 创建文件操作错误 pub fn file_error(detail: impl Into) -> Self { Self::File(t!("errors.document_parser.file", detail = detail.into()).to_string()) } /// 创建格式不支持错误 pub fn unsupported_format(format: impl Into) -> Self { Self::UnsupportedFormat( t!( "errors.document_parser.unsupported_format", format = format.into() ) .to_string(), ) } /// 创建解析错误 pub fn parse_error(detail: impl Into) -> Self { Self::Parse(t!("errors.document_parser.parse", detail = detail.into()).to_string()) } /// 创建 MinerU 错误 pub fn mineru_error(detail: impl Into) -> Self { Self::MinerU(t!("errors.document_parser.mineru", detail = detail.into()).to_string()) } /// 创建 MarkItDown 错误 pub fn markitdown_error(detail: impl Into) -> Self { Self::MarkItDown( t!("errors.document_parser.markitdown", detail = detail.into()).to_string(), ) } /// 创建 OSS 错误 pub fn oss_error(detail: impl Into) -> Self { Self::Oss(t!("errors.document_parser.oss", detail = detail.into()).to_string()) } /// 创建数据库错误 pub fn database_error(detail: impl Into) -> Self { Self::Database(t!("errors.document_parser.database", detail = detail.into()).to_string()) } /// 创建网络错误 pub fn network_error(detail: impl Into) -> Self { Self::Network(t!("errors.document_parser.network", detail = detail.into()).to_string()) } /// 创建任务错误 pub fn task_error(detail: impl Into) -> Self { Self::Task(t!("errors.document_parser.task", detail = detail.into()).to_string()) } /// 创建内部错误 pub fn internal_error(detail: impl Into) -> Self { Self::Internal(t!("errors.document_parser.internal", detail = detail.into()).to_string()) } /// 创建超时错误 pub fn timeout_error(detail: impl Into) -> Self { Self::Timeout(t!("errors.document_parser.timeout", detail = detail.into()).to_string()) } /// 创建验证错误 pub fn validation_error(detail: impl Into) -> Self { Self::Validation( t!("errors.document_parser.validation", detail = detail.into()).to_string(), ) } /// 创建环境错误 pub fn environment_error(detail: impl Into) -> Self { Self::Environment( t!("errors.document_parser.environment", detail = detail.into()).to_string(), ) } /// 创建虚拟环境路径错误 pub fn virtual_environment_path_error(message: String, path: &std::path::Path) -> Self { let path_str = path.display().to_string(); Self::VirtualEnvironmentPath( t!( "errors.document_parser.virtual_environment_path", detail = format!("{} (path: {})", message, path_str) ) .to_string(), ) } /// 创建权限错误 pub fn permission_error(message: String, path: &std::path::Path) -> Self { let path_str = path.display().to_string(); Self::Permission( t!( "errors.document_parser.permission", detail = format!("{} (path: {})", message, path_str) ) .to_string(), ) } /// 创建路径错误 pub fn path_error(message: String, path: &std::path::Path) -> Self { let path_str = path.display().to_string(); Self::Path( t!( "errors.document_parser.path", detail = format!("{} (path: {})", message, path_str) ) .to_string(), ) } /// 创建队列错误 pub fn queue_error(detail: impl Into) -> Self { Self::Queue(t!("errors.document_parser.queue", detail = detail.into()).to_string()) } /// 创建处理错误 pub fn processing_error(detail: impl Into) -> Self { Self::Processing( t!("errors.document_parser.processing", detail = detail.into()).to_string(), ) } /// 获取路径相关错误的详细恢复建议 pub fn get_path_recovery_suggestions(&self) -> Vec { match self { AppError::VirtualEnvironmentPath(msg) => { let mut suggestions = vec![ "检查当前目录是否有写入权限".to_string(), "确保当前目录下没有名为 'venv' 的文件(非目录)".to_string(), "尝试删除损坏的虚拟环境目录: rm -rf ./venv".to_string(), "检查磁盘空间是否充足".to_string(), ]; if msg.contains("权限") || msg.contains("permission") { suggestions.insert(0, "使用 sudo 或管理员权限运行命令".to_string()); suggestions.push("检查目录所有者和权限: ls -la".to_string()); } if msg.contains("存在") || msg.contains("exists") { suggestions.push("备份现有虚拟环境后重新创建".to_string()); } suggestions } AppError::Permission(_msg) => { let mut suggestions = vec![ "检查文件和目录权限设置".to_string(), "确保当前用户有足够的权限".to_string(), ]; if cfg!(unix) { suggestions.extend(vec![ "使用 chmod 修改权限: chmod 755 <目录>".to_string(), "使用 chown 修改所有者: chown $USER <目录>".to_string(), "检查 SELinux 或 AppArmor 安全策略".to_string(), ]); } else if cfg!(windows) { suggestions.extend(vec![ "以管理员身份运行命令提示符".to_string(), "检查 Windows 用户账户控制 (UAC) 设置".to_string(), "确保目录不在受保护的系统路径中".to_string(), ]); } suggestions } AppError::Path(msg) => { let mut suggestions = vec![ "检查路径是否正确拼写".to_string(), "确保路径存在且可访问".to_string(), "检查路径中是否包含特殊字符".to_string(), ]; if msg.contains("不存在") || msg.contains("not found") { suggestions.push("创建缺失的目录结构".to_string()); } if msg.contains("长度") || msg.contains("length") { suggestions.push("使用较短的路径名称".to_string()); } suggestions } _ => vec!["检查系统环境和配置".to_string()], } } /// 获取错误代码 pub fn get_error_code(&self) -> &'static str { match self { AppError::Config(_) => "E001", AppError::File(_) => "E002", AppError::UnsupportedFormat(_) => "E003", AppError::Parse(_) => "E004", AppError::MinerU(_) => "E005", AppError::MarkItDown(_) => "E006", AppError::Oss(_) => "E007", AppError::Database(_) => "E008", AppError::Network(_) => "E009", AppError::Task(_) => "E010", AppError::Internal(_) => "E011", AppError::Timeout(_) => "E012", AppError::Validation(_) => "E013", AppError::Environment(_) => "E014", AppError::Queue(_) => "E015", AppError::Processing(_) => "E016", AppError::VirtualEnvironmentPath(_) => "E017", AppError::Permission(_) => "E018", AppError::Path(_) => "E019", } } /// 获取错误建议(国际化) pub fn get_suggestion(&self) -> String { match self { AppError::Config(_) => t!("errors.document_parser.suggestions.config").to_string(), AppError::File(_) => t!("errors.document_parser.suggestions.file").to_string(), AppError::UnsupportedFormat(_) => { t!("errors.document_parser.suggestions.unsupported_format").to_string() } AppError::Parse(_) => t!("errors.document_parser.suggestions.parse").to_string(), AppError::MinerU(_) => t!("errors.document_parser.suggestions.mineru").to_string(), AppError::MarkItDown(_) => { t!("errors.document_parser.suggestions.markitdown").to_string() } AppError::Oss(_) => t!("errors.document_parser.suggestions.oss").to_string(), AppError::Database(_) => t!("errors.document_parser.suggestions.database").to_string(), AppError::Network(_) => t!("errors.document_parser.suggestions.network").to_string(), AppError::Task(_) => t!("errors.document_parser.suggestions.task").to_string(), AppError::Internal(_) => t!("errors.document_parser.suggestions.internal").to_string(), AppError::Timeout(_) => t!("errors.document_parser.suggestions.timeout").to_string(), AppError::Validation(_) => { t!("errors.document_parser.suggestions.validation").to_string() } AppError::Environment(_) => { t!("errors.document_parser.suggestions.environment").to_string() } AppError::Queue(_) => t!("errors.document_parser.suggestions.queue").to_string(), AppError::Processing(_) => { t!("errors.document_parser.suggestions.processing").to_string() } AppError::VirtualEnvironmentPath(_) => { t!("errors.document_parser.suggestions.virtual_environment_path").to_string() } AppError::Permission(_) => { t!("errors.document_parser.suggestions.permission").to_string() } AppError::Path(_) => t!("errors.document_parser.suggestions.path").to_string(), } } /// 转换为HTTP响应格式 pub fn to_http_result(&self) -> crate::models::HttpResult { use crate::models::HttpResult; HttpResult::::error( self.get_error_code().to_string(), format!("{} - {}", self, self.get_suggestion()), ) } } /// 从标准库错误转换 impl From for AppError { fn from(err: std::io::Error) -> Self { Self::file_error(err.to_string()) } } /// 从serde错误转换 impl From for AppError { fn from(err: serde_json::Error) -> Self { Self::parse_error(format!("JSON: {err}")) } } /// 从serde_yaml错误转换 impl From for AppError { fn from(err: serde_yaml::Error) -> Self { Self::config_error(format!("YAML: {err}")) } } /// 从sled错误转换 impl From for AppError { fn from(err: sled::Error) -> Self { Self::database_error(format!("Sled: {err}")) } } /// 从reqwest错误转换 impl From for AppError { fn from(err: reqwest::Error) -> Self { if err.is_timeout() { Self::timeout_error("HTTP request") } else if err.is_connect() { Self::network_error("connection failed") } else { Self::network_error(err.to_string()) } } } /// 从anyhow错误转换 impl From for AppError { fn from(err: anyhow::Error) -> Self { Self::internal_error(err.to_string()) } } /// 从std::env::VarError转换 impl From for AppError { fn from(err: std::env::VarError) -> Self { Self::config_error(format!("environment variable: {err}")) } } /// 从std::num::ParseIntError转换 impl From for AppError { fn from(err: std::num::ParseIntError) -> Self { Self::config_error(format!("integer parse: {err}")) } } /// 从std::str::ParseBoolError转换 impl From for AppError { fn from(err: std::str::ParseBoolError) -> Self { Self::config_error(format!("boolean parse: {err}")) } } /// 从std::time::SystemTimeError转换 impl From for AppError { fn from(err: std::time::SystemTimeError) -> Self { Self::internal_error(err.to_string()) } }