1use eyre::{Context, Result};
2#[cfg(windows)]
3use tokio::net::TcpStream;
4use tonic::transport::{Channel, Endpoint, Uri};
5use tower::service_fn;
6
7use hyper_util::rt::TokioIo;
8
9#[cfg(unix)]
10use tokio::net::UnixStream;
11
12use atuin_client::history::History;
13
14use crate::history::{
15 history_client::HistoryClient as HistoryServiceClient, EndHistoryRequest, StartHistoryRequest,
16};
17
18pub struct HistoryClient {
19 client: HistoryServiceClient<Channel>,
20}
21
22impl HistoryClient {
24 #[cfg(unix)]
25 pub async fn new(path: String) -> Result<Self> {
26 let log_path = path.clone();
27 let channel = Endpoint::try_from("http://atuin_local_daemon:0")?
28 .connect_with_connector(service_fn(move |_: Uri| {
29 let path = path.clone();
30
31 async move {
32 Ok::<_, std::io::Error>(TokioIo::new(UnixStream::connect(path.clone()).await?))
33 }
34 }))
35 .await
36 .wrap_err_with(|| {
37 format!(
38 "failed to connect to local atuin daemon at {}. Is it running?",
39 &log_path
40 )
41 })?;
42
43 let client = HistoryServiceClient::new(channel);
44
45 Ok(HistoryClient { client })
46 }
47
48 #[cfg(not(unix))]
49 pub async fn new(port: u64) -> Result<Self> {
50 let channel = Endpoint::try_from("http://atuin_local_daemon:0")?
51 .connect_with_connector(service_fn(move |_: Uri| {
52 let url = format!("127.0.0.1:{}", port);
53
54 async move {
55 Ok::<_, std::io::Error>(TokioIo::new(TcpStream::connect(url.clone()).await?))
56 }
57 }))
58 .await
59 .wrap_err_with(|| {
60 format!(
61 "failed to connect to local atuin daemon at 127.0.0.1:{}. Is it running?",
62 port
63 )
64 })?;
65
66 let client = HistoryServiceClient::new(channel);
67
68 Ok(HistoryClient { client })
69 }
70
71 pub async fn start_history(&mut self, h: History) -> Result<String> {
72 let req = StartHistoryRequest {
73 command: h.command,
74 cwd: h.cwd,
75 hostname: h.hostname,
76 session: h.session,
77 timestamp: h.timestamp.unix_timestamp_nanos() as u64,
78 };
79
80 let resp = self.client.start_history(req).await?;
81
82 Ok(resp.into_inner().id)
83 }
84
85 pub async fn end_history(
86 &mut self,
87 id: String,
88 duration: u64,
89 exit: i64,
90 ) -> Result<(String, u64)> {
91 let req = EndHistoryRequest { id, duration, exit };
92
93 let resp = self.client.end_history(req).await?;
94 let resp = resp.into_inner();
95
96 Ok((resp.id, resp.idx))
97 }
98}