use crate::core::{Rpc, RpcName, RpcType};
use crate::error::{into_rpc_result_transport, RpcError, RpcResult};
use crate::transport::{
InternalTransport, TcpTransport, Transport, TransportConfig, TransportError,
};
pub struct RpcClient<Name: RpcName, Q: RpcType, R: RpcType> {
rpc: Rpc<Name, Q, R>,
}
impl<'de, Name: RpcName, Q: RpcType, R: RpcType> RpcClient<Name, Q, R> {
pub fn new(rpc: Rpc<Name, Q, R>) -> Self {
Self { rpc }
}
pub async fn call(
&self,
query: Q,
transport: &mut Transport<impl InternalTransport, Name>,
) -> RpcResult<R> {
let query_bytes = transport.config.wire_config.serialize(&query)?;
let result_bytes = transport.send_query(&query_bytes, &self.rpc.name).await?;
let result = transport.config.wire_config.deserialize(&result_bytes);
into_rpc_result_transport(result)
}
}
pub async fn call_client<Name: RpcName, Q: RpcType, R: RpcType>(
addr: &str,
q: Q,
rpc: Rpc<Name, Q, R>,
) -> RpcResult<R> {
let mut transport = {
match tokio::net::TcpStream::connect(addr).await {
Ok(client_stream) => {
let tcp_transport = TcpTransport::new(client_stream);
Ok(Transport::new(tcp_transport, TransportConfig::default()))
}
Err(e) => Err(e),
}
}
.map_err(|e| RpcError::TransportError(TransportError::ConnectError(format!("{}", e))))?;
let rpc_client = RpcClient::new(rpc);
rpc_client.call(q, &mut transport).await
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tests::make_hello_world_rpc;
use crate::transport::CannedTestingTransport;
#[tokio::test]
async fn client_test() {
let internal_transport = CannedTestingTransport {
always_respond_with: "Foo-Bar".to_string(),
receive_times: 0,
};
let mut transport = Transport::new(internal_transport, Default::default());
let rpc_client = RpcClient {
rpc: make_hello_world_rpc(),
};
let result = rpc_client.call("Foo".into(), &mut transport).await.unwrap();
assert_eq!(String::from("Foo-Bar"), result);
}
}