216 lines
6.3 KiB
Rust
216 lines
6.3 KiB
Rust
mod api;
|
|
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::NoOutpoint
|
|
| commands::CommandError::NoDestination
|
|
| commands::CommandError::UnknownOutpoint(..)
|
|
| commands::CommandError::InvalidFeerate(..)
|
|
| commands::CommandError::AlreadySpent(..)
|
|
| commands::CommandError::AddressNetwork(..)
|
|
| commands::CommandError::InvalidOutputValue(..)
|
|
| commands::CommandError::InsufficientFunds(..)
|
|
| commands::CommandError::InsaneFees(..)
|
|
| commands::CommandError::UnknownSpend(..)
|
|
| commands::CommandError::SpendFinalization(..)
|
|
| commands::CommandError::InsaneRescanTimestamp(..)
|
|
| commands::CommandError::AlreadyRescanning
|
|
| commands::CommandError::RecoveryNotAvailable => {
|
|
Error::new(ErrorCode::InvalidParams, e.to_string())
|
|
}
|
|
commands::CommandError::FetchingTransaction(..)
|
|
| commands::CommandError::SanityCheckFailure(_)
|
|
| 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))
|
|
}
|
|
}
|