use std::fmt;
use jsonrpsee_types::error::{
CallError, ErrorObject, ErrorObjectOwned, CALL_EXECUTION_FAILED_CODE, INVALID_PARAMS_CODE, SUBSCRIPTION_CLOSED,
UNKNOWN_ERROR_CODE,
};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Mismatch<T> {
pub expected: T,
pub got: T,
}
impl<T: fmt::Display> fmt::Display for Mismatch<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_fmt(format_args!("Expected: {}, Got: {}", self.expected, self.got))
}
}
impl From<anyhow::Error> for Error {
fn from(err: anyhow::Error) -> Self {
Error::Call(CallError::Failed(err))
}
}
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("{0}")]
Call(#[from] CallError),
#[error("Networking or low-level protocol error: {0}")]
Transport(#[source] anyhow::Error),
#[error("Frontend/backend channel error: {0}")]
Internal(#[from] futures_channel::mpsc::SendError),
#[error("Invalid response: {0}")]
InvalidResponse(Mismatch<String>),
#[error("The background task been terminated because: {0}; restart required")]
RestartNeeded(String),
#[error("Parse error: {0}")]
ParseError(#[from] serde_json::Error),
#[error("Invalid subscription ID")]
InvalidSubscriptionId,
#[error("Invalid request ID")]
InvalidRequestId,
#[error("Unregistered notification method")]
UnregisteredNotification(String),
#[error("A request with the same request ID has already been registered")]
DuplicateRequestId,
#[error("Method: {0} was already registered")]
MethodAlreadyRegistered(String),
#[error("Method: {0} has not yet been registered")]
MethodNotFound(String),
#[error("Cannot use the same method name for subscribe and unsubscribe, used: {0}")]
SubscriptionNameConflict(String),
#[error("Request timeout")]
RequestTimeout,
#[error("Configured max number of request slots exceeded")]
MaxSlotsExceeded,
#[error("Attempted to stop server that is already stopped")]
AlreadyStopped,
#[error("Must set at least one allowed value for the {0} header")]
EmptyAllowList(&'static str),
#[error("HTTP header: `{0}` value: `{1}` verification failed")]
HttpHeaderRejected(&'static str, String),
#[error("Resource at capacity: {0}")]
ResourceAtCapacity(&'static str),
#[error("Resource name already taken: {0}")]
ResourceNameAlreadyTaken(&'static str),
#[error("Resource name `{0}` not found for method `{1}`")]
ResourceNameNotFoundForMethod(&'static str, &'static str),
#[error("Method `{0}` has uninitialized resources")]
UninitializedMethod(Box<str>),
#[error("Maximum number of resources reached")]
MaxResourcesReached,
#[error("Custom error: {0}")]
Custom(String),
#[error("Not implemented")]
HttpNotImplemented,
#[error("Empty batch request is not allowed")]
EmptyBatchRequest,
}
impl Error {
pub fn to_call_error<E>(err: E) -> Self
where
E: std::error::Error + Send + Sync + 'static,
{
Error::Call(CallError::from_std_error(err))
}
}
impl From<Error> for ErrorObjectOwned {
fn from(err: Error) -> Self {
match err {
Error::Call(CallError::Custom(err)) => err,
Error::Call(CallError::InvalidParams(e)) => {
ErrorObject::owned(INVALID_PARAMS_CODE, e.to_string(), None::<()>)
}
Error::Call(CallError::Failed(e)) => {
ErrorObject::owned(CALL_EXECUTION_FAILED_CODE, e.to_string(), None::<()>)
}
_ => ErrorObject::owned(UNKNOWN_ERROR_CODE, err.to_string(), None::<()>),
}
}
}
#[derive(Clone, Debug)]
pub enum SubscriptionClosed {
RemotePeerAborted,
Success,
Failed(ErrorObject<'static>),
}
impl From<SubscriptionClosed> for ErrorObjectOwned {
fn from(err: SubscriptionClosed) -> Self {
match err {
SubscriptionClosed::RemotePeerAborted => {
ErrorObject::owned(SUBSCRIPTION_CLOSED, "Subscription was closed by the remote peer", None::<()>)
}
SubscriptionClosed::Success => ErrorObject::owned(
SUBSCRIPTION_CLOSED,
"Subscription was completed by the server successfully",
None::<()>,
),
SubscriptionClosed::Failed(err) => err,
}
}
}
#[derive(Debug, thiserror::Error)]
pub enum GenericTransportError<T: std::error::Error + Send + Sync> {
#[error("The request was too big")]
TooLarge,
#[error("Malformed request")]
Malformed,
#[error("Transport error: {0}")]
Inner(T),
}
impl From<std::io::Error> for Error {
fn from(io_err: std::io::Error) -> Error {
Error::Transport(io_err.into())
}
}
#[cfg(feature = "soketto")]
impl From<soketto::handshake::Error> for Error {
fn from(handshake_err: soketto::handshake::Error) -> Error {
Error::Transport(handshake_err.into())
}
}
#[cfg(feature = "soketto")]
impl From<soketto::connection::Error> for Error {
fn from(conn_err: soketto::connection::Error) -> Error {
Error::Transport(conn_err.into())
}
}
#[cfg(feature = "hyper")]
impl From<hyper::Error> for Error {
fn from(hyper_err: hyper::Error) -> Error {
Error::Transport(hyper_err.into())
}
}