1#![warn(clippy::wildcard_imports)]
2
3pub use async_trait::async_trait;
4use serde::{Deserialize, Serialize};
5
6pub use yerpc_derive::rpc;
7
8#[cfg(feature = "openrpc")]
9pub mod openrpc;
10mod requests;
11pub mod typescript;
12mod version;
13
14#[cfg(feature = "openrpc")]
15pub use openrpc::JsonSchema;
16pub use requests::{OutReceiver, RpcClient, RpcSession, RpcSessionSink};
17pub use typescript::TypeDef;
18pub use version::Version;
19
20mod integrations;
21pub use integrations::*;
22
23#[async_trait]
24pub trait RpcServer: Sync + Send + 'static {
25 #[cfg(feature = "openrpc")]
27 fn openrpc_specification() -> Result<String> {
28 Ok(String::new())
29 }
30
31 async fn handle_notification(&self, _method: String, _params: serde_json::Value) -> Result<()> {
32 Ok(())
33 }
34 async fn handle_request(
35 &self,
36 _method: String,
37 _params: serde_json::Value,
38 ) -> Result<serde_json::Value> {
39 Err(Error::new(
40 Error::METHOD_NOT_FOUND,
41 "Method not found".to_string(),
42 ))
43 }
44}
45
46impl RpcServer for () {}
47
48#[derive(Serialize, Deserialize, Debug, TypeDef, Eq, Hash, PartialEq, Clone)]
50#[serde(untagged)]
51pub enum Id {
52 Number(u32),
53 String(String),
54}
55
56pub type Result<T> = std::result::Result<T, Error>;
57
58#[derive(Serialize, Deserialize, Debug, TypeDef)]
60#[serde(untagged)]
61pub enum RpcResult<T: TypeDef> {
62 Ok(T),
63 Err(Error),
64}
65
66#[derive(Serialize, Deserialize, Debug, TypeDef)]
67#[serde(untagged)]
68pub enum Message {
69 Request(Request),
70 Response(Response),
71}
72
73#[derive(Serialize, Deserialize, Debug, TypeDef)]
74#[serde(untagged)]
75pub enum Params {
76 Positional(Vec<serde_json::Value>),
77 Structured(serde_json::Map<String, serde_json::Value>),
78}
79
80impl Params {
81 pub fn into_value(self) -> serde_json::Value {
82 match self {
83 Params::Positional(list) => serde_json::Value::Array(list),
84 Params::Structured(object) => serde_json::Value::Object(object),
85 }
86 }
87}
88
89impl From<Params> for serde_json::Value {
90 fn from(params: Params) -> Self {
91 params.into_value()
92 }
93}
94
95impl TryFrom<serde_json::Value> for Params {
96 type Error = Error;
97 fn try_from(value: serde_json::Value) -> std::result::Result<Self, Self::Error> {
98 match value {
99 serde_json::Value::Object(object) => Ok(Params::Structured(object)),
100 serde_json::Value::Array(list) => Ok(Params::Positional(list)),
101 _ => Err(Error::invalid_params()),
102 }
103 }
104}
105
106#[derive(Serialize, Deserialize, Debug, TypeDef)]
108pub struct Request {
109 #[serde(skip_serializing_if = "Option::is_none")]
111 pub jsonrpc: Option<Version>, pub method: String,
115
116 #[serde(skip_serializing_if = "Option::is_none")]
118 pub params: Option<Params>,
119
120 #[serde(skip_serializing_if = "Option::is_none")]
122 pub id: Option<Id>,
123}
124
125#[derive(Serialize, Deserialize, Debug, TypeDef)]
127pub struct Response {
128 pub jsonrpc: Version,
130
131 pub id: Option<Id>,
133
134 #[serde(skip_serializing_if = "Option::is_none")]
136 pub result: Option<serde_json::Value>,
137
138 #[serde(skip_serializing_if = "Option::is_none")]
140 pub error: Option<Error>,
141}
142impl Response {
143 pub fn error(id: Option<Id>, error: Error) -> Self {
145 Self {
146 jsonrpc: Version::V2,
147 id,
148 error: Some(error),
149 result: None,
150 }
151 }
152 pub fn success(id: Id, result: serde_json::Value) -> Self {
154 Self {
155 jsonrpc: Version::V2,
156 id: Some(id),
157 result: Some(result),
158 error: None,
159 }
160 }
161}
162
163#[derive(Serialize, Deserialize, Debug, TypeDef)]
165#[cfg_attr(feature = "openrpc", derive(JsonSchema))]
166pub struct Error {
167 pub code: i32,
169
170 pub message: String,
172
173 #[serde(skip_serializing_if = "Option::is_none")]
175 pub data: Option<serde_json::Value>,
176}
177impl std::error::Error for Error {}
178impl std::fmt::Display for Error {
179 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
180 write!(f, "JSON-RPC error: {} (code {})", self.message, self.code)
181 }
182}
183impl Error {
184 pub const PARSE_ERROR: i32 = -32700;
185 pub const INVALID_REQUEST: i32 = -32600;
186 pub const METHOD_NOT_FOUND: i32 = -32601;
187 pub const INVALID_PARAMS: i32 = -32602;
188 pub const INTERNAL_ERROR: i32 = -32603;
189
190 pub const BAD_REQUEST: i32 = -32000;
191 pub const BAD_RESPONSE: i32 = -32001;
192 pub const REMOTE_DISCONNECTED: i32 = -32002;
193
194 pub fn new(code: i32, message: String) -> Self {
196 Self {
197 code,
198 message,
199 data: None,
200 }
201 }
202
203 pub fn with_data(code: i32, message: String, data: Option<serde_json::Value>) -> Self {
205 Self {
206 code,
207 message,
208 data,
209 }
210 }
211
212 pub fn invalid_params() -> Self {
214 Self::new(
215 Error::INVALID_PARAMS,
216 "Params has to be an object or array".to_string(),
217 )
218 }
219
220 pub fn method_not_found() -> Self {
222 Self::new(Error::METHOD_NOT_FOUND, "Method not found".to_string())
223 }
224
225 pub fn invalid_args_len(n: usize) -> Self {
226 Self::new(
227 Error::INVALID_PARAMS,
228 format!("This method takes an array of {n} arguments"),
229 )
230 }
231
232 pub fn bad_response() -> Self {
233 Self::new(
234 Error::BAD_RESPONSE,
235 "Error while processing a response".to_string(),
236 )
237 }
238 pub fn bad_request() -> Self {
239 Self::new(
240 Error::BAD_REQUEST,
241 "Error while serializing a request".to_string(),
242 )
243 }
244 pub fn remote_disconnected() -> Self {
245 Self::new(
246 Error::REMOTE_DISCONNECTED,
247 "Remote disconnected".to_string(),
248 )
249 }
250
251 pub fn is_disconnnected(&self) -> bool {
252 self.code == Error::REMOTE_DISCONNECTED
253 }
254}
255
256impl From<serde_json::Error> for Error {
257 fn from(error: serde_json::Error) -> Self {
258 Self {
259 code: Error::PARSE_ERROR,
260 message: format!("{error}"),
261 data: None,
262 }
263 }
264}
265
266#[cfg(feature = "anyhow")]
267#[cfg(feature = "anyhow_expose")]
268impl From<anyhow::Error> for Error {
269 fn from(error: anyhow::Error) -> Self {
270 Self {
271 code: -1,
272 message: format!("{:#}", error),
273 data: None,
274 }
275 }
276}
277
278#[cfg(feature = "anyhow")]
279#[cfg(not(feature = "anyhow_expose"))]
280impl From<anyhow::Error> for Error {
281 fn from(_error: anyhow::Error) -> Self {
282 Self {
283 code: Error::INTERNAL_ERROR,
284 message: "Internal server error".to_string(),
285 data: None,
286 }
287 }
288}