123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- // This file is licensed under the terms of 0BSD:
- //
- // Permission to use, copy, modify, and/or distribute this software for any purpose with or without
- // fee is hereby granted.
- //
- // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
- // SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
- // AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- // NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
- // OF THIS SOFTWARE.
- use std::sync::OnceLock;
- use std::fs::File;
- use std::io::{self, BufRead};
- use std::path::{Path, PathBuf};
- // Ini-like configuration, with sections.
- // Global config first, then config for each subsection
- // key=value
- //
- // [section]
- // key2=value2
- #[derive(Default, Debug)]
- pub struct Config {
- pub maildir: PathBuf,
- pub email_fmt: String,
- pub title_fmt: String,
- pub base_url: String,
- pub description: String,
- pub include_html: bool,
- pub out_dir: PathBuf,
- pub subsections: Vec<Subsection>,
- pub imap_domain: String,
- pub imap_port: u32,
- pub username: String,
- pub password: String,
- pub api_addr: String,
- pub api_port: u32,
- pub smtp_domain: String,
- pub smtp_port: u32,
- pub sonic_search_addr: String,
- pub sonic_search_port: u32,
- pub sonic_search_password: String,
- }
- impl Config {
- // TODO defaults here
- pub fn match_kv(&mut self, key: &str, value: &str) {
- match key {
- "email_fmt" => self.email_fmt = value.to_string(),
- "title_fmt" => self.title_fmt = value.to_string(),
- "base_url" => self.base_url = value.to_string(),
- "description" => self.description = value.to_string(),
- "imap_domain" => self.imap_domain = value.to_string(),
- "imap_port" => self.imap_port = value.parse().unwrap(),
- "username" => self.username = value.to_string(),
- "password" => self.password = value.to_string(),
- "maildir" => self.maildir = PathBuf::from(value),
- "api_addr" => self.api_addr = value.to_string(),
- "api_port" => self.api_port = value.parse().unwrap(),
- "smtp_domain" => self.smtp_domain = value.to_string(),
- "smtp_port" => self.smtp_port = value.parse().unwrap(),
- "sonic_search_addr" => self.sonic_search_addr = value.to_string(),
- "sonic_search_port" => self.sonic_search_port = value.parse().unwrap(),
- "sonic_search_password" => self.sonic_search_password = value.to_string(),
- _ => {}
- }
- }
- }
- #[derive(Default, Clone, Debug)]
- pub struct Subsection {
- pub name: String, // something
- pub title: String, // something mail archive
- pub email: String,
- pub description: String,
- }
- impl Subsection {
- // TODO defaults here
- fn match_kv(&mut self, key: &str, value: &str) {
- match key {
- "title" => self.title = value.to_string(),
- "email" => self.email = value.to_string(),
- "description" => self.description = value.to_string(),
- _ => {}
- }
- }
- }
- pub static INSTANCE: OnceLock<Config> = OnceLock::new();
- impl Config {
- pub fn global() -> &'static Config {
- INSTANCE.get().expect("Config is not initialized")
- }
- pub fn default_subsection(&self, name: &str) -> Subsection {
- Subsection {
- name: name.to_owned(),
- title: self.title_fmt.replace("%s", name),
- email: self.email_fmt.replace("%s", name),
- description: String::new(),
- }
- }
- pub fn get_subsection(&self, name: &str) -> Option<Subsection> {
- self.subsections
- .iter()
- .find(|sub| sub.name == name)
- .cloned()
- }
- pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Config, std::io::Error> {
- let file = File::open(path)?;
- // let sub_sections = vec![];
- let mut conf = Config::default();
- let mut current_section = None;
- for l in io::BufReader::new(file).lines() {
- let line = l?;
- if line.starts_with('[') && line.ends_with(']') {
- let name = &line[1..line.len() - 1];
- // Defaults from global config
- if let Some(section) = current_section {
- conf.subsections.push(section);
- }
- current_section = Some(conf.default_subsection(name))
- }
- if line.is_empty() {
- continue;
- }
- if let Some(i) = line.find('=') {
- let key = &line[..i];
- let value = &line[i + 1..];
- if let Some(ref mut s) = current_section {
- s.match_kv(key, value);
- } else {
- conf.match_kv(key, value);
- }
- } else {
- // panic!("Invalid config")
- }
- }
- if let Some(section) = current_section {
- conf.subsections.push(section);
- }
- Ok(conf)
- }
- }
|