summaryrefslogtreecommitdiffstats
path: root/atuin-client/src/api_client.rs
diff options
context:
space:
mode:
Diffstat (limited to 'atuin-client/src/api_client.rs')
-rw-r--r--atuin-client/src/api_client.rs96
1 files changed, 96 insertions, 0 deletions
diff --git a/atuin-client/src/api_client.rs b/atuin-client/src/api_client.rs
new file mode 100644
index 00000000..db2802c3
--- /dev/null
+++ b/atuin-client/src/api_client.rs
@@ -0,0 +1,96 @@
+use chrono::Utc;
+use eyre::Result;
+use reqwest::header::{HeaderMap, AUTHORIZATION};
+use reqwest::Url;
+use sodiumoxide::crypto::secretbox;
+
+use atuin_common::api::{AddHistoryRequest, CountResponse, SyncHistoryResponse};
+use atuin_common::utils::hash_str;
+
+use crate::encryption::decrypt;
+use crate::history::History;
+
+pub struct Client<'a> {
+ sync_addr: &'a str,
+ token: &'a str,
+ key: secretbox::Key,
+ client: reqwest::Client,
+}
+
+impl<'a> Client<'a> {
+ pub fn new(sync_addr: &'a str, token: &'a str, key: secretbox::Key) -> Self {
+ Client {
+ sync_addr,
+ token,
+ key,
+ client: reqwest::Client::new(),
+ }
+ }
+
+ pub async fn count(&self) -> Result<i64> {
+ let url = format!("{}/sync/count", self.sync_addr);
+ let url = Url::parse(url.as_str())?;
+ let token = format!("Token {}", self.token);
+ let token = token.parse()?;
+
+ let mut headers = HeaderMap::new();
+ headers.insert(AUTHORIZATION, token);
+
+ let resp = self.client.get(url).headers(headers).send().await?;
+
+ let count = resp.json::<CountResponse>().await?;
+
+ Ok(count.count)
+ }
+
+ pub async fn get_history(
+ &self,
+ sync_ts: chrono::DateTime<Utc>,
+ history_ts: chrono::DateTime<Utc>,
+ host: Option<String>,
+ ) -> Result<Vec<History>> {
+ let host = match host {
+ None => hash_str(&format!("{}:{}", whoami::hostname(), whoami::username())),
+ Some(h) => h,
+ };
+
+ let url = format!(
+ "{}/sync/history?sync_ts={}&history_ts={}&host={}",
+ self.sync_addr,
+ urlencoding::encode(sync_ts.to_rfc3339().as_str()),
+ urlencoding::encode(history_ts.to_rfc3339().as_str()),
+ host,
+ );
+
+ let resp = self
+ .client
+ .get(url)
+ .header(AUTHORIZATION, format!("Token {}", self.token))
+ .send()
+ .await?;
+
+ let history = resp.json::<SyncHistoryResponse>().await?;
+ let history = history
+ .history
+ .iter()
+ .map(|h| serde_json::from_str(h).expect("invalid base64"))
+ .map(|h| decrypt(&h, &self.key).expect("failed to decrypt history! check your key"))
+ .collect();
+
+ Ok(history)
+ }
+
+ pub async fn post_history(&self, history: &[AddHistoryRequest]) -> Result<()> {
+ let url = format!("{}/history", self.sync_addr);
+ let url = Url::parse(url.as_str())?;
+
+ self.client
+ .post(url)
+ .json(history)
+ .header(AUTHORIZATION, format!("Token {}", self.token))
+ .send()
+ .await?;
+
+ Ok(())
+ }
+}