1use std::collections::{HashMap, HashSet};
4
5use config::builder::DefaultState;
6use config::{
7 Config as ConfigRaw,
8 ConfigBuilder,
9 ConfigError,
10 Environment,
11 File,
12 FileFormat,
13};
14use serde::Deserialize;
15
16#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
17#[serde(rename_all = "snake_case")]
18#[allow(unused)]
19pub enum Role {
20 Api,
21 Dispatcher,
22 Scheduler,
23}
24
25#[derive(Debug, Clone, Deserialize)]
26pub struct MainConfig {
27 pub roles: HashSet<Role>,
28 pub prometheus_address: String,
29 pub prometheus_port: u16,
30 pub dispatcher_cell_map: HashMap<u64, String>,
31 pub scheduler_cell_map: HashMap<u64, String>,
32}
33
34#[derive(Debug, Clone, Deserialize)]
35pub struct DispatcherConfig {
36 pub cell_id: u32,
37 pub address: String,
38 pub port: u16,
39 pub request_processing_timeout_s: u64,
40 pub database_uri: String,
41}
42
43#[derive(Debug, Clone, Deserialize)]
44pub struct SchedulerConfig {
45 pub cell_id: u32,
47 pub address: String,
48 pub port: u16,
49 pub request_processing_timeout_s: u64,
50 pub spinner_yield_max_ms: u64,
51 pub max_triggers_per_tick: u64,
52 pub database_uri: String,
53 pub db_flush_s: u64,
54 pub dangerous_fast_forward: bool,
55}
56
57#[derive(Debug, Clone, Deserialize)]
58pub struct ApiConfig {
59 pub address: String,
60 pub port: u16,
61 pub database_uri: String,
62 pub admin_api_keys: HashSet<String>,
63 pub log_request_body: bool,
64 pub log_response_body: bool,
65}
66
67#[derive(Debug, Clone, Deserialize)]
68#[allow(unused)]
69pub struct Config {
76 pub main: MainConfig,
77 pub api: ApiConfig,
78 pub dispatcher: DispatcherConfig,
79 pub scheduler: SchedulerConfig,
80}
81
82#[derive(Debug)]
83pub struct ConfigLoader {
84 builder: ConfigBuilder<DefaultState>,
85}
86
87impl ConfigLoader {
88 pub fn load(&self) -> Result<Config, ConfigError> {
90 Self::deserialize(self.builder.build_cloned()?)
91 }
92
93 pub fn from_path(path: &Option<String>) -> ConfigLoader {
98 let raw = include_str!("default.toml");
99 let mut builder = ConfigRaw::builder()
100 .add_source(File::from_str(raw, FileFormat::Toml))
101 .add_source(
102 Environment::with_prefix("CRONBACK")
103 .try_parsing(true)
104 .separator("__")
105 .list_separator(",")
106 .with_list_parse_key("api.admin_api_keys"),
107 );
108 if let Some(path) = path {
109 builder = builder.add_source(File::with_name(path));
110 }
111 ConfigLoader { builder }
112 }
113
114 fn deserialize(config: ConfigRaw) -> Result<Config, ConfigError> {
115 config.try_deserialize()
116 }
117}