1use crate::model::{
2 apps::{
3 AppDataQuery, AppDataQueryResult, AppDataSelectMode, AppDataSelectQuery, ThirdPartyApp,
4 },
5 ApiReturn, Error, Result,
6};
7use reqwest::{
8 multipart::{Form, Part},
9 Client as HttpClient,
10};
11pub use reqwest::Method;
12use serde::{de::DeserializeOwned, Deserialize, Serialize};
13
14macro_rules! api_return_ok {
15 ($ret:ty, $res:ident) => {
16 match $res.json::<ApiReturn<$ret>>().await {
17 Ok(x) => {
18 if x.ok {
19 Ok(x.payload)
20 } else {
21 Err(Error::MiscError(x.message))
22 }
23 }
24 Err(e) => Err(Error::MiscError(e.to_string())),
25 }
26 };
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct SimplifiedQuery {
32 pub query: AppDataSelectQuery,
33 pub mode: AppDataSelectMode,
34 pub cache: bool,
35}
36
37#[derive(Debug, Clone)]
39pub struct DataClient {
40 pub http: HttpClient,
42 pub api_key: String,
44 pub host: String,
47}
48
49impl DataClient {
50 pub fn new(host: Option<String>, api_key: String) -> Self {
52 Self {
53 http: HttpClient::new(),
54 api_key,
55 host: host.unwrap_or("https://tetratto.com".to_string()),
56 }
57 }
58
59 pub async fn get_app(&self) -> Result<ThirdPartyApp> {
67 match self
68 .http
69 .get(format!("{}/api/v1/app_data/app", self.host))
70 .header("Atto-Secret-Key", &self.api_key)
71 .send()
72 .await
73 {
74 Ok(x) => api_return_ok!(ThirdPartyApp, x),
75 Err(e) => Err(Error::MiscError(e.to_string())),
76 }
77 }
78
79 pub async fn check_ip(&self, ip: &str) -> Result<bool> {
83 match self
84 .http
85 .get(format!("{}/api/v1/bans/{}", self.host, ip))
86 .header("Atto-Secret-Key", &self.api_key)
87 .send()
88 .await
89 {
90 Ok(x) => api_return_ok!(bool, x),
91 Err(e) => Err(Error::MiscError(e.to_string())),
92 }
93 }
94
95 pub async fn query(&self, query: &SimplifiedQuery) -> Result<AppDataQueryResult> {
97 match self
98 .http
99 .post(format!("{}/api/v1/app_data/query", self.host))
100 .header("Atto-Secret-Key", &self.api_key)
101 .json(&query)
102 .send()
103 .await
104 {
105 Ok(x) => api_return_ok!(AppDataQueryResult, x),
106 Err(e) => Err(Error::MiscError(e.to_string())),
107 }
108 }
109
110 pub async fn insert(&self, key: String, value: String) -> Result<String> {
112 match self
113 .http
114 .post(format!("{}/api/v1/app_data", self.host))
115 .header("Atto-Secret-Key", &self.api_key)
116 .json(&serde_json::Value::Object({
117 let mut map = serde_json::Map::new();
118 map.insert("key".to_string(), serde_json::Value::String(key));
119 map.insert("value".to_string(), serde_json::Value::String(value));
120 map
121 }))
122 .send()
123 .await
124 {
125 Ok(x) => api_return_ok!(String, x),
126 Err(e) => Err(Error::MiscError(e.to_string())),
127 }
128 }
129
130 pub async fn update(&self, id: usize, value: String) -> Result<()> {
132 match self
133 .http
134 .post(format!("{}/api/v1/app_data/{id}/value", self.host))
135 .header("Atto-Secret-Key", &self.api_key)
136 .json(&serde_json::Value::Object({
137 let mut map = serde_json::Map::new();
138 map.insert("value".to_string(), serde_json::Value::String(value));
139 map
140 }))
141 .send()
142 .await
143 {
144 Ok(x) => api_return_ok!((), x),
145 Err(e) => Err(Error::MiscError(e.to_string())),
146 }
147 }
148
149 pub async fn rename(&self, id: usize, key: String) -> Result<()> {
151 match self
152 .http
153 .post(format!("{}/api/v1/app_data/{id}/key", self.host))
154 .header("Atto-Secret-Key", &self.api_key)
155 .json(&serde_json::Value::Object({
156 let mut map = serde_json::Map::new();
157 map.insert("key".to_string(), serde_json::Value::String(key));
158 map
159 }))
160 .send()
161 .await
162 {
163 Ok(x) => api_return_ok!((), x),
164 Err(e) => Err(Error::MiscError(e.to_string())),
165 }
166 }
167
168 pub async fn remove(&self, id: usize) -> Result<()> {
170 match self
171 .http
172 .delete(format!("{}/api/v1/app_data/{id}", self.host))
173 .header("Atto-Secret-Key", &self.api_key)
174 .send()
175 .await
176 {
177 Ok(x) => api_return_ok!((), x),
178 Err(e) => Err(Error::MiscError(e.to_string())),
179 }
180 }
181
182 pub async fn remove_query(&self, query: &AppDataQuery) -> Result<()> {
184 match self
185 .http
186 .delete(format!("{}/api/v1/app_data/query", self.host))
187 .header("Atto-Secret-Key", &self.api_key)
188 .json(&query)
189 .send()
190 .await
191 {
192 Ok(x) => api_return_ok!((), x),
193 Err(e) => Err(Error::MiscError(e.to_string())),
194 }
195 }
196}
197
198#[derive(Debug, Clone, Default)]
200pub struct ApiClientState {
201 pub user_token: String,
203 pub user_verifier: String,
205 pub user_id: usize,
207 pub app_id: usize,
211}
212
213#[derive(Debug, Clone)]
218pub struct ApiClient {
219 pub http: HttpClient,
221 pub state: ApiClientState,
223 pub host: String,
226}
227
228impl ApiClient {
229 pub fn new(host: Option<String>, state: ApiClientState) -> Self {
231 Self {
232 http: HttpClient::new(),
233 state,
234 host: host.unwrap_or("https://tetratto.com".to_string()),
235 }
236 }
237
238 pub async fn refresh_token(&mut self) -> Result<String> {
240 match self
241 .http
242 .post(format!(
243 "{}/api/v1/auth/user/{}/grants/{}/refresh",
244 self.host, self.state.user_id, self.state.app_id
245 ))
246 .header("X-Cookie", &format!("Atto-Grant={}", self.state.user_token))
247 .json(&serde_json::Value::Object({
248 let mut map = serde_json::Map::new();
249 map.insert(
250 "verifier".to_string(),
251 serde_json::Value::String(self.state.user_verifier.to_owned()),
252 );
253 map
254 }))
255 .send()
256 .await
257 {
258 Ok(x) => {
259 let ret = api_return_ok!(String, x)?;
260 self.state.user_token = ret.clone();
261 Ok(ret)
262 }
263 Err(e) => Err(Error::MiscError(e.to_string())),
264 }
265 }
266
267 pub async fn request<T, B>(
269 &self,
270 route: String,
271 method: Method,
272 body: Option<&B>,
273 ) -> Result<ApiReturn<T>>
274 where
275 T: Serialize + DeserializeOwned,
276 B: Serialize + ?Sized,
277 {
278 if let Some(body) = body {
279 match self
280 .http
281 .request(method, format!("{}/api/v1/auth/{route}", self.host))
282 .header("X-Cookie", &format!("Atto-Grant={}", self.state.user_token))
283 .json(&body)
284 .send()
285 .await
286 {
287 Ok(x) => api_return_ok!(ApiReturn<T>, x),
288 Err(e) => Err(Error::MiscError(e.to_string())),
289 }
290 } else {
291 match self
292 .http
293 .request(method, format!("{}/api/v1/auth/{route}", self.host))
294 .header("X-Cookie", &format!("Atto-Grant={}", self.state.user_token))
295 .send()
296 .await
297 {
298 Ok(x) => api_return_ok!(ApiReturn<T>, x),
299 Err(e) => Err(Error::MiscError(e.to_string())),
300 }
301 }
302 }
303
304 pub async fn request_attachments<T, B>(
311 &self,
312 route: String,
313 attachments: Vec<Vec<u8>>,
314 body: &B,
315 ) -> Result<ApiReturn<T>>
316 where
317 T: Serialize + DeserializeOwned,
318 B: Serialize + ?Sized,
319 {
320 let mut multipart_body = Form::new();
321
322 for v in attachments.clone() {
324 multipart_body = multipart_body.part(String::new(), Part::bytes(v));
326 }
327
328 drop(attachments);
329
330 multipart_body = multipart_body.part(
332 String::new(),
333 Part::text(serde_json::to_string(body).unwrap()),
334 );
335
336 match self
338 .http
339 .post(format!("{}/api/v1/auth/{route}", self.host))
340 .header("X-Cookie", &format!("Atto-Grant={}", self.state.user_token))
341 .multipart(multipart_body)
342 .send()
343 .await
344 {
345 Ok(x) => api_return_ok!(ApiReturn<T>, x),
346 Err(e) => Err(Error::MiscError(e.to_string())),
347 }
348 }
349}