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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use std::fs::File;
use std::path::Path;

use reqwest::Proxy;
use serde::Deserialize;

#[derive(Debug, Clone, Deserialize)]
#[serde(untagged)]
pub enum Authentication {
    EmailPassword { email: String, password: String },
    AccessToken { access_token: String },
    SessionToken { session_token: String },
}

#[derive(Debug, Clone, Deserialize)]
pub struct Config {
    #[serde(default)]
    #[serde(deserialize_with = "deserialize_proxy")]
    pub proxy: Option<Proxy>,
    #[serde(flatten)]
    pub authentication: Authentication,
    #[serde(default)]
    pub paid: bool,
    #[serde(default)]
    pub conversation_id: Option<String>,
}

fn deserialize_proxy<'de, D>(deserializer: D) -> Result<Option<Proxy>, D::Error>
where
    D: serde::Deserializer<'de>,
{
    let s: Option<String> = Option::deserialize(deserializer)?;
    Ok(s.map(|s| Proxy::all(s).unwrap()))
}

impl Config {
    pub fn from_file(filepath: &Path) -> Self {
        // Loading config from file + emoji
        log::info!("📄 Loading config from file {filepath:?} ");

        // Open file
        let f = File::open(filepath).unwrap();

        // Deserialize config file
        let config: Self = serde_json::from_reader(f).unwrap();

        config
    }

    pub fn with_session_token(mut self, session_token: String) -> Self {
        self.authentication = Authentication::SessionToken { session_token };
        self
    }

    pub fn with_access_token(mut self, access_token: String) -> Self {
        self.authentication = Authentication::AccessToken { access_token };
        self
    }

    pub fn with_email_password(mut self, email: String, password: String) -> Self {
        self.authentication = Authentication::EmailPassword { email, password };
        self
    }

    pub fn with_paid(mut self, paid: bool) -> Self {
        self.paid = paid;
        self
    }

    pub fn with_conversation_id(mut self, conversation_id: String) -> Self {
        self.conversation_id = Some(conversation_id);
        self
    }

    pub fn with_proxy(mut self, proxy: Proxy) -> Self {
        self.proxy = Some(proxy);
        self
    }
}

impl Default for Config {
    fn default() -> Self {
        Self {
            proxy: None,
            authentication: Authentication::AccessToken {
                access_token: String::new(),
            },
            paid: false,
            conversation_id: None,
        }
    }
}