1use crate::{ConnectionError, FrontendEvent, FrontendRequest, IpcError};
2use std::{
3 cmp::min,
4 io::{self, prelude::*, BufReader, LineWriter, Lines},
5 thread,
6 time::Duration,
7};
8
9#[cfg(unix)]
10use std::os::unix::net::UnixStream;
11
12#[cfg(windows)]
13use std::net::TcpStream;
14
15pub struct FrontendEventReader {
16 #[cfg(unix)]
17 lines: Lines<BufReader<UnixStream>>,
18 #[cfg(windows)]
19 lines: Lines<BufReader<TcpStream>>,
20}
21
22pub struct FrontendRequestWriter {
23 #[cfg(unix)]
24 line_writer: LineWriter<UnixStream>,
25 #[cfg(windows)]
26 line_writer: LineWriter<TcpStream>,
27}
28
29impl FrontendEventReader {
30 pub fn next_event(&mut self) -> Option<Result<FrontendEvent, IpcError>> {
31 match self.lines.next()? {
32 Err(e) => Some(Err(e.into())),
33 Ok(l) => Some(serde_json::from_str(l.as_str()).map_err(|e| e.into())),
34 }
35 }
36}
37
38impl FrontendRequestWriter {
39 pub fn request(&mut self, request: FrontendRequest) -> Result<(), io::Error> {
40 let mut json = serde_json::to_string(&request).unwrap();
41 log::debug!("requesting: {json}");
42 json.push('\n');
43 self.line_writer.write_all(json.as_bytes())?;
44 Ok(())
45 }
46}
47
48pub fn connect() -> Result<(FrontendEventReader, FrontendRequestWriter), ConnectionError> {
49 let rx = wait_for_service()?;
50 let tx = rx.try_clone()?;
51 let buf_reader = BufReader::new(rx);
52 let lines = buf_reader.lines();
53 let line_writer = LineWriter::new(tx);
54 let reader = FrontendEventReader { lines };
55 let writer = FrontendRequestWriter { line_writer };
56 Ok((reader, writer))
57}
58
59#[cfg(unix)]
61fn wait_for_service() -> Result<UnixStream, ConnectionError> {
62 let socket_path = crate::default_socket_path()?;
63 let mut duration = Duration::from_millis(10);
64 loop {
65 if let Ok(stream) = UnixStream::connect(&socket_path) {
66 break Ok(stream);
67 }
68 thread::sleep(exponential_back_off(&mut duration));
71 }
72}
73
74#[cfg(windows)]
75fn wait_for_service() -> Result<TcpStream, ConnectionError> {
76 let mut duration = Duration::from_millis(10);
77 loop {
78 if let Ok(stream) = TcpStream::connect("127.0.0.1:5252") {
79 break Ok(stream);
80 }
81 thread::sleep(exponential_back_off(&mut duration));
82 }
83}
84
85fn exponential_back_off(duration: &mut Duration) -> Duration {
86 let new = duration.saturating_mul(2);
87 *duration = min(new, Duration::from_secs(1));
88 *duration
89}