1use std::fmt;
28
29use serde::de::Deserializer;
30use serde::ser::Serializer;
31use serde::{Deserialize, Serialize};
32use serde_json::value::RawValue;
33use std::borrow::{Borrow, Cow as StdCow};
34use thiserror::Error;
35
36pub type ErrorObjectOwned = ErrorObject<'static>;
38
39#[derive(Debug, Deserialize, Serialize, Clone, thiserror::Error)]
41#[serde(deny_unknown_fields)]
42#[error("{self:?}")]
43pub struct ErrorObject<'a> {
44 code: ErrorCode,
46 message: StdCow<'a, str>,
48 #[serde(skip_serializing_if = "Option::is_none")]
50 data: Option<StdCow<'a, RawValue>>,
51}
52
53impl<'a> ErrorObject<'a> {
54 pub fn code(&self) -> i32 {
56 self.code.code()
57 }
58
59 pub fn message(&self) -> &str {
61 self.message.borrow()
62 }
63
64 pub fn data(&self) -> Option<&RawValue> {
66 self.data.as_ref().map(|d| d.borrow())
67 }
68
69 pub fn owned<S: Serialize>(code: i32, message: impl Into<String>, data: Option<S>) -> ErrorObject<'static> {
71 let data = data.and_then(|d| serde_json::value::to_raw_value(&d).ok());
72 ErrorObject { code: code.into(), message: message.into().into(), data: data.map(StdCow::Owned) }
73 }
74
75 pub fn borrowed(code: i32, message: &'a str, data: Option<&'a RawValue>) -> ErrorObject<'a> {
77 ErrorObject { code: code.into(), message: StdCow::Borrowed(message), data: data.map(StdCow::Borrowed) }
78 }
79
80 pub fn into_owned(self) -> ErrorObject<'static> {
82 ErrorObject {
83 code: self.code,
84 message: StdCow::Owned(self.message.into_owned()),
85 data: self.data.map(|d| StdCow::Owned(d.into_owned())),
86 }
87 }
88
89 pub fn borrow(&'a self) -> ErrorObject<'a> {
91 ErrorObject {
92 code: self.code,
93 message: StdCow::Borrowed(self.message.borrow()),
94 data: self.data.as_ref().map(|d| StdCow::Borrowed(d.borrow())),
95 }
96 }
97}
98
99impl<'a> PartialEq for ErrorObject<'a> {
100 fn eq(&self, other: &Self) -> bool {
101 let this_raw = self.data.as_ref().map(|r| r.get());
102 let other_raw = other.data.as_ref().map(|r| r.get());
103 self.code == other.code && self.message == other.message && this_raw == other_raw
104 }
105}
106
107impl<'a> From<ErrorCode> for ErrorObject<'a> {
108 fn from(code: ErrorCode) -> Self {
109 Self { code, message: code.message().into(), data: None }
110 }
111}
112
113pub const PARSE_ERROR_CODE: i32 = -32700;
115pub const INVALID_REQUEST_CODE: i32 = -32600;
117pub const METHOD_NOT_FOUND_CODE: i32 = -32601;
119pub const INVALID_PARAMS_CODE: i32 = -32602;
121pub const INTERNAL_ERROR_CODE: i32 = -32603;
123pub const CALL_EXECUTION_FAILED_CODE: i32 = -32000;
125pub const UNKNOWN_ERROR_CODE: i32 = -32001;
127pub const BATCHES_NOT_SUPPORTED_CODE: i32 = -32005;
129pub const TOO_MANY_SUBSCRIPTIONS_CODE: i32 = -32006;
131pub const OVERSIZED_REQUEST_CODE: i32 = -32007;
133pub const OVERSIZED_RESPONSE_CODE: i32 = -32008;
135pub const SERVER_IS_BUSY_CODE: i32 = -32009;
137pub const TOO_BIG_BATCH_REQUEST_CODE: i32 = -32010;
139pub const TOO_BIG_BATCH_RESPONSE_CODE: i32 = -32011;
141
142pub const PARSE_ERROR_MSG: &str = "Parse error";
144pub const OVERSIZED_REQUEST_MSG: &str = "Request is too big";
146pub const OVERSIZED_RESPONSE_MSG: &str = "Response is too big";
148pub const INTERNAL_ERROR_MSG: &str = "Internal error";
150pub const INVALID_PARAMS_MSG: &str = "Invalid params";
152pub const INVALID_REQUEST_MSG: &str = "Invalid request";
154pub const METHOD_NOT_FOUND_MSG: &str = "Method not found";
156pub const SERVER_IS_BUSY_MSG: &str = "Server is busy, try again later";
158pub const SERVER_ERROR_MSG: &str = "Server error";
160pub const BATCHES_NOT_SUPPORTED_MSG: &str = "Batched requests are not supported by this server";
162pub const TOO_MANY_SUBSCRIPTIONS_MSG: &str = "Too many subscriptions on the connection";
164pub const TOO_BIG_BATCH_REQUEST_MSG: &str = "The batch request was too large";
166pub const TOO_BIG_BATCH_RESPONSE_MSG: &str = "The batch response was too large";
168
169#[derive(Error, Debug, PartialEq, Eq, Copy, Clone)]
171pub enum ErrorCode {
172 ParseError,
175 OversizedRequest,
177 InvalidRequest,
179 MethodNotFound,
181 ServerIsBusy,
183 InvalidParams,
185 InternalError,
187 ServerError(i32),
189}
190
191impl ErrorCode {
192 pub const fn code(&self) -> i32 {
194 use ErrorCode::*;
195 match *self {
196 ParseError => PARSE_ERROR_CODE,
197 OversizedRequest => OVERSIZED_REQUEST_CODE,
198 InvalidRequest => INVALID_REQUEST_CODE,
199 MethodNotFound => METHOD_NOT_FOUND_CODE,
200 ServerIsBusy => SERVER_IS_BUSY_CODE,
201 InvalidParams => INVALID_PARAMS_CODE,
202 InternalError => INTERNAL_ERROR_CODE,
203 ServerError(code) => code,
204 }
205 }
206
207 pub const fn message(&self) -> &'static str {
209 use ErrorCode::*;
210 match self {
211 ParseError => PARSE_ERROR_MSG,
212 OversizedRequest => OVERSIZED_REQUEST_MSG,
213 InvalidRequest => INVALID_REQUEST_MSG,
214 MethodNotFound => METHOD_NOT_FOUND_MSG,
215 ServerIsBusy => SERVER_IS_BUSY_MSG,
216 InvalidParams => INVALID_PARAMS_MSG,
217 InternalError => INTERNAL_ERROR_MSG,
218 ServerError(_) => SERVER_ERROR_MSG,
219 }
220 }
221}
222
223impl fmt::Display for ErrorCode {
224 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
225 write!(f, "{}: {}", self.code(), self.message())
226 }
227}
228
229impl From<i32> for ErrorCode {
230 fn from(code: i32) -> Self {
231 use ErrorCode::*;
232 match code {
233 PARSE_ERROR_CODE => ParseError,
234 OVERSIZED_REQUEST_CODE => OversizedRequest,
235 INVALID_REQUEST_CODE => InvalidRequest,
236 METHOD_NOT_FOUND_CODE => MethodNotFound,
237 INVALID_PARAMS_CODE => InvalidParams,
238 INTERNAL_ERROR_CODE => InternalError,
239 code => ServerError(code),
240 }
241 }
242}
243
244impl<'a> serde::Deserialize<'a> for ErrorCode {
245 fn deserialize<D>(deserializer: D) -> Result<ErrorCode, D::Error>
246 where
247 D: Deserializer<'a>,
248 {
249 let code: i32 = Deserialize::deserialize(deserializer)?;
250 Ok(ErrorCode::from(code))
251 }
252}
253
254impl serde::Serialize for ErrorCode {
255 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
256 where
257 S: Serializer,
258 {
259 serializer.serialize_i32(self.code())
260 }
261}
262
263pub fn reject_too_many_subscriptions(limit: u32) -> ErrorObjectOwned {
265 ErrorObjectOwned::owned(
266 TOO_MANY_SUBSCRIPTIONS_CODE,
267 TOO_MANY_SUBSCRIPTIONS_MSG,
268 Some(format!("Exceeded max limit of {limit}")),
269 )
270}
271
272pub fn reject_too_big_request(limit: u32) -> ErrorObjectOwned {
274 ErrorObjectOwned::owned(
275 OVERSIZED_REQUEST_CODE,
276 OVERSIZED_REQUEST_MSG,
277 Some(format!("Exceeded max limit of {limit}")),
278 )
279}
280
281pub fn reject_too_big_batch_request(limit: usize) -> ErrorObjectOwned {
283 ErrorObjectOwned::owned(
284 TOO_BIG_BATCH_REQUEST_CODE,
285 TOO_BIG_BATCH_REQUEST_MSG,
286 Some(format!("Exceeded max limit of {limit}")),
287 )
288}
289
290pub fn reject_too_big_batch_response(limit: usize) -> ErrorObjectOwned {
292 ErrorObjectOwned::owned(
293 TOO_BIG_BATCH_RESPONSE_CODE,
294 TOO_BIG_BATCH_RESPONSE_MSG,
295 Some(format!("Exceeded max limit of {limit}")),
296 )
297}
298
299#[cfg(test)]
300mod tests {
301 use super::{ErrorCode, ErrorObject};
302
303 #[test]
304 fn deserialize_works() {
305 let ser = r#"{"code":-32700,"message":"Parse error"}"#;
306 let exp: ErrorObject = ErrorCode::ParseError.into();
307 let err: ErrorObject = serde_json::from_str(ser).unwrap();
308 assert_eq!(exp, err);
309 }
310
311 #[test]
312 fn deserialize_with_optional_data() {
313 let ser = r#"{"code":-32700,"message":"Parse error", "data":"vegan"}"#;
314 let data = serde_json::value::to_raw_value(&"vegan").unwrap();
315 let exp = ErrorObject::owned(ErrorCode::ParseError.code(), "Parse error", Some(data));
316 let err: ErrorObject = serde_json::from_str(ser).unwrap();
317 assert_eq!(exp, err);
318 }
319
320 #[test]
321 fn deserialized_error_with_quoted_str() {
322 let raw = r#"{
323 "code": 1002,
324 "message": "desc: \"Could not decode `ChargeAssetTxPayment::asset_id`\" } })",
325 "data": "\\\"validate_transaction\\\""
326 }"#;
327 let err: ErrorObject = serde_json::from_str(raw).unwrap();
328
329 let data = serde_json::value::to_raw_value(&"\\\"validate_transaction\\\"").unwrap();
330 let exp = ErrorObject::borrowed(
331 1002,
332 "desc: \"Could not decode `ChargeAssetTxPayment::asset_id`\" } })",
333 Some(&*data),
334 );
335
336 assert_eq!(err, exp);
337 }
338
339 #[test]
340 fn serialize_works() {
341 let exp = r#"{"code":-32603,"message":"Internal error"}"#;
342 let err: ErrorObject = ErrorCode::InternalError.into();
343 let ser = serde_json::to_string(&err).unwrap();
344 assert_eq!(exp, ser);
345 }
346
347 #[test]
348 fn serialize_optional_data_works() {
349 let exp = r#"{"code":-32699,"message":"food","data":"not vegan"}"#;
350 let data = serde_json::value::to_raw_value(&"not vegan").unwrap();
351 let ser = serde_json::to_string(&ErrorObject::owned(-32699, "food", Some(data))).unwrap();
352 assert_eq!(exp, ser);
353 }
354}