thin_jsonrpc_client/
raw_response.rs1use serde_json::value::RawValue;
2use std::borrow::Cow;
3
4#[derive(Debug, derive_more::From, derive_more::Display)]
7pub enum ResponseError {
8 #[from]
10 #[display(fmt = "{error} ({:?})", "std::str::from_utf8(&bytes)")]
11 Deserialize {
12 error: serde_json::Error,
14 bytes: Vec<u8>
16 },
17 #[display(fmt = "failed to decode response: expected '\"jsonrpc\": \"2.0\"'")]
19 InvalidVersion {
20 bytes: Vec<u8>
22 }
23}
24
25#[derive(Clone, Debug, serde::Serialize)]
31#[serde(untagged)]
32pub enum RawResponse<'a> {
33 Ok(OkResponse<'a>),
35 Error(ErrorResponse<'a>)
37}
38
39impl <'a> RawResponse<'a> {
40 pub fn id(&self) -> Option<&str> {
44 match self {
45 RawResponse::Ok(r) => r.id.as_deref(),
46 RawResponse::Error(e) => e.id.as_deref()
47 }
48 }
49
50 pub fn from_bytes(bytes: &[u8]) -> Result<RawResponse<'_>, ResponseError> {
53 let res = match serde_json::from_slice(bytes).map(|res| RawResponse::Ok(res)) {
54 Ok(res) => res,
55 Err(_) => serde_json::from_slice(bytes)
56 .map(|res| RawResponse::Error(res))
57 .map_err(|e| ResponseError::Deserialize { error: e, bytes: bytes.to_owned() })?
58 };
59
60 let version = match &res {
61 RawResponse::Ok(r) => &*r.jsonrpc,
62 RawResponse::Error(e) => &*e.jsonrpc,
63 };
64
65 if version != "2.0" {
66 return Err(ResponseError::InvalidVersion { bytes: bytes.to_owned() })
67 }
68
69 Ok(res)
70 }
71
72 pub fn into_owned(self) -> RawResponse<'static> {
74 match self {
75 RawResponse::Ok(res) => {
76 RawResponse::Ok(res.into_owned())
77 },
78 RawResponse::Error(err) => {
79 RawResponse::Error(err.into_owned())
80 }
81 }
82 }
83
84 pub fn ok_from_value<V: serde::Serialize, Id: ToString>(id: Option<Id>, value: V) -> RawResponse<'static> {
87 let value = serde_json::value::to_raw_value(&value).expect("invalid json");
88 RawResponse::Ok(OkResponse {
89 jsonrpc: "2.0".into(),
90 id: id.map(|id| Cow::Owned(id.to_string())),
91 result: Cow::Owned(value)
92 })
93 }
94
95 pub fn err_from_value<Id: ToString>(id: Option<Id>, error: ErrorObject<'_>) -> RawResponse<'static> {
97 RawResponse::Error(ErrorResponse {
98 jsonrpc: "2.0".into(),
99 id: id.map(|id| Cow::Owned(id.to_string())),
100 error: error.into_owned()
101 })
102 }
103}
104
105#[derive(serde::Deserialize, serde::Serialize, Clone, Debug)]
107pub struct OkResponse<'a> {
108 #[serde(borrow)]
110 pub jsonrpc: Cow<'a, str>,
111 #[serde(borrow)]
113 pub id: Option<Cow<'a, str>>,
114 #[serde(borrow)]
116 pub result: Cow<'a, RawValue>
117}
118
119impl <'a> OkResponse<'a> {
120 pub fn into_owned(self) -> OkResponse<'static> {
122 OkResponse {
123 jsonrpc: Cow::Owned(self.jsonrpc.into_owned()),
124 id: self.id.map(|id| Cow::Owned(id.into_owned())),
125 result: Cow::Owned(self.result.into_owned())
126 }
127 }
128}
129
130#[derive(serde::Deserialize, serde::Serialize, Clone, Debug)]
132pub struct ErrorResponse<'a> {
133 #[serde(borrow)]
135 pub jsonrpc: Cow<'a, str>,
136 #[serde(borrow)]
138 pub id: Option<Cow<'a, str>>,
139 #[serde(borrow)]
141 pub error: ErrorObject<'a>
142}
143
144impl <'a> ErrorResponse<'a> {
145 pub fn into_owned(self) -> ErrorResponse<'static> {
147 ErrorResponse {
148 jsonrpc: Cow::Owned(self.jsonrpc.into_owned()),
149 id: self.id.map(|id| Cow::Owned(id.into_owned())),
150 error: self.error.into_owned()
151 }
152 }
153}
154
155#[derive(serde::Deserialize, serde::Serialize, derive_more::Display, Clone, Debug)]
157#[display(fmt = "Error {code}: {message}")]
158pub struct ErrorObject<'a> {
159 pub code: ErrorCode,
161 #[serde(borrow)]
163 pub message: Cow<'a, str>,
164 #[serde(borrow)]
166 pub data: Option<Cow<'a, RawValue>>
167}
168
169impl <'a> ErrorObject<'a> {
170 pub fn into_owned(self) -> ErrorObject<'static> {
172 ErrorObject {
173 code: self.code,
174 message: Cow::Owned(self.message.into_owned()),
175 data: self.data.map(|data| Cow::Owned(data.into_owned()))
176 }
177 }
178}
179
180pub type ErrorCode = i32;
182pub const CODE_PARSE_ERROR: ErrorCode = -32700;
184pub const CODE_INVALID_REQUEST: ErrorCode = -32600;
186pub const CODE_METHOD_NOT_FOUND: ErrorCode = -32601;
188pub const CODE_INVALID_PARAMS: ErrorCode = -32602;
190pub const CODE_INTERNAL_ERROR: ErrorCode = -32603;