nekoweb_rs/
lib.rs

1/*
2 * Copyright (c) 2026 Choi Madeleine
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16 */
17
18use reqwest::{Response, header::AUTHORIZATION, multipart::Form};
19use serde::Serialize;
20
21pub mod file;
22pub mod site;
23
24pub struct Unauthenticated;
25pub struct Authenticated {
26    token: String,
27}
28
29#[derive(Debug, Clone)]
30pub struct Client<S> {
31    base_url: String,
32    http: reqwest::Client,
33    state: S,
34}
35
36impl Client<Unauthenticated> {
37    pub fn new(user_agent: &str) -> anyhow::Result<Self> {
38        Ok(Self {
39            base_url: "https://nekoweb.org/api".into(),
40            http: reqwest::Client::builder().user_agent(user_agent).build()?,
41            state: Unauthenticated,
42        })
43    }
44
45    pub fn authenticate(self, token: String) -> Client<Authenticated> {
46        Client {
47            state: Authenticated { token },
48            base_url: self.base_url,
49            http: self.http,
50        }
51    }
52
53    async fn get(&self, path: impl Into<String>) -> anyhow::Result<Response> {
54        Ok(self
55            .http
56            .get(format!("{}{}", &self.base_url, path.into()))
57            .send()
58            .await?
59            .error_for_status()?)
60    }
61}
62
63impl Client<Authenticated> {
64    async fn post<T>(&self, path: impl Into<String>, body: &T) -> anyhow::Result<Response>
65    where
66        T: Serialize,
67    {
68        Ok(self
69            .http
70            .post(format!("{}{}", &self.base_url, path.into()))
71            .header(AUTHORIZATION, &self.state.token)
72            .form(body)
73            .send()
74            .await?
75            .error_for_status()?)
76    }
77
78    async fn multipart(&self, path: impl Into<String>, form: Form) -> anyhow::Result<Response> {
79        Ok(self
80            .http
81            .post(format!("{}{}", &self.base_url, path.into()))
82            .header(AUTHORIZATION, &self.state.token)
83            .multipart(form)
84            .send()
85            .await?
86            .error_for_status()?)
87    }
88
89    async fn get(&self, path: impl Into<String>) -> anyhow::Result<Response> {
90        Ok(self
91            .http
92            .get(format!("{}{}", &self.base_url, path.into()))
93            .header(AUTHORIZATION, &self.state.token)
94            .send()
95            .await?
96            .error_for_status()?)
97    }
98}