auc_tool/application/
client.rs1use std::io::{Read, Write};
2use std::os::unix::net::UnixStream;
3use std::path::{Path, PathBuf};
4use std::time::Duration;
5
6use super::protocol::{
7 ApplicationError, ApplicationRequest, ApplicationResponse, PROTOCOL_MAJOR, RequestEnvelope,
8 RequestId, ResponseBody, ResponseEnvelope, decode, encode,
9};
10
11#[derive(Clone, Debug)]
12pub struct ApplicationClient {
13 socket_path: PathBuf,
14 timeout: Duration,
15}
16
17impl ApplicationClient {
18 pub fn new(socket_path: impl Into<PathBuf>) -> Self {
19 Self {
20 socket_path: socket_path.into(),
21 timeout: Duration::from_secs(30),
22 }
23 }
24
25 pub fn socket_path(&self) -> &Path {
26 &self.socket_path
27 }
28
29 pub fn request(
30 &self,
31 request: ApplicationRequest,
32 ) -> Result<ApplicationResponse, ApplicationError> {
33 let request_id = RequestId::random();
34 let payload = encode(&RequestEnvelope {
35 request_id,
36 minimum_protocol_major: PROTOCOL_MAJOR,
37 maximum_protocol_major: PROTOCOL_MAJOR,
38 request,
39 })?;
40 let mut stream = UnixStream::connect(&self.socket_path)?;
41 stream.set_read_timeout(Some(self.timeout))?;
42 stream.set_write_timeout(Some(self.timeout))?;
43 stream.write_all(&(payload.len() as u32).to_be_bytes())?;
44 stream.write_all(&payload)?;
45 stream.flush()?;
46 let response: ResponseEnvelope = decode(&read_frame(&mut stream)?)?;
47 if response.request_id != request_id {
48 return Err(ApplicationError::MismatchedRequestId);
49 }
50 if response.protocol_major != PROTOCOL_MAJOR {
51 return Err(ApplicationError::UnsupportedProtocol(
52 response.protocol_major,
53 ));
54 }
55 match response.body {
56 ResponseBody::Ok(response) => Ok(response),
57 ResponseBody::Error(error) => Err(ApplicationError::Remote {
58 code: error.code,
59 message: error.message,
60 }),
61 }
62 }
63}
64
65fn read_frame(stream: &mut UnixStream) -> Result<Vec<u8>, ApplicationError> {
66 let mut header = [0_u8; 4];
67 read_exact(stream, &mut header)?;
68 let length = u32::from_be_bytes(header) as usize;
69 if length > super::protocol::MAX_FRAME_BYTES {
70 return Err(ApplicationError::FrameTooLarge);
71 }
72 let mut payload = vec![0_u8; length];
73 read_exact(stream, &mut payload)?;
74 Ok(payload)
75}
76
77fn read_exact(stream: &mut UnixStream, buffer: &mut [u8]) -> Result<(), ApplicationError> {
78 match stream.read_exact(buffer) {
79 Ok(()) => Ok(()),
80 Err(error) if error.kind() == std::io::ErrorKind::UnexpectedEof => {
81 Err(ApplicationError::EarlyEof)
82 }
83 Err(error) => Err(error.into()),
84 }
85}