reown_relay_rpc/rpc/
error.rs1use {
2 super::ErrorData,
3 std::fmt::{Debug, Display},
4};
5
6pub trait ServiceError: Sized + Debug + Display + PartialEq + Send + 'static {
10 fn from_tag(tag: &str) -> Result<Self, InvalidErrorData>;
11
12 fn tag(&self) -> &'static str;
13}
14
15impl<T> ServiceError for T
16where
17 T: for<'a> TryFrom<&'a str> + Debug + Display + PartialEq + Send + 'static,
18 for<'a> &'static str: From<&'a T>,
19{
20 fn from_tag(tag: &str) -> Result<Self, InvalidErrorData> {
21 tag.try_into().map_err(|_| InvalidErrorData)
22 }
23
24 fn tag(&self) -> &'static str {
25 self.into()
26 }
27}
28
29#[derive(Debug, thiserror::Error, strum::EnumString, strum::IntoStaticStr, PartialEq, Eq)]
30pub enum AuthError {
31 #[error("Project not found")]
32 ProjectNotFound,
33
34 #[error("Project ID not specified")]
35 ProjectIdNotSpecified,
36
37 #[error("Project inactive")]
38 ProjectInactive,
39
40 #[error("Origin not allowed")]
41 OriginNotAllowed,
42
43 #[error("Invalid JWT")]
44 InvalidJwt,
45
46 #[error("Missing JWT")]
47 MissingJwt,
48
49 #[error("Country blocked")]
50 CountryBlocked,
51}
52
53#[derive(
55 Debug, Clone, thiserror::Error, strum::EnumString, strum::IntoStaticStr, PartialEq, Eq,
56)]
57pub enum PayloadError {
58 #[error("Invalid request method")]
59 InvalidMethod,
60
61 #[error("Invalid request parameters")]
62 InvalidParams,
63
64 #[error("Payload size exceeded")]
65 PayloadSizeExceeded,
66
67 #[error("Topic decoding failed")]
68 InvalidTopic,
69
70 #[error("Subscription ID decoding failed")]
71 InvalidSubscriptionId,
72
73 #[error("Invalid request ID")]
74 InvalidRequestId,
75
76 #[error("Invalid JSON RPC version")]
77 InvalidJsonRpcVersion,
78
79 #[error("The batch contains too many items")]
80 BatchLimitExceeded,
81
82 #[error("The batch contains no items")]
83 BatchEmpty,
84
85 #[error("Failed to deserialize request")]
86 Serialization,
87}
88
89#[derive(Debug, thiserror::Error, strum::EnumString, strum::IntoStaticStr, PartialEq, Eq)]
90pub enum InternalError {
91 #[error("Storage operation failed")]
92 StorageError,
93
94 #[error("Failed to serialize response")]
95 Serialization,
96
97 #[error("Internal error")]
98 Unknown,
99}
100
101#[derive(Debug, thiserror::Error, strum::IntoStaticStr, PartialEq, Eq)]
105pub enum Error<T> {
106 #[error("Auth error: {0}")]
107 Auth(#[from] AuthError),
108
109 #[error("Invalid payload: {0}")]
110 Payload(#[from] PayloadError),
111
112 #[error("Request handler error: {0}")]
113 Handler(T),
114
115 #[error("Internal error: {0}")]
116 Internal(#[from] InternalError),
117
118 #[error("Too many requests")]
119 TooManyRequests,
120}
121
122impl<T: ServiceError> Error<T> {
123 pub fn code(&self) -> i32 {
124 match self {
125 Self::Auth(_) => CODE_AUTH,
126 Self::TooManyRequests => CODE_TOO_MANY_REQUESTS,
127 Self::Payload(_) => CODE_PAYLOAD,
128 Self::Handler(_) => CODE_HANDLER,
129 Self::Internal(_) => CODE_INTERNAL,
130 }
131 }
132
133 pub fn tag(&self) -> &'static str {
134 match &self {
135 Self::Auth(err) => err.tag(),
136 Self::Payload(err) => err.tag(),
137 Self::Handler(err) => err.tag(),
138 Self::Internal(err) => err.tag(),
139 Self::TooManyRequests => self.into(),
140 }
141 }
142}
143
144pub const CODE_AUTH: i32 = 3000;
145pub const CODE_TOO_MANY_REQUESTS: i32 = 3001;
146pub const CODE_PAYLOAD: i32 = -32600;
147pub const CODE_HANDLER: i32 = -32000;
148pub const CODE_INTERNAL: i32 = -32603;
149
150#[derive(Debug, thiserror::Error)]
151#[error("Invalid error data")]
152pub struct InvalidErrorData;
153
154impl<T: ServiceError> TryFrom<ErrorData> for Error<T> {
155 type Error = InvalidErrorData;
156
157 fn try_from(err: ErrorData) -> Result<Self, Self::Error> {
158 let tag = &err.data;
159
160 let err = match err.code {
161 CODE_AUTH => Error::Auth(try_parse_error(tag)?),
162 CODE_TOO_MANY_REQUESTS => Error::TooManyRequests,
163 CODE_PAYLOAD => Error::Payload(try_parse_error(tag)?),
164 CODE_HANDLER => Error::Handler(try_parse_error(tag)?),
165 CODE_INTERNAL => Error::Internal(try_parse_error(tag)?),
166 _ => return Err(InvalidErrorData),
167 };
168
169 Ok(err)
170 }
171}
172
173#[inline]
174fn try_parse_error<T: ServiceError>(tag: &Option<String>) -> Result<T, InvalidErrorData> {
175 tag.as_deref().ok_or(InvalidErrorData).map(T::from_tag)?
176}
177
178impl<T: ServiceError> From<Error<T>> for ErrorData {
179 fn from(err: Error<T>) -> Self {
180 Self {
181 code: err.code(),
182 message: err.to_string(),
183 data: Some(err.tag().to_owned()),
184 }
185 }
186}