use core::fmt::Display;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::prelude::*;
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct ResponseError {
code: Code,
message: String,
data: Option<String>,
}
#[derive(Copy, Clone, Debug, Eq, thiserror::Error, Hash, PartialEq, PartialOrd, Ord)]
pub enum Code {
#[error("HTTP error")]
HttpError,
#[error("WebSocket Error")]
WebSocketError,
#[error("Client internal error")]
ClientInternalError,
#[error("Parse error. Invalid JSON")]
ParseError,
#[error("Invalid Request")]
InvalidRequest,
#[error("Method not found")]
MethodNotFound,
#[error("Invalid params")]
InvalidParams,
#[error("Internal error")]
InternalError,
#[error("Server error")]
ServerError,
#[error("Error (code: {})", 0)]
Other(i32),
}
impl Code {
pub fn value(self) -> i32 {
i32::from(self)
}
}
impl From<i32> for Code {
fn from(value: i32) -> Code {
match value {
0 => Code::HttpError,
1 => Code::WebSocketError,
2 => Code::ClientInternalError,
-32700 => Code::ParseError,
-32600 => Code::InvalidRequest,
-32601 => Code::MethodNotFound,
-32602 => Code::InvalidParams,
-32603 => Code::InternalError,
-32000 => Code::ServerError,
other => Code::Other(other),
}
}
}
impl From<Code> for i32 {
fn from(code: Code) -> i32 {
match code {
Code::HttpError => 0,
Code::WebSocketError => 1,
Code::ClientInternalError => 2,
Code::ParseError => -32700,
Code::InvalidRequest => -32600,
Code::MethodNotFound => -32601,
Code::InvalidParams => -32602,
Code::InternalError => -32603,
Code::ServerError => -32000,
Code::Other(other) => other,
}
}
}
impl Display for ResponseError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match &self.data {
Some(data) => write!(
f,
"{}: {} (code: {})",
self.message,
data,
self.code.value()
),
None => write!(f, "{} (code: {})", self.message, self.code.value()),
}
}
}
impl ResponseError {
pub fn new(code: Code, data: Option<String>) -> ResponseError {
let message = code.to_string();
ResponseError {
code,
message,
data,
}
}
pub fn http_error(message: impl Into<String>) -> ResponseError {
ResponseError {
code: Code::HttpError,
message: message.into(),
data: None,
}
}
pub fn invalid_params(data: &str) -> ResponseError {
ResponseError::new(Code::InvalidParams, Some(data.to_string()))
}
pub fn websocket_error(cause: impl Into<String>) -> ResponseError {
ResponseError::new(Code::WebSocketError, Some(cause.into()))
}
pub fn method_not_found(name: &str) -> ResponseError {
ResponseError::new(Code::MethodNotFound, Some(name.to_string()))
}
pub fn parse_error<E>(error: E) -> ResponseError
where
E: Display,
{
ResponseError::new(Code::ParseError, Some(error.to_string()))
}
pub fn server_error<D>(data: D) -> ResponseError
where
D: Display,
{
ResponseError::new(Code::ServerError, Some(data.to_string()))
}
pub fn client_internal_error(cause: impl Into<String>) -> ResponseError {
ResponseError::new(Code::ClientInternalError, Some(cause.into()))
}
pub fn code(&self) -> Code {
self.code
}
pub fn message(&self) -> &str {
&self.message
}
pub fn data(&self) -> Option<&str> {
self.data.as_ref().map(AsRef::as_ref)
}
}
impl<'de> Deserialize<'de> for Code {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
Ok(Code::from(i32::deserialize(deserializer)?))
}
}
impl Serialize for Code {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.value().serialize(serializer)
}
}