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
use std::env::{current_dir, current_exe};
use std::fs::{read_to_string, write};
use std::path::PathBuf;

use serde::{Deserialize, Serialize};

/// The application config struct
/// Contains all configuration properties available in the application itself
/// Reads its values automatically inside the constructor
/// Creates the config file if not existed
/// Will search for the given file/path inside the current working directory or in `/etc/new-home-core`
#[derive(Serialize, Deserialize)]
pub struct ApplicationConfig {
    /// The address/interface on which the web server will listen
    #[serde(default = "ApplicationConfig::default_server_address")]
    pub server_address: String,

    /// The port on which the web server will listen
    #[serde(default = "ApplicationConfig::default_server_port")]
    pub server_port: u16,
}

impl ApplicationConfig {
    /// Reads the given file and creates a new `ApplicationConfig` instance
    /// Creates the config file if it not exists
    pub fn new(filename: String) -> Self {
        let application_name = Self::get_application_name(String::from("new-home-core"));
        let working_directory = Self::get_working_directory(
            String::from("/etc"),
            application_name,
        );
        let config_path = format!("{}/{}", working_directory, filename);
        let file_content = Self::get_file_content_or_empty(config_path);

        serde_yaml::from_str(&file_content).unwrap()
    }

    /// Returns the application name from the `current_exe` function or returns the given default application name
    fn get_application_name(default_application_name: String) -> String {
        let current_exe = current_exe().unwrap_or(PathBuf::from(&default_application_name));

        current_exe.into_os_string().into_string().unwrap_or(default_application_name)
    }

    /// Returns the current working directory from `current_dir` function or will return the default
    /// working directory with the appended `application_name`
    fn get_working_directory(default_working_dir: String, application_name: String) -> String {
        let config_dir = current_dir()
            .unwrap_or(PathBuf::from(format!(
                "{}/{}",
                &default_working_dir,
                &application_name
            )));

        config_dir.into_os_string().into_string().unwrap_or(format!(
            "{}/{}",
            &default_working_dir,
            &application_name,
        ))
    }

    /// Reads from the given file path and returns the config
    /// If the file is not found, it will be created from the default config and the function will
    /// return the YAML-fied default config
    fn get_file_content_or_empty(config_path: String) -> String {
        match read_to_string(&config_path) {
            Err(error) => {
                println!("Could not read config from {}: {}", &config_path, error);

                let config_as_string = serde_yaml::to_string(
                    &Self::default_config()
                ).unwrap_or(String::new());

                Self::write_config(&config_path, &config_as_string);

                config_as_string
            }
            Ok(content) => content
        }
    }

    /// Writes the given file content into the given config file
    fn write_config(config_path: &String, file_content: &String) {
        match write(config_path, file_content) {
            Err(error) => {
                println!("Could not write default config: {}", error)
            }
            _ => {}
        };
    }

    /// Returns `Self` with default values
    fn default_config() -> Self {
        Self {
            server_address: Self::default_server_address(),
            server_port: Self::default_server_port(),
        }
    }

    /// Returns the default value for the `server_address` field
    fn default_server_address() -> String {
        return String::from("[::]");
    }

    /// Returns the default value for the `server_port` field
    fn default_server_port() -> u16 {
        return 5354;
    }
}