1use serde::{Deserialize, Serialize};
2
3use crate::{
4 de_validate_version,
5 response::{HandlerResponse, Response},
6 serialize_version, Id, RpcError, RpcErrorKind, String, VERSION_HEADER,
7};
8
9#[cfg(feature = "canonical")]
10use crate::{ERR_INVALID_PROTOCOL_VERSION, JSONRPC_VERSION};
11
12#[derive(Serialize, Deserialize, Debug)]
13#[serde(deny_unknown_fields)]
14pub struct Request<M> {
16 #[serde(
17 default,
18 deserialize_with = "de_validate_version",
19 serialize_with = "serialize_version",
20 skip_serializing_if = "Option::is_none"
21 )]
22 jsonrpc: Option<()>,
23 #[cfg_attr(
24 feature = "canonical",
25 serde(skip_serializing_if = "Option::is_none", alias = "i")
26 )]
27 #[cfg_attr(
28 not(feature = "canonical"),
29 serde(rename = "i", skip_serializing_if = "Option::is_none")
30 )]
31 pub(crate) id: Option<Id>,
32 #[cfg_attr(feature = "std", serde(flatten))]
33 #[cfg_attr(not(feature = "std"), serde(rename = "p"))]
34 pub(crate) method: M,
35}
36
37impl<'a, M> Request<M>
38where
39 M: Serialize + Deserialize<'a>,
40{
41 pub fn new0(method: M) -> Request<M> {
43 Request {
44 jsonrpc: VERSION_HEADER,
45 id: None,
46 method,
47 }
48 }
49 pub fn new(id: Id, method: M) -> Request<M> {
51 Request {
52 jsonrpc: VERSION_HEADER,
53 id: Some(id),
54 method,
55 }
56 }
57 pub fn into_parts(self) -> (Option<Id>, M) {
59 (self.id, self.method)
60 }
61 pub fn from_parts(id: Option<Id>, method: M) -> Request<M> {
63 Request {
64 jsonrpc: VERSION_HEADER,
65 id,
66 method,
67 }
68 }
69}
70
71#[allow(clippy::module_name_repetitions)]
72#[derive(Deserialize, Debug)]
73pub struct InvalidRequest<'a> {
75 #[allow(dead_code)]
76 jsonrpc: Option<&'a str>,
77 id: Option<Id>,
78}
79
80impl InvalidRequest<'_> {
81 pub fn into_response<R>(self, error: String) -> Option<Response<R>> {
83 if let Some(id) = self.id {
84 #[cfg(feature = "canonical")]
85 let (code, message) = if let Some(jsonrpc) = self.jsonrpc {
86 if jsonrpc == JSONRPC_VERSION {
87 (RpcErrorKind::MethodNotFound, Some(error))
88 } else {
89 (
90 RpcErrorKind::InvalidRequest,
91 #[allow(clippy::unnecessary_fallible_conversions)]
92 ERR_INVALID_PROTOCOL_VERSION.try_into().ok(),
93 )
94 }
95 } else {
96 (RpcErrorKind::InvalidRequest, None)
97 };
98 #[cfg(not(feature = "canonical"))]
99 let (code, message) = (RpcErrorKind::MethodNotFound, Some(error));
100 Some(Response::from_handler_response(
101 id,
102 HandlerResponse::Err(RpcError {
103 kind: code,
104 message,
105 }),
106 ))
107 } else {
108 None
109 }
110 }
111}