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}