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
// Copyright 2022 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use rand::{
    distributions::{Alphanumeric, DistString},
    Rng,
};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
use url::Url;

use super::ConfigurationSection;

fn default_homeserver() -> String {
    "localhost:8008".to_owned()
}

fn default_endpoint() -> Url {
    Url::parse("http://localhost:8008/").unwrap()
}

/// Configuration related to the Matrix homeserver
#[serde_as]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct MatrixConfig {
    /// The server name of the homeserver.
    #[serde(default = "default_homeserver")]
    pub homeserver: String,

    /// Shared secret to use for calls to the admin API
    pub secret: String,

    /// The base URL of the homeserver's client API
    #[serde(default = "default_endpoint")]
    pub endpoint: Url,
}

impl ConfigurationSection for MatrixConfig {
    const PATH: Option<&'static str> = Some("matrix");
}

impl MatrixConfig {
    pub(crate) fn generate<R>(mut rng: R) -> Self
    where
        R: Rng + Send,
    {
        Self {
            homeserver: default_homeserver(),
            secret: Alphanumeric.sample_string(&mut rng, 32),
            endpoint: default_endpoint(),
        }
    }

    pub(crate) fn test() -> Self {
        Self {
            homeserver: default_homeserver(),
            secret: "test".to_owned(),
            endpoint: default_endpoint(),
        }
    }
}

#[cfg(test)]
mod tests {
    use figment::{
        providers::{Format, Yaml},
        Figment, Jail,
    };

    use super::*;

    #[test]
    fn load_config() {
        Jail::expect_with(|jail| {
            jail.create_file(
                "config.yaml",
                r"
                    matrix:
                      homeserver: matrix.org
                      secret: test
                ",
            )?;

            let config = Figment::new()
                .merge(Yaml::file("config.yaml"))
                .extract_inner::<MatrixConfig>("matrix")?;

            assert_eq!(&config.homeserver, "matrix.org");
            assert_eq!(&config.secret, "test");

            Ok(())
        });
    }
}