move rpc code to its own module
This commit is contained in:
parent
a636cda2f7
commit
c8112ab027
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
commands::{CoinStatus, LabelItem},
|
||||
jsonrpc::{Error, Params, Request, Response},
|
||||
jsonrpc::rpc::{Error, Params, Request, Response},
|
||||
DaemonControl,
|
||||
};
|
||||
|
||||
|
||||
@ -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<serde_json::Value>),
|
||||
Map(serde_json::Map<String, serde_json::Value>),
|
||||
}
|
||||
|
||||
impl Params {
|
||||
/// Get the parameter supposed to be at a given index / of a given name.
|
||||
pub fn get<Q>(&self, index: usize, name: &Q) -> Option<&serde_json::Value>
|
||||
where
|
||||
String: std::borrow::Borrow<Q>,
|
||||
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<Params>,
|
||||
/// 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<i64> 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<D>(deserializer: D) -> Result<ErrorCode, D::Error>
|
||||
where
|
||||
D: Deserializer<'a>,
|
||||
{
|
||||
let code: i64 = Deserialize::deserialize(deserializer)?;
|
||||
Ok(code.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for ErrorCode {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
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<serde_json::Value>,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub fn new(code: ErrorCode, message: impl Into<String>) -> 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<String>) -> 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<commands::CommandError> 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<serde_json::Value>,
|
||||
/// Required on error. Must not exist on success.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
error: Option<Error>,
|
||||
/// Request identifier.
|
||||
id: ReqId,
|
||||
}
|
||||
|
||||
impl Response {
|
||||
fn new(id: ReqId, result: Option<serde_json::Value>, error: Option<Error>) -> 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))
|
||||
}
|
||||
}
|
||||
|
||||
212
liana/src/jsonrpc/rpc.rs
Normal file
212
liana/src/jsonrpc/rpc.rs
Normal file
@ -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<serde_json::Value>),
|
||||
Map(serde_json::Map<String, serde_json::Value>),
|
||||
}
|
||||
|
||||
impl Params {
|
||||
/// Get the parameter supposed to be at a given index / of a given name.
|
||||
pub fn get<Q>(&self, index: usize, name: &Q) -> Option<&serde_json::Value>
|
||||
where
|
||||
String: std::borrow::Borrow<Q>,
|
||||
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<Params>,
|
||||
/// 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<i64> 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<D>(deserializer: D) -> Result<ErrorCode, D::Error>
|
||||
where
|
||||
D: Deserializer<'a>,
|
||||
{
|
||||
let code: i64 = Deserialize::deserialize(deserializer)?;
|
||||
Ok(code.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for ErrorCode {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
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<serde_json::Value>,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub fn new(code: ErrorCode, message: impl Into<String>) -> 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<String>) -> 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<commands::CommandError> 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<serde_json::Value>,
|
||||
/// Required on error. Must not exist on success.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
error: Option<Error>,
|
||||
/// Request identifier.
|
||||
id: ReqId,
|
||||
}
|
||||
|
||||
impl Response {
|
||||
fn new(id: ReqId, result: Option<serde_json::Value>, error: Option<Error>) -> 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))
|
||||
}
|
||||
}
|
||||
@ -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<net::UnixListener, io
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{
|
||||
jsonrpc::{Params, ReqId},
|
||||
jsonrpc::rpc::{Params, ReqId},
|
||||
testutils::*,
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user