jsonrpc.rs 16 KB

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