Rust:如何在运行时读取配置文件并将其存储在全局结构中,以便跨线程访问?

7 configuration runtime lifetime ownership rust

这是我在 Rust 中的第一个项目,我认为我错过了一些简单的东西。

我正在尝试创建一个简单的 Web API 守护程序,它将接收 JSON 的 POST、解析 JSON,并使用配置文件中提供的凭据发送电子邮件。90% 的问题都很简单。我正在努力解决“在运行时解析配置文件”的问题。

我成功地使用 hyper 和 letter 接收 JSON 并发送电子邮件。但我希望这个守护进程可以在服务器上配置,而不是在构建时配置(像大多数 Linux / Unix 守护进程一样)。我一直孜孜不倦地走过这里

我创建了一个配置模块,声明了一个结构,并用于lazy_static!{}存储配置结构的初始版本。

我想我已经将问题归结为一个核心问题:如何读取和解析配置文件,然后将值克隆到我的结构中?特别是考虑到这些值的大小在运行时无法得知......

例如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
    }
}
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

有什么想法吗?建议?

Spf*_*cal 0

你的结构应该存储Strings。Strings 是可变且可增长的——与 s 不同,您可以将文件中的数据读入其中&'static str&'static strs 通常仅适用于常量字符串文字。我认为使用Strings 应该可以让您的示例以最小的调整工作。

此外,您可以用来std::mem::swap()一次编写整个配置。这也更有效,因为它不需要克隆字符串。

RwLock我认为如果您希望配置成为全局变量,则全局静态是合理的。或者,正如 Sahsahae 的评论中那样,您可以避免全局状态并将 an 传递Arc<RimfireCfg>给任何使用它的东西。这通常更干净。