Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Тема
Описание
Доп.

упрощает создание и использование структур конфигурации с иерархической типизацией 12-факторным способом.

Config позволяет вам установить набор параметров по умолчанию, а затем расширить их путем объединения в конфигурации из различных источников:

  • Переменные среды
  • Другой экземпляр конфигурации
  • Удаленная настройка: etcd, Consul
  • Файлы: JSON, YAML, TOML, HJSON
  • Ручное, программное переопределение (с помощью .set метода в экземпляре Config)

Дополнительно Config поддерживает:

  • Просмотр и перечитывание файлов конфигурации в реальном времени
  • Глубокий доступ к объединенной конфигурации через синтаксис пути
  • Десериализация через serde конфигурацию или любое подмножество, определенное через путь
[dependencies]
config = "0.9"
ini - Добавляет поддержку для чтения файлов INI
json - Добавляет поддержку для чтения файлов JSON
hjson - Добавляет поддержку для чтения файлов HJSON
yaml - Добавляет поддержку для чтения файлов YAML
toml - Добавляет поддержку для чтения файлов TOML (по умолчанию включена)

Многоуровневая система конфигурации для приложений Rust (с сильной поддержкой 12-факторных приложений).

  • Установка значений по умолчанию
  • Установите явные значения (для программного переопределения)
  • Чтение из JSON, TOML, YAML, HJSON, INI - файлов
  • Чтение из среды

Неверно введенный тип - значения конфигурации могут считываться любым поддерживаемым типом, если существует разумное преобразование.

Доступ к вложенным полям с использованием форматированного пути. Использует подмножество JSONPath; в настоящее время поддерживает дочерние (redis.port) и индексированные операторы (databases[0].name)

Приложение двенадцати факторов( III. Конфигурация )

12factor.net/config

Другим подходом к конфигурации является использование конфигурационных файлов, которые не сохраняются в систему контроля версия, например ‘config/database.yml’ в Rails. Это огромное улучшение перед использованием констант, которые сохраняются в коде, но по-прежнему и у этого метода есть недостатки: легко по ошибке сохранить конфигурационный файл в репозиторий; существует тенденция когда конфигурационные файлы разбросаны в разных местах и в разных форматах, из за этого становится трудно просматривать и управлять всеми настройками в одном месте. Кроме того форматы этих файлов, как правило, специфичны для конкретного языка или фреймворка.

Приложение двенадцати факторов хранит конфигурацию в переменных окружения (часто сокращается до env vars или env). Переменные окружения легко изменить между развёртываниями, не изменяя код; в отличие от файлов конфигурации, менее вероятно случайно сохранить их в репозиторий кода; и в отличие от пользовательских конфигурационных файлов или других механизмов конфигурации.

В приложении двенадцати факторов переменные окружения являются не связанными между собой средствами управления, где каждая переменная окружения полностью независима от других. Они никогда не группируются вместе в “окружения”, а вместо этого управляются независимо для каждого развёртывания. Эта модель которая масштабируется постепенно вместе с естественным появлением большего количества развёртываний приложения за время его жизни.

File Cargo.toml:

dotenv = "0.15"
config = "0.14"
once_cell = "1.10"
serde = { version = "1.0", features = ["derive"] }

File .dev.env:

RUST_LOG=trace #debug
NO_COLOR=1 # Do not output ANSI escape codes
APP_CLIENT_AI_MOCK=true

File config/dev.toml

[open_ai]
key="mock"
model="davinci-002"

File settings.rs:

use config::{Config, Environment};
use serde::Deserialize;
use once_cell::sync::Lazy;
use std::env;
#[derive(Debug, Deserialize)]
pub struct SettingsClientOpenAI {
    pub model: String,
    pub key: String,
}
#[derive(Debug, Deserialize)]
pub struct Settings {
    client_ai_mock: bool,
    open_ai: SettingsClientOpenAI,
}
static CONFIG: Lazy<Settings> = Lazy::new(|| {
    Settings::new().unwrap()
});
impl Settings {
    pub fn global_init(){
        let _ = &*CONFIG;
    }
    fn new() -> Result<Self, config::ConfigError> {
        dotenv::from_filename(".dev.env").ok();
        if env::var("RUST_LOG").is_err() {
            env::set_var("RUST_LOG", "debug");
        }
        if env::var("NO_COLOR").is_err() {
            env::set_var("NO_COLOR", "1");
        }
        if env::var("APP_CLIENT_AI_MOCK").is_err() {
            env::set_var("APP_CLIENT_AI_MOCK", "1");
        }
        let run_mode = env::var("RUN_MODE").unwrap_or_else(|_| "dev".into());
        let conf = Config::builder()
        .add_source(config::File::with_name(&format!("config/{}",run_mode)).required(true))
        // Eg.. `APP_DEBUG=1 ./target/app` would set the `debug` key
        .add_source(Environment::with_prefix("app").list_separator("_"))
        .build()?;
        conf.try_deserialize()
    }
    pub fn get_settings_ai_client<'a>() -> &'a SettingsClientOpenAI{
        &CONFIG.open_ai
    }
    pub fn is_mock_client_ai() -> bool{
        CONFIG.client_ai_mock
    }
}

File Settings.toml:

debug = false
priority = 32
key = "189rjfadoisfj8923fjio"

File simple.rs:


extern crate config;

