coa_website/
config.rs

1use std::{collections::HashMap, fs, str::FromStr};
2
3use serde::Deserialize;
4
5#[derive(Debug, Deserialize)]
6pub struct Config {
7    /// Root folder of the static resources to serve
8    pub root_folder: String,
9    /// Log file path
10    pub log_file: String,
11    /// Name of the index file
12    pub index_file: String,
13    /// File to serve as 404 error content page
14    pub not_found_file: String,
15    /// Supported mime types with their corresponding file extensions
16    pub mime_types: HashMap<String, String>,
17}
18
19impl Default for Config {
20    fn default() -> Self {
21        Self { 
22            root_folder: "public".to_string(), 
23            log_file: "logs.log".to_string(), 
24            index_file: "index.html".to_string(), 
25            not_found_file: "404.html".to_string(), 
26            mime_types: [("html".into(), "text/html".into())].into_iter().collect()
27        }
28    }
29}
30
31impl FromStr for Config {
32    type Err = String;
33
34    /// Crates a Config from a string
35    fn from_str(s: &str) -> Result<Self, String> {
36        toml::from_str(s).map_err(|e| format!("Failed to parse TOML: {e}"))
37    }
38}
39
40impl Config {
41    /// Loads a Config from a TOML file at the given path
42    pub fn from_file(path: &str) -> Result<Self, String> {
43        let content = fs::read_to_string(path).map_err(|e| format!("Failed to read config: {e}"))?;
44        content.parse::<Config>()
45    }
46
47    /// Gets the MIME type for a file extension, or returns a default
48    pub fn mime_type(&self, extension: &str) -> &str {
49        self.mime_types
50            .get(extension)
51            .map(|s| s.as_str())
52            .unwrap_or("text/plain")
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59
60    #[test]
61    fn test_load_config() {
62        let toml = r#"
63            root_folder = "./public"
64            index_file = "index.html"
65            not_found_file = "404.html"
66            log_file = "logs.log"
67
68            [mime_types]
69            html = "text/html"
70        "#;
71
72        let config = Config::from_str(toml).unwrap();
73        assert_eq!(config.root_folder, "./public");
74        assert_eq!(config.index_file, "index.html");
75        assert_eq!(config.not_found_file, "404.html");
76        assert_eq!(config.log_file, "logs.log");
77        assert_eq!(config.mime_type("html"), "text/html");
78        assert_eq!(config.mime_type("txt"), "text/plain");
79    }
80
81    #[test]
82    fn test_default_config() {
83        let config = Config::default();
84        assert_eq!(config.root_folder, "public");
85        assert_eq!(config.index_file, "index.html");
86        assert_eq!(config.not_found_file, "404.html");
87        assert_eq!(config.log_file, "logs.log");
88        assert_eq!(config.mime_type("html"), "text/html");
89    }
90}