tencentcloud_sms/
error.rs1use crate::api::send_sms::response::SendStatus;
2use std::time::Duration;
3use thiserror::Error;
4
5#[derive(Debug, Error)]
6pub enum SmsError {
7 #[error("HTTP请求失败: {0}")]
8 Http(#[from] reqwest::Error),
9
10 #[error("JSON序列化失败: {0}")]
11 Serialization(#[from] serde_json::Error),
12
13 #[error("认证失败 [{code}]: {message} (request_id: {request_id})")]
14 Authentication {
15 code: String,
16 message: String,
17 request_id: String,
18 },
19
20 #[error("参数错误 [{code}]: {message} (request_id: {request_id})")]
21 InvalidParameter {
22 code: String,
23 message: String,
24 request_id: String,
25 },
26
27 #[error(
28 "频率限制 [{code}]: {message}, 建议重试延迟: {retry_after:?} (request_id: {request_id})"
29 )]
30 RateLimited {
31 code: String,
32 message: String,
33 retry_after: Option<Duration>,
34 request_id: String,
35 },
36
37 #[error("余额不足: {message} (request_id: {request_id})")]
38 InsufficientBalance {
39 code: String,
40 message: String,
41 request_id: String,
42 },
43
44 #[error("业务错误 [{code}]: {message} (request_id: {request_id})")]
45 Business {
46 code: String,
47 message: String,
48 request_id: String,
49 },
50
51 #[error("内部错误 [{code}]: {message} (request_id: {request_id})")]
52 Internal {
53 code: String,
54 message: String,
55 request_id: String,
56 },
57
58 #[error("部分号码发送失败: 成功 {} 个, 失败 {} 个", succeeded.len(), failed.len())]
59 PartialFailure {
60 succeeded: Vec<SendStatus>,
61 failed: Vec<SendStatus>,
62 },
63
64 #[error("配置错误: {0}")]
65 Configuration(String),
66
67 #[error("API 响应异常: {0}")]
68 UnexpectedResponse(String),
69}
70
71impl SmsError {
72 pub fn is_retryable(&self) -> bool {
74 matches!(
75 self,
76 Self::Http(_) | Self::RateLimited { .. } | Self::Internal { .. }
77 )
78 }
79
80 pub fn retry_after(&self) -> Option<Duration> {
82 match self {
83 Self::RateLimited { retry_after, .. } => *retry_after,
84 Self::Internal { .. } => Some(Duration::from_millis(100)),
85 _ => None,
86 }
87 }
88
89 pub fn request_id(&self) -> Option<&str> {
91 match self {
92 Self::Authentication { request_id, .. }
93 | Self::InvalidParameter { request_id, .. }
94 | Self::RateLimited { request_id, .. }
95 | Self::InsufficientBalance { request_id, .. }
96 | Self::Business { request_id, .. }
97 | Self::Internal { request_id, .. } => Some(request_id),
98 _ => None,
99 }
100 }
101
102 pub fn is_partial_failure(&self) -> bool {
117 matches!(self, Self::PartialFailure { .. })
118 }
119
120 pub fn partial_results(&self) -> Option<(&[SendStatus], &[SendStatus])> {
136 match self {
137 Self::PartialFailure { succeeded, failed } => Some((succeeded, failed)),
138 _ => None,
139 }
140 }
141
142 pub fn into_partial_results(self) -> Option<(Vec<SendStatus>, Vec<SendStatus>)> {
159 match self {
160 Self::PartialFailure { succeeded, failed } => Some((succeeded, failed)),
161 _ => None,
162 }
163 }
164}
165
166pub type SmsResult<T> = Result<T, SmsError>;