Skip to main content

auc_tool/application/
client.rs

1use 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}