jsonrpc.rs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  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: JsonValue) -> Self {
  141. assert!(params.is_object() || params.is_array());
  142. Self { jsonrpc: "2.0", id: OsRng::gen(&mut OsRng), method: method.to_string(), params }
  143. }
  144. /// Convert the object into a JSON string
  145. pub fn stringify(&self) -> Result<String> {
  146. let v: JsonValue = self.into();
  147. Ok(v.stringify()?)
  148. }
  149. }
  150. impl From<&JsonRequest> for JsonValue {
  151. fn from(req: &JsonRequest) -> JsonValue {
  152. JsonValue::Object(HashMap::from([
  153. ("jsonrpc".to_string(), JsonValue::String(req.jsonrpc.to_string())),
  154. ("id".to_string(), JsonValue::Number(req.id.into())),
  155. ("method".to_string(), JsonValue::String(req.method.clone())),
  156. ("params".to_string(), req.params.clone()),
  157. ]))
  158. }
  159. }
  160. impl TryFrom<&JsonValue> for JsonRequest {
  161. type Error = RpcError;
  162. fn try_from(value: &JsonValue) -> std::result::Result<Self, Self::Error> {
  163. if !value.is_object() {
  164. return Err(RpcError::InvalidJson("JSON is not an Object".to_string()))
  165. }
  166. let map: &HashMap<String, JsonValue> = value.get().unwrap();
  167. if !map.contains_key("jsonrpc") ||
  168. !map["jsonrpc"].is_string() ||
  169. map["jsonrpc"] != JsonValue::String("2.0".to_string())
  170. {
  171. return Err(RpcError::InvalidJson(
  172. "Request does not contain valid \"jsonrpc\" field".to_string(),
  173. ))
  174. }
  175. if !map.contains_key("id") || !map["id"].is_number() {
  176. return Err(RpcError::InvalidJson(
  177. "Request does not contain valid \"id\" field".to_string(),
  178. ))
  179. }
  180. if !map.contains_key("method") || !map["method"].is_string() {
  181. return Err(RpcError::InvalidJson(
  182. "Request does not contain valid \"method\" field".to_string(),
  183. ))
  184. }
  185. if !map.contains_key("params") {
  186. return Err(RpcError::InvalidJson(
  187. "Request does not contain valid \"params\" field".to_string(),
  188. ))
  189. }
  190. if !map["params"].is_object() && !map["params"].is_array() {
  191. return Err(RpcError::InvalidJson(
  192. "Request does not contain valid \"params\" field".to_string(),
  193. ))
  194. }
  195. Ok(Self {
  196. jsonrpc: "2.0",
  197. id: *map["id"].get::<f64>().unwrap() as u16,
  198. method: map["method"].get::<String>().unwrap().clone(),
  199. params: map["params"].clone(),
  200. })
  201. }
  202. }
  203. /// A JSON-RPC notification object
  204. #[derive(Clone, Debug)]
  205. pub struct JsonNotification {
  206. /// JSON-RPC version
  207. pub jsonrpc: &'static str,
  208. /// Notification method
  209. pub method: String,
  210. /// Notification parameters
  211. pub params: JsonValue,
  212. }
  213. impl JsonNotification {
  214. /// Create a new [`JsonNotification`] object with the given method and parameters.
  215. pub fn new(method: &str, params: JsonValue) -> Self {
  216. assert!(params.is_object() || params.is_array());
  217. Self { jsonrpc: "2.0", method: method.to_string(), params }
  218. }
  219. /// Convert the object into a JSON string
  220. pub fn stringify(&self) -> Result<String> {
  221. let v: JsonValue = self.into();
  222. Ok(v.stringify()?)
  223. }
  224. }
  225. impl From<&JsonNotification> for JsonValue {
  226. fn from(notif: &JsonNotification) -> JsonValue {
  227. JsonValue::Object(HashMap::from([
  228. ("jsonrpc".to_string(), JsonValue::String(notif.jsonrpc.to_string())),
  229. ("method".to_string(), JsonValue::String(notif.method.clone())),
  230. ("params".to_string(), notif.params.clone()),
  231. ]))
  232. }
  233. }
  234. impl TryFrom<&JsonValue> for JsonNotification {
  235. type Error = RpcError;
  236. fn try_from(value: &JsonValue) -> std::result::Result<Self, Self::Error> {
  237. if !value.is_object() {
  238. return Err(RpcError::InvalidJson("JSON is not an Object".to_string()))
  239. }
  240. let map: &HashMap<String, JsonValue> = value.get().unwrap();
  241. if !map.contains_key("jsonrpc") ||
  242. !map["jsonrpc"].is_string() ||
  243. map["jsonrpc"] != JsonValue::String("2.0".to_string())
  244. {
  245. return Err(RpcError::InvalidJson(
  246. "Notification does not contain valid \"jsonrpc\" field".to_string(),
  247. ))
  248. }
  249. if !map.contains_key("method") || !map["method"].is_string() {
  250. return Err(RpcError::InvalidJson(
  251. "Notification does not contain valid \"method\" field".to_string(),
  252. ))
  253. }
  254. if !map.contains_key("params") {
  255. return Err(RpcError::InvalidJson(
  256. "Notification does not contain valid \"params\" field".to_string(),
  257. ))
  258. }
  259. if !map["params"].is_object() && !map["params"].is_array() {
  260. return Err(RpcError::InvalidJson(
  261. "Request does not contain valid \"params\" field".to_string(),
  262. ))
  263. }
  264. Ok(Self {
  265. jsonrpc: "2.0",
  266. method: map["method"].get::<String>().unwrap().clone(),
  267. params: map["params"].clone(),
  268. })
  269. }
  270. }
  271. /// A JSON-RPC response object
  272. #[derive(Clone, Debug)]
  273. pub struct JsonResponse {
  274. /// JSON-RPC version
  275. pub jsonrpc: &'static str,
  276. /// Request ID
  277. pub id: u16,
  278. /// Response result
  279. pub result: JsonValue,
  280. }
  281. impl JsonResponse {
  282. /// Create a new [`JsonResponse`] object with the given ID and result value.
  283. /// Creating a `JsonResponse` implies that the method call was successful.
  284. pub fn new(result: JsonValue, id: u16) -> Self {
  285. Self { jsonrpc: "2.0", id, result }
  286. }
  287. /// Convert the object into a JSON string
  288. pub fn stringify(&self) -> Result<String> {
  289. let v: JsonValue = self.into();
  290. Ok(v.stringify()?)
  291. }
  292. }
  293. impl From<&JsonResponse> for JsonValue {
  294. fn from(rep: &JsonResponse) -> JsonValue {
  295. JsonValue::Object(HashMap::from([
  296. ("jsonrpc".to_string(), JsonValue::String(rep.jsonrpc.to_string())),
  297. ("id".to_string(), JsonValue::Number(rep.id.into())),
  298. ("result".to_string(), rep.result.clone()),
  299. ]))
  300. }
  301. }
  302. impl TryFrom<&JsonValue> for JsonResponse {
  303. type Error = RpcError;
  304. fn try_from(value: &JsonValue) -> std::result::Result<Self, Self::Error> {
  305. if !value.is_object() {
  306. return Err(RpcError::InvalidJson("Json is not an Object".to_string()))
  307. }
  308. let map: &HashMap<String, JsonValue> = value.get().unwrap();
  309. if !map.contains_key("jsonrpc") ||
  310. !map["jsonrpc"].is_string() ||
  311. map["jsonrpc"] != JsonValue::String("2.0".to_string())
  312. {
  313. return Err(RpcError::InvalidJson(
  314. "Response does not contain valid \"jsonrpc\" field".to_string(),
  315. ))
  316. }
  317. if !map.contains_key("id") || !map["id"].is_number() {
  318. return Err(RpcError::InvalidJson(
  319. "Response does not contain valid \"id\" field".to_string(),
  320. ))
  321. }
  322. Ok(Self {
  323. jsonrpc: "2.0",
  324. id: *map["id"].get::<f64>().unwrap() as u16,
  325. result: map["result"].clone(),
  326. })
  327. }
  328. }
  329. /// A JSON-RPC error object
  330. #[derive(Clone, Debug)]
  331. pub struct JsonError {
  332. /// JSON-RPC version
  333. pub jsonrpc: &'static str,
  334. /// Request ID
  335. pub id: u16,
  336. /// JSON-RPC error (code and message)
  337. pub error: JsonErrorVal,
  338. }
  339. /// A JSON-RPC error value (code and message)
  340. #[derive(Clone, Debug)]
  341. pub struct JsonErrorVal {
  342. /// Error code
  343. pub code: i32,
  344. /// Error message
  345. pub message: String,
  346. }
  347. impl JsonError {
  348. /// Create a new [`JsonError`] object with the given error code, optional
  349. /// message, and a response ID.
  350. /// Creating a `JsonError` implies that the method call was unsuccessful.
  351. pub fn new(c: ErrorCode, message: Option<String>, id: u16) -> Self {
  352. let error = JsonErrorVal { code: c.code(), message: message.unwrap_or(c.message()) };
  353. Self { jsonrpc: "2.0", id, error }
  354. }
  355. /// Convert the object into a JSON string
  356. pub fn stringify(&self) -> Result<String> {
  357. let v: JsonValue = self.into();
  358. Ok(v.stringify()?)
  359. }
  360. }
  361. impl From<&JsonError> for JsonValue {
  362. fn from(err: &JsonError) -> JsonValue {
  363. let errmap = JsonValue::Object(HashMap::from([
  364. ("code".to_string(), JsonValue::Number(err.error.code.into())),
  365. ("message".to_string(), JsonValue::String(err.error.message.clone())),
  366. ]));
  367. JsonValue::Object(HashMap::from([
  368. ("jsonrpc".to_string(), JsonValue::String(err.jsonrpc.to_string())),
  369. ("id".to_string(), JsonValue::Number(err.id.into())),
  370. ("error".to_string(), errmap),
  371. ]))
  372. }
  373. }
  374. impl TryFrom<&JsonValue> for JsonError {
  375. type Error = RpcError;
  376. fn try_from(value: &JsonValue) -> std::result::Result<Self, Self::Error> {
  377. if !value.is_object() {
  378. return Err(RpcError::InvalidJson("JSON is not an Object".to_string()))
  379. }
  380. let map: &HashMap<String, JsonValue> = value.get().unwrap();
  381. if !map.contains_key("jsonrpc") ||
  382. !map["jsonrpc"].is_string() ||
  383. map["jsonrpc"] != JsonValue::String("2.0".to_string())
  384. {
  385. return Err(RpcError::InvalidJson(
  386. "Error does not contain valid \"jsonrpc\" field".to_string(),
  387. ))
  388. }
  389. if !map.contains_key("id") || !map["id"].is_number() {
  390. return Err(RpcError::InvalidJson(
  391. "Error does not contain valid \"id\" field".to_string(),
  392. ))
  393. }
  394. if !map.contains_key("error") || !map["error"].is_object() {
  395. return Err(RpcError::InvalidJson(
  396. "Error does not contain valid \"error\" field".to_string(),
  397. ))
  398. }
  399. if !map["error"]["code"].is_number() {
  400. return Err(RpcError::InvalidJson(
  401. "Error does not contain valid \"error.code\" field".to_string(),
  402. ))
  403. }
  404. if !map["error"]["message"].is_string() {
  405. return Err(RpcError::InvalidJson(
  406. "Error does not contain valid \"error.message\" field".to_string(),
  407. ))
  408. }
  409. Ok(Self {
  410. jsonrpc: "2.0",
  411. id: *map["id"].get::<f64>().unwrap() as u16,
  412. error: JsonErrorVal {
  413. code: *map["error"]["code"].get::<f64>().unwrap() as i32,
  414. message: map["error"]["message"].get::<String>().unwrap().to_string(),
  415. },
  416. })
  417. }
  418. }
  419. /// A JSON-RPC subscriber for notifications
  420. #[derive(Clone, Debug)]
  421. pub struct JsonSubscriber {
  422. /// Notification method
  423. pub method: &'static str,
  424. /// Notification subscriber
  425. pub sub: SubscriberPtr<JsonNotification>,
  426. }
  427. impl JsonSubscriber {
  428. pub fn new(method: &'static str) -> Self {
  429. let sub = Subscriber::new();
  430. Self { method, sub }
  431. }
  432. /// Send a notification to the subscriber with the given JSON object
  433. pub async fn notify(&self, params: JsonValue) {
  434. let notification = JsonNotification::new(self.method, params);
  435. self.sub.notify(notification).await;
  436. }
  437. }