syncthing/
client.rs

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