1use super::*;
3use futures_util::TryStreamExt;
4use http_client::CLIENT;
5use reqwest::{Method, StatusCode};
6use serde::de::DeserializeOwned;
7use std::{
8 pin::Pin,
9 task::{Context, Poll},
10};
11use tokio::io::AsyncRead;
12use tokio_tungstenite::tungstenite::{Error, client::IntoClientRequest, http::HeaderValue};
13
14#[derive(Debug)]
15pub enum ApiHttpError {
16 Http(StatusCode, super::ApiError),
17 Reqwest(reqwest::Error),
18 WebSocket(tokio_tungstenite::tungstenite::Error),
19 MsgpackEncode(rmp_serde::encode::Error),
20 MsgpackDecode(rmp_serde::decode::Error),
21}
22
23impl From<ApiHttpError> for anyhow::Error {
24 fn from(value: ApiHttpError) -> Self {
25 match value {
26 ApiHttpError::Http(status, err) => {
27 anyhow::anyhow!("wings api status code {status}: {}", err.error)
28 }
29 ApiHttpError::Reqwest(err) => anyhow::anyhow!(err),
30 ApiHttpError::WebSocket(err) => anyhow::anyhow!(err),
31 ApiHttpError::MsgpackEncode(err) => anyhow::anyhow!(err),
32 ApiHttpError::MsgpackDecode(err) => anyhow::anyhow!(err),
33 }
34 }
35}
36
37pub struct AsyncResponseReader(Box<dyn AsyncRead + Send + Unpin>);
38
39impl AsyncRead for AsyncResponseReader {
40 fn poll_read(
41 mut self: Pin<&mut Self>,
42 cx: &mut Context<'_>,
43 buf: &mut tokio::io::ReadBuf<'_>,
44 ) -> Poll<std::io::Result<()>> {
45 Pin::new(&mut self.0).poll_read(cx, buf)
46 }
47}
48
49impl<'de> Deserialize<'de> for AsyncResponseReader {
50 fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
51 where
52 D: serde::Deserializer<'de>,
53 {
54 Ok(Self(Box::new(tokio::io::empty())))
55 }
56}
57
58pub struct AsyncRequestReader(Box<dyn AsyncRead + Send + Unpin>);
59
60impl AsyncRequestReader {
61 #[inline]
62 pub fn new(reader: impl AsyncRead + Send + Unpin + 'static) -> Self {
63 Self(Box::new(reader))
64 }
65}
66
67impl AsyncRead for AsyncRequestReader {
68 fn poll_read(
69 mut self: Pin<&mut Self>,
70 cx: &mut Context<'_>,
71 buf: &mut tokio::io::ReadBuf<'_>,
72 ) -> Poll<std::io::Result<()>> {
73 Pin::new(&mut self.0).poll_read(cx, buf)
74 }
75}
76
77async fn request_impl<T: DeserializeOwned + 'static>(
78 client: &WingsClient,
79 method: Method,
80 endpoint: impl AsRef<str>,
81 body: Option<&impl Serialize>,
82 body_reader: Option<AsyncRequestReader>,
83) -> Result<T, ApiHttpError> {
84 let url = format!(
85 "{}{}",
86 client.base_url.trim_end_matches('/'),
87 endpoint.as_ref()
88 );
89 let mut request = CLIENT.request(method, &url);
90 request = request.header("Accept", "application/msgpack");
91
92 if !client.token.is_empty() {
93 request = request.header("Authorization", format!("Bearer {}", client.token));
94 }
95
96 if let Some(body) = body {
97 request = request.header("Content-Type", "application/msgpack");
98
99 let mut bytes = Vec::new();
100 let mut se = rmp_serde::Serializer::new(&mut bytes)
101 .with_struct_map()
102 .with_human_readable();
103 if let Err(err) = body.serialize(&mut se) {
104 return Err(ApiHttpError::MsgpackEncode(err));
105 }
106 request = request.body(bytes);
107 } else if let Some(body_reader) = body_reader {
108 request = request.body(reqwest::Body::wrap_stream(
109 tokio_util::io::ReaderStream::new(body_reader),
110 ));
111 }
112
113 match request.send().await {
114 Ok(response) => {
115 if response.status().is_success() {
116 if std::any::type_name::<T>() == std::any::type_name::<AsyncResponseReader>() {
117 let stream = response.bytes_stream().map_err(|err| {
118 std::io::Error::other(format!("failed to read multipart field: {err}"))
119 });
120 let stream_reader = tokio_util::io::StreamReader::new(stream);
121
122 return Ok(*(Box::new(AsyncResponseReader(Box::new(stream_reader)))
123 as Box<dyn std::any::Any>)
124 .downcast::<T>()
125 .unwrap());
126 }
127
128 match response.bytes().await {
129 Ok(data) => {
130 let mut de =
131 rmp_serde::Deserializer::new(data.as_ref()).with_human_readable();
132 match T::deserialize(&mut de) {
133 Ok(data) => Ok(data),
134 Err(err) => Err(ApiHttpError::MsgpackDecode(err)),
135 }
136 }
137 Err(err) => Err(ApiHttpError::Reqwest(err)),
138 }
139 } else {
140 Err(ApiHttpError::Http(
141 response.status(),
142 match response.bytes().await {
143 Ok(data) => {
144 let mut de =
145 rmp_serde::Deserializer::new(data.as_ref()).with_human_readable();
146 match super::ApiError::deserialize(&mut de) {
147 Ok(data) => data,
148 Err(err) => super::ApiError {
149 error: err.to_string().into(),
150 },
151 }
152 }
153 Err(err) => super::ApiError {
154 error: err.to_string().into(),
155 },
156 },
157 ))
158 }
159 }
160 Err(err) => Err(ApiHttpError::Reqwest(err)),
161 }
162}
163
164pub struct WingsClient {
165 base_url: String,
166 token: String,
167}
168
169impl WingsClient {
170 #[inline]
171 pub fn new(base_url: String, token: String) -> Self {
172 Self { base_url, token }
173 }
174
175 pub fn request_raw(
176 &self,
177 method: Method,
178 endpoint: impl AsRef<str>,
179 ) -> reqwest::RequestBuilder {
180 let url = format!(
181 "{}/{}",
182 self.base_url.trim_end_matches('/'),
183 endpoint.as_ref().trim_start_matches('/')
184 );
185 let mut request = CLIENT.request(method, &url);
186
187 if !self.token.is_empty() {
188 request = request.header("Authorization", format!("Bearer {}", self.token));
189 }
190
191 request
192 }
193
194 pub async fn open_websocket(
195 &self,
196 endpoint: impl AsRef<str>,
197 headers: reqwest::header::HeaderMap,
198 ) -> Result<
199 tokio_tungstenite::WebSocketStream<
200 tokio_tungstenite::MaybeTlsStream<tokio::net::TcpStream>,
201 >,
202 ApiHttpError,
203 > {
204 let url = format!(
205 "{}{}",
206 self.base_url.trim_end_matches('/'),
207 endpoint.as_ref()
208 );
209 let url = if let Some(rest) = url.strip_prefix("https://") {
210 format!("wss://{rest}")
211 } else if let Some(rest) = url.strip_prefix("http://") {
212 format!("ws://{rest}")
213 } else {
214 url
215 };
216
217 let mut request = url.into_client_request().map_err(ApiHttpError::WebSocket)?;
218
219 if !self.token.is_empty() {
220 let value = HeaderValue::from_str(&format!("Bearer {}", self.token))
221 .map_err(|err| ApiHttpError::WebSocket(Error::HttpFormat(err.into())))?;
222 request.headers_mut().insert("Authorization", value);
223 }
224
225 for (header, value) in headers {
226 let Some(header) = header else {
227 continue;
228 };
229 request.headers_mut().insert(header, value);
230 }
231
232 let (stream, _) = tokio_tungstenite::connect_async(request)
233 .await
234 .map_err(ApiHttpError::WebSocket)?;
235
236 Ok(stream)
237 }
238
239 pub async fn delete_backups_backup(
240 &self,
241 backup: uuid::Uuid,
242 data: &super::backups_backup::delete::RequestBody,
243 ) -> Result<super::backups_backup::delete::Response, ApiHttpError> {
244 request_impl(
245 self,
246 Method::DELETE,
247 format!("/api/backups/{backup}"),
248 Some(data),
249 None,
250 )
251 .await
252 }
253
254 pub async fn post_backups_backup_export(
255 &self,
256 backup: uuid::Uuid,
257 data: &super::backups_backup_export::post::RequestBody,
258 ) -> Result<super::backups_backup_export::post::Response, ApiHttpError> {
259 request_impl(
260 self,
261 Method::POST,
262 format!("/api/backups/{backup}/export"),
263 Some(data),
264 None,
265 )
266 .await
267 }
268
269 pub async fn get_backups_backup_query(
270 &self,
271 backup: uuid::Uuid,
272 query: &super::backups_backup_query::get::Query,
273 ) -> Result<super::backups_backup_query::get::Response, ApiHttpError> {
274 let mut query_parts: Vec<compact_str::CompactString> = Vec::new();
275 if let Some(value) = query.adapter {
276 query_parts.push(format!("adapter={}", value).into());
277 }
278 let query = if query_parts.is_empty() {
279 String::new()
280 } else {
281 format!("?{}", query_parts.join("&"))
282 };
283 request_impl(
284 self,
285 Method::GET,
286 format!("/api/backups/{backup}/query{query}"),
287 None::<&()>,
288 None,
289 )
290 .await
291 }
292
293 pub async fn post_deauthorize_user(
294 &self,
295 data: &super::deauthorize_user::post::RequestBody,
296 ) -> Result<super::deauthorize_user::post::Response, ApiHttpError> {
297 request_impl(
298 self,
299 Method::POST,
300 "/api/deauthorize-user",
301 Some(data),
302 None,
303 )
304 .await
305 }
306
307 pub async fn get_ports_used(
308 &self,
309 query: &super::ports_used::get::Query,
310 ) -> Result<super::ports_used::get::Response, ApiHttpError> {
311 let mut query_parts: Vec<compact_str::CompactString> = Vec::new();
312 if let Some(value) = &query.ip {
313 for value in value {
314 query_parts.push(format!("ip={}", urlencoding::encode(value)).into());
315 }
316 }
317 let query = if query_parts.is_empty() {
318 String::new()
319 } else {
320 format!("?{}", query_parts.join("&"))
321 };
322 request_impl(
323 self,
324 Method::GET,
325 format!("/api/ports/used{query}"),
326 None::<&()>,
327 None,
328 )
329 .await
330 }
331
332 pub async fn get_servers(&self) -> Result<super::servers::get::Response, ApiHttpError> {
333 request_impl(self, Method::GET, "/api/servers", None::<&()>, None).await
334 }
335
336 pub async fn post_servers(
337 &self,
338 data: &super::servers::post::RequestBody,
339 ) -> Result<super::servers::post::Response, ApiHttpError> {
340 request_impl(self, Method::POST, "/api/servers", Some(data), None).await
341 }
342
343 pub async fn post_servers_power(
344 &self,
345 data: &super::servers_power::post::RequestBody,
346 ) -> Result<super::servers_power::post::Response, ApiHttpError> {
347 request_impl(self, Method::POST, "/api/servers/power", Some(data), None).await
348 }
349
350 pub async fn get_servers_utilization(
351 &self,
352 ) -> Result<super::servers_utilization::get::Response, ApiHttpError> {
353 request_impl(
354 self,
355 Method::GET,
356 "/api/servers/utilization",
357 None::<&()>,
358 None,
359 )
360 .await
361 }
362
363 pub async fn get_servers_server(
364 &self,
365 server: uuid::Uuid,
366 ) -> Result<super::servers_server::get::Response, ApiHttpError> {
367 request_impl(
368 self,
369 Method::GET,
370 format!("/api/servers/{server}"),
371 None::<&()>,
372 None,
373 )
374 .await
375 }
376
377 pub async fn delete_servers_server(
378 &self,
379 server: uuid::Uuid,
380 ) -> Result<super::servers_server::delete::Response, ApiHttpError> {
381 request_impl(
382 self,
383 Method::DELETE,
384 format!("/api/servers/{server}"),
385 None::<&()>,
386 None,
387 )
388 .await
389 }
390
391 pub async fn post_servers_server_backup(
392 &self,
393 server: uuid::Uuid,
394 data: &super::servers_server_backup::post::RequestBody,
395 ) -> Result<super::servers_server_backup::post::Response, ApiHttpError> {
396 request_impl(
397 self,
398 Method::POST,
399 format!("/api/servers/{server}/backup"),
400 Some(data),
401 None,
402 )
403 .await
404 }
405
406 pub async fn delete_servers_server_backup_backup(
407 &self,
408 server: uuid::Uuid,
409 backup: uuid::Uuid,
410 ) -> Result<super::servers_server_backup_backup::delete::Response, ApiHttpError> {
411 request_impl(
412 self,
413 Method::DELETE,
414 format!("/api/servers/{server}/backup/{backup}"),
415 None::<&()>,
416 None,
417 )
418 .await
419 }
420
421 pub async fn post_servers_server_backup_backup_restore(
422 &self,
423 server: uuid::Uuid,
424 backup: uuid::Uuid,
425 data: &super::servers_server_backup_backup_restore::post::RequestBody,
426 ) -> Result<super::servers_server_backup_backup_restore::post::Response, ApiHttpError> {
427 request_impl(
428 self,
429 Method::POST,
430 format!("/api/servers/{server}/backup/{backup}/restore"),
431 Some(data),
432 None,
433 )
434 .await
435 }
436
437 pub async fn post_servers_server_commands(
438 &self,
439 server: uuid::Uuid,
440 data: &super::servers_server_commands::post::RequestBody,
441 ) -> Result<super::servers_server_commands::post::Response, ApiHttpError> {
442 request_impl(
443 self,
444 Method::POST,
445 format!("/api/servers/{server}/commands"),
446 Some(data),
447 None,
448 )
449 .await
450 }
451
452 pub async fn post_servers_server_files_chmod(
453 &self,
454 server: uuid::Uuid,
455 data: &super::servers_server_files_chmod::post::RequestBody,
456 ) -> Result<super::servers_server_files_chmod::post::Response, ApiHttpError> {
457 request_impl(
458 self,
459 Method::POST,
460 format!("/api/servers/{server}/files/chmod"),
461 Some(data),
462 None,
463 )
464 .await
465 }
466
467 pub async fn post_servers_server_files_compress(
468 &self,
469 server: uuid::Uuid,
470 data: &super::servers_server_files_compress::post::RequestBody,
471 ) -> Result<super::servers_server_files_compress::post::Response, ApiHttpError> {
472 request_impl(
473 self,
474 Method::POST,
475 format!("/api/servers/{server}/files/compress"),
476 Some(data),
477 None,
478 )
479 .await
480 }
481
482 pub async fn get_servers_server_files_contents(
483 &self,
484 server: uuid::Uuid,
485 query: &super::servers_server_files_contents::get::Query,
486 ) -> Result<super::servers_server_files_contents::get::Response, ApiHttpError> {
487 let mut query_parts: Vec<compact_str::CompactString> = Vec::new();
488 if let Some(value) = &query.file {
489 query_parts.push(format!("file={}", urlencoding::encode(value)).into());
490 }
491 if let Some(value) = query.download {
492 query_parts.push(format!("download={}", value).into());
493 }
494 if let Some(value) = query.max_size {
495 query_parts.push(format!("max_size={}", value).into());
496 }
497 let query = if query_parts.is_empty() {
498 String::new()
499 } else {
500 format!("?{}", query_parts.join("&"))
501 };
502 request_impl(
503 self,
504 Method::GET,
505 format!("/api/servers/{server}/files/contents{query}"),
506 None::<&()>,
507 None,
508 )
509 .await
510 }
511
512 pub async fn post_servers_server_files_copy(
513 &self,
514 server: uuid::Uuid,
515 data: &super::servers_server_files_copy::post::RequestBody,
516 ) -> Result<super::servers_server_files_copy::post::Response, ApiHttpError> {
517 request_impl(
518 self,
519 Method::POST,
520 format!("/api/servers/{server}/files/copy"),
521 Some(data),
522 None,
523 )
524 .await
525 }
526
527 pub async fn post_servers_server_files_copy_many(
528 &self,
529 server: uuid::Uuid,
530 data: &super::servers_server_files_copy_many::post::RequestBody,
531 ) -> Result<super::servers_server_files_copy_many::post::Response, ApiHttpError> {
532 request_impl(
533 self,
534 Method::POST,
535 format!("/api/servers/{server}/files/copy-many"),
536 Some(data),
537 None,
538 )
539 .await
540 }
541
542 pub async fn post_servers_server_files_copy_remote(
543 &self,
544 server: uuid::Uuid,
545 data: &super::servers_server_files_copy_remote::post::RequestBody,
546 ) -> Result<super::servers_server_files_copy_remote::post::Response, ApiHttpError> {
547 request_impl(
548 self,
549 Method::POST,
550 format!("/api/servers/{server}/files/copy-remote"),
551 Some(data),
552 None,
553 )
554 .await
555 }
556
557 pub async fn post_servers_server_files_create_directory(
558 &self,
559 server: uuid::Uuid,
560 data: &super::servers_server_files_create_directory::post::RequestBody,
561 ) -> Result<super::servers_server_files_create_directory::post::Response, ApiHttpError> {
562 request_impl(
563 self,
564 Method::POST,
565 format!("/api/servers/{server}/files/create-directory"),
566 Some(data),
567 None,
568 )
569 .await
570 }
571
572 pub async fn post_servers_server_files_create_symlink(
573 &self,
574 server: uuid::Uuid,
575 data: &super::servers_server_files_create_symlink::post::RequestBody,
576 ) -> Result<super::servers_server_files_create_symlink::post::Response, ApiHttpError> {
577 request_impl(
578 self,
579 Method::POST,
580 format!("/api/servers/{server}/files/create-symlink"),
581 Some(data),
582 None,
583 )
584 .await
585 }
586
587 pub async fn post_servers_server_files_decompress(
588 &self,
589 server: uuid::Uuid,
590 data: &super::servers_server_files_decompress::post::RequestBody,
591 ) -> Result<super::servers_server_files_decompress::post::Response, ApiHttpError> {
592 request_impl(
593 self,
594 Method::POST,
595 format!("/api/servers/{server}/files/decompress"),
596 Some(data),
597 None,
598 )
599 .await
600 }
601
602 pub async fn post_servers_server_files_delete(
603 &self,
604 server: uuid::Uuid,
605 data: &super::servers_server_files_delete::post::RequestBody,
606 ) -> Result<super::servers_server_files_delete::post::Response, ApiHttpError> {
607 request_impl(
608 self,
609 Method::POST,
610 format!("/api/servers/{server}/files/delete"),
611 Some(data),
612 None,
613 )
614 .await
615 }
616
617 pub async fn get_servers_server_files_fingerprints(
618 &self,
619 server: uuid::Uuid,
620 query: &super::servers_server_files_fingerprints::get::Query,
621 ) -> Result<super::servers_server_files_fingerprints::get::Response, ApiHttpError> {
622 let mut query_parts: Vec<compact_str::CompactString> = Vec::new();
623 if let Some(value) = query.algorithm {
624 query_parts.push(format!("algorithm={}", value).into());
625 }
626 if let Some(value) = &query.files {
627 for value in value {
628 query_parts.push(format!("files={}", urlencoding::encode(value)).into());
629 }
630 }
631 let query = if query_parts.is_empty() {
632 String::new()
633 } else {
634 format!("?{}", query_parts.join("&"))
635 };
636 request_impl(
637 self,
638 Method::GET,
639 format!("/api/servers/{server}/files/fingerprints{query}"),
640 None::<&()>,
641 None,
642 )
643 .await
644 }
645
646 pub async fn get_servers_server_files_largest_directories(
647 &self,
648 server: uuid::Uuid,
649 query: &super::servers_server_files_largest_directories::get::Query,
650 ) -> Result<super::servers_server_files_largest_directories::get::Response, ApiHttpError> {
651 let mut query_parts: Vec<compact_str::CompactString> = Vec::new();
652 if let Some(value) = &query.directory {
653 query_parts.push(format!("directory={}", urlencoding::encode(value)).into());
654 }
655 if let Some(value) = &query.ignored {
656 for value in value {
657 query_parts.push(format!("ignored={}", urlencoding::encode(value)).into());
658 }
659 }
660 let query = if query_parts.is_empty() {
661 String::new()
662 } else {
663 format!("?{}", query_parts.join("&"))
664 };
665 request_impl(
666 self,
667 Method::GET,
668 format!("/api/servers/{server}/files/largest-directories{query}"),
669 None::<&()>,
670 None,
671 )
672 .await
673 }
674
675 pub async fn get_servers_server_files_list(
676 &self,
677 server: uuid::Uuid,
678 query: &super::servers_server_files_list::get::Query,
679 ) -> Result<super::servers_server_files_list::get::Response, ApiHttpError> {
680 let mut query_parts: Vec<compact_str::CompactString> = Vec::new();
681 if let Some(value) = &query.directory {
682 query_parts.push(format!("directory={}", urlencoding::encode(value)).into());
683 }
684 if let Some(value) = &query.ignored {
685 for value in value {
686 query_parts.push(format!("ignored={}", urlencoding::encode(value)).into());
687 }
688 }
689 if let Some(value) = query.per_page {
690 query_parts.push(format!("per_page={}", value).into());
691 }
692 if let Some(value) = query.page {
693 query_parts.push(format!("page={}", value).into());
694 }
695 if let Some(value) = query.sort {
696 query_parts.push(format!("sort={}", value).into());
697 }
698 let query = if query_parts.is_empty() {
699 String::new()
700 } else {
701 format!("?{}", query_parts.join("&"))
702 };
703 request_impl(
704 self,
705 Method::GET,
706 format!("/api/servers/{server}/files/list{query}"),
707 None::<&()>,
708 None,
709 )
710 .await
711 }
712
713 pub async fn get_servers_server_files_list_directory(
714 &self,
715 server: uuid::Uuid,
716 query: &super::servers_server_files_list_directory::get::Query,
717 ) -> Result<super::servers_server_files_list_directory::get::Response, ApiHttpError> {
718 let mut query_parts: Vec<compact_str::CompactString> = Vec::new();
719 if let Some(value) = &query.directory {
720 query_parts.push(format!("directory={}", urlencoding::encode(value)).into());
721 }
722 let query = if query_parts.is_empty() {
723 String::new()
724 } else {
725 format!("?{}", query_parts.join("&"))
726 };
727 request_impl(
728 self,
729 Method::GET,
730 format!("/api/servers/{server}/files/list-directory{query}"),
731 None::<&()>,
732 None,
733 )
734 .await
735 }
736
737 pub async fn get_servers_server_files_operations(
738 &self,
739 server: uuid::Uuid,
740 ) -> Result<super::servers_server_files_operations::get::Response, ApiHttpError> {
741 request_impl(
742 self,
743 Method::GET,
744 format!("/api/servers/{server}/files/operations"),
745 None::<&()>,
746 None,
747 )
748 .await
749 }
750
751 pub async fn delete_servers_server_files_operations_operation(
752 &self,
753 server: uuid::Uuid,
754 operation: uuid::Uuid,
755 ) -> Result<super::servers_server_files_operations_operation::delete::Response, ApiHttpError>
756 {
757 request_impl(
758 self,
759 Method::DELETE,
760 format!("/api/servers/{server}/files/operations/{operation}"),
761 None::<&()>,
762 None,
763 )
764 .await
765 }
766
767 pub async fn get_servers_server_files_pull(
768 &self,
769 server: uuid::Uuid,
770 ) -> Result<super::servers_server_files_pull::get::Response, ApiHttpError> {
771 request_impl(
772 self,
773 Method::GET,
774 format!("/api/servers/{server}/files/pull"),
775 None::<&()>,
776 None,
777 )
778 .await
779 }
780
781 pub async fn post_servers_server_files_pull(
782 &self,
783 server: uuid::Uuid,
784 data: &super::servers_server_files_pull::post::RequestBody,
785 ) -> Result<super::servers_server_files_pull::post::Response, ApiHttpError> {
786 request_impl(
787 self,
788 Method::POST,
789 format!("/api/servers/{server}/files/pull"),
790 Some(data),
791 None,
792 )
793 .await
794 }
795
796 pub async fn post_servers_server_files_pull_query(
797 &self,
798 server: uuid::Uuid,
799 data: &super::servers_server_files_pull_query::post::RequestBody,
800 ) -> Result<super::servers_server_files_pull_query::post::Response, ApiHttpError> {
801 request_impl(
802 self,
803 Method::POST,
804 format!("/api/servers/{server}/files/pull/query"),
805 Some(data),
806 None,
807 )
808 .await
809 }
810
811 pub async fn delete_servers_server_files_pull_pull(
812 &self,
813 server: uuid::Uuid,
814 pull: uuid::Uuid,
815 ) -> Result<super::servers_server_files_pull_pull::delete::Response, ApiHttpError> {
816 request_impl(
817 self,
818 Method::DELETE,
819 format!("/api/servers/{server}/files/pull/{pull}"),
820 None::<&()>,
821 None,
822 )
823 .await
824 }
825
826 pub async fn put_servers_server_files_rename(
827 &self,
828 server: uuid::Uuid,
829 data: &super::servers_server_files_rename::put::RequestBody,
830 ) -> Result<super::servers_server_files_rename::put::Response, ApiHttpError> {
831 request_impl(
832 self,
833 Method::PUT,
834 format!("/api/servers/{server}/files/rename"),
835 Some(data),
836 None,
837 )
838 .await
839 }
840
841 pub async fn get_servers_server_files_revisions(
842 &self,
843 server: uuid::Uuid,
844 query: &super::servers_server_files_revisions::get::Query,
845 ) -> Result<super::servers_server_files_revisions::get::Response, ApiHttpError> {
846 let mut query_parts: Vec<compact_str::CompactString> = Vec::new();
847 if let Some(value) = &query.file {
848 query_parts.push(format!("file={}", urlencoding::encode(value)).into());
849 }
850 let query = if query_parts.is_empty() {
851 String::new()
852 } else {
853 format!("?{}", query_parts.join("&"))
854 };
855 request_impl(
856 self,
857 Method::GET,
858 format!("/api/servers/{server}/files/revisions{query}"),
859 None::<&()>,
860 None,
861 )
862 .await
863 }
864
865 pub async fn get_servers_server_files_revisions_revision(
866 &self,
867 server: uuid::Uuid,
868 revision: i64,
869 query: &super::servers_server_files_revisions_revision::get::Query,
870 ) -> Result<super::servers_server_files_revisions_revision::get::Response, ApiHttpError> {
871 let mut query_parts: Vec<compact_str::CompactString> = Vec::new();
872 if let Some(value) = &query.file {
873 query_parts.push(format!("file={}", urlencoding::encode(value)).into());
874 }
875 let query = if query_parts.is_empty() {
876 String::new()
877 } else {
878 format!("?{}", query_parts.join("&"))
879 };
880 request_impl(
881 self,
882 Method::GET,
883 format!("/api/servers/{server}/files/revisions/{revision}{query}"),
884 None::<&()>,
885 None,
886 )
887 .await
888 }
889
890 pub async fn post_servers_server_files_search(
891 &self,
892 server: uuid::Uuid,
893 data: &super::servers_server_files_search::post::RequestBody,
894 ) -> Result<super::servers_server_files_search::post::Response, ApiHttpError> {
895 request_impl(
896 self,
897 Method::POST,
898 format!("/api/servers/{server}/files/search"),
899 Some(data),
900 None,
901 )
902 .await
903 }
904
905 pub async fn post_servers_server_files_sqlite_query(
906 &self,
907 server: uuid::Uuid,
908 data: &super::servers_server_files_sqlite_query::post::RequestBody,
909 ) -> Result<super::servers_server_files_sqlite_query::post::Response, ApiHttpError> {
910 request_impl(
911 self,
912 Method::POST,
913 format!("/api/servers/{server}/files/sqlite-query"),
914 Some(data),
915 None,
916 )
917 .await
918 }
919
920 pub async fn post_servers_server_files_write(
921 &self,
922 server: uuid::Uuid,
923 data: super::servers_server_files_write::post::RequestBody,
924 query: &super::servers_server_files_write::post::Query,
925 ) -> Result<super::servers_server_files_write::post::Response, ApiHttpError> {
926 let mut query_parts: Vec<compact_str::CompactString> = Vec::new();
927 if let Some(value) = &query.file {
928 query_parts.push(format!("file={}", urlencoding::encode(value)).into());
929 }
930 if let Some(value) = query.user {
931 query_parts.push(format!("user={}", value).into());
932 }
933 let query = if query_parts.is_empty() {
934 String::new()
935 } else {
936 format!("?{}", query_parts.join("&"))
937 };
938 request_impl(
939 self,
940 Method::POST,
941 format!("/api/servers/{server}/files/write{query}"),
942 None::<&()>,
943 Some(data),
944 )
945 .await
946 }
947
948 pub async fn post_servers_server_install_abort(
949 &self,
950 server: uuid::Uuid,
951 ) -> Result<super::servers_server_install_abort::post::Response, ApiHttpError> {
952 request_impl(
953 self,
954 Method::POST,
955 format!("/api/servers/{server}/install/abort"),
956 None::<&()>,
957 None,
958 )
959 .await
960 }
961
962 pub async fn get_servers_server_logs(
963 &self,
964 server: uuid::Uuid,
965 query: &super::servers_server_logs::get::Query,
966 ) -> Result<super::servers_server_logs::get::Response, ApiHttpError> {
967 let mut query_parts: Vec<compact_str::CompactString> = Vec::new();
968 if let Some(value) = query.lines {
969 query_parts.push(format!("lines={}", value).into());
970 }
971 let query = if query_parts.is_empty() {
972 String::new()
973 } else {
974 format!("?{}", query_parts.join("&"))
975 };
976 request_impl(
977 self,
978 Method::GET,
979 format!("/api/servers/{server}/logs{query}"),
980 None::<&()>,
981 None,
982 )
983 .await
984 }
985
986 pub async fn get_servers_server_logs_install(
987 &self,
988 server: uuid::Uuid,
989 query: &super::servers_server_logs_install::get::Query,
990 ) -> Result<super::servers_server_logs_install::get::Response, ApiHttpError> {
991 let mut query_parts: Vec<compact_str::CompactString> = Vec::new();
992 if let Some(value) = query.lines {
993 query_parts.push(format!("lines={}", value).into());
994 }
995 let query = if query_parts.is_empty() {
996 String::new()
997 } else {
998 format!("?{}", query_parts.join("&"))
999 };
1000 request_impl(
1001 self,
1002 Method::GET,
1003 format!("/api/servers/{server}/logs/install{query}"),
1004 None::<&()>,
1005 None,
1006 )
1007 .await
1008 }
1009
1010 pub async fn post_servers_server_power(
1011 &self,
1012 server: uuid::Uuid,
1013 data: &super::servers_server_power::post::RequestBody,
1014 ) -> Result<super::servers_server_power::post::Response, ApiHttpError> {
1015 request_impl(
1016 self,
1017 Method::POST,
1018 format!("/api/servers/{server}/power"),
1019 Some(data),
1020 None,
1021 )
1022 .await
1023 }
1024
1025 pub async fn post_servers_server_reinstall(
1026 &self,
1027 server: uuid::Uuid,
1028 data: &super::servers_server_reinstall::post::RequestBody,
1029 ) -> Result<super::servers_server_reinstall::post::Response, ApiHttpError> {
1030 request_impl(
1031 self,
1032 Method::POST,
1033 format!("/api/servers/{server}/reinstall"),
1034 Some(data),
1035 None,
1036 )
1037 .await
1038 }
1039
1040 pub async fn get_servers_server_schedules_schedule(
1041 &self,
1042 server: uuid::Uuid,
1043 schedule: uuid::Uuid,
1044 ) -> Result<super::servers_server_schedules_schedule::get::Response, ApiHttpError> {
1045 request_impl(
1046 self,
1047 Method::GET,
1048 format!("/api/servers/{server}/schedules/{schedule}"),
1049 None::<&()>,
1050 None,
1051 )
1052 .await
1053 }
1054
1055 pub async fn post_servers_server_schedules_schedule_abort(
1056 &self,
1057 server: uuid::Uuid,
1058 schedule: uuid::Uuid,
1059 ) -> Result<super::servers_server_schedules_schedule_abort::post::Response, ApiHttpError> {
1060 request_impl(
1061 self,
1062 Method::POST,
1063 format!("/api/servers/{server}/schedules/{schedule}/abort"),
1064 None::<&()>,
1065 None,
1066 )
1067 .await
1068 }
1069
1070 pub async fn post_servers_server_schedules_schedule_trigger(
1071 &self,
1072 server: uuid::Uuid,
1073 schedule: uuid::Uuid,
1074 data: &super::servers_server_schedules_schedule_trigger::post::RequestBody,
1075 ) -> Result<super::servers_server_schedules_schedule_trigger::post::Response, ApiHttpError>
1076 {
1077 request_impl(
1078 self,
1079 Method::POST,
1080 format!("/api/servers/{server}/schedules/{schedule}/trigger"),
1081 Some(data),
1082 None,
1083 )
1084 .await
1085 }
1086
1087 pub async fn post_servers_server_script(
1088 &self,
1089 server: uuid::Uuid,
1090 data: &super::servers_server_script::post::RequestBody,
1091 ) -> Result<super::servers_server_script::post::Response, ApiHttpError> {
1092 request_impl(
1093 self,
1094 Method::POST,
1095 format!("/api/servers/{server}/script"),
1096 Some(data),
1097 None,
1098 )
1099 .await
1100 }
1101
1102 pub async fn post_servers_server_sync(
1103 &self,
1104 server: uuid::Uuid,
1105 data: &super::servers_server_sync::post::RequestBody,
1106 ) -> Result<super::servers_server_sync::post::Response, ApiHttpError> {
1107 request_impl(
1108 self,
1109 Method::POST,
1110 format!("/api/servers/{server}/sync"),
1111 Some(data),
1112 None,
1113 )
1114 .await
1115 }
1116
1117 pub async fn delete_servers_server_transfer(
1118 &self,
1119 server: uuid::Uuid,
1120 ) -> Result<super::servers_server_transfer::delete::Response, ApiHttpError> {
1121 request_impl(
1122 self,
1123 Method::DELETE,
1124 format!("/api/servers/{server}/transfer"),
1125 None::<&()>,
1126 None,
1127 )
1128 .await
1129 }
1130
1131 pub async fn post_servers_server_transfer(
1132 &self,
1133 server: uuid::Uuid,
1134 data: &super::servers_server_transfer::post::RequestBody,
1135 ) -> Result<super::servers_server_transfer::post::Response, ApiHttpError> {
1136 request_impl(
1137 self,
1138 Method::POST,
1139 format!("/api/servers/{server}/transfer"),
1140 Some(data),
1141 None,
1142 )
1143 .await
1144 }
1145
1146 pub async fn get_servers_server_utilization(
1147 &self,
1148 server: uuid::Uuid,
1149 ) -> Result<super::servers_server_utilization::get::Response, ApiHttpError> {
1150 request_impl(
1151 self,
1152 Method::GET,
1153 format!("/api/servers/{server}/utilization"),
1154 None::<&()>,
1155 None,
1156 )
1157 .await
1158 }
1159
1160 pub async fn get_servers_server_version(
1161 &self,
1162 server: uuid::Uuid,
1163 query: &super::servers_server_version::get::Query,
1164 ) -> Result<super::servers_server_version::get::Response, ApiHttpError> {
1165 let mut query_parts: Vec<compact_str::CompactString> = Vec::new();
1166 if let Some(value) = query.game {
1167 query_parts.push(format!("game={}", value).into());
1168 }
1169 let query = if query_parts.is_empty() {
1170 String::new()
1171 } else {
1172 format!("?{}", query_parts.join("&"))
1173 };
1174 request_impl(
1175 self,
1176 Method::GET,
1177 format!("/api/servers/{server}/version{query}"),
1178 None::<&()>,
1179 None,
1180 )
1181 .await
1182 }
1183
1184 pub async fn post_servers_server_ws_broadcast(
1185 &self,
1186 server: uuid::Uuid,
1187 data: &super::servers_server_ws_broadcast::post::RequestBody,
1188 ) -> Result<super::servers_server_ws_broadcast::post::Response, ApiHttpError> {
1189 request_impl(
1190 self,
1191 Method::POST,
1192 format!("/api/servers/{server}/ws/broadcast"),
1193 Some(data),
1194 None,
1195 )
1196 .await
1197 }
1198
1199 pub async fn post_servers_server_ws_deny(
1200 &self,
1201 server: uuid::Uuid,
1202 data: &super::servers_server_ws_deny::post::RequestBody,
1203 ) -> Result<super::servers_server_ws_deny::post::Response, ApiHttpError> {
1204 request_impl(
1205 self,
1206 Method::POST,
1207 format!("/api/servers/{server}/ws/deny"),
1208 Some(data),
1209 None,
1210 )
1211 .await
1212 }
1213
1214 pub async fn post_servers_server_ws_permissions(
1215 &self,
1216 server: uuid::Uuid,
1217 data: &super::servers_server_ws_permissions::post::RequestBody,
1218 ) -> Result<super::servers_server_ws_permissions::post::Response, ApiHttpError> {
1219 request_impl(
1220 self,
1221 Method::POST,
1222 format!("/api/servers/{server}/ws/permissions"),
1223 Some(data),
1224 None,
1225 )
1226 .await
1227 }
1228
1229 pub async fn get_system(&self) -> Result<super::system::get::Response, ApiHttpError> {
1230 request_impl(self, Method::GET, "/api/system", None::<&()>, None).await
1231 }
1232
1233 pub async fn get_system_config(
1234 &self,
1235 ) -> Result<super::system_config::get::Response, ApiHttpError> {
1236 request_impl(self, Method::GET, "/api/system/config", None::<&()>, None).await
1237 }
1238
1239 pub async fn get_system_logs(&self) -> Result<super::system_logs::get::Response, ApiHttpError> {
1240 request_impl(self, Method::GET, "/api/system/logs", None::<&()>, None).await
1241 }
1242
1243 pub async fn get_system_logs_file(
1244 &self,
1245 file: &str,
1246 query: &super::system_logs_file::get::Query,
1247 ) -> Result<super::system_logs_file::get::Response, ApiHttpError> {
1248 let mut query_parts: Vec<compact_str::CompactString> = Vec::new();
1249 if let Some(value) = query.lines {
1250 query_parts.push(format!("lines={}", value).into());
1251 }
1252 let query = if query_parts.is_empty() {
1253 String::new()
1254 } else {
1255 format!("?{}", query_parts.join("&"))
1256 };
1257 request_impl(
1258 self,
1259 Method::GET,
1260 format!("/api/system/logs/{file}{query}"),
1261 None::<&()>,
1262 None,
1263 )
1264 .await
1265 }
1266
1267 pub async fn get_system_overview(
1268 &self,
1269 ) -> Result<super::system_overview::get::Response, ApiHttpError> {
1270 request_impl(self, Method::GET, "/api/system/overview", None::<&()>, None).await
1271 }
1272
1273 pub async fn get_system_restic_prune(
1274 &self,
1275 ) -> Result<super::system_restic_prune::get::Response, ApiHttpError> {
1276 request_impl(
1277 self,
1278 Method::GET,
1279 "/api/system/restic/prune",
1280 None::<&()>,
1281 None,
1282 )
1283 .await
1284 }
1285
1286 pub async fn post_system_restic_prune(
1287 &self,
1288 data: &super::system_restic_prune::post::RequestBody,
1289 ) -> Result<super::system_restic_prune::post::Response, ApiHttpError> {
1290 request_impl(
1291 self,
1292 Method::POST,
1293 "/api/system/restic/prune",
1294 Some(data),
1295 None,
1296 )
1297 .await
1298 }
1299
1300 pub async fn get_system_restic_stats(
1301 &self,
1302 ) -> Result<super::system_restic_stats::get::Response, ApiHttpError> {
1303 request_impl(
1304 self,
1305 Method::GET,
1306 "/api/system/restic/stats",
1307 None::<&()>,
1308 None,
1309 )
1310 .await
1311 }
1312
1313 pub async fn post_system_restic_stats(
1314 &self,
1315 data: &super::system_restic_stats::post::RequestBody,
1316 ) -> Result<super::system_restic_stats::post::Response, ApiHttpError> {
1317 request_impl(
1318 self,
1319 Method::POST,
1320 "/api/system/restic/stats",
1321 Some(data),
1322 None,
1323 )
1324 .await
1325 }
1326
1327 pub async fn get_system_restic_unlock(
1328 &self,
1329 ) -> Result<super::system_restic_unlock::get::Response, ApiHttpError> {
1330 request_impl(
1331 self,
1332 Method::GET,
1333 "/api/system/restic/unlock",
1334 None::<&()>,
1335 None,
1336 )
1337 .await
1338 }
1339
1340 pub async fn post_system_restic_unlock(
1341 &self,
1342 data: &super::system_restic_unlock::post::RequestBody,
1343 ) -> Result<super::system_restic_unlock::post::Response, ApiHttpError> {
1344 request_impl(
1345 self,
1346 Method::POST,
1347 "/api/system/restic/unlock",
1348 Some(data),
1349 None,
1350 )
1351 .await
1352 }
1353
1354 pub async fn get_system_stats(
1355 &self,
1356 ) -> Result<super::system_stats::get::Response, ApiHttpError> {
1357 request_impl(self, Method::GET, "/api/system/stats", None::<&()>, None).await
1358 }
1359
1360 pub async fn post_system_upgrade(
1361 &self,
1362 data: &super::system_upgrade::post::RequestBody,
1363 ) -> Result<super::system_upgrade::post::Response, ApiHttpError> {
1364 request_impl(self, Method::POST, "/api/system/upgrade", Some(data), None).await
1365 }
1366
1367 pub async fn get_transfers(&self) -> Result<super::transfers::get::Response, ApiHttpError> {
1368 request_impl(self, Method::GET, "/api/transfers", None::<&()>, None).await
1369 }
1370
1371 pub async fn post_transfers(&self) -> Result<super::transfers::post::Response, ApiHttpError> {
1372 request_impl(self, Method::POST, "/api/transfers", None::<&()>, None).await
1373 }
1374
1375 pub async fn get_transfers_capabilities(
1376 &self,
1377 ) -> Result<super::transfers_capabilities::get::Response, ApiHttpError> {
1378 request_impl(
1379 self,
1380 Method::GET,
1381 "/api/transfers/capabilities",
1382 None::<&()>,
1383 None,
1384 )
1385 .await
1386 }
1387
1388 pub async fn post_transfers_files(
1389 &self,
1390 ) -> Result<super::transfers_files::post::Response, ApiHttpError> {
1391 request_impl(
1392 self,
1393 Method::POST,
1394 "/api/transfers/files",
1395 None::<&()>,
1396 None,
1397 )
1398 .await
1399 }
1400
1401 pub async fn get_transfers_query(
1402 &self,
1403 ) -> Result<super::transfers_query::get::Response, ApiHttpError> {
1404 request_impl(self, Method::GET, "/api/transfers/query", None::<&()>, None).await
1405 }
1406
1407 pub async fn delete_transfers_server(
1408 &self,
1409 server: uuid::Uuid,
1410 ) -> Result<super::transfers_server::delete::Response, ApiHttpError> {
1411 request_impl(
1412 self,
1413 Method::DELETE,
1414 format!("/api/transfers/{server}"),
1415 None::<&()>,
1416 None,
1417 )
1418 .await
1419 }
1420
1421 pub async fn post_update(
1422 &self,
1423 data: &super::update::post::RequestBody,
1424 ) -> Result<super::update::post::Response, ApiHttpError> {
1425 request_impl(self, Method::POST, "/api/update", Some(data), None).await
1426 }
1427}