Skip to main content

office_rs/error/
mod.rs

1use quick_xml::Error as XmlError;
2use serde_json::Error as JsonError;
3use std::error::Error;
4use std::io;
5use thiserror::Error;
6use zip::result::ZipError;
7
8pub use category::ErrorCategory;
9pub use category::ErrorSeverity;
10pub use format::file::FileError;
11pub use format::parse::ParseError;
12pub use format::xlsx::XlsxError;
13pub use format::docx::DocxError;
14pub use format::pptx::PptxError;
15
16use crate::code::RecoverySuggestion;
17use crate::error::code::*; // 导入所有错误码类型
18use crate::error::monitor::{ ErrorMonitor, ErrorStats };
19use crate::error::code::RecoveryAction;
20use crate::error::context::ErrorContext;
21use crate::error::monitor::error_monitor;
22
23pub mod mod_backup;
24pub mod category;
25pub mod format;
26pub mod code;
27pub mod context;
28pub mod monitor;
29
30/// 带上下文的文档错误类型
31#[derive(Error, Debug)]
32pub enum OfficeError {
33    /// IO错误
34    #[error("IO错误: {0}")]
35    Io(#[from] io::Error),
36
37    /// ZIP文件错误
38    #[error("ZIP文件错误: {0}")]
39    Zip(#[from] ZipError),
40
41    /// XML解析错误
42    #[error("XML解析错误: {0}")]
43    Xml(#[from] XmlError),
44
45    /// JSON序列化错误
46    #[error("JSON错误: {0}")]
47    Json(#[from] JsonError),
48
49    /// 编码错误
50    #[error("编码错误: {0}")]
51    Encoding(#[from] std::string::FromUtf8Error),
52
53    /// 文件相关错误
54    #[error("文件错误: {0}")]
55    File(#[from] FileError),
56
57    /// 解析相关错误
58    #[error("解析错误: {0}")]
59    Parse(#[from] ParseError),
60
61    /// Excel特定错误
62    #[error("Excel错误: {0}")]
63    Xlsx(#[from] XlsxError),
64
65    /// Word特定错误
66    #[error("Word错误: {0}")]
67    Docx(#[from] DocxError),
68
69    /// PowerPoint特定错误
70    #[error("PowerPoint错误: {0}")]
71    Pptx(#[from] PptxError),
72
73    /// 格式错误
74    #[error("格式错误: {0}")]
75    Format(String),
76
77    /// 不支持的文件类型
78    #[error("不支持的文件类型: {0}")]
79    UnsupportedFormat(String),
80
81    /// 文档结构错误
82    #[error("文档结构错误: {0}")]
83    Structure(String),
84
85    /// 其他错误
86    #[error("其他错误: {0}")]
87    Other(String),
88
89    /// 带上下文的错误
90    #[error("{error}\n上下文: {context:?}")]
91    WithContext {
92        error: Box<OfficeError>,
93        context: ErrorContext,
94    },
95}
96
97impl OfficeError {
98    /// 创建带上下文的文件未找到错误
99    pub fn file_not_found_with_context(path: String, context: ErrorContext) -> Self {
100        Self::File(FileError::NotFound { path }).with_context(context)
101    }
102
103    /// 创建带上下文的解析错误
104    pub fn parse_error_with_context(element: String, context: ErrorContext) -> Self {
105        Self::Parse(ParseError::MissingElement { element }).with_context(context)
106    }
107
108    /// 创建带上下文的Excel错误
109    pub fn xlsx_error_with_context(name: String, context: ErrorContext) -> Self {
110        Self::Xlsx(XlsxError::WorksheetNotFound { name }).with_context(context)
111    }
112
113    /// 记录错误到监控器
114    pub fn record(&self) -> &Self {
115        error_monitor().record_error(self);
116        self
117    }
118
119    /// 创建错误并自动记录
120    pub fn new_and_record(error: OfficeError) -> Self {
121        error_monitor().record_error(&error);
122        error
123    }
124    /// 获取错误严重程度
125    pub fn severity(&self) -> ErrorSeverity {
126        match self {
127            Self::Io(_) => ErrorSeverity::Fatal,
128            Self::Zip(_) => ErrorSeverity::Fatal,
129            Self::Xml(_) => ErrorSeverity::Error,
130            Self::Json(_) => ErrorSeverity::Error,
131            Self::Encoding(_) => ErrorSeverity::Error,
132            Self::File(FileError::NotFound { .. }) => ErrorSeverity::Fatal,
133            Self::File(FileError::PermissionDenied { .. }) => ErrorSeverity::Fatal,
134            Self::File(FileError::Corrupted { .. }) => ErrorSeverity::Fatal,
135            Self::File(FileError::InvalidFormat { .. }) => ErrorSeverity::Error,
136            Self::Parse(_) => ErrorSeverity::Error,
137            Self::Xlsx(_) => ErrorSeverity::Error,
138            Self::Docx(_) => ErrorSeverity::Error,
139            Self::Pptx(_) => ErrorSeverity::Error,
140            Self::Format(_) => ErrorSeverity::Error,
141            Self::UnsupportedFormat(_) => ErrorSeverity::Fatal,
142            Self::Structure(_) => ErrorSeverity::Warning,
143            Self::Other(_) => ErrorSeverity::Error,
144            Self::WithContext { error, .. } => error.severity(),
145        }
146    }
147
148    /// 获取错误分类
149    pub fn category(&self) -> ErrorCategory {
150        match self {
151            Self::Io(_) | Self::File(_) => ErrorCategory::FileSystem,
152            Self::Zip(_) => ErrorCategory::FileSystem,
153            Self::Xml(_) | Self::Json(_) | Self::Encoding(_) => ErrorCategory::Parsing,
154            Self::Parse(_) => ErrorCategory::Parsing,
155            Self::Xlsx(_) | Self::Docx(_) | Self::Pptx(_) => ErrorCategory::Validation,
156            Self::Format(_) | Self::Structure(_) => ErrorCategory::Validation,
157            Self::UnsupportedFormat(_) => ErrorCategory::Parsing,
158            Self::Other(_) => ErrorCategory::Internal,
159            Self::WithContext { error, .. } => error.category(),
160        }
161    }
162
163    /// 获取错误码
164    pub fn error_code(&self) -> ErrorCode {
165        match self {
166            // 系统级错误(IO、文件系统等)
167            Self::Io(_) => ErrorCode::System(SystemErrorCode::IoError),
168            Self::Zip(_) => ErrorCode::System(SystemErrorCode::ZipError),
169            Self::File(FileError::NotFound { .. }) => ErrorCode::System(SystemErrorCode::NotFound),
170            Self::File(FileError::PermissionDenied { .. }) =>
171                ErrorCode::System(SystemErrorCode::PermissionDenied),
172            Self::File(FileError::Corrupted { .. }) =>
173                ErrorCode::System(SystemErrorCode::Corrupted),
174            Self::File(FileError::InvalidFormat { .. }) =>
175                ErrorCode::Format(FormatErrorCode::InvalidFormat),
176
177            // 解析错误
178            Self::Xml(_) => ErrorCode::Parse(ParseErrorCode::Xml),
179            Self::Json(_) => ErrorCode::Parse(ParseErrorCode::Json),
180            Self::Encoding(_) => ErrorCode::Parse(ParseErrorCode::Encoding),
181            Self::Parse(parse_err) =>
182                match parse_err {
183                    ParseError::MissingElement { .. } =>
184                        ErrorCode::Parse(ParseErrorCode::MissingElement),
185                    ParseError::InvalidAttribute { .. } =>
186                        ErrorCode::Parse(ParseErrorCode::InvalidAttribute),
187                    ParseError::UnsupportedVersion { .. } =>
188                        ErrorCode::Parse(ParseErrorCode::UnsupportedVersion),
189                    ParseError::InvalidNamespace { .. } =>
190                        ErrorCode::Parse(ParseErrorCode::InvalidNamespace),
191                }
192
193            // Excel相关错误
194            Self::Xlsx(xlsx_err) =>
195                match xlsx_err {
196                    XlsxError::WorksheetNotFound { .. } =>
197                        ErrorCode::Document(DocumentErrorCode::XlsxWorksheetNotFound),
198                    XlsxError::InvalidCellReference { .. } =>
199                        ErrorCode::Document(DocumentErrorCode::XlsxInvalidCellReference),
200                    XlsxError::InvalidFormula { .. } =>
201                        ErrorCode::Document(DocumentErrorCode::XlsxInvalidFormula),
202                    XlsxError::InvalidStyleId { .. } =>
203                        ErrorCode::Document(DocumentErrorCode::XlsxInvalidStyle),
204                    XlsxError::SharedStringIndexOutOfRange { .. } =>
205                        ErrorCode::Format(FormatErrorCode::OutOfRange),
206                    XlsxError::WorksheetCreationFailed { .. } =>
207                        ErrorCode::Document(DocumentErrorCode::XlsxWorksheetNotFound),
208                }
209
210            // Word相关错误
211            Self::Docx(docx_err) =>
212                match docx_err {
213                    DocxError::StyleNotFound { .. } =>
214                        ErrorCode::Document(DocumentErrorCode::DocxStyleNotFound),
215                    DocxError::InvalidTableStructure =>
216                        ErrorCode::Document(DocumentErrorCode::DocxInvalidTableStructure),
217                    DocxError::InvalidParagraphFormat { .. } =>
218                        ErrorCode::Document(DocumentErrorCode::DocxInvalidParagraph),
219                    DocxError::BookmarkNotFound { .. } =>
220                        ErrorCode::Document(DocumentErrorCode::DocxBookmarkNotFound),
221                }
222
223            // PowerPoint相关错误
224            Self::Pptx(_) => ErrorCode::Document(DocumentErrorCode::PptxInvalidPresentation),
225
226            // 通用错误
227            Self::Format(_) => ErrorCode::Format(FormatErrorCode::InvalidFormat),
228            Self::UnsupportedFormat(_) => ErrorCode::Format(FormatErrorCode::UnsupportedFormat),
229            Self::Structure(_) => ErrorCode::Common(CommonErrorCode::InvalidOperation),
230            Self::Other(_) => ErrorCode::Common(CommonErrorCode::UnknownError),
231
232            // 带上下文的错误
233            Self::WithContext { error, .. } => error.error_code(),
234        }
235    }
236
237    /// 判断错误是否可恢复
238    pub fn is_recoverable(&self) -> bool {
239        matches!(self.severity(), ErrorSeverity::Warning | ErrorSeverity::Error)
240    }
241
242    /// 添加错误上下文
243    pub fn with_context(self, context: ErrorContext) -> Self {
244        let error_with_context = Self::WithContext {
245            error: Box::new(self),
246            context,
247        };
248        // 记录带上下文的错误
249        error_monitor().record_error(&error_with_context);
250        error_with_context
251    }
252
253    /// 获取错误上下文
254    pub fn context(&self) -> Option<&ErrorContext> {
255        match self {
256            Self::WithContext { context, .. } => Some(context),
257            _ => None,
258        }
259    }
260
261    /// 获取根错误(去除上下文包装)
262    pub fn root_error(&self) -> &OfficeError {
263        match self {
264            Self::WithContext { error, .. } => error.root_error(),
265            _ => self,
266        }
267    }
268
269    /// 获取错误恢复建议
270    pub fn recovery_suggestion(&self) -> Option<RecoverySuggestion> {
271        match self.root_error() {
272            Self::File(FileError::NotFound { path }) =>
273                Some(RecoverySuggestion {
274                    message: format!("检查文件路径是否正确: {}", path),
275                    action: RecoveryAction::UserInput("请提供正确的文件路径".to_string()),
276                }),
277            Self::File(FileError::PermissionDenied { path }) =>
278                Some(RecoverySuggestion {
279                    message: format!("检查文件权限: {}", path),
280                    action: RecoveryAction::UserInput("请确保有足够的文件访问权限".to_string()),
281                }),
282            Self::Xlsx(XlsxError::WorksheetNotFound { name }) =>
283                Some(RecoverySuggestion {
284                    message: format!("工作表 '{}' 不存在,可以使用默认工作表", name),
285                    action: RecoveryAction::UseDefault,
286                }),
287            Self::Xlsx(XlsxError::InvalidCellReference { reference }) =>
288                Some(RecoverySuggestion {
289                    message: format!("单元格引用 '{}' 无效,跳过此单元格", reference),
290                    action: RecoveryAction::SkipElement,
291                }),
292            Self::Docx(DocxError::StyleNotFound { style_id }) =>
293                Some(RecoverySuggestion {
294                    message: format!("样式 '{}' 不存在,使用默认样式", style_id),
295                    action: RecoveryAction::UseDefault,
296                }),
297            Self::Pptx(PptxError::SlideNotFound { slide_id }) =>
298                Some(RecoverySuggestion {
299                    message: format!("幻灯片 '{}' 不存在,跳过此幻灯片", slide_id),
300                    action: RecoveryAction::SkipElement,
301                }),
302            Self::Structure(_) =>
303                Some(RecoverySuggestion {
304                    message: "文档结构异常,但可以继续处理".to_string(),
305                    action: RecoveryAction::SkipElement,
306                }),
307            Self::Io(_) | Self::Zip(_) | Self::UnsupportedFormat(_) =>
308                Some(RecoverySuggestion {
309                    message: "致命错误,无法恢复".to_string(),
310                    action: RecoveryAction::None,
311                }),
312            _ =>
313                Some(RecoverySuggestion {
314                    message: "可以重试操作".to_string(),
315                    action: RecoveryAction::Retry(3),
316                }),
317        }
318    }
319
320    /// 获取错误链
321    pub fn error_chain(&self) -> Vec<&dyn std::error::Error> {
322        let mut chain = vec![self as &dyn std::error::Error];
323        let mut source = self.source();
324        while let Some(err) = source {
325            chain.push(err);
326            source = err.source();
327        }
328        chain
329    }
330
331    /// 获取根因错误
332    pub fn root_cause(&self) -> &dyn std::error::Error {
333        self.error_chain().into_iter().last().unwrap()
334    }
335
336    pub fn try_recover(&self, strategy: RecoveryStrategy) -> Result<()> {
337        // 实现恢复逻辑
338
339        match strategy.operation {
340            RecoveryAction::Retry(times) => {
341                for _ in 0..times {
342                    // 尝试重试操作
343                    if self.is_recoverable() {
344                        return Ok(());
345                    }
346                }
347                Err(Self::Other("重试失败".to_string()))
348            }
349            RecoveryAction::Fallback(fallback) => {
350                // 执行降级方案
351                println!("执行降级方案: {}", fallback);
352                todo!("Implement fallback logic");
353                Ok(())
354            }
355            RecoveryAction::Ignore => Ok(()),
356            _ => { Ok(()) }
357        }
358    }
359}
360
361/// 简化的结果类型
362pub type Result<T> = std::result::Result<T, OfficeError>;