use std::time::Duration;
use nojson::{DisplayJson, RawJsonOwned};
use crate::error::Result;
use crate::types::JsonString;
#[derive(Debug, Clone)]
pub struct RpcRequestOptions {
pub notification: bool,
pub timeout: Duration,
}
impl Default for RpcRequestOptions {
fn default() -> Self {
Self {
notification: false,
timeout: Duration::from_secs(5),
}
}
}
#[derive(Debug, Clone)]
pub enum RpcResponse {
Success {
result: JsonString,
},
Error {
code: i32,
message: String,
data: Option<JsonString>,
},
}
impl RpcResponse {
pub(crate) fn parse(text: &str) -> Result<(Option<u64>, Self)> {
let raw = RawJsonOwned::parse(text)?;
let value = raw.value();
let id: Option<u64> = value
.to_member("id")?
.optional()
.map(|v| v.try_into())
.transpose()?;
if let Some(error_value) = value.to_member("error")?.optional() {
let code: i32 = error_value.to_member("code")?.required()?.try_into()?;
let message: String = error_value.to_member("message")?.required()?.try_into()?;
let data: Option<JsonString> = error_value
.to_member("data")?
.optional()
.map(|v| RawJsonOwned::json(|f| DisplayJson::fmt(&v, f)))
.map(JsonString::from);
Ok((
id,
RpcResponse::Error {
code,
message,
data,
},
))
} else {
let result_raw = value
.to_member("result")?
.optional()
.map(|v| RawJsonOwned::json(|f| DisplayJson::fmt(&v, f)))
.unwrap_or_else(|| RawJsonOwned::json(|f| f.value("null")));
let result = JsonString::from(result_raw);
Ok((id, RpcResponse::Success { result }))
}
}
}
pub(crate) fn build_rpc_message(
id_counter: &mut u64,
method: &str,
params: Option<&JsonString>,
notification: bool,
) -> (String, Option<u64>) {
let id = if notification {
None
} else {
*id_counter += 1;
Some(*id_counter)
};
let message = nojson::object(|f| {
f.member("jsonrpc", "2.0")?;
f.member("method", method)?;
if let Some(params) = params {
f.member("params", params)?;
}
if let Some(id) = id {
f.member("id", id)?;
}
Ok(())
})
.to_string();
(message, id)
}