summaryrefslogtreecommitdiffstats
path: root/src/config.rs
blob: 09ec99771a9e38a7ff7a558457282d667663c56d (plain)
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
use std::net::SocketAddr;

use serde::{Deserialize, Serialize};
use unnamed_server::Error;

#[derive(Debug, Clone)]
pub struct Config {
    pub listen_addr: SocketAddr,
    pub jwt_secret: String,
    pub database_url: String,
}

impl Config {
    pub fn builder() -> ConfigBuilder {
        ConfigBuilder::default()
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConfigBuilder {
    listen_addr: Option<String>,
    jwt_secret: Option<String>,
    database_url: Option<String>,
}

impl ConfigBuilder {
    pub fn file(self) -> Result<Self, Error> {
        let file = std::env::args()
            .nth(1)
            .unwrap_or("/etc/unnamed_server.toml".to_string());

        match std::fs::read_to_string(file) {
            Ok(s) => Ok(self.merge(toml::from_str(&s)?)),
            Err(err) => {
                tracing::warn!("Error reading config file: {err}");
                Ok(self)
            }
        }
    }

    pub fn env(self) -> Self {
        let _ = dotenvy::dotenv();

        self.merge(Self {
            listen_addr: std::env::var("LISTEN_ADDR").ok(),
            jwt_secret: std::env::var("JWT_SECRET").ok(),
            database_url: std::env::var("DATABASE_URL").ok(),
        })
    }

    /// Merge self with other, overwriting any existing values on self with other's.
    fn merge(self, other: Self) -> Self {
        Self {
            listen_addr: other.listen_addr.or(self.listen_addr),
            jwt_secret: other.jwt_secret.or(self.jwt_secret),
            database_url: other.database_url.or(self.database_url),
        }
    }

    pub fn build(self) -> Result<Config, Error> {
        Ok(Config {
            listen_addr: self
                .listen_addr
                .and_then(|s| s.parse().ok())
                .ok_or_else(|| Error::Config("listen_addr".to_string()))?,
            jwt_secret: self
                .jwt_secret
                .ok_or_else(|| Error::Config("jwt_secret".to_string()))?,
            database_url: self
                .database_url
                .ok_or_else(|| Error::Config("database_url".to_string()))?,
        })
    }
}

impl Default for ConfigBuilder {
    fn default() -> Self {
        Self {
            listen_addr: Some("127.0.0.1:30000".to_string()),
            jwt_secret: None,
            database_url: None,
        }
    }
}