1
//! The top level configuration `server`.
2

            
3
use std::env;
4

            
5
use clap::{builder::RangedU64ValueParser, Arg, ArgMatches, Command};
6
use serde::Deserialize;
7

            
8
/// Server configuration object.
9
#[derive(Default, Deserialize)]
10
pub struct Config {
11
    /// HTTP port.
12
    ///
13
    /// Default is `1080`.
14
    #[serde(rename = "httpPort")]
15
    pub http_port: Option<u16>,
16
    /// HTTPS port.
17
    ///
18
    /// Default is `1443`.
19
    #[serde(rename = "httpsPort")]
20
    pub https_port: Option<u16>,
21
    /// HTTPS CA certificate file path.
22
    #[serde(rename = "cacertFile")]
23
    pub cacert_file: Option<String>,
24
    /// HTTPS certificate file path. Missing this to disable HTTPS.
25
    #[serde(rename = "certFile")]
26
    pub cert_file: Option<String>,
27
    /// HTTPS private key file path. Missing this to disable HTTPS.
28
    #[serde(rename = "keyFile")]
29
    pub key_file: Option<String>,
30
    /// Static file path.
31
    #[serde(rename = "staticPath")]
32
    pub static_path: Option<String>,
33
}
34

            
35
pub const DEF_HTTP_PORT: u16 = 1080;
36
pub const DEF_HTTPS_PORT: u16 = 1443;
37

            
38
/// To register Clap arguments.
39
5
pub fn reg_args(cmd: Command) -> Command {
40
5
    cmd.arg(
41
5
        Arg::new("server.httpport")
42
5
            .long("server.httpport")
43
5
            .help("HTTP port")
44
5
            .num_args(1)
45
5
            .value_parser(RangedU64ValueParser::<u64>::new().range(1..=65535)),
46
5
    )
47
5
    .arg(
48
5
        Arg::new("server.httpsport")
49
5
            .long("server.httpsport")
50
5
            .help("HTTPS port")
51
5
            .num_args(1)
52
5
            .value_parser(RangedU64ValueParser::<u64>::new().range(1..=65535)),
53
5
    )
54
5
    .arg(
55
5
        Arg::new("server.cacertfile")
56
5
            .long("server.cacertfile")
57
5
            .help("HTTPS CA certificate file")
58
5
            .num_args(1),
59
5
    )
60
5
    .arg(
61
5
        Arg::new("server.certfile")
62
5
            .long("server.certfile")
63
5
            .help("HTTPS certificate file")
64
5
            .num_args(1),
65
5
    )
66
5
    .arg(
67
5
        Arg::new("server.keyfile")
68
5
            .long("server.keyfile")
69
5
            .help("HTTPS private key file")
70
5
            .num_args(1),
71
5
    )
72
5
    .arg(
73
5
        Arg::new("server.static")
74
5
            .long("server.static")
75
5
            .help("Static files directory path")
76
5
            .num_args(1),
77
5
    )
78
5
}
79

            
80
/// To read input arguments from command-line arguments and environment variables.
81
///
82
/// This function will call [`apply_default()`] to fill missing values so you do not need call it
83
/// again.
84
4
pub fn read_args(args: &ArgMatches) -> Config {
85
4
    apply_default(&Config {
86
4
        http_port: match args.get_one::<u64>("server.httpport") {
87
2
            None => match env::var("SERVER_HTTP_PORT") {
88
1
                Err(_) => Some(DEF_HTTP_PORT),
89
1
                Ok(v) => match v.parse::<u16>() {
90
                    Err(_) => Some(DEF_HTTP_PORT),
91
1
                    Ok(v) => Some(v),
92
                },
93
            },
94
2
            Some(v) => Some(*v as u16),
95
        },
96
4
        https_port: match args.get_one::<u64>("server.httpsport") {
97
2
            None => match env::var("SERVER_HTTPS_PORT") {
98
1
                Err(_) => Some(DEF_HTTPS_PORT),
99
1
                Ok(v) => match v.parse::<u16>() {
100
                    Err(_) => Some(DEF_HTTPS_PORT),
101
1
                    Ok(v) => Some(v),
102
                },
103
            },
104
2
            Some(v) => Some(*v as u16),
105
        },
106
4
        cacert_file: match args.get_one::<String>("server.cacertfile") {
107
2
            None => match env::var("SERVER_CACERT_FILE") {
108
1
                Err(_) => None,
109
1
                Ok(v) => Some(v),
110
            },
111
2
            Some(v) => Some(v.clone()),
112
        },
113
4
        cert_file: match args.get_one::<String>("server.certfile") {
114
2
            None => match env::var("SERVER_CERT_FILE") {
115
1
                Err(_) => None,
116
1
                Ok(v) => Some(v),
117
            },
118
2
            Some(v) => Some(v.clone()),
119
        },
120
4
        key_file: match args.get_one::<String>("server.keyfile") {
121
2
            None => match env::var("SERVER_KEY_FILE") {
122
1
                Err(_) => None,
123
1
                Ok(v) => Some(v),
124
            },
125
2
            Some(v) => Some(v.clone()),
126
        },
127
4
        static_path: match args.get_one::<String>("server.static") {
128
2
            None => match env::var("SERVER_STATIC_PATH") {
129
1
                Err(_) => None,
130
1
                Ok(v) => Some(v),
131
            },
132
2
            Some(v) => Some(v.clone()),
133
        },
134
    })
135
4
}
136

            
137
/// Fill missing configuration with default values.
138
6
pub fn apply_default(config: &Config) -> Config {
139
6
    Config {
140
6
        http_port: match config.http_port {
141
1
            None => Some(DEF_HTTP_PORT),
142
5
            Some(v) => Some(v),
143
        },
144
6
        https_port: match config.https_port {
145
1
            None => Some(DEF_HTTPS_PORT),
146
5
            Some(v) => Some(v),
147
        },
148
6
        cacert_file: match config.cacert_file.as_ref() {
149
2
            None => None,
150
4
            Some(v) => Some(v.clone()),
151
        },
152
6
        cert_file: match config.cert_file.as_ref() {
153
2
            None => None,
154
4
            Some(v) => Some(v.clone()),
155
        },
156
6
        key_file: match config.key_file.as_ref() {
157
2
            None => None,
158
4
            Some(v) => Some(v.clone()),
159
        },
160
6
        static_path: match config.static_path.as_ref() {
161
2
            None => None,
162
4
            Some(v) => Some(v.clone()),
163
        },
164
    }
165
6
}