tact_client/
error.rs

1//! Error types for TACT client
2
3use thiserror::Error;
4
5#[derive(Error, Debug)]
6pub enum Error {
7    // Network errors
8    #[error("HTTP request failed: {0}")]
9    Http(#[from] reqwest::Error),
10
11    #[error("All CDN hosts exhausted for {resource}")]
12    CdnExhausted { resource: String },
13
14    #[error("Connection timeout to {host}")]
15    ConnectionTimeout { host: String },
16
17    // Data format errors
18    #[error("BPSV parse error: {0}")]
19    Bpsv(#[from] ngdp_bpsv::Error),
20
21    #[error("JSON serialization/deserialization error: {0}")]
22    Json(#[from] serde_json::Error),
23
24    #[error("Invalid manifest format at line {line}: {reason}")]
25    InvalidManifest { line: usize, reason: String },
26
27    #[error("Missing required field: {field}")]
28    MissingField { field: &'static str },
29
30    #[error("Invalid hash format: {hash}")]
31    InvalidHash { hash: String },
32
33    #[error("Checksum verification failed: expected {expected}, got {actual}")]
34    ChecksumMismatch { expected: String, actual: String },
35
36    #[error("Invalid response format")]
37    InvalidResponse,
38
39    // Configuration errors
40    #[error("Invalid region: {0}")]
41    InvalidRegion(String),
42
43    #[error("Product not supported: {0}")]
44    UnsupportedProduct(String),
45
46    #[error("Invalid protocol version")]
47    InvalidProtocolVersion,
48
49    // File errors
50    #[error("File not found: {path}")]
51    FileNotFound { path: String },
52
53    #[error("IO error: {0}")]
54    Io(#[from] std::io::Error),
55}
56
57// Helper methods for common error construction
58impl Error {
59    /// Create an invalid manifest error with line number and reason
60    pub fn invalid_manifest(line: usize, reason: impl Into<String>) -> Self {
61        Self::InvalidManifest {
62            line,
63            reason: reason.into(),
64        }
65    }
66
67    /// Create a missing field error
68    pub fn missing_field(field: &'static str) -> Self {
69        Self::MissingField { field }
70    }
71
72    /// Create a CDN exhausted error
73    pub fn cdn_exhausted(resource: impl Into<String>) -> Self {
74        Self::CdnExhausted {
75            resource: resource.into(),
76        }
77    }
78
79    /// Create a file not found error
80    pub fn file_not_found(path: impl Into<String>) -> Self {
81        Self::FileNotFound { path: path.into() }
82    }
83
84    /// Create an invalid hash error
85    pub fn invalid_hash(hash: impl Into<String>) -> Self {
86        Self::InvalidHash { hash: hash.into() }
87    }
88
89    /// Create a checksum mismatch error
90    pub fn checksum_mismatch(expected: impl Into<String>, actual: impl Into<String>) -> Self {
91        Self::ChecksumMismatch {
92            expected: expected.into(),
93            actual: actual.into(),
94        }
95    }
96}
97
98pub type Result<T> = std::result::Result<T, Error>;