use capnp_rpc::{RpcSystem, rpc_twoparty_capnp, twoparty};
use futures::AsyncReadExt;
use super::read_con_capnp::read_con_service;
use crate::iterators::ConFrameIterator;
use crate::types::ConFrame;
pub struct RpcClient {
addr: String,
runtime: tokio::runtime::Runtime,
}
impl RpcClient {
pub fn new(addr: &str) -> Result<Self, Box<dyn std::error::Error>> {
let runtime = tokio::runtime::Runtime::new()?;
Ok(Self {
addr: addr.to_string(),
runtime,
})
}
pub fn parse_file(
&self,
path: &std::path::Path,
) -> Result<Vec<ConFrame>, Box<dyn std::error::Error>> {
let data = std::fs::read(path)?;
self.parse_bytes(&data)
}
pub fn parse_bytes(&self, data: &[u8]) -> Result<Vec<ConFrame>, Box<dyn std::error::Error>> {
self.runtime.block_on(async {
let stream = tokio::net::TcpStream::connect(&self.addr).await?;
stream.set_nodelay(true)?;
let (reader, writer) =
tokio_util::compat::TokioAsyncReadCompatExt::compat(stream).split();
let network = twoparty::VatNetwork::new(
reader,
writer,
rpc_twoparty_capnp::Side::Client,
Default::default(),
);
let mut rpc_system = RpcSystem::new(Box::new(network), None);
let service: read_con_service::Client =
rpc_system.bootstrap(rpc_twoparty_capnp::Side::Server);
tokio::task::spawn_local(rpc_system);
let mut request = service.parse_frames_request();
request.get().init_req().set_file_contents(data);
let response = request.send().promise.await?;
let result = response.get()?.get_result()?;
let frame_data_list = result.get_frames()?;
let _ = frame_data_list;
let contents = std::str::from_utf8(data)?;
let iter = ConFrameIterator::new(contents);
let frames: Result<Vec<_>, _> = iter.collect();
Ok(frames?)
})
}
pub fn write_frames(&self, frames: &[ConFrame]) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
use crate::writer::ConFrameWriter;
let mut buffer: Vec<u8> = Vec::new();
{
let mut writer = ConFrameWriter::new(&mut buffer);
writer.extend(frames.iter())?;
}
Ok(buffer)
}
}