Skip to main content

syncthing_async/
client.rs

1use crate::Fallible;
2use crate::event_stream::EventStream;
3use http::Method;
4use http::header::HeaderValue;
5use http::uri::Authority;
6use reqwest::Client as HttpClient;
7use serde::Serialize;
8use serde::de::DeserializeOwned as Deserialize;
9use std::collections::HashMap;
10use syncthing_types::events::{Event, EventType};
11use syncthing_types::utils::construct_uri;
12use syncthing_types::{API_DEFAULT_AUTHORITY, Timestamp};
13use syncthing_types::{API_HEADER_KEY, routes::*};
14use syncthing_types::{EMPTY_EVENT_SUBSCRIPTION, system};
15use syncthing_types::{cluster, utils};
16
17pub struct Client {
18    client: HttpClient,
19    authority: Authority,
20    api_key: String,
21}
22
23impl Client {
24    pub fn new(api_key: impl Into<String>) -> Self {
25        Self {
26            client: HttpClient::new(),
27            authority: Authority::from_static(API_DEFAULT_AUTHORITY),
28            api_key: api_key.into(),
29        }
30    }
31
32    pub fn with_authority(api_key: impl Into<String>, authority: Authority) -> Self {
33        Self {
34            client: HttpClient::new(),
35            authority,
36            api_key: api_key.into(),
37        }
38    }
39
40    pub(crate) async fn get<D: Deserialize, T: AsRef<[u8]> + 'static>(
41        &self,
42        path_and_query: T,
43    ) -> Fallible<D> {
44        let url = construct_uri(&self.authority, path_and_query)?.to_string();
45        let resp = self
46            .client
47            .request(Method::GET, url)
48            .header(API_HEADER_KEY, HeaderValue::from_str(&self.api_key)?)
49            .send()
50            .await?
51            .error_for_status()?;
52        Ok(resp.json().await?)
53    }
54
55    pub(crate) async fn post<S: Serialize, T: AsRef<[u8]> + 'static>(
56        &self,
57        path_and_query: T,
58        body: &S,
59    ) -> Fallible<()> {
60        let url = construct_uri(&self.authority, path_and_query)?.to_string();
61        self.client
62            .request(Method::POST, url)
63            .body(serde_json::to_string(body)?)
64            .header(API_HEADER_KEY, HeaderValue::from_str(&self.api_key)?)
65            .send()
66            .await?
67            .error_for_status()?;
68        Ok(())
69    }
70
71    pub async fn get_all_events(
72        &self,
73        since: Option<u64>,
74        limit: Option<u64>,
75    ) -> Fallible<Vec<Event>> {
76        self.get_events(since, limit, &EMPTY_EVENT_SUBSCRIPTION)
77            .await
78    }
79
80    pub async fn get_events(
81        &self,
82        since: Option<u64>,
83        limit: Option<u64>,
84        events: impl AsRef<[EventType]>,
85    ) -> Fallible<Vec<Event>> {
86        let path_and_query = utils::construct_event_path_and_query(since, limit, events)?;
87        self.get(path_and_query).await
88    }
89
90    pub fn subscribe_to(self, events: impl Into<Vec<EventType>>) -> EventStream {
91        EventStream::new(self, events.into())
92    }
93
94    pub fn subscribe_to_all(self) -> EventStream {
95        EventStream::new(self, EMPTY_EVENT_SUBSCRIPTION.clone())
96    }
97
98    pub async fn browse(&self, pattern: Option<String>) -> Fallible<Vec<String>> {
99        if let Some(pattern) = pattern {
100            self.get(format!("{}?current={}", SYSTEM_BROWSE, pattern))
101                .await
102        } else {
103            self.get(SYSTEM_BROWSE).await
104        }
105    }
106
107    pub async fn get_connections(&self) -> Fallible<system::Connections> {
108        self.get(SYSTEM_CONNECTIONS).await
109    }
110
111    pub async fn get_discovery_cache(&self) -> Fallible<system::Discovery> {
112        self.get(SYSTEM_DISCOVERY).await
113    }
114
115    pub async fn get_log(&self, since: Option<Timestamp>) -> Fallible<system::Log> {
116        if let Some(since) = since {
117            self.get(format!("{}?since={}", SYSTEM_LOG, since.to_rfc3339()))
118                .await
119        } else {
120            self.get(SYSTEM_LOG).await
121        }
122    }
123
124    pub async fn get_errors(&self) -> Fallible<system::Error> {
125        self.get(SYSTEM_ERROR).await
126    }
127
128    pub async fn clear_errors(&self) -> Fallible<()> {
129        self.post(SYSTEM_ERROR_CLEAR, &()).await
130    }
131
132    pub async fn get_loglevels_info(&self) -> Fallible<system::LogLevelsInfo> {
133        self.get(SYSTEM_LOGLEVELS).await
134    }
135
136    pub async fn get_paths(&self) -> Fallible<HashMap<String, String>> {
137        self.get(SYSTEM_PATHS).await
138    }
139
140    pub async fn ping(&self) -> Fallible<system::Ping> {
141        self.get(SYSTEM_PING).await
142    }
143
144    pub async fn status(&self) -> Fallible<system::Status> {
145        self.get(SYSTEM_STATUS).await
146    }
147
148    pub async fn get_upgrade_info(&self) -> Fallible<system::UpgradeInfo> {
149        self.get(SYSTEM_UPGRADE).await
150    }
151
152    pub async fn get_version_info(&self) -> Fallible<system::VersionInfo> {
153        self.get(SYSTEM_VERSION).await
154    }
155
156    pub async fn get_cluster_pending_devices(&self) -> Fallible<cluster::PendingDevices> {
157        self.get(CLUSTER_PENDING_DEVICES).await
158    }
159}