This is my first project in Rust, and I think I'm missing something simple.
I'm attempting to create a simple Web API daemon that will receive POSTs of JSON, parse the JSON, and send an email using credentials provided in a config file. 90% of that problem has been easy. I am struggling with "parse the config file at runtime".
I'm successfully use hyper and letter to receive JSON and send emails. But I'd like this daemon to be configurable on the server, not at build-time (like most Linux / Unix daemons). I've diligently followed through here.
I've created a config module, declared a struct, and used lazy_static!{}
to store an initial version of the configuration struct.
I think I've boiled my problem down to one core question: How do I read and parse a config file, then clone the values into my struct? Especially considering the fact that the size of those values can't be known at runtime...
e.g. src/config.rs
use std::sync::RwLock;
use serde::Deserialize;
use std::fs;
use std::io::prelude::*;
#[derive(Debug, Deserialize, Clone, Copy)]
pub struct RimfireCfg {
pub verbose: u8,
/* web api server config */
pub listen_address: &'static str,
/* mail server config */
pub mailserver: &'static str,
pub port: u16,
pub user: &'static str,
pub password: &'static str,
}
lazy_static! {
pub static ref CONFIG: RwLock<RimfireCfg> = RwLock::new(
RimfireCfg {
verbose: 0,
listen_address: "127.0.0.1:3000",
mailserver: "smtp-mail.outlook.com",
port: 587,
user: "",
password: "",
}
);
}
impl RimfireCfg {
pub fn init() -> Result<(), i32> {
let mut w = CONFIG.write().unwrap();
/* read the config file */
let _lcfg: RimfireCfg =
toml::from_slice(&fs::read("rimfire.toml").unwrap()).unwrap();
// this is clearly wrong ...
*w.listen_address = _lcfg.listen_address.clone();
dbg!(*w);
Ok(())
}
pub fn clone_config() -> RimfireCfg {
let m = CONFIG.read().unwrap();
*m
}
}
and src/main.rs
:
#[macro_use]
extern crate lazy_static;
mod config;
use config::RimfireCfg;
fn main() {
let a = RimfireCfg::clone_config();
dbg!(a);
RimfireCfg::init().unwrap();
let a = RimfireCfg::clone_config();
dbg!(a);
}
Any thoughts? suggestions?
toml
crate to do it for you. I see you already use serde, andtoml
depends on it :) Since you seem to write to it only once, there's no reason not to constructArc<Config>
in main and share it immutably without any locks by cloning just theArc
. – Horned