use std::{error, fmt};
use hyper;
use json;
use json::value::Value as JsonValue;
use serde;
use Response;
#[derive(Debug)]
pub enum Error {
Json(json::error::Error),
BadStatus(hyper::status::StatusCode),
Hyper(hyper::error::Error),
Rpc(RpcError),
NoErrorOrResult
}
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::BadStatus(s) => write!(f, "HTTP error {}", s),
Error::Hyper(ref e) => write!(f, "Hyper error: {}", e),
Error::Rpc(ref r) => write!(f, "RPC error response: {:?}", r),
Error::NoErrorOrResult => f.write_str("RPC response had neither error nor result")
}
}
}
impl error::Error for Error {
fn description(&self) -> &str {
match *self {
Error::Json(_) => "JSON decode error",
Error::BadStatus(_) => "Bad HTTP status",
Error::Hyper(_) => "Hyper error",
Error::Rpc(_) => "RPC error response",
Error::NoErrorOrResult => "Malformed RPC response",
}
}
fn cause(&self) -> Option<&error::Error> {
match *self {
Error::Json(ref e) => Some(e),
Error::BadStatus(_) => None,
Error::Hyper(ref e) => Some(e),
Error::Rpc(_) => None,
Error::NoErrorOrResult => None
}
}
}
#[derive(Debug)]
pub enum StandardError {
ParseError,
InvalidRequest,
MethodNotFound,
InvalidParams,
InternalError
}
#[derive(Clone, Debug, PartialEq)]
pub struct RpcError {
pub code: i32,
pub message: String,
pub data: Option<JsonValue>
}
pub fn standard_error(code: StandardError, data: Option<JsonValue>) -> 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<JsonValue, RpcError>, id: JsonValue) -> Response {
match result {
Ok(data) => Response { result: Some(data), error: None, id: id },
Err(err) => Response { result: None, error: Some(err), id: id }
}
}
serde_struct_impl!(
RpcError,
code,
message,
data
);
#[cfg(test)]
mod tests {
use super::StandardError::{ParseError, InvalidRequest, MethodNotFound, InvalidParams, InternalError};
use super::{standard_error, result_to_response};
use json::value::Value as JsonValue;
#[test]
fn test_parse_error() {
let resp = result_to_response(Err(standard_error(ParseError, None)), JsonValue::U64(1));
assert!(resp.result.is_none());
assert!(resp.error.is_some());
assert_eq!(resp.id, JsonValue::U64(1));
assert_eq!(resp.error.unwrap().code, -32700);
}
#[test]
fn test_invalid_request() {
let resp = result_to_response(Err(standard_error(InvalidRequest, None)), JsonValue::I64(1));
assert!(resp.result.is_none());
assert!(resp.error.is_some());
assert_eq!(resp.id, JsonValue::I64(1));
assert_eq!(resp.error.unwrap().code, -32600);
}
#[test]
fn test_method_not_found() {
let resp = result_to_response(Err(standard_error(MethodNotFound, None)), JsonValue::U64(1));
assert!(resp.result.is_none());
assert!(resp.error.is_some());
assert_eq!(resp.id, JsonValue::U64(1));
assert_eq!(resp.error.unwrap().code, -32601);
}
#[test]
fn test_invalid_params() {
let resp = result_to_response(Err(standard_error(InvalidParams, None)), JsonValue::String("123".to_string()));
assert!(resp.result.is_none());
assert!(resp.error.is_some());
assert_eq!(resp.id, JsonValue::String("123".to_string()));
assert_eq!(resp.error.unwrap().code, -32602);
}
#[test]
fn test_internal_error() {
let resp = result_to_response(Err(standard_error(InternalError, None)), JsonValue::I64(-1));
assert!(resp.result.is_none());
assert!(resp.error.is_some());
assert_eq!(resp.id, JsonValue::I64(-1));
assert_eq!(resp.error.unwrap().code, -32603);
}
}