1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
use std::str::FromStr;

use decrypt_cookies::{get_cookie, Browser, LeetCodeCookies};
use lcode_config::global::G_USER_CONFIG;
use miette::{IntoDiagnostic, Result};
use reqwest::header::{HeaderMap, HeaderName, HeaderValue};
use strum::IntoEnumIterator;

/// headers for `LeetCode` reqwest
///
/// * `headers`: headers for reqwest
#[derive(Debug)]
#[derive(Default)]
#[derive(Clone)]
#[derive(PartialEq, Eq)]
pub struct Headers {
    pub headers: HeaderMap,
}

impl Headers {
    pub async fn build_default() -> Result<Self> {
        let host = format!("{}.{}", "leetcode", G_USER_CONFIG.config.url_suffix);
        Self::build(&host).await
    }
    pub async fn build(host: &str) -> Result<Self> {
        let default_headers = HeaderMap::new();
        let mut cookies = G_USER_CONFIG.cookies.clone();

        if !cookies.is_completion() {
            let browser = Browser::from_str(G_USER_CONFIG.config.browser.as_str())
                .into_diagnostic()
                .unwrap_or_default();
            cookies = get_cookie(browser, host)
                .await
                .unwrap_or_else(|err| {
                    tracing::warn!("{err}");
                    LeetCodeCookies::default()
                });
        }

        if !cookies.is_completion() {
            for browser in Browser::iter() {
                let pat = get_cookie(browser, host)
                    .await
                    .unwrap_or_default();
                if pat.is_completion() {
                    cookies = pat;
                    break;
                }
            }
        }

        let cookie = cookies.to_string();

        let kv_vec: Vec<(&str, &str)> = vec![
            ("cookie", &cookie),
            ("x-csrftoken", &cookies.csrf),
            ("origin", &G_USER_CONFIG.urls.origin),
        ];
        let default_headers = Self::mod_headers(default_headers, kv_vec)?;

        Ok(Self { headers: default_headers })
    }

    /// new or modify headers
    ///
    /// * `headers`: be modified headers
    /// * `kv_vec`: added content
    pub fn mod_headers(mut headers: HeaderMap, kv_vec: Vec<(&str, &str)>) -> Result<HeaderMap> {
        for (k, v) in kv_vec {
            let name = HeaderName::from_str(k).into_diagnostic()?;
            let value = HeaderValue::from_str(v).into_diagnostic()?;

            headers.insert(name, value);
        }
        Ok(headers)
    }
}