jsonrpc.rs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2023 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. //! JSON-RPC 2.0 object definitions
  19. use std::collections::HashMap;
  20. use rand::{rngs::OsRng, Rng};
  21. use tinyjson::JsonValue;
  22. use crate::{
  23. error::RpcError,
  24. system::{Subscriber, SubscriberPtr},
  25. Result,
  26. };
  27. /// JSON-RPC error codes.
  28. /// The error codes `[-32768, -32000]` are reserved for predefined errors.
  29. #[derive(Copy, Clone, Debug)]
  30. pub enum ErrorCode {
  31. /// Invalid JSON was received by the server.
  32. /// An error occurred on the server while parsing the JSON text.
  33. ParseError,
  34. /// The JSON sent is not a valid Request object.
  35. InvalidRequest,
  36. /// The method does not exist / is not available.
  37. MethodNotFound,
  38. /// Invalid method parameter(s).
  39. InvalidParams,
  40. /// Internal JSON-RPC error.
  41. InternalError,
  42. /// ID mismatch
  43. IdMismatch,
  44. /// Invalid/Unexpected reply
  45. InvalidReply,
  46. /// Reserved for implementation-defined server-errors.
  47. ServerError(i32),
  48. }
  49. impl ErrorCode {
  50. pub fn code(&self) -> i32 {
  51. match *self {
  52. Self::ParseError => -32700,
  53. Self::InvalidRequest => -32600,
  54. Self::MethodNotFound => -32601,
  55. Self::InvalidParams => -32602,
  56. Self::InternalError => -32603,
  57. Self::IdMismatch => -32360,
  58. Self::InvalidReply => -32361,
  59. Self::ServerError(c) => c,
  60. }
  61. }
  62. pub fn message(&self) -> String {
  63. match *self {
  64. Self::ParseError => "parse error".to_string(),
  65. Self::InvalidRequest => "invalid request".to_string(),
  66. Self::MethodNotFound => "method not found".to_string(),
  67. Self::InvalidParams => "invalid params".to_string(),
  68. Self::InternalError => "internal error".to_string(),
  69. Self::IdMismatch => "id mismatch".to_string(),
  70. Self::InvalidReply => "invalid reply".to_string(),
  71. Self::ServerError(_) => "server error".to_string(),
  72. }
  73. }
  74. pub fn desc(&self) -> JsonValue {
  75. JsonValue::String(self.message())
  76. }
  77. }
  78. // ANCHOR: jsonresult
  79. /// Wrapping enum around the available JSON-RPC object types
  80. #[derive(Clone, Debug)]
  81. pub enum JsonResult {
  82. Response(JsonResponse),
  83. Error(JsonError),
  84. Notification(JsonNotification),
  85. /// Subscriber is a special object that yields a channel
  86. Subscriber(JsonSubscriber),
  87. Request(JsonRequest),
  88. }
  89. impl JsonResult {
  90. pub fn try_from_value(value: &JsonValue) -> Result<Self> {
  91. if let Ok(response) = JsonResponse::try_from(value) {
  92. return Ok(Self::Response(response))
  93. }
  94. if let Ok(error) = JsonError::try_from(value) {
  95. return Ok(Self::Error(error))
  96. }
  97. if let Ok(notification) = JsonNotification::try_from(value) {
  98. return Ok(Self::Notification(notification))
  99. }
  100. Err(RpcError::InvalidJson("Invalid JSON Result".to_string()).into())
  101. }
  102. }
  103. impl From<JsonResponse> for JsonResult {
  104. fn from(resp: JsonResponse) -> Self {
  105. Self::Response(resp)
  106. }
  107. }
  108. impl From<JsonError> for JsonResult {
  109. fn from(err: JsonError) -> Self {
  110. Self::Error(err)
  111. }
  112. }
  113. impl From<JsonNotification> for JsonResult {
  114. fn from(notif: JsonNotification) -> Self {
  115. Self::Notification(notif)
  116. }
  117. }
  118. impl From<JsonSubscriber> for JsonResult {
  119. fn from(sub: JsonSubscriber) -> Self {
  120. Self::Subscriber(sub)
  121. }
  122. }
  123. // ANCHOR: jsonrequest
  124. /// A JSON-RPC request object
  125. #[derive(Clone, Debug)]
  126. pub struct JsonRequest {
  127. /// JSON-RPC version
  128. pub jsonrpc: &'static str,
  129. /// Request ID
  130. pub id: u16,
  131. /// Request method
  132. pub method: String,
  133. /// Request parameters
  134. pub params: JsonValue,
  135. }
  136. // ANCHOR_END: jsonrequest
  137. impl JsonRequest {
  138. /// Create a new [`JsonRequest`] object with the given method and parameters.
  139. /// The request ID is chosen randomly.
  140. pub fn new(method: &str, params: Vec<JsonValue>) -> Self {
  141. Self {
  142. jsonrpc: "2.0",
  143. id: OsRng::gen(&mut OsRng),
  144. method: method.to_string(),
  145. params: JsonValue::Array(params),
  146. }
  147. }
  148. /// Convert the object into a JSON string
  149. pub fn stringify(&self) -> Result<String> {
  150. let v: JsonValue = self.into();
  151. Ok(v.stringify()?)
  152. }
  153. }
  154. impl From<&JsonRequest> for JsonValue {
  155. fn from(req: &JsonRequest) -> JsonValue {
  156. JsonValue::Object(HashMap::from([
  157. ("jsonrpc".to_string(), JsonValue::String(req.jsonrpc.to_string())),
  158. ("id".to_string(), JsonValue::Number(req.id.into())),
  159. ("method".to_string(), JsonValue::String(req.method.clone())),
  160. ("params".to_string(), req.params.clone()),
  161. ]))
  162. }
  163. }
  164. impl TryFrom<&JsonValue> for JsonRequest {
  165. type Error = RpcError;
  166. fn try_from(value: &JsonValue) -> std::result::Result<Self, Self::Error> {
  167. if !value.is_object() {
  168. return Err(RpcError::InvalidJson("JSON is not an Object".to_string()))
  169. }
  170. let map: &HashMap<String, JsonValue> = value.get().unwrap();
  171. if !map.contains_key("jsonrpc") ||
  172. !map["jsonrpc"].is_string() ||
  173. map["jsonrpc"] != JsonValue::String("2.0".to_string())
  174. {
  175. return Err(RpcError::InvalidJson(
  176. "Request does not contain valid \"jsonrpc\" field".to_string(),
  177. ))
  178. }
  179. if !map.contains_key("id") || !map["id"].is_number() {
  180. return Err(RpcError::InvalidJson(
  181. "Request does not contain valid \"id\" field".to_string(),
  182. ))
  183. }
  184. if !map.contains_key("method") || !map["method"].is_string() {
  185. return Err(RpcError::InvalidJson(
  186. "Request does not contain valid \"method\" field".to_string(),
  187. ))
  188. }
  189. if !map.contains_key("params") || !map["params"].is_array() {
  190. return Err(RpcError::InvalidJson(
  191. "Request does not contain valid \"params\" field".to_string(),
  192. ))
  193. }
  194. Ok(Self {
  195. jsonrpc: "2.0",
  196. id: *map["id"].get::<f64>().unwrap() as u16,
  197. method: map["method"].get::<String>().unwrap().clone(),
  198. params: map["params"].clone(),
  199. })
  200. }
  201. }
  202. /// A JSON-RPC notification object
  203. #[derive(Clone, Debug)]
  204. pub struct JsonNotification {
  205. /// JSON-RPC version
  206. pub jsonrpc: &'static str,
  207. /// Notification method
  208. pub method: String,
  209. /// Notification parameters
  210. pub params: JsonValue,
  211. }
  212. impl JsonNotification {
  213. /// Create a new [`JsonNotification`] object with the given method and parameters.
  214. pub fn new(method: &str, params: JsonValue) -> Self {
  215. assert!(params.is_array());
  216. Self { jsonrpc: "2.0", method: method.to_string(), params }
  217. }
  218. /// Convert the object into a JSON string
  219. pub fn stringify(&self) -> Result<String> {
  220. let v: JsonValue = self.into();
  221. Ok(v.stringify()?)
  222. }
  223. }
  224. impl From<&JsonNotification> for JsonValue {
  225. fn from(notif: &JsonNotification) -> JsonValue {
  226. JsonValue::Object(HashMap::from([
  227. ("jsonrpc".to_string(), JsonValue::String(notif.jsonrpc.to_string())),
  228. ("method".to_string(), JsonValue::String(notif.method.clone())),
  229. ("params".to_string(), notif.params.clone()),
  230. ]))
  231. }
  232. }
  233. impl TryFrom<&JsonValue> for JsonNotification {
  234. type Error = RpcError;
  235. fn try_from(value: &JsonValue) -> std::result::Result<Self, Self::Error> {
  236. if !value.is_object() {
  237. return Err(RpcError::InvalidJson("JSON is not an Object".to_string()))
  238. }
  239. let map: &HashMap<String, JsonValue> = value.get().unwrap();
  240. if !map.contains_key("jsonrpc") ||
  241. !map["jsonrpc"].is_string() ||
  242. map["jsonrpc"] != JsonValue::String("2.0".to_string())
  243. {
  244. return Err(RpcError::InvalidJson(
  245. "Notification does not contain valid \"jsonrpc\" field".to_string(),
  246. ))
  247. }
  248. if !map.contains_key("method") || !map["method"].is_string() {
  249. return Err(RpcError::InvalidJson(
  250. "Notification does not contain valid \"method\" field".to_string(),
  251. ))
  252. }
  253. if !map.contains_key("params") || !map["params"].is_array() {
  254. return Err(RpcError::InvalidJson(
  255. "Notification does not contain valid \"params\" field".to_string(),
  256. ))
  257. }
  258. Ok(Self {
  259. jsonrpc: "2.0",
  260. method: map["method"].get::<String>().unwrap().clone(),
  261. params: map["params"].clone(),
  262. })
  263. }
  264. }
  265. /// A JSON-RPC response object
  266. #[derive(Clone, Debug)]
  267. pub struct JsonResponse {
  268. /// JSON-RPC version
  269. pub jsonrpc: &'static str,
  270. /// Request ID
  271. pub id: u16,
  272. /// Response result
  273. pub result: JsonValue,
  274. }
  275. impl JsonResponse {
  276. /// Create a new [`JsonResponse`] object with the given ID and result value.
  277. /// Creating a `JsonResponse` implies that the method call was successful.
  278. pub fn new(result: JsonValue, id: u16) -> Self {
  279. Self { jsonrpc: "2.0", id, result }
  280. }
  281. /// Convert the object into a JSON string
  282. pub fn stringify(&self) -> Result<String> {
  283. let v: JsonValue = self.into();
  284. Ok(v.stringify()?)
  285. }
  286. }
  287. impl From<&JsonResponse> for JsonValue {
  288. fn from(rep: &JsonResponse) -> JsonValue {
  289. JsonValue::Object(HashMap::from([
  290. ("jsonrpc".to_string(), JsonValue::String(rep.jsonrpc.to_string())),
  291. ("id".to_string(), JsonValue::Number(rep.id.into())),
  292. ("result".to_string(), rep.result.clone()),
  293. ]))
  294. }
  295. }
  296. impl TryFrom<&JsonValue> for JsonResponse {
  297. type Error = RpcError;
  298. fn try_from(value: &JsonValue) -> std::result::Result<Self, Self::Error> {
  299. if !value.is_object() {
  300. return Err(RpcError::InvalidJson("Json is not an Object".to_string()))
  301. }
  302. let map: &HashMap<String, JsonValue> = value.get().unwrap();
  303. if !map.contains_key("jsonrpc") ||
  304. !map["jsonrpc"].is_string() ||
  305. map["jsonrpc"] != JsonValue::String("2.0".to_string())
  306. {
  307. return Err(RpcError::InvalidJson(
  308. "Response does not contain valid \"jsonrpc\" field".to_string(),
  309. ))
  310. }
  311. if !map.contains_key("id") || !map["id"].is_number() {
  312. return Err(RpcError::InvalidJson(
  313. "Response does not contain valid \"id\" field".to_string(),
  314. ))
  315. }
  316. Ok(Self {
  317. jsonrpc: "2.0",
  318. id: *map["id"].get::<f64>().unwrap() as u16,
  319. result: map["result"].clone(),
  320. })
  321. }
  322. }
  323. /// A JSON-RPC error object
  324. #[derive(Clone, Debug)]
  325. pub struct JsonError {
  326. /// JSON-RPC version
  327. pub jsonrpc: &'static str,
  328. /// Request ID
  329. pub id: u16,
  330. /// JSON-RPC error (code and message)
  331. pub error: JsonErrorVal,
  332. }
  333. /// A JSON-RPC error value (code and message)
  334. #[derive(Clone, Debug)]
  335. pub struct JsonErrorVal {
  336. /// Error code
  337. pub code: i32,
  338. /// Error message
  339. pub message: String,
  340. }
  341. impl JsonError {
  342. /// Create a new [`JsonError`] object with the given error code, optional
  343. /// message, and a response ID.
  344. /// Creating a `JsonError` implies that the method call was unsuccessful.
  345. pub fn new(c: ErrorCode, message: Option<String>, id: u16) -> Self {
  346. let error = JsonErrorVal { code: c.code(), message: message.unwrap_or(c.message()) };
  347. Self { jsonrpc: "2.0", id, error }
  348. }
  349. /// Convert the object into a JSON string
  350. pub fn stringify(&self) -> Result<String> {
  351. let v: JsonValue = self.into();
  352. Ok(v.stringify()?)
  353. }
  354. }
  355. impl From<&JsonError> for JsonValue {
  356. fn from(err: &JsonError) -> JsonValue {
  357. let errmap = JsonValue::Object(HashMap::from([
  358. ("code".to_string(), JsonValue::Number(err.error.code.into())),
  359. ("message".to_string(), JsonValue::String(err.error.message.clone())),
  360. ]));
  361. JsonValue::Object(HashMap::from([
  362. ("jsonrpc".to_string(), JsonValue::String(err.jsonrpc.to_string())),
  363. ("id".to_string(), JsonValue::Number(err.id.into())),
  364. ("error".to_string(), errmap),
  365. ]))
  366. }
  367. }
  368. impl TryFrom<&JsonValue> for JsonError {
  369. type Error = RpcError;
  370. fn try_from(value: &JsonValue) -> std::result::Result<Self, Self::Error> {
  371. if !value.is_object() {
  372. return Err(RpcError::InvalidJson("JSON is not an Object".to_string()))
  373. }
  374. let map: &HashMap<String, JsonValue> = value.get().unwrap();
  375. if !map.contains_key("jsonrpc") ||
  376. !map["jsonrpc"].is_string() ||
  377. map["jsonrpc"] != JsonValue::String("2.0".to_string())
  378. {
  379. return Err(RpcError::InvalidJson(
  380. "Error does not contain valid \"jsonrpc\" field".to_string(),
  381. ))
  382. }
  383. if !map.contains_key("id") || !map["id"].is_number() {
  384. return Err(RpcError::InvalidJson(
  385. "Error does not contain valid \"id\" field".to_string(),
  386. ))
  387. }
  388. if !map.contains_key("error") || !map["error"].is_object() {
  389. return Err(RpcError::InvalidJson(
  390. "Error does not contain valid \"error\" field".to_string(),
  391. ))
  392. }
  393. if !map["error"]["code"].is_number() {
  394. return Err(RpcError::InvalidJson(
  395. "Error does not contain valid \"error.code\" field".to_string(),
  396. ))
  397. }
  398. if !map["error"]["message"].is_string() {
  399. return Err(RpcError::InvalidJson(
  400. "Error does not contain valid \"error.message\" field".to_string(),
  401. ))
  402. }
  403. Ok(Self {
  404. jsonrpc: "2.0",
  405. id: *map["id"].get::<f64>().unwrap() as u16,
  406. error: JsonErrorVal {
  407. code: *map["error"]["code"].get::<f64>().unwrap() as i32,
  408. message: map["error"]["message"].get::<String>().unwrap().to_string(),
  409. },
  410. })
  411. }
  412. }
  413. /// A JSON-RPC subscriber for notifications
  414. #[derive(Clone, Debug)]
  415. pub struct JsonSubscriber {
  416. /// Notification method
  417. pub method: &'static str,
  418. /// Notification subscriber
  419. pub sub: SubscriberPtr<JsonNotification>,
  420. }
  421. impl JsonSubscriber {
  422. pub fn new(method: &'static str) -> Self {
  423. let sub = Subscriber::new();
  424. Self { method, sub }
  425. }
  426. /// Send a notification to the subscriber with the given JSON object
  427. pub async fn notify(&self, params: Vec<JsonValue>) {
  428. let notification = JsonNotification::new(self.method, JsonValue::Array(params));
  429. self.sub.notify(notification).await;
  430. }
  431. }