use std::{
convert::TryFrom,
fmt::{Display, Formatter},
ops::RangeInclusive,
str::FromStr,
};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use thiserror::Error;
mod sensitive;
pub use self::sensitive::Sensitive;
pub const JSONRPC_VERSION: &str = "2.0";
pub const JSONRPC_RESERVED_ERROR_CODES: RangeInclusive<i64> = -32768..=-32000;
#[derive(Debug, Error)]
pub enum Error {
#[error("The server responded with an error: {0}")]
JsonRpc(#[from] RpcError),
#[error("JSON error: {0}")]
Json(#[from] serde_json::Error),
#[error("Received invalid response")]
InvalidResponse,
#[error("Invalid subscription ID: {0:?}")]
InvalidSubscriptionId(Value),
}
#[derive(Copy, Clone, Default)]
pub enum FrameType {
#[default]
Binary,
Text,
}
impl From<&String> for FrameType {
fn from(value: &String) -> Self {
match value.as_str() {
"text" => FrameType::Text,
"binary" => FrameType::Binary,
_ => FrameType::Binary,
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum SingleOrBatch<T> {
Single(T),
Batch(Vec<T>),
}
#[derive(Clone, Debug, Deserialize)]
#[serde(untagged)]
pub enum RequestOrResponse {
Request(Request),
Response(Response),
}
impl RequestOrResponse {
pub fn from_slice(d: &[u8]) -> Result<Self, Error> {
Ok(serde_json::from_slice(d)?)
}
pub fn from_value(v: Value) -> Result<Self, Error> {
Ok(serde_json::from_value(v)?)
}
}
impl FromStr for RequestOrResponse {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(serde_json::from_str(s)?)
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Request {
pub jsonrpc: String,
pub method: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub params: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<Value>,
}
impl Request {
pub fn new(method: String, params: Option<Value>, id: Option<Value>) -> Self {
Self {
jsonrpc: JSONRPC_VERSION.to_owned(),
method,
params,
id,
}
}
pub fn build<P, I>(
method: String,
params_opt: Option<&P>,
id_opt: Option<&I>,
) -> Result<Self, Error>
where
P: Serialize,
I: Serialize,
{
let params = params_opt.map(serde_json::to_value).transpose()?;
let id = id_opt.map(serde_json::to_value).transpose()?;
Ok(Self::new(method, params, id))
}
pub fn verify(&self) -> Result<(), RpcError> {
if self.jsonrpc != JSONRPC_VERSION {
return Err(RpcError::invalid_request(Some(format!(
"Field 'jsonrpc' must be '2.0', but was '{}'",
self.jsonrpc
))));
}
match &self.id {
Some(Value::String(_)) => {} Some(Value::Number(n)) => {
if n.is_f64() {
return Err(RpcError::invalid_request(Some(format!(
"Field 'id' is a number, but should not be fractional: {:?}",
self.id
))));
}
}
_ => {
return Err(RpcError::invalid_request(Some(format!(
"Invalid type in field 'id': {:?}",
self.id
))))
}
}
Ok(())
}
pub fn from_slice(d: &[u8]) -> Result<Self, Error> {
Ok(serde_json::from_slice(d)?)
}
pub fn to_value(&self) -> Result<Value, Error> {
Ok(serde_json::to_value(self)?)
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Response {
pub jsonrpc: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub result: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<RpcError>,
pub id: Value,
}
impl Response {
pub fn new_success(id: Value, result: Value) -> Self {
Self {
jsonrpc: JSONRPC_VERSION.to_owned(),
result: Some(result),
error: None,
id,
}
}
pub fn new_error(id: Value, error: RpcError) -> Self {
Self {
jsonrpc: JSONRPC_VERSION.to_owned(),
result: None,
error: Some(error),
id,
}
}
pub fn from_result<R>(id: Value, result: Result<R, RpcError>) -> Result<Self, Error>
where
R: Serialize,
{
Ok(match result {
Ok(result) => Self::new_success(id, serde_json::to_value(&result)?),
Err(e) => Self::new_error(id, e),
})
}
pub fn into_result<R>(self) -> Result<R, Error>
where
R: for<'de> Deserialize<'de>,
{
match (self.result, self.error) {
(Some(result), None) => Ok(serde_json::from_value(result)?),
(None, Some(error)) => Err(error.into()),
_ => Err(Error::InvalidResponse),
}
}
pub fn from_slice(d: &[u8]) -> Result<Self, Error> {
Ok(serde_json::from_slice(d)?)
}
}
pub type ErrorCode = i64;
#[derive(Clone, Debug, Error, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct RpcError {
pub code: i64,
pub message: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<Value>,
}
impl std::fmt::Display for RpcError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
write!(f, "JSON-RPC error: code={}", self.code)?;
if let Some(message) = &self.message {
write!(f, ": {}", message)?;
}
if let Some(data) = &self.data {
write!(f, " - Caused by: {}", data)?;
}
Ok(())
}
}
impl RpcError {
fn new_reserved(code: i64, message: &'static str, data: Option<Value>) -> Self {
Self {
code,
message: Some(message.to_owned()),
data,
}
}
fn new_reserved_with_description(
code: i64,
message: &'static str,
description: Option<String>,
) -> Self {
Self {
code,
message: Some(message.to_owned()),
data: description.map(Value::from),
}
}
pub fn parse_error(description: Option<String>) -> Self {
Self::new_reserved_with_description(-32700, "Parse error", description)
}
pub fn invalid_request(description: Option<String>) -> Self {
Self::new_reserved_with_description(-32600, "Invalid Request", description)
}
pub fn method_not_found(description: Option<String>) -> Self {
Self::new_reserved_with_description(-32601, "Method not found", description)
}
pub fn invalid_params(description: Option<String>) -> Self {
Self::new_reserved_with_description(-32602, "Invalid params", description)
}
pub fn internal_from_string(description: Option<String>) -> Self {
Self::new_reserved_with_description(-32603, "Internal error", description)
}
pub fn internal_error(data: Option<Value>) -> Self {
Self::new_reserved(-32603, "Internal error", data)
}
}
impl Default for RpcError {
fn default() -> Self {
Self::internal_error(None)
}
}
impl From<()> for RpcError {
fn from(_: ()) -> Self {
Self::default()
}
}
#[derive(Clone, Debug, Serialize, Deserialize, Hash, PartialEq, Eq)]
#[serde(untagged)]
pub enum SubscriptionId {
String(String),
Number(u64),
}
impl TryFrom<Value> for SubscriptionId {
type Error = Error;
fn try_from(value: Value) -> Result<Self, Error> {
match value {
Value::String(s) => Ok(SubscriptionId::String(s)),
Value::Number(n) => n
.as_u64()
.map(SubscriptionId::Number)
.ok_or(Error::InvalidSubscriptionId(Value::Number(n))),
value => Err(Error::InvalidSubscriptionId(value)),
}
}
}
impl From<u64> for SubscriptionId {
fn from(n: u64) -> Self {
SubscriptionId::Number(n)
}
}
impl From<String> for SubscriptionId {
fn from(s: String) -> Self {
SubscriptionId::String(s)
}
}
impl Display for SubscriptionId {
fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
match self {
SubscriptionId::String(s) => write!(f, "{}", s),
SubscriptionId::Number(n) => write!(f, "{}", n),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SubscriptionMessage<T> {
pub subscription: SubscriptionId,
pub result: T,
}