use crate::RpcSend;
use serde::Serialize;
use serde_json::value::{to_raw_value, RawValue};
use std::borrow::Cow;
use std::fmt;
const INTERNAL_ERROR: Cow<'_, str> = Cow::Borrowed("Internal error");
#[derive(Clone, Debug, PartialEq, Eq)]
#[repr(transparent)]
pub struct ResponsePayload<Payload, ErrData>(pub Result<Payload, ErrorPayload<ErrData>>);
impl<T, E> From<Result<T, E>> for ResponsePayload<T, E>
where
E: RpcSend,
{
fn from(res: Result<T, E>) -> Self {
match res {
Ok(payload) => Self(Ok(payload)),
Err(err) => Self(Err(ErrorPayload::internal_error_with_obj(err))),
}
}
}
impl<Payload, ErrData> ResponsePayload<Payload, ErrData> {
pub const fn parse_error() -> Self {
Self(Err(ErrorPayload::parse_error()))
}
pub const fn invalid_request() -> Self {
Self(Err(ErrorPayload::invalid_request()))
}
pub const fn method_not_found() -> Self {
Self(Err(ErrorPayload::method_not_found()))
}
pub const fn invalid_params() -> Self {
Self(Err(ErrorPayload::invalid_params()))
}
pub const fn internal_error() -> Self {
Self(Err(ErrorPayload::internal_error()))
}
pub const fn internal_error_message(message: Cow<'static, str>) -> Self {
Self(Err(ErrorPayload::internal_error_message(message)))
}
pub const fn internal_error_with_obj(data: ErrData) -> Self
where
ErrData: RpcSend,
{
Self(Err(ErrorPayload::internal_error_with_obj(data)))
}
pub const fn internal_error_with_message_and_obj(
message: Cow<'static, str>,
data: ErrData,
) -> Self
where
ErrData: RpcSend,
{
Self(Err(ErrorPayload::internal_error_with_message_and_obj(
message, data,
)))
}
pub const fn as_success(&self) -> Option<&Payload> {
match self {
Self(Ok(payload)) => Some(payload),
_ => None,
}
}
pub const fn as_error(&self) -> Option<&ErrorPayload<ErrData>> {
match self {
Self(Err(payload)) => Some(payload),
_ => None,
}
}
pub const fn is_success(&self) -> bool {
matches!(self, Self(Ok(_)))
}
pub const fn is_error(&self) -> bool {
matches!(self, Self(Err(_)))
}
pub fn convert_internal_error_msg<T>(res: Result<Payload, T>) -> Self
where
T: Into<Cow<'static, str>>,
{
match res {
Ok(payload) => Self(Ok(payload)),
Err(err) => Self(Err(ErrorPayload::internal_error_message(err.into()))),
}
}
}
#[derive(Clone, Debug, Serialize, PartialEq, Eq)]
pub struct ErrorPayload<ErrData = Box<RawValue>> {
pub code: i64,
pub message: Cow<'static, str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<ErrData>,
}
impl<E> ErrorPayload<E> {
pub const fn parse_error() -> Self {
Self {
code: -32700,
message: Cow::Borrowed("Parse error"),
data: None,
}
}
pub const fn invalid_request() -> Self {
Self {
code: -32600,
message: Cow::Borrowed("Invalid Request"),
data: None,
}
}
pub const fn method_not_found() -> Self {
Self {
code: -32601,
message: Cow::Borrowed("Method not found"),
data: None,
}
}
pub const fn invalid_params() -> Self {
Self {
code: -32602,
message: Cow::Borrowed("Invalid params"),
data: None,
}
}
pub const fn internal_error() -> Self {
Self {
code: -32603,
message: INTERNAL_ERROR,
data: None,
}
}
pub const fn internal_error_message(message: Cow<'static, str>) -> Self {
Self {
code: -32603,
message,
data: None,
}
}
pub const fn internal_error_with_obj(data: E) -> Self
where
E: RpcSend,
{
Self {
code: -32603,
message: INTERNAL_ERROR,
data: Some(data),
}
}
pub const fn internal_error_with_message_and_obj(message: Cow<'static, str>, data: E) -> Self
where
E: RpcSend,
{
Self {
code: -32603,
message,
data: Some(data),
}
}
pub fn is_retry_err(&self) -> bool {
if self.code == 429 {
return true;
}
if self.code == -32005 {
return true;
}
if self.code == -32016 && self.message.contains("rate limit") {
return true;
}
if self.code == -32012 && self.message.contains("credits") {
return true;
}
if self.code == -32007 && self.message.contains("request limit reached") {
return true;
}
match self.message.as_ref() {
"header not found" => true,
"daily request count exceeded, request rate limited" => true,
msg => {
msg.contains("rate limit")
|| msg.contains("rate exceeded")
|| msg.contains("too many requests")
|| msg.contains("credits limited")
|| msg.contains("request limit")
}
}
}
}
impl<T> From<T> for ErrorPayload<T>
where
T: std::error::Error + RpcSend,
{
fn from(value: T) -> Self {
Self {
code: -32603,
message: INTERNAL_ERROR,
data: Some(value),
}
}
}
impl<E> ErrorPayload<E>
where
E: RpcSend,
{
pub fn serialize_payload(&self) -> serde_json::Result<ErrorPayload> {
Ok(ErrorPayload {
code: self.code,
message: self.message.clone(),
data: match self.data.as_ref() {
Some(data) => Some(to_raw_value(data)?),
None => None,
},
})
}
}
impl<ErrData: fmt::Display> fmt::Display for ErrorPayload<ErrData> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"error code {}: {}{}",
self.code,
self.message,
self.data
.as_ref()
.map(|data| format!(", data: {}", data))
.unwrap_or_default()
)
}
}