1use serde::Deserialize;
3use std::error::Error;
4use std::fmt;
5
6#[derive(Debug, Clone, Eq, PartialEq, Deserialize)]
8pub struct ApiError {
9 pub message: String,
10 #[serde(rename = "type")]
11 pub error_type: String,
12 pub param: Option<String>,
14 pub code: Option<String>,
16}
17
18#[derive(Debug, Clone, Eq, PartialEq, Deserialize)]
20pub(crate) struct ApiErrorEnvelope {
21 pub error: ApiError,
22}
23
24#[derive(Debug, Clone, Eq, PartialEq)]
26pub enum ReqwestErrorKind {
27 Decode,
28 Timeout,
29 Connect,
30 Request,
31 Body,
32 Status,
33}
34
35impl ReqwestErrorKind {
36 fn as_str(&self) -> &'static str {
37 match self {
38 ReqwestErrorKind::Decode => "decode",
39 ReqwestErrorKind::Timeout => "timeout",
40 ReqwestErrorKind::Connect => "connect",
41 ReqwestErrorKind::Request => "request",
42 ReqwestErrorKind::Body => "body",
43 ReqwestErrorKind::Status => "status",
44 }
45 }
46}
47
48#[derive(Debug)]
50pub struct TransportError {
51 pub source: reqwest::Error,
52 pub kind: Option<ReqwestErrorKind>,
53}
54
55#[derive(Debug)]
57pub enum DeepSeekError {
58 Api {
60 error: ApiError,
61 status: Option<u16>,
62 body: Option<String>,
63 },
64 Http { status: u16, body: Option<String> },
66 Decode {
68 message: String,
69 body: Option<String>,
70 },
71 Transport(TransportError),
73}
74
75impl DeepSeekError {
76 pub(crate) fn api(error: ApiError, status: Option<u16>, body: Option<String>) -> Self {
77 DeepSeekError::Api {
78 error,
79 status,
80 body,
81 }
82 }
83
84 pub(crate) fn http(status: u16, body: String) -> Self {
85 DeepSeekError::Http {
86 status,
87 body: Some(body),
88 }
89 }
90
91 pub(crate) fn decode(message: String, body: String) -> Self {
92 DeepSeekError::Decode {
93 message,
94 body: Some(body),
95 }
96 }
97}
98
99impl fmt::Display for DeepSeekError {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 match self {
102 DeepSeekError::Api { error, status, .. } => write!(
103 f,
104 "DeepSeek API error: {} (type={}, param={:?}, code={:?}, status={:?})",
105 error.message, error.error_type, error.param, error.code, status
106 ),
107 DeepSeekError::Http { status, body } => {
108 write!(f, "HTTP error: status={}, body={:?}", status, body)
109 }
110 DeepSeekError::Decode { message, body } => {
111 write!(f, "Decode error: {} (body={:?})", message, body)
112 }
113 DeepSeekError::Transport(transport) => {
114 if let Some(kind) = &transport.kind {
115 write!(f, "reqwest {} error: {}", kind.as_str(), transport.source)
116 } else {
117 write!(f, "reqwest error: {}", transport.source)
118 }
119 }
120 }
121 }
122}
123
124impl Error for DeepSeekError {
125 fn source(&self) -> Option<&(dyn Error + 'static)> {
126 match self {
127 DeepSeekError::Transport(transport) => Some(&transport.source),
128 _ => None,
129 }
130 }
131}
132
133impl From<reqwest::Error> for DeepSeekError {
134 fn from(value: reqwest::Error) -> Self {
135 let kind = if value.is_decode() {
136 Some(ReqwestErrorKind::Decode)
137 } else if value.is_timeout() {
138 Some(ReqwestErrorKind::Timeout)
139 } else if value.is_connect() {
140 Some(ReqwestErrorKind::Connect)
141 } else if value.is_request() {
142 Some(ReqwestErrorKind::Request)
143 } else if value.is_body() {
144 Some(ReqwestErrorKind::Body)
145 } else if value.is_status() {
146 Some(ReqwestErrorKind::Status)
147 } else {
148 None
149 };
150
151 DeepSeekError::Transport(TransportError {
152 source: value,
153 kind,
154 })
155 }
156}