1use reqwest::{Client, Method};
2use serde::de::DeserializeOwned;
3use serde::Serialize;
4use serde_json::Value;
5
6use crate::wire::{
7 ApiError, BackupCreateFlags, BackupCreateRequestWire, BackupInfoWire, BackupLoadFlags,
8 BackupLoadRequestWire, BackupMetaWire,
9};
10
11#[derive(Clone, Debug)]
12pub struct XenonApiClient {
13 host: String,
14 client: Client,
15}
16
17type ApiResult<T> = Result<T, ApiError>;
18
19impl XenonApiClient {
20 pub fn new(host: String) -> Self {
21 Self {
22 host,
23 client: Client::new(), }
25 }
26
27 pub async fn request<T: DeserializeOwned, D: Serialize>(
28 &self,
29 method: Method,
30 path: &str,
31 data: &D,
32 ) -> ApiResult<T> {
33 let url = format!("{}{}", self.host, path);
34
35 let resp = self
36 .client
37 .request(method, &url)
38 .json(data)
39 .send()
40 .await
41 .map_err(|e| ApiError::Unexpected {
42 message: "sending api request failed".into(),
43 details: Some(e.to_string().into()),
44 })?
45 .json::<Value>()
46 .await
47 .map_err(|e| ApiError::Unexpected {
48 message: "parsing api response failed".into(),
49 details: Some(e.to_string().into()),
50 })?;
51
52 if let Some(Value::Bool(true)) = resp.get("success") {
53 Ok(serde_json::from_value(resp.get("data").unwrap().clone()).unwrap())
54 } else {
55 Err(serde_json::from_value(resp).unwrap())
56 }
57 }
58
59 pub async fn backup_create(
60 &self,
61 guild_id: u64,
62 flags: BackupCreateFlags,
63 message_count: u32,
64 ) -> ApiResult<BackupMetaWire> {
65 let path = format!("/guilds/{}/backups", guild_id);
66 let data = BackupCreateRequestWire {
67 message_count,
68 flags: flags.bits(),
69 };
70 self.request(Method::POST, &path, &data).await
71 }
72
73 pub async fn backup_delete(&self, backup_id: &str) -> ApiResult<()> {
74 let path = format!("/backups/{}", backup_id);
75 self.request(Method::DELETE, &path, &()).await
76 }
77
78 pub async fn backup_get(&self, backup_id: &str) -> ApiResult<BackupInfoWire> {
79 let path = format!("/backups/{}", backup_id);
80 self.request(Method::GET, &path, &()).await
81 }
82
83 pub async fn backup_list(&self) -> ApiResult<Vec<BackupMetaWire>> {
84 self.request(Method::GET, "/backups", &()).await
85 }
86
87 pub async fn backup_load(
88 &self,
89 guild_id: u64,
90 backup_id: &str,
91 flags: BackupLoadFlags,
92 message_count: u32,
93 ) -> ApiResult<()> {
94 let path = format!("/guilds/{}/backups/{}", guild_id, backup_id);
95 let data = BackupLoadRequestWire {
96 message_count,
97 flags: flags.bits(),
98 };
99 self.request(Method::POST, &path, &data).await
100 }
101}