kiteconnect_async_wasm/models/common/
errors.rs1use thiserror::Error;
8
9#[derive(Debug, Error)]
11pub enum KiteError {
12 #[error("HTTP request failed: {0}")]
14 Http(#[from] reqwest::Error),
15
16 #[error("JSON parsing failed: {0}")]
18 Json(#[from] serde_json::Error),
19
20 #[error("Token exception: {0}")]
24 TokenException(String),
25
26 #[error("User exception: {0}")]
28 UserException(String),
29
30 #[error("Order exception: {0}")]
32 OrderException(String),
33
34 #[error("Input exception: {0}")]
36 InputException(String),
37
38 #[error("Margin exception: {0}")]
40 MarginException(String),
41
42 #[error("Holding exception: {0}")]
44 HoldingException(String),
45
46 #[error("Network exception: {0}")]
48 NetworkException(String),
49
50 #[error("Data exception: {0}")]
52 DataException(String),
53
54 #[error("General exception: {0}")]
56 GeneralException(String),
57
58 #[error("API error: {status} - {message}")]
61 Api {
62 status: String,
63 message: String,
64 error_type: Option<String>,
65 },
66
67 #[error("Authentication failed: {0}")]
69 Authentication(String),
70
71 #[error("Invalid parameter: {0}")]
73 InvalidParameter(String),
74
75 #[cfg(feature = "native")]
77 #[error("CSV parsing failed: {0}")]
78 CsvParsing(#[from] csv::Error),
79
80 #[error("Date/time parsing failed: {0}")]
82 DateTimeParsing(#[from] chrono::ParseError),
83
84 #[error("URL parsing failed: {0}")]
86 UrlParsing(#[from] url::ParseError),
87
88 #[error("KiteConnect error: {0}")]
90 General(String),
91
92 #[error("Legacy error: {0}")]
94 Legacy(#[from] anyhow::Error),
95}
96
97pub type KiteResult<T> = Result<T, KiteError>;
99
100impl KiteError {
101 pub fn from_api_response(
104 status_code: u16,
105 status: impl Into<String>,
106 message: impl Into<String>,
107 error_type: Option<String>,
108 ) -> Self {
109 let message = message.into();
110
111 if let Some(error_type) = error_type.as_ref() {
113 return match error_type.as_str() {
114 "TokenException" => Self::TokenException(message),
115 "UserException" => Self::UserException(message),
116 "OrderException" => Self::OrderException(message),
117 "InputException" => Self::InputException(message),
118 "MarginException" => Self::MarginException(message),
119 "HoldingException" => Self::HoldingException(message),
120 "NetworkException" => Self::NetworkException(message),
121 "DataException" => Self::DataException(message),
122 "GeneralException" => Self::GeneralException(message),
123 _ => Self::Api {
124 status: status.into(),
125 message,
126 error_type: Some(error_type.clone()),
127 },
128 };
129 }
130
131 match status_code {
133 400 => Self::InputException(message), 403 => Self::TokenException(message), 404 => Self::Api {
136 status: status.into(),
137 message,
138 error_type: Some("ResourceNotFound".to_string()), },
140 405 => Self::Api {
141 status: status.into(),
142 message,
143 error_type: Some("MethodNotAllowed".to_string()), },
145 410 => Self::Api {
146 status: status.into(),
147 message,
148 error_type: Some("ResourceGone".to_string()), },
150 429 => Self::Api {
151 status: status.into(),
152 message,
153 error_type: Some("RateLimited".to_string()), },
155 500 => Self::GeneralException(message), 502 => Self::NetworkException(message), 503 => Self::NetworkException(message), 504 => Self::NetworkException(message), _ => Self::Api {
160 status: status.into(),
161 message,
162 error_type,
163 },
164 }
165 }
166
167 pub fn api_error(status: impl Into<String>, message: impl Into<String>) -> Self {
169 Self::Api {
170 status: status.into(),
171 message: message.into(),
172 error_type: None,
173 }
174 }
175
176 pub fn api_error_with_type(
178 status: impl Into<String>,
179 message: impl Into<String>,
180 error_type: impl Into<String>,
181 ) -> Self {
182 Self::Api {
183 status: status.into(),
184 message: message.into(),
185 error_type: Some(error_type.into()),
186 }
187 }
188
189 pub fn auth_error(message: impl Into<String>) -> Self {
191 Self::Authentication(message.into())
192 }
193
194 pub fn invalid_param(message: impl Into<String>) -> Self {
196 Self::InvalidParameter(message.into())
197 }
198
199 pub fn general(message: impl Into<String>) -> Self {
201 Self::General(message.into())
202 }
203
204 pub fn token_exception(message: impl Into<String>) -> Self {
208 Self::TokenException(message.into())
209 }
210
211 pub fn user_exception(message: impl Into<String>) -> Self {
213 Self::UserException(message.into())
214 }
215
216 pub fn order_exception(message: impl Into<String>) -> Self {
218 Self::OrderException(message.into())
219 }
220
221 pub fn input_exception(message: impl Into<String>) -> Self {
223 Self::InputException(message.into())
224 }
225
226 pub fn margin_exception(message: impl Into<String>) -> Self {
228 Self::MarginException(message.into())
229 }
230
231 pub fn holding_exception(message: impl Into<String>) -> Self {
233 Self::HoldingException(message.into())
234 }
235
236 pub fn network_exception(message: impl Into<String>) -> Self {
238 Self::NetworkException(message.into())
239 }
240
241 pub fn data_exception(message: impl Into<String>) -> Self {
243 Self::DataException(message.into())
244 }
245
246 pub fn general_exception(message: impl Into<String>) -> Self {
248 Self::GeneralException(message.into())
249 }
250
251 pub fn requires_reauth(&self) -> bool {
253 matches!(self, Self::TokenException(_) | Self::Authentication(_))
254 }
255
256 pub fn is_client_error(&self) -> bool {
258 match self {
259 Self::TokenException(_) | Self::InputException(_) | Self::InvalidParameter(_) => true,
260 Self::Api { status, .. } => status.starts_with('4'),
261 _ => false,
262 }
263 }
264
265 pub fn is_server_error(&self) -> bool {
267 match self {
268 Self::NetworkException(_) | Self::DataException(_) | Self::GeneralException(_) => true,
269 Self::Api { status, .. } => status.starts_with('5'),
270 _ => false,
271 }
272 }
273
274 pub fn is_retryable(&self) -> bool {
276 match self {
277 Self::NetworkException(_) | Self::Http(_) => true, Self::Api { status, .. } => matches!(status.as_str(), "429"), _ => false,
280 }
281 }
282}