From c8112ab02752f3f49e67452cc2ef5e628d6804ac Mon Sep 17 00:00:00 2001 From: edouardparis Date: Mon, 18 Nov 2024 11:42:05 +0100 Subject: [PATCH] move rpc code to its own module --- liana/src/jsonrpc/api.rs | 2 +- liana/src/jsonrpc/mod.rs | 216 +------------------------------ liana/src/jsonrpc/rpc.rs | 212 ++++++++++++++++++++++++++++++ liana/src/jsonrpc/server/unix.rs | 7 +- 4 files changed, 221 insertions(+), 216 deletions(-) create mode 100644 liana/src/jsonrpc/rpc.rs diff --git a/liana/src/jsonrpc/api.rs b/liana/src/jsonrpc/api.rs index 3ff137afb..d27a7f1d9 100644 --- a/liana/src/jsonrpc/api.rs +++ b/liana/src/jsonrpc/api.rs @@ -1,6 +1,6 @@ use crate::{ commands::{CoinStatus, LabelItem}, - jsonrpc::{Error, Params, Request, Response}, + jsonrpc::rpc::{Error, Params, Request, Response}, DaemonControl, }; diff --git a/liana/src/jsonrpc/mod.rs b/liana/src/jsonrpc/mod.rs index 131a96a6b..027774111 100644 --- a/liana/src/jsonrpc/mod.rs +++ b/liana/src/jsonrpc/mod.rs @@ -1,215 +1,5 @@ +#[cfg(unix)] mod api; +#[cfg(unix)] +pub mod rpc; pub mod server; - -use crate::commands; - -use std::{error, fmt}; - -use serde::{self, Deserialize, Deserializer, Serialize, Serializer}; - -#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] -#[serde(deny_unknown_fields)] -#[serde(untagged)] -pub enum Params { - Array(Vec), - Map(serde_json::Map), -} - -impl Params { - /// Get the parameter supposed to be at a given index / of a given name. - pub fn get(&self, index: usize, name: &Q) -> Option<&serde_json::Value> - where - String: std::borrow::Borrow, - Q: ?Sized + Ord + Eq + std::hash::Hash, - { - match self { - Params::Array(vec) => vec.get(index), - Params::Map(map) => map.get(name), - } - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] -#[serde(deny_unknown_fields)] -#[serde(untagged)] -pub enum ReqId { - Num(u64), - Str(String), -} - -/// A JSONRPC2 request. See https://www.jsonrpc.org/specification#request_object. -#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] -#[serde(deny_unknown_fields)] -pub struct Request { - /// Version. Must be "2.0". - pub jsonrpc: String, - /// Command name. - pub method: String, - /// Command parameters. - pub params: Option, - /// Request identifier. - pub id: ReqId, -} - -/// A failure to broadcast a transaction to the P2P network. -const BROADCAST_ERROR: i64 = 1_000; - -/// JSONRPC2 error codes. See https://www.jsonrpc.org/specification#error_object. -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum ErrorCode { - /// The method does not exist / is not available. - MethodNotFound, - /// Invalid method parameter(s). - InvalidParams, - /// Internal error while handling the command. - InternalError, - /// Reserved for implementation-defined server-errors. - ServerError(i64), -} - -impl From<&ErrorCode> for i64 { - fn from(code: &ErrorCode) -> i64 { - match code { - ErrorCode::MethodNotFound => -32601, - ErrorCode::InvalidParams => -32602, - ErrorCode::InternalError => -32603, - ErrorCode::ServerError(code) => *code, - } - } -} - -impl From for ErrorCode { - fn from(code: i64) -> ErrorCode { - match code { - -32601 => ErrorCode::MethodNotFound, - -32602 => ErrorCode::InvalidParams, - -32603 => ErrorCode::InternalError, - code => ErrorCode::ServerError(code), - } - } -} - -impl<'a> Deserialize<'a> for ErrorCode { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'a>, - { - let code: i64 = Deserialize::deserialize(deserializer)?; - Ok(code.into()) - } -} - -impl Serialize for ErrorCode { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_i64(self.into()) - } -} - -/// JSONRPC2 error response. See https://www.jsonrpc.org/specification#error_object. -#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct Error { - pub code: ErrorCode, - pub message: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub data: Option, -} - -impl Error { - pub fn new(code: ErrorCode, message: impl Into) -> Error { - Error { - message: message.into(), - code, - data: None, - } - } - - pub fn method_not_found() -> Error { - Error::new(ErrorCode::MethodNotFound, "Method not found") - } - - pub fn invalid_params(message: impl Into) -> Error { - Error::new( - ErrorCode::InvalidParams, - format!("Invalid params: {}", message.into()), - ) - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let code: i64 = (&self.code).into(); - write!(f, "{}: {}", code, self.message) - } -} - -impl error::Error for Error {} - -impl From for Error { - fn from(e: commands::CommandError) -> Error { - match e { - commands::CommandError::NoOutpointForSelfSend - | commands::CommandError::UnknownOutpoint(..) - | commands::CommandError::InvalidFeerate(..) - | commands::CommandError::AlreadySpent(..) - | commands::CommandError::ImmatureCoinbase(..) - | commands::CommandError::Address(..) - | commands::CommandError::SpendCreation(..) - | commands::CommandError::InsufficientFunds(..) - | commands::CommandError::UnknownSpend(..) - | commands::CommandError::SpendFinalization(..) - | commands::CommandError::InsaneRescanTimestamp(..) - | commands::CommandError::AlreadyRescanning - | commands::CommandError::InvalidDerivationIndex - | commands::CommandError::RbfError(..) - | commands::CommandError::EmptyFilterList - | commands::CommandError::RecoveryNotAvailable => { - Error::new(ErrorCode::InvalidParams, e.to_string()) - } - commands::CommandError::RescanTrigger(..) => { - Error::new(ErrorCode::InternalError, e.to_string()) - } - commands::CommandError::TxBroadcast(_) => { - Error::new(ErrorCode::ServerError(BROADCAST_ERROR), e.to_string()) - } - } - } -} - -/// JSONRPC2 response. See https://www.jsonrpc.org/specification#response_object. -#[derive(Clone, Debug, PartialEq, Eq, Serialize)] -#[serde(deny_unknown_fields)] -pub struct Response { - /// Version. Must be "2.0". - jsonrpc: String, - /// Required on success. Must not exist on error. - #[serde(skip_serializing_if = "Option::is_none")] - result: Option, - /// Required on error. Must not exist on success. - #[serde(skip_serializing_if = "Option::is_none")] - error: Option, - /// Request identifier. - id: ReqId, -} - -impl Response { - fn new(id: ReqId, result: Option, error: Option) -> Response { - Response { - jsonrpc: "2.0".to_string(), - result, - error, - id, - } - } - - pub fn success(id: ReqId, result: serde_json::Value) -> Response { - Response::new(id, Some(result), None) - } - - pub fn error(id: ReqId, error: Error) -> Response { - Response::new(id, None, Some(error)) - } -} diff --git a/liana/src/jsonrpc/rpc.rs b/liana/src/jsonrpc/rpc.rs new file mode 100644 index 000000000..dcfd19a83 --- /dev/null +++ b/liana/src/jsonrpc/rpc.rs @@ -0,0 +1,212 @@ +use crate::commands; + +use std::{error, fmt}; + +use serde::{self, Deserialize, Deserializer, Serialize, Serializer}; + +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +#[serde(untagged)] +pub enum Params { + Array(Vec), + Map(serde_json::Map), +} + +impl Params { + /// Get the parameter supposed to be at a given index / of a given name. + pub fn get(&self, index: usize, name: &Q) -> Option<&serde_json::Value> + where + String: std::borrow::Borrow, + Q: ?Sized + Ord + Eq + std::hash::Hash, + { + match self { + Params::Array(vec) => vec.get(index), + Params::Map(map) => map.get(name), + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +#[serde(untagged)] +pub enum ReqId { + Num(u64), + Str(String), +} + +/// A JSONRPC2 request. See https://www.jsonrpc.org/specification#request_object. +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct Request { + /// Version. Must be "2.0". + pub jsonrpc: String, + /// Command name. + pub method: String, + /// Command parameters. + pub params: Option, + /// Request identifier. + pub id: ReqId, +} + +/// A failure to broadcast a transaction to the P2P network. +const BROADCAST_ERROR: i64 = 1_000; + +/// JSONRPC2 error codes. See https://www.jsonrpc.org/specification#error_object. +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum ErrorCode { + /// The method does not exist / is not available. + MethodNotFound, + /// Invalid method parameter(s). + InvalidParams, + /// Internal error while handling the command. + InternalError, + /// Reserved for implementation-defined server-errors. + ServerError(i64), +} + +impl From<&ErrorCode> for i64 { + fn from(code: &ErrorCode) -> i64 { + match code { + ErrorCode::MethodNotFound => -32601, + ErrorCode::InvalidParams => -32602, + ErrorCode::InternalError => -32603, + ErrorCode::ServerError(code) => *code, + } + } +} + +impl From for ErrorCode { + fn from(code: i64) -> ErrorCode { + match code { + -32601 => ErrorCode::MethodNotFound, + -32602 => ErrorCode::InvalidParams, + -32603 => ErrorCode::InternalError, + code => ErrorCode::ServerError(code), + } + } +} + +impl<'a> Deserialize<'a> for ErrorCode { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'a>, + { + let code: i64 = Deserialize::deserialize(deserializer)?; + Ok(code.into()) + } +} + +impl Serialize for ErrorCode { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_i64(self.into()) + } +} + +/// JSONRPC2 error response. See https://www.jsonrpc.org/specification#error_object. +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Error { + pub code: ErrorCode, + pub message: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option, +} + +impl Error { + pub fn new(code: ErrorCode, message: impl Into) -> Error { + Error { + message: message.into(), + code, + data: None, + } + } + + pub fn method_not_found() -> Error { + Error::new(ErrorCode::MethodNotFound, "Method not found") + } + + pub fn invalid_params(message: impl Into) -> Error { + Error::new( + ErrorCode::InvalidParams, + format!("Invalid params: {}", message.into()), + ) + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let code: i64 = (&self.code).into(); + write!(f, "{}: {}", code, self.message) + } +} + +impl error::Error for Error {} + +impl From for Error { + fn from(e: commands::CommandError) -> Error { + match e { + commands::CommandError::NoOutpointForSelfSend + | commands::CommandError::UnknownOutpoint(..) + | commands::CommandError::InvalidFeerate(..) + | commands::CommandError::AlreadySpent(..) + | commands::CommandError::ImmatureCoinbase(..) + | commands::CommandError::Address(..) + | commands::CommandError::SpendCreation(..) + | commands::CommandError::InsufficientFunds(..) + | commands::CommandError::UnknownSpend(..) + | commands::CommandError::SpendFinalization(..) + | commands::CommandError::InsaneRescanTimestamp(..) + | commands::CommandError::AlreadyRescanning + | commands::CommandError::InvalidDerivationIndex + | commands::CommandError::RbfError(..) + | commands::CommandError::EmptyFilterList + | commands::CommandError::RecoveryNotAvailable => { + Error::new(ErrorCode::InvalidParams, e.to_string()) + } + commands::CommandError::RescanTrigger(..) => { + Error::new(ErrorCode::InternalError, e.to_string()) + } + commands::CommandError::TxBroadcast(_) => { + Error::new(ErrorCode::ServerError(BROADCAST_ERROR), e.to_string()) + } + } + } +} + +/// JSONRPC2 response. See https://www.jsonrpc.org/specification#response_object. +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct Response { + /// Version. Must be "2.0". + jsonrpc: String, + /// Required on success. Must not exist on error. + #[serde(skip_serializing_if = "Option::is_none")] + result: Option, + /// Required on error. Must not exist on success. + #[serde(skip_serializing_if = "Option::is_none")] + error: Option, + /// Request identifier. + id: ReqId, +} + +impl Response { + fn new(id: ReqId, result: Option, error: Option) -> Response { + Response { + jsonrpc: "2.0".to_string(), + result, + error, + id, + } + } + + pub fn success(id: ReqId, result: serde_json::Value) -> Response { + Response::new(id, Some(result), None) + } + + pub fn error(id: ReqId, error: Error) -> Response { + Response::new(id, None, Some(error)) + } +} diff --git a/liana/src/jsonrpc/server/unix.rs b/liana/src/jsonrpc/server/unix.rs index b0e542310..121ccd0d3 100644 --- a/liana/src/jsonrpc/server/unix.rs +++ b/liana/src/jsonrpc/server/unix.rs @@ -4,7 +4,10 @@ //! JSONRPC2 requests on a Unix Domain Socket. use crate::{ - jsonrpc::{api, Request, Response}, + jsonrpc::{ + api, + rpc::{Request, Response}, + }, DaemonControl, }; @@ -207,7 +210,7 @@ pub fn rpcserver_setup(socket_path: &path::Path) -> Result