use std::collections::HashMap;
use std::collections::BTreeMap;
fn main() {
    // Запуск с переменной среды APP_DEBUG переопределит вант файла Settings.toml
    // APP_DEBUG=1 cargo run --bin=simple

    let mut settings:config::Config = config::Config::default();
    settings
        // Add in `./Settings.toml`
        .merge(config::File::with_name("Settings")).unwrap()
        // Add in settings from the environment (with a prefix of APP) Eg.. `APP_DEBUG=1 ./target/app` would set the `debug` key
        .merge(config::Environment::with_prefix("APP")).unwrap();

   // println!("{:?}",settings.try_into::>().unwrap());
      println!("{:?}",settings.try_into::>().unwrap());
}

Запуск:

$ cargo run --bin=simple

OUTPUT: {"debug": "false", "key": "189rjfadoisfj8923fjio", "priority": "32"}

APP_DEBUG=1 cargo run --bin=simple
OUTPUT: {"debug": "1", "key": "189rjfadoisfj8923fjio", "priority": "32"}
  • new
  • merge
  • refresh
  • set_default
  • set
  • get
  • get_str
  • get_int
  • get_float
  • get_bool
  • get_table
  • get_array
  • try_into
  • try_from
  • deserialize

Можно преобразовывать в свои тип конфига

config.get::<Vec<Addr>>("db.redis.addrs")


#[macro_use]
extern crate lazy_static;
extern crate config;
use std::error::Error;
use std::sync::RwLock;
use config::Config;
use std::collections::btree_map::BTreeMap;

// Глобальный конфиг с изначальной загрузкой и последующем изменении на уровня умного счетчика ссылок !!!!
/*lazy_static! {
        static ref SETTINGS: RwLock = RwLock::new(Config::default());
}*/
lazy_static! {
        static ref SETTINGS: RwLock = {
           let mut settings: Config = Config::default();
            settings
             .merge(config::File::with_name("Settings")).unwrap()
             .merge(config::Environment::with_prefix("APP")).unwrap();
            RwLock::new(settings)
        };
}

//  APP_DEBUG=1  APP_KEY=mykey cargo run --bin=global
fn try_main() -> Result<(), Box> {
    // Set property
    SETTINGS.write()?.set("property", 42)?;

    // Get property
    println!("property: {}", SETTINGS.read()?.get::("property")?);

    println!("debug: {}", SETTINGS.read()?.get::("debug")?);
    println!("priority: {}", SETTINGS.read()?.get::("priority")?);
    println!("priority: {}", SETTINGS.read()?.get_int("priority")?);

    println!("key: {}", SETTINGS.read()?.get::("key")?);
    println!("key: {}", SETTINGS.read()?.get_str("key")?);
    Ok(())
}
fn main() {
    try_main().unwrap()
}

File lib.rs:

pub mod settings{
    use config::{Config};
    use std::sync::RwLock;
    use lazy_static::lazy_static;

    lazy_static! {
        static ref SETTINGS: RwLock<Config> = {
        let mut settings: Config = Config::default();
            settings
            .merge(config::File::with_name("src/settings/settings.toml")).unwrap()
            .merge(config::Environment::with_prefix("APP")).unwrap();
            RwLock::new(settings)
        };
    }
   pub fn config() -> Result<String, Box<std::error::Error>>{
        let config = format!("host={host} user={user} port={port} password={password} dbname={dbname}",
        host=SETTINGS.read()?.get::<String>("host")?,
        user=SETTINGS.read()?.get::<String>("user")?,
        port=SETTINGS.read()?.get::<i32>("port")?,
        password=SETTINGS.read()?.get::<String>("password")?,
        dbname=SETTINGS.read()?.get::<String>("dbname")?);

        Ok(config)
   } 
}

File settings/settings.toml:

host="localhost" 
user="rust" 
port=5432 
password='job_queue' 
dbname="rust"

Used File main.rs:

use tokio_postgres_example::settings;

#[tokio::main] 
async fn main() -> std::result::Result<(), tokio_postgres::Error> { 

    let config = settings::config().expect("Error parse config");
    let (mut client, connection):(Client,Connection<_,_>) =
        tokio_postgres::connect(&config, NoTls).await?;
...
}

try_into() - Попытка десериализации всей конфигурации в запрошенный тип


extern crate config;
use std::collections::HashMap;
use std::collections::BTreeMap;
fn main() {
    // Запуск с переменной среды APP_DEBUG переопределит вариант файла Settings.toml
    // APP_DEBUG=1 cargo run --bin=simple

    let mut settings:config::Config = config::Config::default();
    settings
        .merge(config::File::with_name("Settings")).unwrap()
        .merge(config::Environment::with_prefix("APP")).unwrap();

    // Print out our settings (as a HashMap)
    // println!("{:?}",settings.try_into::>().unwrap());
       println!("{:?}",settings.try_into::>().unwrap());
}

Как создать конфиг с действующего объекта структуры

fn main(){
    let mut c = Config::default();
    //let mut c = Config::new();

    //c.set_default("mode.debug", true).unwrap();

    let mut c2 = Config::try_from(&my_conf)?; Работатет слияние двух конфигов
    c.merge(c2).unwrap();

    //let mut c = Config::try_from(&my_conf)?; Создание с состояния структуры и последующий merge не работатет
    c.merge(File::new("Settings_test", FileFormat::Toml)).unwrap();
    c.merge(File::new("Settings_test2", FileFormat::Toml)).unwrap();
}