use crate::v2::params::{Id, TwoPointZero}; use serde::de::Deserializer; use serde::ser::Serializer; use serde::{Deserialize, Serialize}; use serde_json::value::{RawValue, Value as JsonValue}; use std::fmt; use thiserror::Error; /// [Failed JSON-RPC response object](https://www.jsonrpc.org/specification#response_object). #[derive(Serialize, Debug)] pub struct JsonRpcError<'a> { /// JSON-RPC version. pub jsonrpc: TwoPointZero, /// Error. pub error: JsonRpcErrorObject<'a>, /// Request ID pub id: Option<&'a RawValue>, } /// [Failed JSON-RPC response object with allocations](https://www.jsonrpc.org/specification#response_object). #[derive(Error, Debug, Deserialize, PartialEq)] pub struct JsonRpcErrorAlloc { /// JSON-RPC version. pub jsonrpc: TwoPointZero, /// JSON-RPC error object. pub error: JsonRpcErrorObjectAlloc, /// Request ID. pub id: Id, } impl fmt::Display for JsonRpcErrorAlloc { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:?}: {:?}: {:?}", self.jsonrpc, self.error, self.id) } } /// JSON-RPC error object. #[derive(Debug, PartialEq, Clone, Deserialize)] #[serde(deny_unknown_fields)] pub struct JsonRpcErrorObjectAlloc { /// Code pub code: JsonRpcErrorCode, /// Message pub message: String, /// Optional data pub data: Option, } impl From for JsonRpcErrorObjectAlloc { fn from(code: JsonRpcErrorCode) -> Self { Self { code, message: code.message().to_owned(), data: None } } } /// JSON-RPC error object with no extra allocations. #[derive(Debug, Serialize)] #[serde(deny_unknown_fields)] pub struct JsonRpcErrorObject<'a> { /// Code pub code: JsonRpcErrorCode, /// Message pub message: &'a str, /// Optional data #[serde(skip_serializing_if = "Option::is_none")] pub data: Option<&'a RawValue>, } impl<'a> From for JsonRpcErrorObject<'a> { fn from(code: JsonRpcErrorCode) -> Self { Self { code, message: code.message(), data: None } } } /// Parse error code. pub const PARSE_ERROR_CODE: i32 = -32700; /// Internal error code. pub const INTERNAL_ERROR_CODE: i32 = -32603; /// Invalid params error code. pub const INVALID_PARAMS_CODE: i32 = -32602; /// Invalid request error code. pub const INVALID_REQUEST_CODE: i32 = -32600; /// Method not found error code. pub const METHOD_NOT_FOUND_CODE: i32 = -32601; /// Custom server error when a call failed. pub const CALL_EXECUTION_FAILED_CODE: i32 = -32000; /// Parse error message pub const PARSE_ERROR_MSG: &str = "Parse error"; /// Internal error message. pub const INTERNAL_ERROR_MSG: &str = "Internal error"; /// Invalid params error message. pub const INVALID_PARAMS_MSG: &str = "Invalid params"; /// Invalid request error message. pub const INVALID_REQUEST_MSG: &str = "Invalid request"; /// Method not found error message. pub const METHOD_NOT_FOUND_MSG: &str = "Method not found"; /// Reserved for implementation-defined server-errors. pub const SERVER_ERROR_MSG: &str = "Server error"; /// JSONRPC error code #[derive(Error, Debug, PartialEq, Copy, Clone)] pub enum JsonRpcErrorCode { /// Invalid JSON was received by the server. /// An error occurred on the server while parsing the JSON text. ParseError, /// The JSON sent is not a valid Request object. InvalidRequest, /// The method does not exist / is not available. MethodNotFound, /// Invalid method parameter(s). InvalidParams, /// Internal JSON-RPC error. InternalError, /// Reserved for implementation-defined server-errors. ServerError(i32), } impl JsonRpcErrorCode { /// Returns integer code value pub const fn code(&self) -> i32 { match *self { JsonRpcErrorCode::ParseError => PARSE_ERROR_CODE, JsonRpcErrorCode::InvalidRequest => INVALID_REQUEST_CODE, JsonRpcErrorCode::MethodNotFound => METHOD_NOT_FOUND_CODE, JsonRpcErrorCode::InvalidParams => INVALID_PARAMS_CODE, JsonRpcErrorCode::InternalError => INTERNAL_ERROR_CODE, JsonRpcErrorCode::ServerError(code) => code, } } /// Returns the message for the given error code. pub const fn message(&self) -> &'static str { match self { JsonRpcErrorCode::ParseError => PARSE_ERROR_MSG, JsonRpcErrorCode::InvalidRequest => INVALID_REQUEST_MSG, JsonRpcErrorCode::MethodNotFound => METHOD_NOT_FOUND_MSG, JsonRpcErrorCode::InvalidParams => INVALID_PARAMS_MSG, JsonRpcErrorCode::InternalError => INTERNAL_ERROR_MSG, JsonRpcErrorCode::ServerError(_) => SERVER_ERROR_MSG, } } } impl fmt::Display for JsonRpcErrorCode { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}: {}", self.code(), self.message()) } } impl From for JsonRpcErrorCode { fn from(code: i32) -> Self { match code { PARSE_ERROR_CODE => JsonRpcErrorCode::ParseError, INVALID_REQUEST_CODE => JsonRpcErrorCode::InvalidRequest, METHOD_NOT_FOUND_CODE => JsonRpcErrorCode::MethodNotFound, INVALID_PARAMS_CODE => JsonRpcErrorCode::InvalidParams, INTERNAL_ERROR_CODE => JsonRpcErrorCode::InternalError, code => JsonRpcErrorCode::ServerError(code), } } } impl<'a> serde::Deserialize<'a> for JsonRpcErrorCode { fn deserialize(deserializer: D) -> Result where D: Deserializer<'a>, { let code: i32 = Deserialize::deserialize(deserializer)?; Ok(JsonRpcErrorCode::from(code)) } } impl serde::Serialize for JsonRpcErrorCode { fn serialize(&self, serializer: S) -> Result where S: Serializer, { serializer.serialize_i32(self.code()) } } #[cfg(test)] mod tests { use super::{ Id, JsonRpcError, JsonRpcErrorAlloc, JsonRpcErrorCode, JsonRpcErrorObject, JsonRpcErrorObjectAlloc, TwoPointZero, }; #[test] fn deserialize_works() { let ser = r#"{"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error"},"id":null}"#; let err: JsonRpcErrorAlloc = serde_json::from_str(ser).unwrap(); assert_eq!(err.jsonrpc, TwoPointZero); assert_eq!( err.error, JsonRpcErrorObjectAlloc { code: JsonRpcErrorCode::ParseError, message: "Parse error".into(), data: None } ); assert_eq!(err.id, Id::Null); } #[test] fn deserialize_with_optional_data() { let ser = r#"{"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error", "data":"vegan"},"id":null}"#; let err: JsonRpcErrorAlloc = serde_json::from_str(ser).unwrap(); assert_eq!(err.jsonrpc, TwoPointZero); assert_eq!( err.error, JsonRpcErrorObjectAlloc { code: JsonRpcErrorCode::ParseError, message: "Parse error".into(), data: Some("vegan".into()) } ); assert_eq!(err.id, Id::Null); } #[test] fn serialize_works() { let exp = r#"{"jsonrpc":"2.0","error":{"code":-32603,"message":"Internal error"},"id":1337}"#; let raw_id = serde_json::value::to_raw_value(&1337).unwrap(); let err = JsonRpcError { jsonrpc: TwoPointZero, error: JsonRpcErrorObject { code: JsonRpcErrorCode::InternalError, message: "Internal error", data: None }, id: Some(&*raw_id), }; let ser = serde_json::to_string(&err).unwrap(); assert_eq!(exp, ser); } }