/* This file is part of DarkFi (https://dark.fi) * * Copyright (C) 2020-2023 Dyne.org foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ //! JSON-RPC 2.0 primitives use std::fmt; use async_std::sync::Arc; use darkfi_serial::{serialize, Encodable}; use rand::{rngs::OsRng, Rng}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde_json::{json, Value}; use crate::system::{Subscriber, SubscriberPtr}; /// JSON-RPC error codes. /// The error codes from and including -32768 to -32000 are reserved for pre-defined errors. #[derive(Debug, Clone)] pub enum ErrorCode { ParseError, InvalidRequest, MethodNotFound, InvalidParams, InternalError, ServerError(i64), InvalidId, } impl ErrorCode { pub fn code(&self) -> i64 { match *self { Self::ParseError => -32700, Self::InvalidRequest => -32600, Self::MethodNotFound => -32601, Self::InvalidParams => -32602, Self::InternalError => -32603, // -32000 to -32099 Self::ServerError(c) => c, Self::InvalidId => -32001, } } pub fn desc(&self) -> String { let desc = match *self { Self::ParseError => "Parse error", Self::InvalidRequest => "Invalid request", Self::MethodNotFound => "Method not found", Self::InvalidParams => "Invalid params", Self::InternalError => "Internal error", Self::ServerError(_) => "", Self::InvalidId => "Request ID mismatch", }; desc.to_string() } } /// Wrapping enum around the possible JSON-RPC object types. // ANCHOR: jsonresult #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(untagged)] pub enum JsonResult { Response(JsonResponse), Error(JsonError), Notification(JsonNotification), Subscriber(JsonSubscriber), } // ANCHOR_END: jsonresult impl From for JsonResult { fn from(resp: JsonResponse) -> Self { Self::Response(resp) } } impl From for JsonResult { fn from(err: JsonError) -> Self { Self::Error(err) } } impl From for JsonResult { fn from(notif: JsonNotification) -> Self { Self::Notification(notif) } } impl From for JsonResult { fn from(sub: JsonSubscriber) -> Self { Self::Subscriber(sub) } } /// A JSON-RPC request object. // ANCHOR: jsonrequest #[derive(Clone, Debug, Serialize, Deserialize)] pub struct JsonRequest { /// JSON-RPC version pub jsonrpc: Value, /// Request ID pub id: Value, /// Request method pub method: Value, /// Request parameters pub params: Value, } // ANCHOR_END: jsonrequest impl JsonRequest { pub fn new(method: &str, parameters: Value) -> Self { Self { jsonrpc: json!("2.0"), id: json!(OsRng.gen::()), method: json!(method), params: parameters, } } } /// A JSON-RPC notification object. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct JsonNotification { /// JSON-RPC version pub jsonrpc: Value, /// Notification method pub method: Value, /// Notification parameters pub params: Value, } impl JsonNotification { pub fn new(method: Value, params: Value) -> Self { Self { jsonrpc: json!("2.0"), method, params } } } /// A method specific JSON-RPC subscriber for notifications #[derive(Clone)] pub struct MethodSubscriber { /// Notification method pub method: Value, /// Notification subscriber pub subscriber: SubscriberPtr, } impl MethodSubscriber { pub fn new(method: Value) -> Self { let subscriber = Subscriber::new(); Self { method, subscriber } } /// Auxiliary function to format provided message and notify the subscriber. pub async fn notify(&self, message: &T) { let params = json!([bs58::encode(&serialize(message)).into_string()]); let notif = JsonNotification::new(self.method.clone(), params); self.subscriber.notify(notif).await; } } impl fmt::Debug for MethodSubscriber { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("MethodSubscriber") .field("method", &self.method) .field("pointer", &Arc::as_ptr(&self.subscriber)) .finish() } } /// A JSON-RPC subscriber for notifications #[derive(Clone, Debug)] pub struct JsonSubscriber { /// JSON-RPC version pub jsonrpc: Value, /// Method subscriber pub subscriber: MethodSubscriber, } impl JsonSubscriber { pub fn new(subscriber: MethodSubscriber) -> Self { Self { jsonrpc: json!("2.0"), subscriber } } } impl Serialize for JsonSubscriber { fn serialize(&self, _serializer: S) -> Result where S: Serializer, { unimplemented!(); } } impl<'de> Deserialize<'de> for JsonSubscriber { fn deserialize(_deserializer: D) -> Result where D: Deserializer<'de>, { unimplemented!(); } } /// A JSON-RPC response object. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct JsonResponse { /// JSON-RPC version pub jsonrpc: Value, /// Request ID pub id: Value, /// Response result pub result: Value, } impl JsonResponse { pub fn new(result: Value, id: Value) -> Self { Self { jsonrpc: json!("2.0"), id, result } } } /// A JSON-RPC error object. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct JsonError { /// JSON-RPC version pub jsonrpc: Value, /// Request ID pub id: Value, /// JSON-RPC error (code and message) pub error: JsonErrorVal, } /// A JSON-RPC error value (code and message) #[derive(Clone, Debug, Serialize, Deserialize)] pub struct JsonErrorVal { /// Error code pub code: Value, /// Error message pub message: Value, } impl JsonError { pub fn new(c: ErrorCode, m: Option, id: Value) -> Self { let error = JsonErrorVal { code: json!(c.code()), message: if m.is_none() { json!(c.desc()) } else { json!(m.unwrap()) }, }; Self { jsonrpc: json!("2.0"), error, id } } }