Skip to main content

docker_types/
errors.rs

1#![warn(missing_docs)]
2
3//! 错误类型定义
4//!
5//! 提供统一的错误处理机制,支持国际化和 HTTP 状态码映射。
6
7use serde::{Deserialize, Serialize};
8use serde_json::{Value, json};
9use std::fmt;
10
11/// 结果类型
12pub type Result<T> = std::result::Result<T, DockerError>;
13
14/// 中心化错误类型
15///
16/// 包含错误类型标识,支持国际化。
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct DockerError {
19    /// 错误类型
20    pub kind: Box<DockerErrorKind>,
21}
22
23/// 错误分类
24///
25/// 用于将错误映射到 HTTP 状态码等场景。
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
27pub enum ErrorCategory {
28    /// 验证错误 (400)
29    Validation,
30    /// 认证错误 (401)
31    Auth,
32    /// 权限错误 (403)
33    Permission,
34    /// 资源未找到 (404)
35    NotFound,
36    /// 请求冲突 (409)
37    Conflict,
38    /// 请求过多 (429)
39    RateLimited,
40    /// 网络/服务错误 (502/503)
41    Network,
42    /// 存储错误 (500)
43    Storage,
44    /// 数据库错误 (500)
45    Database,
46    /// 缓存错误 (500)
47    Cache,
48    /// 配置错误 (500)
49    Config,
50    /// 超时错误 (408/504)
51    Timeout,
52    /// 内部错误 (500)
53    Internal,
54}
55
56impl ErrorCategory {
57    /// 获取对应的 HTTP 状态码
58    pub fn http_status(&self) -> u16 {
59        match self {
60            ErrorCategory::Validation => 400,
61            ErrorCategory::Auth => 401,
62            ErrorCategory::Permission => 403,
63            ErrorCategory::NotFound => 404,
64            ErrorCategory::Conflict => 409,
65            ErrorCategory::RateLimited => 429,
66            ErrorCategory::Network => 502,
67            ErrorCategory::Storage => 500,
68            ErrorCategory::Database => 500,
69            ErrorCategory::Cache => 500,
70            ErrorCategory::Config => 500,
71            ErrorCategory::Timeout => 408,
72            ErrorCategory::Internal => 500,
73        }
74    }
75}
76
77/// 统一错误类型枚举
78///
79/// 整合所有模块的错误变体,每个变体对应一个 i18n key。
80#[derive(Debug, Clone, Serialize, Deserialize)]
81pub enum DockerErrorKind {
82    // ========== 验证错误 ==========
83    /// 无效格式
84    InvalidFormat {
85        /// 字段名
86        field: String,
87        /// 期望格式
88        expected: String,
89    },
90    /// 值超出范围
91    OutOfRange {
92        /// 字段名
93        field: String,
94        /// 最小值
95        min: Option<String>,
96        /// 最大值
97        max: Option<String>,
98    },
99    /// 必填字段缺失
100    Required {
101        /// 字段名
102        field: String,
103    },
104    /// 值已存在
105    AlreadyExists {
106        /// 字段名
107        field: String,
108        /// 值
109        value: String,
110    },
111    /// 值不允许
112    NotAllowed {
113        /// 字段名
114        field: String,
115        /// 允许的值
116        allowed: Vec<String>,
117    },
118    /// 无效参数
119    InvalidParams {
120        /// 参数名
121        param: String,
122        /// 原因
123        reason: String,
124    },
125
126    // ========== 认证错误 (Auth) ==========
127    /// 无效凭证
128    InvalidCredentials,
129    /// 账户已锁定
130    AccountLocked,
131    /// 用户未找到
132    UserNotFound {
133        /// 用户标识
134        identifier: String,
135    },
136    /// 用户已存在
137    UserAlreadyExists {
138        /// 用户名
139        username: String,
140    },
141    /// 无效令牌
142    InvalidToken {
143        /// 原因
144        reason: String,
145    },
146    /// 令牌已过期
147    TokenExpired,
148
149    // ========== 权限错误 ==========
150    /// 权限拒绝
151    PermissionDenied {
152        /// 操作
153        action: String,
154    },
155    /// 禁止访问
156    Forbidden {
157        /// 资源
158        resource: String,
159    },
160
161    // ========== 资源未找到 ==========
162    /// 资源未找到
163    ResourceNotFound {
164        /// 资源类型
165        resource_type: String,
166        /// 资源标识
167        identifier: String,
168    },
169
170    // ========== 冲突错误 ==========
171    /// 资源冲突
172    ResourceConflict {
173        /// 资源
174        resource: String,
175        /// 原因
176        reason: String,
177    },
178
179    // ========== 限流错误 ==========
180    /// 限流超出
181    RateLimited {
182        /// 限制
183        limit: u64,
184    },
185
186    // ========== 网络错误 ==========
187    /// 连接失败
188    ConnectionFailed {
189        /// 目标
190        target: String,
191    },
192    /// DNS 解析失败
193    DnsResolutionFailed {
194        /// 主机
195        host: String,
196    },
197    /// 服务不可用
198    ServiceUnavailable {
199        /// 服务名
200        service: String,
201    },
202
203    // ========== 存储错误 ==========
204    /// 读取失败
205    StorageReadFailed {
206        /// 路径
207        path: String,
208    },
209    /// 写入失败
210    StorageWriteFailed {
211        /// 路径
212        path: String,
213    },
214    /// 删除失败
215    StorageDeleteFailed {
216        /// 路径
217        path: String,
218    },
219    /// 容量不足
220    InsufficientCapacity {
221        /// 需要
222        required: u64,
223        /// 可用
224        available: u64,
225    },
226    /// 文件未找到
227    StorageFileNotFound {
228        /// 路径
229        path: String,
230    },
231
232    // ========== 配置错误 ==========
233    /// 配置缺失
234    ConfigMissing {
235        /// 配置键
236        key: String,
237    },
238    /// 配置无效
239    ConfigInvalid {
240        /// 配置键
241        key: String,
242        /// 原因
243        reason: String,
244    },
245
246    // ========== 内部错误 ==========
247    /// 内部错误
248    InternalError {
249        /// 原因
250        reason: String,
251    },
252    /// 未实现
253    NotImplemented {
254        /// 功能
255        feature: String,
256    },
257    /// IO 错误
258    IoError {
259        /// 操作
260        operation: String,
261        /// 原因
262        reason: String,
263    },
264    /// JSON 错误
265    JsonError {
266        /// 原因
267        reason: String,
268    },
269    /// 解析错误
270    ParseError {
271        /// 类型
272        type_name: String,
273        /// 原因
274        reason: String,
275    },
276    /// 请求错误
277    RequestError {
278        /// URL
279        url: String,
280        /// 原因
281        reason: String,
282    },
283
284    // ========== Docker 特定错误 ==========
285    /// 容器错误
286    ContainerError {
287        /// 原因
288        reason: String,
289    },
290    /// 镜像错误
291    ImageError {
292        /// 原因
293        reason: String,
294    },
295    /// 网络错误
296    NetworkError {
297        /// 原因
298        reason: String,
299    },
300    /// 运行时错误
301    RuntimeError {
302        /// 原因
303        reason: String,
304    },
305    /// 注册表错误
306    RegistryError {
307        /// 原因
308        reason: String,
309    },
310    /// Etcd 错误
311    EtcdError {
312        /// 原因
313        reason: String,
314    },
315    /// 监控错误
316    MonitorError {
317        /// 原因
318        reason: String,
319    },
320    /// Kubernetes 错误
321    KubernetesError {
322        /// 原因
323        reason: String,
324    },
325}
326
327impl DockerErrorKind {
328    /// 获取错误分类
329    pub fn category(&self) -> ErrorCategory {
330        match self {
331            DockerErrorKind::InvalidFormat { .. }
332            | DockerErrorKind::OutOfRange { .. }
333            | DockerErrorKind::Required { .. }
334            | DockerErrorKind::AlreadyExists { .. }
335            | DockerErrorKind::NotAllowed { .. }
336            | DockerErrorKind::InvalidParams { .. } => ErrorCategory::Validation,
337
338            DockerErrorKind::InvalidCredentials
339            | DockerErrorKind::AccountLocked
340            | DockerErrorKind::UserNotFound { .. }
341            | DockerErrorKind::UserAlreadyExists { .. }
342            | DockerErrorKind::InvalidToken { .. }
343            | DockerErrorKind::TokenExpired => ErrorCategory::Auth,
344
345            DockerErrorKind::PermissionDenied { .. } | DockerErrorKind::Forbidden { .. } => {
346                ErrorCategory::Permission
347            }
348
349            DockerErrorKind::ResourceNotFound { .. } => ErrorCategory::NotFound,
350
351            DockerErrorKind::ResourceConflict { .. } => ErrorCategory::Conflict,
352
353            DockerErrorKind::RateLimited { .. } => ErrorCategory::RateLimited,
354
355            DockerErrorKind::ConnectionFailed { .. }
356            | DockerErrorKind::DnsResolutionFailed { .. }
357            | DockerErrorKind::ServiceUnavailable { .. } => ErrorCategory::Network,
358
359            DockerErrorKind::StorageReadFailed { .. }
360            | DockerErrorKind::StorageWriteFailed { .. }
361            | DockerErrorKind::StorageDeleteFailed { .. }
362            | DockerErrorKind::InsufficientCapacity { .. }
363            | DockerErrorKind::StorageFileNotFound { .. } => ErrorCategory::Storage,
364
365            DockerErrorKind::ConfigMissing { .. } | DockerErrorKind::ConfigInvalid { .. } => {
366                ErrorCategory::Config
367            }
368
369            DockerErrorKind::InternalError { .. }
370            | DockerErrorKind::NotImplemented { .. }
371            | DockerErrorKind::IoError { .. }
372            | DockerErrorKind::JsonError { .. }
373            | DockerErrorKind::ParseError { .. }
374            | DockerErrorKind::RequestError { .. }
375            | DockerErrorKind::ContainerError { .. }
376            | DockerErrorKind::ImageError { .. }
377            | DockerErrorKind::NetworkError { .. }
378            | DockerErrorKind::RuntimeError { .. }
379            | DockerErrorKind::RegistryError { .. }
380            | DockerErrorKind::EtcdError { .. }
381            | DockerErrorKind::MonitorError { .. }
382            | DockerErrorKind::KubernetesError { .. } => ErrorCategory::Internal,
383        }
384    }
385
386    /// 获取国际化键
387    pub fn i18n_key(&self) -> &'static str {
388        match self {
389            DockerErrorKind::InvalidFormat { .. } => "docker.error.validation.invalid_format",
390            DockerErrorKind::OutOfRange { .. } => "docker.error.validation.out_of_range",
391            DockerErrorKind::Required { .. } => "docker.error.validation.required",
392            DockerErrorKind::AlreadyExists { .. } => "docker.error.validation.already_exists",
393            DockerErrorKind::NotAllowed { .. } => "docker.error.validation.not_allowed",
394            DockerErrorKind::InvalidParams { .. } => "docker.error.validation.invalid_params",
395
396            DockerErrorKind::InvalidCredentials => "docker.error.auth.invalid_credentials",
397            DockerErrorKind::AccountLocked => "docker.error.auth.account_locked",
398            DockerErrorKind::UserNotFound { .. } => "docker.error.auth.user_not_found",
399            DockerErrorKind::UserAlreadyExists { .. } => "docker.error.auth.user_already_exists",
400            DockerErrorKind::InvalidToken { .. } => "docker.error.auth.invalid_token",
401            DockerErrorKind::TokenExpired => "docker.error.auth.token_expired",
402
403            DockerErrorKind::PermissionDenied { .. } => "docker.error.permission.denied",
404            DockerErrorKind::Forbidden { .. } => "docker.error.permission.forbidden",
405
406            DockerErrorKind::ResourceNotFound { .. } => "docker.error.not_found.resource",
407
408            DockerErrorKind::ResourceConflict { .. } => "docker.error.conflict.resource",
409
410            DockerErrorKind::RateLimited { .. } => "docker.error.rate_limited",
411
412            DockerErrorKind::ConnectionFailed { .. } => "docker.error.network.connection_failed",
413            DockerErrorKind::DnsResolutionFailed { .. } => {
414                "docker.error.network.dns_resolution_failed"
415            }
416            DockerErrorKind::ServiceUnavailable { .. } => {
417                "docker.error.network.service_unavailable"
418            }
419
420            DockerErrorKind::StorageReadFailed { .. } => "docker.error.storage.read_failed",
421            DockerErrorKind::StorageWriteFailed { .. } => "docker.error.storage.write_failed",
422            DockerErrorKind::StorageDeleteFailed { .. } => "docker.error.storage.delete_failed",
423            DockerErrorKind::InsufficientCapacity { .. } => {
424                "docker.error.storage.insufficient_capacity"
425            }
426            DockerErrorKind::StorageFileNotFound { .. } => "docker.error.storage.file_not_found",
427
428            DockerErrorKind::ConfigMissing { .. } => "docker.error.config.missing",
429            DockerErrorKind::ConfigInvalid { .. } => "docker.error.config.invalid",
430
431            DockerErrorKind::InternalError { .. } => "docker.error.internal.error",
432            DockerErrorKind::NotImplemented { .. } => "docker.error.internal.not_implemented",
433            DockerErrorKind::IoError { .. } => "docker.error.internal.io_error",
434            DockerErrorKind::JsonError { .. } => "docker.error.internal.json_error",
435            DockerErrorKind::ParseError { .. } => "docker.error.internal.parse_error",
436            DockerErrorKind::RequestError { .. } => "docker.error.internal.request_error",
437
438            DockerErrorKind::ContainerError { .. } => "docker.error.container.error",
439            DockerErrorKind::ImageError { .. } => "docker.error.image.error",
440            DockerErrorKind::NetworkError { .. } => "docker.error.network.error",
441            DockerErrorKind::RuntimeError { .. } => "docker.error.runtime.error",
442            DockerErrorKind::RegistryError { .. } => "docker.error.registry.error",
443            DockerErrorKind::EtcdError { .. } => "docker.error.etcd.error",
444            DockerErrorKind::MonitorError { .. } => "docker.error.monitor.error",
445            DockerErrorKind::KubernetesError { .. } => "docker.error.kubernetes.error",
446        }
447    }
448
449    /// 获取国际化数据
450    pub fn i18n_data(&self) -> Value {
451        match self {
452            DockerErrorKind::InvalidFormat { field, expected } => {
453                json!({ "field": field, "expected": expected })
454            }
455            DockerErrorKind::OutOfRange { field, min, max } => {
456                json!({ "field": field, "min": min, "max": max })
457            }
458            DockerErrorKind::Required { field } => json!({ "field": field }),
459            DockerErrorKind::AlreadyExists { field, value } => {
460                json!({ "field": field, "value": value })
461            }
462            DockerErrorKind::NotAllowed { field, allowed } => {
463                json!({ "field": field, "allowed": allowed })
464            }
465            DockerErrorKind::InvalidParams { param, reason } => {
466                json!({ "param": param, "reason": reason })
467            }
468
469            DockerErrorKind::InvalidCredentials => json!({}),
470            DockerErrorKind::AccountLocked => json!({}),
471            DockerErrorKind::UserNotFound { identifier } => json!({ "identifier": identifier }),
472            DockerErrorKind::UserAlreadyExists { username } => json!({ "username": username }),
473            DockerErrorKind::InvalidToken { reason } => json!({ "reason": reason }),
474            DockerErrorKind::TokenExpired => json!({}),
475
476            DockerErrorKind::PermissionDenied { action } => json!({ "action": action }),
477            DockerErrorKind::Forbidden { resource } => json!({ "resource": resource }),
478
479            DockerErrorKind::ResourceNotFound {
480                resource_type,
481                identifier,
482            } => {
483                json!({ "resource_type": resource_type, "identifier": identifier })
484            }
485
486            DockerErrorKind::ResourceConflict { resource, reason } => {
487                json!({ "resource": resource, "reason": reason })
488            }
489
490            DockerErrorKind::RateLimited { limit } => json!({ "limit": limit }),
491
492            DockerErrorKind::ConnectionFailed { target } => json!({ "target": target }),
493            DockerErrorKind::DnsResolutionFailed { host } => json!({ "host": host }),
494            DockerErrorKind::ServiceUnavailable { service } => json!({ "service": service }),
495
496            DockerErrorKind::StorageReadFailed { path } => json!({ "path": path }),
497            DockerErrorKind::StorageWriteFailed { path } => json!({ "path": path }),
498            DockerErrorKind::StorageDeleteFailed { path } => json!({ "path": path }),
499            DockerErrorKind::InsufficientCapacity {
500                required,
501                available,
502            } => {
503                json!({ "required": required, "available": available })
504            }
505            DockerErrorKind::StorageFileNotFound { path } => json!({ "path": path }),
506
507            DockerErrorKind::ConfigMissing { key } => json!({ "key": key }),
508            DockerErrorKind::ConfigInvalid { key, reason } => {
509                json!({ "key": key, "reason": reason })
510            }
511
512            DockerErrorKind::InternalError { reason } => json!({ "reason": reason }),
513            DockerErrorKind::NotImplemented { feature } => json!({ "feature": feature }),
514            DockerErrorKind::IoError { operation, reason } => {
515                json!({ "operation": operation, "reason": reason })
516            }
517            DockerErrorKind::JsonError { reason } => json!({ "reason": reason }),
518            DockerErrorKind::ParseError { type_name, reason } => {
519                json!({ "type": type_name, "reason": reason })
520            }
521            DockerErrorKind::RequestError { url, reason } => {
522                json!({ "url": url, "reason": reason })
523            }
524
525            DockerErrorKind::ContainerError { reason } => json!({ "reason": reason }),
526            DockerErrorKind::ImageError { reason } => json!({ "reason": reason }),
527            DockerErrorKind::NetworkError { reason } => json!({ "reason": reason }),
528            DockerErrorKind::RuntimeError { reason } => json!({ "reason": reason }),
529            DockerErrorKind::RegistryError { reason } => json!({ "reason": reason }),
530            DockerErrorKind::EtcdError { reason } => json!({ "reason": reason }),
531            DockerErrorKind::MonitorError { reason } => json!({ "reason": reason }),
532            DockerErrorKind::KubernetesError { reason } => json!({ "reason": reason }),
533        }
534    }
535}
536
537impl fmt::Display for DockerErrorKind {
538    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
539        write!(f, "{}", self.i18n_key())
540    }
541}
542
543impl DockerError {
544    /// 创建新的错误
545    pub fn new(kind: DockerErrorKind) -> Self {
546        Self {
547            kind: Box::new(kind),
548        }
549    }
550
551    /// 获取国际化键
552    pub fn i18n_key(&self) -> &'static str {
553        self.kind.i18n_key()
554    }
555
556    /// 获取国际化数据
557    pub fn i18n_data(&self) -> Value {
558        self.kind.i18n_data()
559    }
560
561    /// 获取错误分类
562    pub fn category(&self) -> ErrorCategory {
563        self.kind.category()
564    }
565
566    /// 获取 HTTP 状态码
567    pub fn http_status(&self) -> u16 {
568        self.category().http_status()
569    }
570
571    // ========== 验证错误便捷方法 ==========
572
573    /// 创建无效格式错误
574    pub fn invalid_format(field: impl Into<String>, expected: impl Into<String>) -> Self {
575        Self::new(DockerErrorKind::InvalidFormat {
576            field: field.into(),
577            expected: expected.into(),
578        })
579    }
580
581    /// 创建超出范围错误
582    pub fn out_of_range(
583        field: impl Into<String>,
584        min: Option<String>,
585        max: Option<String>,
586    ) -> Self {
587        Self::new(DockerErrorKind::OutOfRange {
588            field: field.into(),
589            min,
590            max,
591        })
592    }
593
594    /// 创建必填字段缺失错误
595    pub fn required(field: impl Into<String>) -> Self {
596        Self::new(DockerErrorKind::Required {
597            field: field.into(),
598        })
599    }
600
601    /// 创建已存在错误
602    pub fn already_exists(field: impl Into<String>, value: impl Into<String>) -> Self {
603        Self::new(DockerErrorKind::AlreadyExists {
604            field: field.into(),
605            value: value.into(),
606        })
607    }
608
609    /// 创建不允许错误
610    pub fn not_allowed(field: impl Into<String>, allowed: Vec<String>) -> Self {
611        Self::new(DockerErrorKind::NotAllowed {
612            field: field.into(),
613            allowed,
614        })
615    }
616
617    /// 创建无效参数错误
618    pub fn invalid_params(param: impl Into<String>, reason: impl Into<String>) -> Self {
619        Self::new(DockerErrorKind::InvalidParams {
620            param: param.into(),
621            reason: reason.into(),
622        })
623    }
624
625    // ========== 认证错误便捷方法 ==========
626
627    /// 创建无效凭证错误
628    pub fn invalid_credentials() -> Self {
629        Self::new(DockerErrorKind::InvalidCredentials)
630    }
631
632    /// 创建账户已锁定错误
633    pub fn account_locked() -> Self {
634        Self::new(DockerErrorKind::AccountLocked)
635    }
636
637    /// 创建用户未找到错误
638    pub fn user_not_found(identifier: impl Into<String>) -> Self {
639        Self::new(DockerErrorKind::UserNotFound {
640            identifier: identifier.into(),
641        })
642    }
643
644    /// 创建用户已存在错误
645    pub fn user_already_exists(username: impl Into<String>) -> Self {
646        Self::new(DockerErrorKind::UserAlreadyExists {
647            username: username.into(),
648        })
649    }
650
651    /// 创建无效令牌错误
652    pub fn invalid_token(reason: impl Into<String>) -> Self {
653        Self::new(DockerErrorKind::InvalidToken {
654            reason: reason.into(),
655        })
656    }
657
658    /// 创建令牌过期错误
659    pub fn token_expired() -> Self {
660        Self::new(DockerErrorKind::TokenExpired)
661    }
662
663    // ========== 权限错误便捷方法 ==========
664
665    /// 创建权限拒绝错误
666    pub fn permission_denied(action: impl Into<String>) -> Self {
667        Self::new(DockerErrorKind::PermissionDenied {
668            action: action.into(),
669        })
670    }
671
672    /// 创建禁止访问错误
673    pub fn forbidden(resource: impl Into<String>) -> Self {
674        Self::new(DockerErrorKind::Forbidden {
675            resource: resource.into(),
676        })
677    }
678
679    // ========== 资源未找到便捷方法 ==========
680
681    /// 创建资源未找到错误
682    pub fn not_found(resource_type: impl Into<String>, identifier: impl Into<String>) -> Self {
683        Self::new(DockerErrorKind::ResourceNotFound {
684            resource_type: resource_type.into(),
685            identifier: identifier.into(),
686        })
687    }
688
689    // ========== 网络错误便捷方法 ==========
690
691    /// 创建连接失败错误
692    pub fn connection_failed(target: impl Into<String>) -> Self {
693        Self::new(DockerErrorKind::ConnectionFailed {
694            target: target.into(),
695        })
696    }
697
698    /// 创建服务不可用错误
699    pub fn service_unavailable(service: impl Into<String>) -> Self {
700        Self::new(DockerErrorKind::ServiceUnavailable {
701            service: service.into(),
702        })
703    }
704
705    // ========== 存储错误便捷方法 ==========
706
707    /// 创建存储读取失败错误
708    pub fn storage_read_failed(path: impl Into<String>) -> Self {
709        Self::new(DockerErrorKind::StorageReadFailed { path: path.into() })
710    }
711
712    /// 创建存储写入失败错误
713    pub fn storage_write_failed(path: impl Into<String>) -> Self {
714        Self::new(DockerErrorKind::StorageWriteFailed { path: path.into() })
715    }
716
717    /// 创建存储文件未找到错误
718    pub fn storage_file_not_found(path: impl Into<String>) -> Self {
719        Self::new(DockerErrorKind::StorageFileNotFound { path: path.into() })
720    }
721
722    // ========== 配置错误便捷方法 ==========
723
724    /// 创建配置缺失错误
725    pub fn config_missing(key: impl Into<String>) -> Self {
726        Self::new(DockerErrorKind::ConfigMissing { key: key.into() })
727    }
728
729    /// 创建配置无效错误
730    pub fn config_invalid(key: impl Into<String>, reason: impl Into<String>) -> Self {
731        Self::new(DockerErrorKind::ConfigInvalid {
732            key: key.into(),
733            reason: reason.into(),
734        })
735    }
736
737    // ========== 内部错误便捷方法 ==========
738
739    /// 创建内部错误
740    pub fn internal(reason: impl Into<String>) -> Self {
741        Self::new(DockerErrorKind::InternalError {
742            reason: reason.into(),
743        })
744    }
745
746    /// 创建未实现错误
747    pub fn not_implemented(feature: impl Into<String>) -> Self {
748        Self::new(DockerErrorKind::NotImplemented {
749            feature: feature.into(),
750        })
751    }
752
753    /// 创建 IO 错误
754    pub fn io_error(operation: impl Into<String>, reason: impl Into<String>) -> Self {
755        Self::new(DockerErrorKind::IoError {
756            operation: operation.into(),
757            reason: reason.into(),
758        })
759    }
760
761    /// 创建 JSON 错误
762    pub fn json_error(reason: impl Into<String>) -> Self {
763        Self::new(DockerErrorKind::JsonError {
764            reason: reason.into(),
765        })
766    }
767
768    /// 创建解析错误
769    pub fn parse_error(type_name: impl Into<String>, reason: impl Into<String>) -> Self {
770        Self::new(DockerErrorKind::ParseError {
771            type_name: type_name.into(),
772            reason: reason.into(),
773        })
774    }
775
776    /// 创建请求错误
777    pub fn request_error(url: impl Into<String>, reason: impl Into<String>) -> Self {
778        Self::new(DockerErrorKind::RequestError {
779            url: url.into(),
780            reason: reason.into(),
781        })
782    }
783
784    // ========== Docker 特定错误便捷方法 ==========
785
786    /// 创建容器错误
787    pub fn container_error(reason: impl Into<String>) -> Self {
788        Self::new(DockerErrorKind::ContainerError {
789            reason: reason.into(),
790        })
791    }
792
793    /// 创建镜像错误
794    pub fn image_error(reason: impl Into<String>) -> Self {
795        Self::new(DockerErrorKind::ImageError {
796            reason: reason.into(),
797        })
798    }
799
800    /// 创建网络错误
801    pub fn network_error(reason: impl Into<String>) -> Self {
802        Self::new(DockerErrorKind::NetworkError {
803            reason: reason.into(),
804        })
805    }
806
807    /// 创建运行时错误
808    pub fn runtime_error(reason: impl Into<String>) -> Self {
809        Self::new(DockerErrorKind::RuntimeError {
810            reason: reason.into(),
811        })
812    }
813
814    /// 创建注册表错误
815    pub fn registry_error(reason: impl Into<String>) -> Self {
816        Self::new(DockerErrorKind::RegistryError {
817            reason: reason.into(),
818        })
819    }
820
821    /// 创建 Etcd 错误
822    pub fn etcd_error(reason: impl Into<String>) -> Self {
823        Self::new(DockerErrorKind::EtcdError {
824            reason: reason.into(),
825        })
826    }
827
828    /// 创建监控错误
829    pub fn monitor_error(reason: impl Into<String>) -> Self {
830        Self::new(DockerErrorKind::MonitorError {
831            reason: reason.into(),
832        })
833    }
834
835    /// 创建 Kubernetes 错误
836    pub fn kubernetes_error(reason: impl Into<String>) -> Self {
837        Self::new(DockerErrorKind::KubernetesError {
838            reason: reason.into(),
839        })
840    }
841}
842
843impl fmt::Display for DockerError {
844    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
845        write!(f, "{:?}: {}", self.kind.category(), self.kind.i18n_key())
846    }
847}
848
849impl std::error::Error for DockerError {}
850
851impl From<std::io::Error> for DockerError {
852    fn from(err: std::io::Error) -> Self {
853        Self::io_error("unknown", err.to_string())
854    }
855}
856
857impl From<serde_json::Error> for DockerError {
858    fn from(err: serde_json::Error) -> Self {
859        Self::json_error(err.to_string())
860    }
861}
862
863/// 向后兼容:RustyDockerError 类型别名
864#[deprecated(note = "请使用 DockerError 替代")]
865pub type RustyDockerError = DockerError;