Skip to main content

client_core/patch_executor/
error.rs

1// client-core/src/patch_executor/error.rs
2//! 补丁执行器错误定义
3
4use thiserror::Error;
5
6/// 补丁执行器错误类型
7#[derive(Debug, Error)]
8pub enum PatchExecutorError {
9    /// 文件操作错误
10    #[error("文件操作失败: {0}")]
11    IoError(#[from] std::io::Error),
12
13    /// 路径错误
14    #[error("路径错误: {path}")]
15    PathError { path: String },
16
17    /// 权限错误
18    #[error("权限错误: {path}")]
19    PermissionError { path: String },
20
21    /// 原子操作失败
22    #[error("原子操作失败: {reason}")]
23    AtomicOperationFailed { reason: String },
24
25    /// 回滚失败
26    #[error("回滚失败: {reason}")]
27    RollbackFailed { reason: String },
28
29    /// 补丁下载失败
30    #[error("补丁下载失败: {url}")]
31    DownloadFailed { url: String },
32
33    /// 补丁验证失败
34    #[error("补丁验证失败: {reason}")]
35    VerificationFailed { reason: String },
36
37    /// 补丁解压失败
38    #[error("补丁解压失败: {reason}")]
39    ExtractionFailed { reason: String },
40
41    /// 哈希校验失败
42    #[error("哈希校验失败: 期望 {expected}, 实际 {actual}")]
43    HashMismatch { expected: String, actual: String },
44
45    /// 数字签名验证失败
46    #[error("数字签名验证失败: {reason}")]
47    SignatureVerificationFailed { reason: String },
48
49    /// 不支持的操作
50    #[error("不支持的操作: {operation}")]
51    UnsupportedOperation { operation: String },
52
53    /// 备份模式未启用
54    #[error("备份模式未启用,无法执行回滚操作")]
55    BackupNotEnabled,
56
57    /// 补丁源目录未设置
58    #[error("补丁源目录未设置")]
59    PatchSourceNotSet,
60
61    /// 临时文件操作错误
62    #[error("临时文件操作错误: {0}")]
63    TempFileError(#[from] tempfile::PersistError),
64
65    /// HTTP 错误
66    #[error("HTTP 请求错误: {0}")]
67    HttpError(#[from] reqwest::Error),
68
69    /// JSON 解析错误
70    #[error("JSON 解析错误: {0}")]
71    JsonError(#[from] serde_json::Error),
72
73    /// ZIP 操作错误
74    #[error("ZIP 操作错误: {0}")]
75    ZipError(#[from] zip::result::ZipError),
76
77    /// fs_extra 错误
78    #[error("文件系统扩展操作错误: {0}")]
79    FsExtraError(#[from] fs_extra::error::Error),
80
81    /// 自定义错误
82    #[error("补丁执行错误: {message}")]
83    Custom { message: String },
84}
85
86impl PatchExecutorError {
87    /// 创建自定义错误
88    pub fn custom<S: Into<String>>(message: S) -> Self {
89        Self::Custom {
90            message: message.into(),
91        }
92    }
93
94    /// 创建路径错误
95    pub fn path_error<S: Into<String>>(path: S) -> Self {
96        Self::PathError { path: path.into() }
97    }
98
99    /// 创建权限错误
100    pub fn permission_error<S: Into<String>>(path: S) -> Self {
101        Self::PermissionError { path: path.into() }
102    }
103
104    /// 创建原子操作失败错误
105    pub fn atomic_operation_failed<S: Into<String>>(reason: S) -> Self {
106        Self::AtomicOperationFailed {
107            reason: reason.into(),
108        }
109    }
110
111    /// 创建回滚失败错误
112    pub fn rollback_failed<S: Into<String>>(reason: S) -> Self {
113        Self::RollbackFailed {
114            reason: reason.into(),
115        }
116    }
117
118    /// 创建下载失败错误
119    pub fn download_failed<S: Into<String>>(url: S) -> Self {
120        Self::DownloadFailed { url: url.into() }
121    }
122
123    /// 创建验证失败错误
124    pub fn verification_failed<S: Into<String>>(reason: S) -> Self {
125        Self::VerificationFailed {
126            reason: reason.into(),
127        }
128    }
129
130    /// 创建解压失败错误
131    pub fn extraction_failed<S: Into<String>>(reason: S) -> Self {
132        Self::ExtractionFailed {
133            reason: reason.into(),
134        }
135    }
136
137    /// 创建哈希校验失败错误
138    pub fn hash_mismatch<S: Into<String>>(expected: S, actual: S) -> Self {
139        Self::HashMismatch {
140            expected: expected.into(),
141            actual: actual.into(),
142        }
143    }
144
145    /// 创建数字签名验证失败错误
146    pub fn signature_verification_failed<S: Into<String>>(reason: S) -> Self {
147        Self::SignatureVerificationFailed {
148            reason: reason.into(),
149        }
150    }
151
152    /// 创建不支持的操作错误
153    pub fn unsupported_operation<S: Into<String>>(operation: S) -> Self {
154        Self::UnsupportedOperation {
155            operation: operation.into(),
156        }
157    }
158
159    /// 检查是否是可恢复的错误
160    pub fn is_recoverable(&self) -> bool {
161        match self {
162            Self::IoError(_) => true,
163            Self::HttpError(_) => true,
164            Self::DownloadFailed { .. } => true,
165            Self::TempFileError(_) => true,
166            Self::VerificationFailed { .. } => false,
167            Self::HashMismatch { .. } => false,
168            Self::SignatureVerificationFailed { .. } => false,
169            Self::PermissionError { .. } => false,
170            Self::UnsupportedOperation { .. } => false,
171            Self::BackupNotEnabled => false,
172            Self::PatchSourceNotSet => false,
173            _ => true,
174        }
175    }
176
177    /// 检查是否需要回滚
178    pub fn requires_rollback(&self) -> bool {
179        match self {
180            Self::VerificationFailed { .. } => false,
181            Self::HashMismatch { .. } => false,
182            Self::SignatureVerificationFailed { .. } => false,
183            Self::DownloadFailed { .. } => false,
184            Self::BackupNotEnabled => false,
185            Self::PatchSourceNotSet => false,
186            _ => true,
187        }
188    }
189}
190
191/// Result 类型别名
192pub type Result<T> = std::result::Result<T, PatchExecutorError>;
193
194#[cfg(test)]
195mod tests {
196    use super::*;
197
198    #[test]
199    fn test_error_creation() {
200        let error = PatchExecutorError::custom("test error");
201        assert!(matches!(error, PatchExecutorError::Custom { .. }));
202        assert_eq!(error.to_string(), "补丁执行错误: test error");
203    }
204
205    #[test]
206    fn test_error_recoverability() {
207        let recoverable = PatchExecutorError::download_failed("http://example.com");
208        assert!(recoverable.is_recoverable());
209
210        let non_recoverable = PatchExecutorError::hash_mismatch("abc", "def");
211        assert!(!non_recoverable.is_recoverable());
212    }
213
214    #[test]
215    fn test_rollback_requirement() {
216        let requires_rollback = PatchExecutorError::atomic_operation_failed("test");
217        assert!(requires_rollback.requires_rollback());
218
219        let no_rollback = PatchExecutorError::verification_failed("test");
220        assert!(!no_rollback.requires_rollback());
221    }
222}