use crate::{ErrorVariant, JsonValue};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct JrpcRequest {
jsonrpc: String,
method: String,
#[serde(skip_serializing_if = "Option::is_none")]
params: Option<JsonValue>,
#[serde(skip_serializing_if = "Option::is_none")]
id: Option<JsonValue>,
}
impl JrpcRequest {
pub fn new<T: ToString>(
method: T,
params: Option<JsonValue>,
id: Option<JsonValue>,
) -> Result<JrpcRequest, ErrorVariant> {
let method = method.to_string();
let jrpc_request = JrpcRequest {
jsonrpc: "2.0".to_string(),
method,
params,
id,
};
jrpc_request.validate()
}
pub fn prepare_to_send_notification<T: ToString>(
method: T,
params: Option<JsonValue>,
) -> Result<JrpcRequest, ErrorVariant> {
let method = method.to_string();
let id = None;
let jrpc_request = JrpcRequest {
jsonrpc: "2.0".to_string(),
method,
params,
id,
};
jrpc_request.validate()
}
pub fn prepare_to_send_request<T: ToString>(
method: T,
params: Option<JsonValue>,
) -> Result<JrpcRequest, ErrorVariant> {
let method = method.to_string();
let id = Some(JsonValue::String(Uuid::new_v4().to_string()));
let jrpc_request = JrpcRequest {
jsonrpc: "2.0".to_string(),
method,
params,
id,
};
jrpc_request.validate()
}
pub fn parse<F: ToString>(message: F) -> Result<Self, ErrorVariant> {
let message = message.to_string();
serde_json::from_str::<Self>(message.as_str())
.map_err(|e| ErrorVariant::JsonParseError(e))
.and_then(|parsed| parsed.validate())
}
pub fn generate_response(
&self,
response: JrpcResponseParam,
) -> Result<JrpcResponse, ErrorVariant> {
JrpcResponse::from_jrpc_request(self, response)
}
fn validate(self) -> Result<Self, ErrorVariant> {
if self.get_jsonrpc() != "2.0" {
return Err(ErrorVariant::InvalidJsonRpcVersion);
}
match self.get_id() {
Some(JsonValue::String(_)) => (),
Some(JsonValue::Number(_)) => (),
Some(JsonValue::Null) => (),
None => (),
_ => return Err(ErrorVariant::InvalidJsonRpcId),
}
Ok(self)
}
pub fn is_notification(&self) -> bool {
self.id.is_none()
}
pub fn get_jsonrpc(&self) -> &String {
&self.jsonrpc
}
pub fn get_method(&self) -> &String {
&self.method
}
pub fn get_params(&self) -> &Option<JsonValue> {
&self.params
}
pub fn get_id(&self) -> &Option<JsonValue> {
&self.id
}
}
#[derive(Debug, Clone)]
pub enum JrpcResponseParam {
JrpcResult(JsonValue),
JrpcError(JrpcError),
}
impl JrpcResponseParam {
pub fn generate_result(response: JsonValue) -> Result<Self, ErrorVariant> {
Ok(JrpcResponseParam::JrpcResult(response))
}
pub fn generate_error(response: JrpcError) -> Result<Self, ErrorVariant> {
Ok(JrpcResponseParam::JrpcError(response))
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct JrpcResponse {
jsonrpc: String,
#[serde(skip_serializing_if = "Option::is_none")]
result: Option<JsonValue>,
#[serde(skip_serializing_if = "Option::is_none")]
error: Option<JrpcError>,
id: JsonValue,
}
impl JrpcResponse {
pub fn new(
result: Option<JsonValue>,
error: Option<JrpcError>,
id: JsonValue,
) -> Result<Self, ErrorVariant> {
let jrpc_response = JrpcResponse {
jsonrpc: "2.0".to_string(),
result,
error,
id,
};
jrpc_response.validate()
}
pub fn from_jrpc_request(
request: &JrpcRequest,
response: JrpcResponseParam,
) -> Result<Self, ErrorVariant> {
let mut result = None;
let mut error = None;
let id = match request.get_id() {
Some(i) => i.clone(),
None => JsonValue::Null,
};
match response {
JrpcResponseParam::JrpcResult(r) => result = Some(r),
JrpcResponseParam::JrpcError(e) => error = Some(e),
}
JrpcResponse::new(result, error, id)
}
pub fn parse<F: ToString>(message: F) -> Result<Self, ErrorVariant> {
let message = message.to_string();
serde_json::from_str::<Self>(message.as_str())
.map_err(|e| ErrorVariant::JsonParseError(e))
.and_then(|parsed| parsed.validate())
}
pub fn validate(self) -> Result<Self, ErrorVariant> {
if self.get_jsonrpc() != "2.0" {
return Err(ErrorVariant::InvalidJsonRpcVersion);
}
if self.get_result().is_some() && self.get_error().is_some() {
return Err(ErrorVariant::ResponseCannotContainResultAndError);
}
if self.get_result().is_none() && self.get_error().is_none() {
return Err(ErrorVariant::ResponseCannotContainResultAndError);
}
match self.get_id() {
JsonValue::String(_) => (),
JsonValue::Number(_) => (),
JsonValue::Null => (),
_ => return Err(ErrorVariant::InvalidJsonRpcId),
}
Ok(self)
}
pub fn get_jsonrpc(&self) -> &String {
&self.jsonrpc
}
pub fn get_result(&self) -> &Option<JsonValue> {
&self.result
}
pub fn get_error(&self) -> &Option<JrpcError> {
&self.error
}
pub fn get_id(&self) -> &JsonValue {
&self.id
}
}
#[derive(Debug, Clone)]
pub enum JrpcErrorEnum {
ParseError = -32700,
InvalidRequest = -32600,
MethodNotFound = -32601,
InvalidParams = -32602,
InternalError = -32603,
ServerError = -32000,
Other = 0,
}
impl From<i32> for JrpcErrorEnum {
fn from(code: i32) -> Self {
if code == -32700 {
JrpcErrorEnum::ParseError
} else if code == -32600 {
JrpcErrorEnum::InvalidRequest
} else if code == -32601 {
JrpcErrorEnum::MethodNotFound
} else if code == -32602 {
JrpcErrorEnum::InvalidParams
} else if code == -32603 {
JrpcErrorEnum::InternalError
} else if code >= -32099 && code <= -32000 {
JrpcErrorEnum::ServerError
} else {
JrpcErrorEnum::Other
}
}
}
impl From<JrpcErrorEnum> for i32 {
fn from(jrpc_error: JrpcErrorEnum) -> i32 {
match jrpc_error {
JrpcErrorEnum::ParseError => -32700,
JrpcErrorEnum::InvalidRequest => -32600,
JrpcErrorEnum::MethodNotFound => -32601,
JrpcErrorEnum::InvalidParams => -32602,
JrpcErrorEnum::InternalError => -32603,
JrpcErrorEnum::ServerError => -32000,
JrpcErrorEnum::Other => 0,
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct JrpcError {
code: i32,
message: String,
data: Option<JsonValue>,
}
impl JrpcError {
pub fn new<T: ToString>(code: i32, message: T, data: Option<JsonValue>) -> Self {
let message = message.to_string();
JrpcError {
code,
message,
data,
}
}
pub fn parse<F: ToString>(message: F) -> Result<Self, ErrorVariant> {
let message = message.to_string();
let parsed: JrpcError =
serde_json::from_str(message.as_str()).map_err(|e| ErrorVariant::JsonParseError(e))?;
Ok(parsed)
}
pub fn get_code(&self) -> &i32 {
&self.code
}
pub fn get_message(&self) -> &String {
&self.message
}
pub fn get_data(&self) -> &Option<JsonValue> {
&self.data
}
}
impl From<JrpcErrorEnum> for JrpcError {
fn from(error_enum: JrpcErrorEnum) -> Self {
let message = match error_enum {
JrpcErrorEnum::ParseError => "Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text.",
JrpcErrorEnum::InvalidRequest => "The JSON sent is not a valid Request object.",
JrpcErrorEnum::MethodNotFound => "The method does not exist / is not available.",
JrpcErrorEnum::InvalidParams => "Invalid method parameter(s).",
JrpcErrorEnum::InternalError => "Internal JSON-RPC error.",
JrpcErrorEnum::ServerError => "Reserved for implementation-defined server-errors.",
JrpcErrorEnum::Other => "JsonRpc Error",
};
let code = i32::from(error_enum);
let message = message.to_string();
let data = None;
JrpcError::new(code, message, data)
}
}
impl From<i32> for JrpcError {
fn from(error_code: i32) -> Self {
let jrpc_error_enum = JrpcErrorEnum::from(error_code);
JrpcError::from(jrpc_error_enum)
}
}
impl From<ErrorVariant> for JrpcError {
fn from(error_variant: ErrorVariant) -> Self {
match error_variant {
ErrorVariant::MethodSignatureNotFound(_) => JrpcError::from(-32601),
ErrorVariant::JsonParseError(_) => JrpcError::from(-32700),
ErrorVariant::InvalidJsonRpcVersion => JrpcError::from(-32600),
ErrorVariant::InvalidJsonRpcId => JrpcError::from(-32600),
ErrorVariant::ResponseCannotContainResultAndError => JrpcError::from(-32600),
ErrorVariant::ResponseMustContainResultOrError => JrpcError::from(-32600),
_ => JrpcError::from(-32603),
}
}
}