1use crate::{FilesClient, PaginationInfo, Result};
7use serde::{Deserialize, Serialize};
8use serde_json::json;
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct RemoteServerEntity {
13 #[serde(skip_serializing_if = "Option::is_none")]
15 pub id: Option<i64>,
16
17 #[serde(skip_serializing_if = "Option::is_none")]
19 pub server_type: Option<String>,
20
21 #[serde(skip_serializing_if = "Option::is_none")]
23 pub name: Option<String>,
24
25 #[serde(skip_serializing_if = "Option::is_none")]
27 pub authentication_method: Option<String>,
28
29 #[serde(skip_serializing_if = "Option::is_none")]
31 pub hostname: Option<String>,
32
33 #[serde(skip_serializing_if = "Option::is_none")]
35 pub port: Option<i64>,
36
37 #[serde(skip_serializing_if = "Option::is_none")]
39 pub username: Option<String>,
40
41 #[serde(skip_serializing_if = "Option::is_none")]
43 pub remote_home_path: Option<String>,
44
45 #[serde(skip_serializing_if = "Option::is_none")]
47 pub ssl: Option<String>,
48
49 #[serde(skip_serializing_if = "Option::is_none")]
51 pub max_connections: Option<i64>,
52
53 #[serde(skip_serializing_if = "Option::is_none")]
55 pub pin_to_site_region: Option<bool>,
56
57 #[serde(skip_serializing_if = "Option::is_none")]
59 pub pinned_region: Option<String>,
60
61 #[serde(skip_serializing_if = "Option::is_none")]
63 pub s3_bucket: Option<String>,
64
65 #[serde(skip_serializing_if = "Option::is_none")]
67 pub s3_region: Option<String>,
68
69 #[serde(skip_serializing_if = "Option::is_none")]
71 pub aws_access_key: Option<String>,
72
73 #[serde(skip_serializing_if = "Option::is_none")]
75 pub server_host_key: Option<String>,
76
77 #[serde(skip_serializing_if = "Option::is_none")]
79 pub server_certificate: Option<String>,
80
81 #[serde(skip_serializing_if = "Option::is_none")]
83 pub azure_blob_storage_account: Option<String>,
84
85 #[serde(skip_serializing_if = "Option::is_none")]
87 pub azure_blob_storage_container: Option<String>,
88
89 #[serde(skip_serializing_if = "Option::is_none")]
91 pub azure_blob_storage_dns_suffix: Option<String>,
92
93 #[serde(skip_serializing_if = "Option::is_none")]
95 pub azure_blob_storage_hierarchical_namespace: Option<bool>,
96
97 #[serde(skip_serializing_if = "Option::is_none")]
99 pub azure_files_storage_account: Option<String>,
100
101 #[serde(skip_serializing_if = "Option::is_none")]
103 pub azure_files_storage_share_name: Option<String>,
104
105 #[serde(skip_serializing_if = "Option::is_none")]
107 pub azure_files_storage_dns_suffix: Option<String>,
108
109 #[serde(skip_serializing_if = "Option::is_none")]
111 pub backblaze_b2_bucket: Option<String>,
112
113 #[serde(skip_serializing_if = "Option::is_none")]
115 pub backblaze_b2_s3_endpoint: Option<String>,
116
117 #[serde(skip_serializing_if = "Option::is_none")]
119 pub wasabi_bucket: Option<String>,
120
121 #[serde(skip_serializing_if = "Option::is_none")]
123 pub wasabi_region: Option<String>,
124
125 #[serde(skip_serializing_if = "Option::is_none")]
127 pub wasabi_access_key: Option<String>,
128
129 #[serde(skip_serializing_if = "Option::is_none")]
131 pub google_cloud_storage_bucket: Option<String>,
132
133 #[serde(skip_serializing_if = "Option::is_none")]
135 pub google_cloud_storage_project_id: Option<String>,
136
137 #[serde(skip_serializing_if = "Option::is_none")]
139 pub s3_compatible_access_key: Option<String>,
140
141 #[serde(skip_serializing_if = "Option::is_none")]
143 pub s3_compatible_bucket: Option<String>,
144
145 #[serde(skip_serializing_if = "Option::is_none")]
147 pub s3_compatible_endpoint: Option<String>,
148
149 #[serde(skip_serializing_if = "Option::is_none")]
151 pub s3_compatible_region: Option<String>,
152
153 #[serde(skip_serializing_if = "Option::is_none")]
155 pub files_agent_api_token: Option<String>,
156
157 #[serde(skip_serializing_if = "Option::is_none")]
159 pub files_agent_root: Option<String>,
160
161 #[serde(skip_serializing_if = "Option::is_none")]
163 pub files_agent_permission_set: Option<String>,
164
165 #[serde(skip_serializing_if = "Option::is_none")]
167 pub files_agent_version: Option<String>,
168
169 #[serde(skip_serializing_if = "Option::is_none")]
171 pub filebase_bucket: Option<String>,
172
173 #[serde(skip_serializing_if = "Option::is_none")]
175 pub filebase_access_key: Option<String>,
176
177 #[serde(skip_serializing_if = "Option::is_none")]
179 pub cloudflare_bucket: Option<String>,
180
181 #[serde(skip_serializing_if = "Option::is_none")]
183 pub cloudflare_access_key: Option<String>,
184
185 #[serde(skip_serializing_if = "Option::is_none")]
187 pub cloudflare_endpoint: Option<String>,
188
189 #[serde(skip_serializing_if = "Option::is_none")]
191 pub dropbox_teams: Option<bool>,
192
193 #[serde(skip_serializing_if = "Option::is_none")]
195 pub linode_bucket: Option<String>,
196
197 #[serde(skip_serializing_if = "Option::is_none")]
199 pub linode_access_key: Option<String>,
200
201 #[serde(skip_serializing_if = "Option::is_none")]
203 pub linode_region: Option<String>,
204
205 #[serde(skip_serializing_if = "Option::is_none")]
207 pub one_drive_account_type: Option<String>,
208
209 #[serde(skip_serializing_if = "Option::is_none")]
211 pub disabled: Option<bool>,
212
213 #[serde(skip_serializing_if = "Option::is_none")]
215 pub supports_versioning: Option<bool>,
216
217 #[serde(skip_serializing_if = "Option::is_none")]
219 pub enable_dedicated_ips: Option<bool>,
220
221 #[serde(skip_serializing_if = "Option::is_none")]
223 pub auth_account_name: Option<String>,
224
225 #[serde(skip_serializing_if = "Option::is_none")]
227 pub auth_status: Option<String>,
228
229 #[serde(skip_serializing_if = "Option::is_none")]
231 pub google_cloud_storage_s3_compatible_access_key: Option<String>,
232}
233
234pub struct RemoteServerHandler {
236 client: FilesClient,
237}
238
239impl RemoteServerHandler {
240 pub fn new(client: FilesClient) -> Self {
242 Self { client }
243 }
244
245 pub async fn list(
266 &self,
267 cursor: Option<&str>,
268 per_page: Option<i64>,
269 ) -> Result<(Vec<RemoteServerEntity>, PaginationInfo)> {
270 let mut params = vec![];
271 if let Some(c) = cursor {
272 params.push(("cursor", c.to_string()));
273 }
274 if let Some(pp) = per_page {
275 params.push(("per_page", pp.to_string()));
276 }
277
278 let query = if params.is_empty() {
279 String::new()
280 } else {
281 format!(
282 "?{}",
283 params
284 .iter()
285 .map(|(k, v)| format!("{}={}", k, v))
286 .collect::<Vec<_>>()
287 .join("&")
288 )
289 };
290
291 let response = self
292 .client
293 .get_raw(&format!("/remote_servers{}", query))
294 .await?;
295 let servers: Vec<RemoteServerEntity> = serde_json::from_value(response)?;
296
297 let pagination = PaginationInfo {
298 cursor_next: None,
299 cursor_prev: None,
300 };
301
302 Ok((servers, pagination))
303 }
304
305 pub async fn get(&self, id: i64) -> Result<RemoteServerEntity> {
310 let response = self
311 .client
312 .get_raw(&format!("/remote_servers/{}", id))
313 .await?;
314 Ok(serde_json::from_value(response)?)
315 }
316
317 pub async fn get_configuration_file(&self, id: i64) -> Result<serde_json::Value> {
322 let response = self
323 .client
324 .get_raw(&format!("/remote_servers/{}/configuration_file", id))
325 .await?;
326 Ok(response)
327 }
328
329 #[allow(clippy::too_many_arguments)]
343 pub async fn create(
344 &self,
345 name: &str,
346 server_type: &str,
347 hostname: Option<&str>,
348 username: Option<&str>,
349 port: Option<i64>,
350 s3_bucket: Option<&str>,
351 s3_region: Option<&str>,
352 ) -> Result<RemoteServerEntity> {
353 let mut request_body = json!({
354 "name": name,
355 "server_type": server_type,
356 });
357
358 if let Some(h) = hostname {
359 request_body["hostname"] = json!(h);
360 }
361 if let Some(u) = username {
362 request_body["username"] = json!(u);
363 }
364 if let Some(p) = port {
365 request_body["port"] = json!(p);
366 }
367 if let Some(b) = s3_bucket {
368 request_body["s3_bucket"] = json!(b);
369 }
370 if let Some(r) = s3_region {
371 request_body["s3_region"] = json!(r);
372 }
373
374 let response = self
375 .client
376 .post_raw("/remote_servers", request_body)
377 .await?;
378 Ok(serde_json::from_value(response)?)
379 }
380
381 #[allow(clippy::too_many_arguments)]
393 pub async fn update(
394 &self,
395 id: i64,
396 name: Option<&str>,
397 hostname: Option<&str>,
398 port: Option<i64>,
399 disabled: Option<bool>,
400 ) -> Result<RemoteServerEntity> {
401 let mut request_body = json!({});
402
403 if let Some(n) = name {
404 request_body["name"] = json!(n);
405 }
406 if let Some(h) = hostname {
407 request_body["hostname"] = json!(h);
408 }
409 if let Some(p) = port {
410 request_body["port"] = json!(p);
411 }
412 if let Some(d) = disabled {
413 request_body["disabled"] = json!(d);
414 }
415
416 let response = self
417 .client
418 .patch_raw(&format!("/remote_servers/{}", id), request_body)
419 .await?;
420 Ok(serde_json::from_value(response)?)
421 }
422
423 pub async fn delete(&self, id: i64) -> Result<()> {
428 self.client
429 .delete_raw(&format!("/remote_servers/{}", id))
430 .await?;
431 Ok(())
432 }
433}
434
435#[cfg(test)]
436mod tests {
437 use super::*;
438
439 #[test]
440 fn test_handler_creation() {
441 let client = FilesClient::builder().api_key("test-key").build().unwrap();
442 let _handler = RemoteServerHandler::new(client);
443 }
444}