use std::{error, fmt};
use serde::{Deserialize, Serialize};
pub fn build_request<'a, 'b>(name: &'a str, params: &'b serde_json::Value) -> Request<'a, 'b> {
Request {
method: name,
params: params,
id: From::from(1),
jsonrpc: Some("2.0"),
}
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct Request<'a, 'b> {
pub method: &'a str,
pub params: &'b serde_json::Value,
pub id: serde_json::Value,
pub jsonrpc: Option<&'a str>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct Response {
pub result: Option<serde_json::Value>,
pub error: Option<RpcError>,
pub id: serde_json::Value,
pub jsonrpc: Option<String>,
}
impl Response {
pub fn result<T: serde::de::DeserializeOwned>(&self) -> Result<T, Error> {
if let Some(ref e) = self.error {
return Err(Error::Rpc(e.clone()));
}
let result = match self.result.clone() {
Some(r) => serde_json::from_value(r["Ok"].clone()).map_err(Error::Json),
None => serde_json::from_value(serde_json::Value::Null).map_err(Error::Json),
}?;
Ok(result)
}
pub fn into_result<T: serde::de::DeserializeOwned>(self) -> Result<T, Error> {
if let Some(e) = self.error {
return Err(Error::Rpc(e));
}
self.result()
}
pub fn _check_error(self) -> Result<(), Error> {
if let Some(e) = self.error {
Err(Error::Rpc(e))
} else {
Ok(())
}
}
pub fn _is_none(&self) -> bool {
self.result.is_none()
}
}
#[derive(Debug)]
pub enum Error {
Json(serde_json::Error),
Hyper(hyper::error::Error),
Rpc(RpcError),
_NonceMismatch,
_VersionMismatch,
_EmptyBatch,
_WrongBatchResponseSize,
_BatchDuplicateResponseId(serde_json::Value),
_WrongBatchResponseId(serde_json::Value),
}
impl From<serde_json::Error> for Error {
fn from(e: serde_json::Error) -> Error {
Error::Json(e)
}
}
impl From<hyper::error::Error> for Error {
fn from(e: hyper::error::Error) -> Error {
Error::Hyper(e)
}
}
impl From<RpcError> for Error {
fn from(e: RpcError) -> Error {
Error::Rpc(e)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::Json(ref e) => write!(f, "JSON decode error: {}", e),
Error::Hyper(ref e) => write!(f, "Hyper error: {}", e),
Error::Rpc(ref r) => write!(f, "RPC error response: {:?}", r),
Error::_BatchDuplicateResponseId(ref v) => {
write!(f, "duplicate RPC batch response ID: {}", v)
}
Error::_WrongBatchResponseId(ref v) => write!(f, "wrong RPC batch response ID: {}", v),
_ => write!(f, "{}", self),
}
}
}
impl std::error::Error for Error {
fn description(&self) -> &str {
match *self {
Error::Json(_) => "JSON decode error",
Error::Hyper(_) => "Hyper error",
Error::Rpc(_) => "RPC error response",
Error::_NonceMismatch => "Nonce of response did not match nonce of request",
Error::_VersionMismatch => "`jsonrpc` field set to non-\"2.0\"",
Error::_EmptyBatch => "batches can't be empty",
Error::_WrongBatchResponseSize => "too many responses returned in batch",
Error::_BatchDuplicateResponseId(_) => "batch response contained a duplicate ID",
Error::_WrongBatchResponseId(_) => {
"batch response contained an ID that didn't correspond to any request ID"
}
}
}
fn cause(&self) -> Option<&dyn error::Error> {
match *self {
Error::Json(ref e) => Some(e),
Error::Hyper(ref e) => Some(e),
_ => None,
}
}
}
#[allow(dead_code)]
#[derive(Debug)]
pub enum StandardError {
ParseError,
InvalidRequest,
MethodNotFound,
InvalidParams,
InternalError,
}
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct RpcError {
pub code: i32,
pub message: String,
pub data: Option<serde_json::Value>,
}
pub fn _standard_error(code: StandardError, data: Option<serde_json::Value>) -> RpcError {
match code {
StandardError::ParseError => RpcError {
code: -32700,
message: "Parse error".to_string(),
data: data,
},
StandardError::InvalidRequest => RpcError {
code: -32600,
message: "Invalid Request".to_string(),
data: data,
},
StandardError::MethodNotFound => RpcError {
code: -32601,
message: "Method not found".to_string(),
data: data,
},
StandardError::InvalidParams => RpcError {
code: -32602,
message: "Invalid params".to_string(),
data: data,
},
StandardError::InternalError => RpcError {
code: -32603,
message: "Internal error".to_string(),
data: data,
},
}
}
pub fn _result_to_response(
result: Result<serde_json::Value, RpcError>,
id: serde_json::Value,
) -> Response {
match result {
Ok(data) => Response {
result: Some(data),
error: None,
id: id,
jsonrpc: Some(String::from("2.0")),
},
Err(err) => Response {
result: None,
error: Some(err),
id: id,
jsonrpc: Some(String::from("2.0")),
},
}
}