use crate::line_io::{read_json_line, write_json_line};
use crate::{Error, ErrorCode, JSONRPC_VERSION, RpcRequest, RpcResponse};
use serde::Serialize;
use serde::de::DeserializeOwned;
use serde_json::Value;
use tokio::io::{AsyncBufRead, AsyncWrite};
pub struct Client<R, W> {
reader: R,
writer: W,
next_id: u64,
}
impl<R, W> Client<R, W>
where
R: AsyncBufRead + Unpin,
W: AsyncWrite + Unpin,
{
pub fn new(reader: R, writer: W) -> Self {
Self {
reader,
writer,
next_id: 1,
}
}
pub async fn call<P, T>(&mut self, method: &str, params: P) -> Result<T, Error>
where
P: Serialize,
T: DeserializeOwned,
{
let id = self.next_id;
self.next_id += 1;
let request = RpcRequest {
jsonrpc: JSONRPC_VERSION,
id,
method,
params,
};
write_json_line(&mut self.writer, &request).await?;
let Some(response) = read_json_line::<_, RpcResponse>(&mut self.reader).await? else {
return Err(Error::Protocol("no response"));
};
if response.id != Some(id) {
return Err(Error::Protocol("unexpected JSON-RPC id"));
}
if let Some(error) = response.error {
return Err(Error::Rpc {
code: ErrorCode::ServerError,
message: error.message,
data: error.data,
});
}
let result = response.result.unwrap_or(Value::Null);
Ok(serde_json::from_value(result)?)
}
}