简体   繁体   English

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

[英]Rust: How to read a config file at runtime and store in a global struct, accessible across threads?

This is my first project in Rust, and I think I'm missing something simple.这是我在 Rust 中的第一个项目,我想我错过了一些简单的东西。

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.我正在尝试创建一个简单的 Web API 守护程序,它将接收 JSON 的 POST,解析 JSON,并使用配置文件中提供的凭据发送电子邮件。 90% of that problem has been easy. 90% 的问题都很简单。 I am struggling with "parse the config file at runtime".我正在努力解决“在运行时解析配置文件”。

I'm successfully use hyper and letter to receive JSON and send emails.我成功地使用 hyper 和 letter 来接收 JSON 并发送电子邮件。 But I'd like this daemon to be configurable on the server, not at build-time (like most Linux / Unix daemons).但是我希望这个守护进程可以在服务器上配置,而不是在构建时(像大多数 Linux / Unix 守护进程)。 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.我创建了一个配置模块,声明了一个结构,并使用了lazy_static!{}来存储配置结构的初始版本。

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...特别是考虑到这些值的大小在运行时无法知道的事实......

eg src/config.rs例如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 :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?建议?

Your struct should store String s.你的结构应该存储String s。 String s are mutable and growable -- you can read data from a file into them, unlike &'static str s. String s 是可变的和可增长的——你可以从文件中读取数据到它们中,不像&'static str s。 &'static str s are usually only for constant string literals. &'static str通常仅用于常量字符串文字。 I think using String s should get your example working with minimal tweaks.我认为使用String s 应该让您的示例以最少的调整工作。

Also, you can use std::mem::swap() to write the whole config at once.此外,您可以使用std::mem::swap()一次编写整个配置。 This is also more efficient because it doesn't require cloning strings.这也更有效,因为它不需要克隆字符串。

I think the global static RwLock is reasonable if you want the config to be a global variable.如果您希望配置成为全局变量,我认为全局静态RwLock是合理的。 Alternatively, as in Sahsahae's comment, you could avoid global state and pass an Arc<RimfireCfg> into anything that uses it.或者,如 Sahsahae 的评论中所示,您可以避免全局状态并将Arc<RimfireCfg>传递给使用它的任何内容。 This is often cleaner.这通常更清洁。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在运行时正确创建并读取存储在先前 session 期间保存的配置文件中的属性? - How do I properly create during runtime and read the properties that are stored in the config file that saved during a previous session? 如何在运行时更新配置文件中的assemblyBinding部分? - how to update assemblyBinding section in config file at runtime? 如何在运行时修改配置文件 - How do I modify config file at runtime 如何在应用程序配置文件中存储类对象 - How to store class object in app config file 如何在配置文件中存储整数但将其作为枚举检索? - How to store integer in config file but retrieve it as an enumeration? 如何在web.config中存储特定于应用程序的信息,例如要运行的线程数? - How can I store application specific info in web.config such as number of threads to be run? 在python中读取配置文件 - Read config file in python 如何从配置文件中的相对路径读取文件内容 - How to read file content from the relative path in config file 如何存储配置文件并使用 React 读取它 - How to store Configuration file and read it using React 如何将自定义对象的集合存储到user.config文件? - How to store a collection of custom objects to an user.config file?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM