use core::fmt;
use std::io;
use sonic_rs::{Value, json};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum RpcError {
#[error("parse error: {0}")]
Parse(String),
#[error("invalid request: {0}")]
InvalidRequest(&'static str),
#[error("method not found: {0}")]
MethodNotFound(String),
#[error("invalid params: {0}")]
InvalidParams(&'static str),
#[error("invalid type: {0}")]
InvalidType(&'static str),
#[error("not found: {0}")]
NotFound(&'static str),
#[error("{0}")]
MethodDisabled(&'static str),
#[error("internal error: {0}")]
Internal(String),
}
impl RpcError {
pub const PARSE_ERROR: i64 = -32_700;
pub const INVALID_REQUEST: i64 = -32_600;
pub const METHOD_NOT_FOUND: i64 = -32_601;
pub const INVALID_PARAMS: i64 = -32_602;
pub const INTERNAL_ERROR: i64 = -32_603;
pub const CORE_INVALID_TYPE: i64 = -3;
pub const CORE_NOT_FOUND: i64 = -5;
pub const CORE_INVALID_PARAMETER: i64 = -8;
#[must_use]
pub const fn method_disabled(message: &'static str) -> Self {
Self::MethodDisabled(message)
}
#[must_use]
pub const fn code(&self) -> i64 {
match self {
Self::Parse(_) => Self::PARSE_ERROR,
Self::InvalidRequest(_) => Self::INVALID_REQUEST,
Self::MethodNotFound(_) => Self::METHOD_NOT_FOUND,
Self::InvalidParams(_) => Self::INVALID_PARAMS,
Self::InvalidType(_) => Self::CORE_INVALID_TYPE,
Self::NotFound(_) => Self::CORE_NOT_FOUND,
Self::MethodDisabled(_) | Self::Internal(_) => Self::INTERNAL_ERROR,
}
}
#[must_use]
pub fn response(&self, id: &Value) -> Value {
json!({
"jsonrpc": "2.0",
"result": null,
"error": {"code": self.code(), "message": self.to_string()},
"id": id
})
}
}
impl From<sonic_rs::Error> for RpcError {
fn from(error: sonic_rs::Error) -> Self {
Self::Parse(error.to_string())
}
}
impl From<serde_json::Error> for RpcError {
fn from(error: serde_json::Error) -> Self {
Self::Internal(error.to_string())
}
}
impl From<io::Error> for RpcError {
fn from(error: io::Error) -> Self {
Self::Internal(error.to_string())
}
}
impl From<bitcoin::consensus::encode::Error> for RpcError {
fn from(_error: bitcoin::consensus::encode::Error) -> Self {
Self::InvalidParams("consensus decoding failed")
}
}
impl From<bitcoin::hex::HexToBytesError> for RpcError {
fn from(_error: bitcoin::hex::HexToBytesError) -> Self {
Self::InvalidParams("hex string is invalid")
}
}
impl From<core::str::Utf8Error> for RpcError {
fn from(error: core::str::Utf8Error) -> Self {
Self::Parse(error.to_string())
}
}
impl From<fmt::Error> for RpcError {
fn from(error: fmt::Error) -> Self {
Self::Internal(error.to_string())
}
}