1use std::{
2 convert::TryFrom,
3 fmt::{Display, Formatter},
4 ops::RangeInclusive,
5 str::FromStr,
6};
7
8use serde::{Deserialize, Serialize};
9use serde_json::Value;
10use thiserror::Error;
11
12mod sensitive;
13
14pub use self::sensitive::Sensitive;
15
16pub const JSONRPC_VERSION: &str = "2.0";
17pub const JSONRPC_RESERVED_ERROR_CODES: RangeInclusive<i64> = -32768..=-32000;
18
19#[derive(Debug, Error)]
22pub enum Error {
23 #[error("The server responded with an error: {0}")]
25 JsonRpc(#[from] RpcError),
26
27 #[error("JSON error: {0}")]
29 Json(#[from] serde_json::Error),
30
31 #[error("Received invalid response")]
32 InvalidResponse,
33
34 #[error("Invalid subscription ID: {0:?}")]
35 InvalidSubscriptionId(Value),
36}
37
38#[derive(Copy, Clone, Default)]
40pub enum FrameType {
41 #[default]
43 Binary,
44 Text,
46}
47
48impl From<&String> for FrameType {
49 fn from(value: &String) -> Self {
50 match value.as_str() {
51 "text" => FrameType::Text,
52 "binary" => FrameType::Binary,
53 _ => FrameType::Binary,
54 }
55 }
56}
57
58#[derive(Clone, Debug, Serialize, Deserialize)]
64#[serde(untagged)]
65pub enum SingleOrBatch<T> {
66 Single(T),
67 Batch(Vec<T>),
68}
69
70#[derive(Clone, Debug, Deserialize)]
72#[serde(untagged)]
73pub enum RequestOrResponse {
74 Request(Request),
75 Response(Response),
76}
77
78impl RequestOrResponse {
79 pub fn from_slice(d: &[u8]) -> Result<Self, Error> {
80 Ok(serde_json::from_slice(d)?)
81 }
82
83 pub fn from_value(v: Value) -> Result<Self, Error> {
84 Ok(serde_json::from_value(v)?)
85 }
86}
87
88impl FromStr for RequestOrResponse {
89 type Err = Error;
90
91 fn from_str(s: &str) -> Result<Self, Self::Err> {
92 Ok(serde_json::from_str(s)?)
93 }
94}
95
96#[derive(Clone, Debug, Serialize, Deserialize)]
101#[serde(deny_unknown_fields)]
102pub struct Request {
103 pub jsonrpc: String,
105
106 pub method: String,
108
109 #[serde(skip_serializing_if = "Option::is_none")]
111 pub params: Option<Value>,
112
113 #[serde(skip_serializing_if = "Option::is_none")]
116 pub id: Option<Value>,
117}
118
119impl Request {
120 pub fn new(method: String, params: Option<Value>, id: Option<Value>) -> Self {
123 Self {
124 jsonrpc: JSONRPC_VERSION.to_owned(),
125 method,
126 params,
127 id,
128 }
129 }
130
131 pub fn build<P, I>(
132 method: String,
133 params_opt: Option<&P>,
134 id_opt: Option<&I>,
135 ) -> Result<Self, Error>
136 where
137 P: Serialize,
138 I: Serialize,
139 {
140 let params = params_opt.map(serde_json::to_value).transpose()?;
141 let id = id_opt.map(serde_json::to_value).transpose()?;
142
143 Ok(Self::new(method, params, id))
144 }
145
146 pub fn verify(&self) -> Result<(), RpcError> {
149 if self.jsonrpc != JSONRPC_VERSION {
150 return Err(RpcError::invalid_request(Some(format!(
151 "Field 'jsonrpc' must be '2.0', but was '{}'",
152 self.jsonrpc
153 ))));
154 }
155
156 match &self.id {
157 Some(Value::String(_)) => {} Some(Value::Number(n)) => {
159 if n.is_f64() {
160 return Err(RpcError::invalid_request(Some(format!(
161 "Field 'id' is a number, but should not be fractional: {:?}",
162 self.id
163 ))));
164 }
165 }
167 _ => {
168 return Err(RpcError::invalid_request(Some(format!(
169 "Invalid type in field 'id': {:?}",
170 self.id
171 ))))
172 }
173 }
174
175 Ok(())
176 }
177
178 pub fn from_slice(d: &[u8]) -> Result<Self, Error> {
179 Ok(serde_json::from_slice(d)?)
180 }
181
182 pub fn to_value(&self) -> Result<Value, Error> {
183 Ok(serde_json::to_value(self)?)
184 }
185}
186
187#[derive(Clone, Debug, Serialize, Deserialize)]
192#[serde(deny_unknown_fields)]
193pub struct Response {
194 pub jsonrpc: String,
196
197 #[serde(skip_serializing_if = "Option::is_none")]
200 pub result: Option<Value>,
201
202 #[serde(skip_serializing_if = "Option::is_none")]
204 pub error: Option<RpcError>,
205
206 pub id: Value,
210}
211
212impl Response {
213 pub fn new_success(id: Value, result: Value) -> Self {
215 Self {
216 jsonrpc: JSONRPC_VERSION.to_owned(),
217 result: Some(result),
218 error: None,
219 id,
220 }
221 }
222
223 pub fn new_error(id: Value, error: RpcError) -> Self {
225 Self {
226 jsonrpc: JSONRPC_VERSION.to_owned(),
227 result: None,
228 error: Some(error),
229 id,
230 }
231 }
232
233 pub fn from_result<R>(id: Value, result: Result<R, RpcError>) -> Result<Self, Error>
235 where
236 R: Serialize,
237 {
238 Ok(match result {
239 Ok(result) => Self::new_success(id, serde_json::to_value(&result)?),
240 Err(e) => Self::new_error(id, e),
241 })
242 }
243
244 pub fn into_result<R>(self) -> Result<R, Error>
246 where
247 R: for<'de> Deserialize<'de>,
248 {
249 match (self.result, self.error) {
250 (Some(result), None) => Ok(serde_json::from_value(result)?),
251 (None, Some(error)) => Err(error.into()),
252 _ => Err(Error::InvalidResponse),
253 }
254 }
255
256 pub fn from_slice(d: &[u8]) -> Result<Self, Error> {
257 Ok(serde_json::from_slice(d)?)
258 }
259}
260
261pub type ErrorCode = i64;
263
264#[derive(Clone, Debug, Error, Serialize, Deserialize)]
269#[serde(deny_unknown_fields)]
270pub struct RpcError {
271 pub code: i64,
273
274 pub message: Option<String>,
276
277 #[serde(skip_serializing_if = "Option::is_none")]
279 pub data: Option<Value>,
280}
281
282impl std::fmt::Display for RpcError {
283 fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
284 write!(f, "JSON-RPC error: code={}", self.code)?;
285 if let Some(message) = &self.message {
286 write!(f, ": {}", message)?;
287 }
288 if let Some(data) = &self.data {
289 write!(f, " - Caused by: {}", data)?;
290 }
291 Ok(())
292 }
293}
294
295impl RpcError {
296 fn new_reserved(code: i64, message: &'static str, data: Option<Value>) -> Self {
297 Self {
298 code,
299 message: Some(message.to_owned()),
300 data,
301 }
302 }
303
304 fn new_reserved_with_description(
305 code: i64,
306 message: &'static str,
307 description: Option<String>,
308 ) -> Self {
309 Self {
310 code,
311 message: Some(message.to_owned()),
312 data: description.map(Value::from),
313 }
314 }
315
316 pub fn parse_error(description: Option<String>) -> Self {
317 Self::new_reserved_with_description(-32700, "Parse error", description)
318 }
319
320 pub fn invalid_request(description: Option<String>) -> Self {
321 Self::new_reserved_with_description(-32600, "Invalid Request", description)
322 }
323
324 pub fn method_not_found(description: Option<String>) -> Self {
325 Self::new_reserved_with_description(-32601, "Method not found", description)
326 }
327
328 pub fn invalid_params(description: Option<String>) -> Self {
329 Self::new_reserved_with_description(-32602, "Invalid params", description)
330 }
331
332 pub fn internal_from_string(description: Option<String>) -> Self {
333 Self::new_reserved_with_description(-32603, "Internal error", description)
334 }
335
336 pub fn internal_error(data: Option<Value>) -> Self {
337 Self::new_reserved(-32603, "Internal error", data)
338 }
339}
340
341impl Default for RpcError {
342 fn default() -> Self {
343 Self::internal_error(None)
344 }
345}
346
347impl From<()> for RpcError {
348 fn from(_: ()) -> Self {
349 Self::default()
350 }
351}
352
353#[derive(Clone, Debug, Serialize, Deserialize, Hash, PartialEq, Eq)]
354#[serde(untagged)]
355pub enum SubscriptionId {
356 String(String),
357 Number(u64),
358}
359
360impl TryFrom<Value> for SubscriptionId {
361 type Error = Error;
362
363 fn try_from(value: Value) -> Result<Self, Error> {
364 match value {
365 Value::String(s) => Ok(SubscriptionId::String(s)),
366 Value::Number(n) => n
367 .as_u64()
368 .map(SubscriptionId::Number)
369 .ok_or(Error::InvalidSubscriptionId(Value::Number(n))),
370 value => Err(Error::InvalidSubscriptionId(value)),
371 }
372 }
373}
374
375impl From<u64> for SubscriptionId {
376 fn from(n: u64) -> Self {
377 SubscriptionId::Number(n)
378 }
379}
380
381impl From<String> for SubscriptionId {
382 fn from(s: String) -> Self {
383 SubscriptionId::String(s)
384 }
385}
386
387impl Display for SubscriptionId {
388 fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
389 match self {
390 SubscriptionId::String(s) => write!(f, "{}", s),
391 SubscriptionId::Number(n) => write!(f, "{}", n),
392 }
393 }
394}
395
396#[derive(Clone, Debug, Serialize, Deserialize)]
397pub struct SubscriptionMessage<T> {
398 pub subscription: SubscriptionId,
399 pub result: T,
400}