Skip to main content

shinden_pl_api/
client.rs

1use crate::headers::{get_headers_for_type, RequestType};
2use anyhow::{Context, Result};
3use cookie_store::serde;
4use cookie_store::CookieStore;
5use reqwest::Client;
6use reqwest_cookie_store::CookieStoreMutex;
7use std::fs::{create_dir_all, File};
8use std::io::{BufReader, BufWriter};
9use std::path::PathBuf;
10use std::sync::Arc;
11
12#[derive(Clone)]
13
14pub struct ShindenAPI {
15    pub client: Client,
16    jar: Arc<CookieStoreMutex>,
17    cookie_path: PathBuf,
18}
19
20impl ShindenAPI {
21    pub fn new() -> Result<Self> {
22        let mut cookie_path =
23            dirs::data_local_dir().context("Could not find user local data directory")?;
24        cookie_path.push("shinden_api");
25        create_dir_all(&cookie_path)?;
26        cookie_path.push("cookies.json");
27
28        let store = load_cookies(&cookie_path)?;
29        let jar = Arc::new(CookieStoreMutex::new(store));
30
31        let client = Client::builder()
32            .cookie_provider(jar.clone())
33            .redirect(reqwest::redirect::Policy::default())
34            .gzip(true)
35            .deflate(true)
36            .brotli(true)
37            .build()?;
38
39        Ok(Self {
40            client,
41            jar,
42            cookie_path,
43        })
44    }
45
46    pub async fn get_html(&self, url: &str) -> Result<String> {
47        let headers = get_headers_for_type(RequestType::Frontend, Some(url))?;
48        let response = self.client.get(url)
49            .headers(headers)
50            .send()
51            .await?
52            .error_for_status()?;
53
54        let body = response.text().await?;
55
56        save_cookies(&self.jar.lock().unwrap(), &self.cookie_path)?;
57        Ok(body)
58    }
59
60    pub async fn post_form(&self, url: &str, form: &[(String, String)], custom_headers: Option<reqwest::header::HeaderMap>) -> Result<String> {
61        let mut headers = get_headers_for_type(RequestType::Login, Some(url))?;
62
63        if let Some(ch) = custom_headers {
64            headers.extend(ch);
65        }
66
67        let response = self.client.post(url)
68            .form(form)
69            .headers(headers)
70            .send()
71            .await?
72            .error_for_status()?;
73
74        let body = response.text().await?;
75        save_cookies(&self.jar.lock().unwrap(), &self.cookie_path)?;
76        Ok(body)
77    }
78}
79
80fn load_cookies(path: &std::path::Path) -> Result<CookieStore> {
81    if path.exists() {
82        let file = File::open(path)?;
83        let reader = BufReader::new(file);
84        serde::json::load(reader).map_err(|e| anyhow::anyhow!(e.to_string()))
85    } else {
86        Ok(CookieStore::default())
87    }
88}
89
90fn save_cookies(store: &CookieStore, path: &std::path::Path) -> Result<()> {
91    let file = File::create(path)?;
92    let mut writer = BufWriter::new(file);
93
94    serde::json::save(store, &mut writer).map_err(|e| anyhow::anyhow!(e.to_string()))?;
95
96    Ok(())
97}