Crate configory

Source
Expand description

Batteries included application config management.

This crate aims to provide a simple configuration interface while making the implementation of live config file reload and IPC updates trivial.

§Example

To get a configuration which is backed by a file that is automatically reloaded on change, you just need to create a config with Config::new:

use configory::Config;

let config = Config::<()>::new("configory").unwrap();
config.set(&["option"], 3);

assert_eq!(config.get::<_, i32>(&["option"]), Some(3));

This will also automatically spawn an IPC server which allows configuration file access and modification through a socket file. If you want to disable this, you can use Config::with_options.

You can subscribe to the Config::update_rx channel to receive notifications about configuration changes and errors:

use configory::{Config, Event};

let config = Config::<()>::new("configory").unwrap();

while let Ok(event) = config.update_rx().recv() {
    match event {
        // To update your application when a config value changes, you need to handle
        // both `Event::FileChanged` and `Event::IpcChanged`.
        Event::FileChanged | Event::IpcChanged => (),
        // File errors will be dispatched when the user's configuration file is invalid.
        Event::FileError(_err) => (),
        // This will only be called if you send custom IPC messages.
        Event::Ipc(_msg) => (),
        // This will only be called if you send your own events through the config channel.
        Event::User(_data) => (),
    }
}

§IPC client

The client side of the IPC interface is constructed from the socket path, which can be acquired using Config::ipc and Ipc::socket_path.

use configory::Config;
use configory::ipc::Ipc;

// This would typically happen in a separate process.
let config = Config::<()>::new("configory").unwrap();
let socket_path = config.ipc().unwrap().socket_path();

// Set and retrieve a configuration value through the socket.
let ipc = Ipc::client(socket_path);
ipc.set(&["option"], 3).unwrap();
let value = ipc.get::<_, i32>(&["option"]).unwrap();
assert_eq!(value, Some(3));

§Struct Deserialization

If you prefer accessing configuration values through a struct rather than using the dynamic syntax of Config::get, you can deserialize the toplevel value into your struct:

use configory::Config;
use serde::Deserialize;

#[derive(Deserialize, Default, PartialEq, Debug)]
#[serde(default)]
struct MyConfig {
    field: String,
}

let config = Config::<()>::new("configory").unwrap();

// Without configuration file, the default will be empty.
let my_config = config.get::<&str, MyConfig>(&[]);
assert_eq!(my_config, None);

// Once changed wit the path syntax, the field will be uptaded.
config.set(&["field"], "demo");
let my_config = config.get::<&str, MyConfig>(&[]).unwrap();
assert_eq!(my_config.field, String::from("demo"));

Modules§

ipc
IPC config changes.

Structs§

Config
Configuration file manager.
Options
Config monitor options.

Enums§

Error
Configuration errors.
Event
Configuration events.