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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use serde::{Deserialize, Serialize};
use std::{
    fs,
    io::{Read, Write},
};

#[derive(Serialize, Deserialize, Clone)]
pub struct IdentityConfig {
    pub nickname: Option<String>,
    pub identity: String,
    pub email: Option<String>,
    pub token: String,
}

#[derive(Deserialize)]
pub struct RawConfig {
    host: Option<String>,
    default_identity: Option<String>,
    identity_configs: Option<Vec<IdentityConfig>>,
}

#[derive(Serialize)]
pub struct Config {
    pub host: String,
    pub default_identity: Option<String>,
    pub identity_configs: Vec<IdentityConfig>,
}

const CONFIG_DIR: &str = ".spacetime";
const CONFIG_FILENAME: &str = "config.toml";

impl Config {
    pub fn load() -> Self {
        let home_dir = dirs::home_dir().unwrap();
        let config_dir = home_dir.join(CONFIG_DIR);
        if !config_dir.exists() {
            fs::create_dir_all(&config_dir).unwrap();
        }

        let config_path = config_dir.join(CONFIG_FILENAME);
        let mut file = fs::OpenOptions::new()
            .create(true)
            .write(true)
            .read(true)
            .open(config_path)
            .unwrap();

        let mut text = String::new();
        file.read_to_string(&mut text).unwrap();
        let config: RawConfig = toml::from_str(&text).unwrap();

        Self::from_raw(config)
    }

    fn from_raw(raw: RawConfig) -> Self {
        Self {
            identity_configs: raw.identity_configs.unwrap_or(Vec::new()),
            host: raw.host.unwrap_or("spacetime.spacetimedb.net:3000".into()),
            default_identity: raw.default_identity,
        }
    }

    pub fn save(&self) {
        let home_dir = dirs::home_dir().unwrap();
        let config_dir = home_dir.join(CONFIG_DIR);
        if !config_dir.exists() {
            fs::create_dir_all(&config_dir).unwrap();
        }

        let config_path = config_dir.join(CONFIG_FILENAME);
        let mut file = fs::OpenOptions::new()
            .create(true)
            .write(true)
            .open(config_path)
            .unwrap();

        let str = toml::to_string_pretty(self).unwrap();

        file.set_len(0).unwrap();
        file.write_all(str.as_bytes()).unwrap();
        file.sync_all().unwrap();
    }

    pub fn get_default_identity_config(&self) -> Option<&IdentityConfig> {
        if let Some(identity) = &self.default_identity {
            let config = self.identity_configs.iter().find(|c| &c.identity == identity).unwrap();
            Some(config)
        } else {
            None
        }
    }

    pub fn name_exists(&self, nickname: &str) -> bool {
        for name in self.identity_configs.iter().map(|c| &c.nickname) {
            if name.as_ref() == Some(&nickname.to_string()) {
                return true;
            }
        }
        return false;
    }

    pub fn get_identity_config_by_name(&self, name: &str) -> Option<&IdentityConfig> {
        self.identity_configs
            .iter()
            .find(|c| c.nickname.as_ref() == Some(&name.to_string()))
    }

    pub fn get_identity_config_by_identity(&self, identity: &str) -> Option<&IdentityConfig> {
        self.identity_configs.iter().find(|c| &c.identity == identity)
    }

    pub fn get_identity_config_by_identity_mut(&mut self, identity: &str) -> Option<&mut IdentityConfig> {
        self.identity_configs.iter_mut().find(|c| &c.identity == identity)
    }

    pub fn update_default_identity(&mut self) {
        if let Some(default_identity) = &self.default_identity {
            if self
                .identity_configs
                .iter()
                .map(|c| &c.identity)
                .any(|i| i == default_identity)
            {
                return;
            }
        }
        self.default_identity = self.identity_configs.first().map(|c| c.identity.clone())
    }
}