pzzld_server/config/
settings.rs1use super::{kinds::*, types::*};
6use crate::workers::WorkerConfig;
7
8type ConfigBuilder<S = config::builder::DefaultState> = config::builder::ConfigBuilder<S>;
9
10type ConfigResult<T> = core::result::Result<T, config::ConfigError>;
11
12fn fmt_src(dir: impl core::fmt::Display, fname: impl core::fmt::Display) -> String {
13 format!("{dir}/{fname}")
14}
15
16fn set_default(builder: ConfigBuilder) -> ConfigResult<ConfigBuilder> {
17 let builder = builder
18 .set_default("mode", "debug")?
19 .set_default("name", crate::APP_NAME)?
20 .set_default("version", env!("CARGO_PKG_VERSION"))?
21 .set_default("scope.context", ".")?
22 .set_default("scope.workdir", crate::DEFAULT_WORKDIR)?
23 .set_default("network.address.host", crate::DEFAULT_HOST)?
24 .set_default("network.address.port", crate::DEFAULT_PORT)?
25 .set_default("services.tracing.level", "info")?;
26 Ok(builder)
27}
28
29fn add_sources(builder: ConfigBuilder) -> ConfigBuilder {
30 let workdir =
31 std::env::var("PZZLD_CONFIG").unwrap_or_else(|_| crate::DEFAULT_CONFIG_DIR.to_string());
32 let fname = std::env::var("PZZLD_SETTINGS").unwrap_or_else(|_| "Puzzled.toml".to_string());
33
34 builder
35 .add_source(config::Environment::with_prefix("PZZLD").separator("_"))
36 .add_source(config::File::with_name(&fmt_src(&workdir, "default.config")).required(false))
37 .add_source(config::File::with_name(&fmt_src(&workdir, "server.config")).required(false))
38 .add_source(config::File::with_name(&fmt_src(&workdir, "docker.config")).required(false))
39 .add_source(config::File::with_name(&fmt_src(&workdir, &fname)).required(false))
40 .add_source(config::File::with_name(&fname).required(false))
41 .add_source(config::File::with_name(&fmt_src(&workdir, "prod.config")).required(false))
42}
43
44fn set_overrides(builder: ConfigBuilder) -> ConfigResult<ConfigBuilder> {
45 Ok(builder
46 .set_override_option("mode", std::env::var("RUNMODE").ok())?
47 .set_override_option("name", std::env::var("APP_NAME").ok())?
48 .set_override_option("network.address.host", std::env::var("HOSTNAME").ok())?
49 .set_override_option("network.address.port", std::env::var("HOSTPORT").ok())?
50 .set_override_option("scope.context", std::env::var("PZZLD_CONTEXT").ok())?
51 .set_override_option("scope.workdir", std::env::var("PZZLD_WORKDIR").ok())?)
52}
53
54#[derive(
55 Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, serde::Deserialize, serde::Serialize,
56)]
57#[serde(default)]
58pub struct Settings {
59 pub mode: Mode,
60 pub name: String,
61 pub network: NetworkConfig,
62 pub scope: Scope,
63 pub services: ServicesConfig,
64 pub version: String,
65 pub worker: Vec<WorkerConfig>,
66}
67
68impl Settings {
69 pub fn new(mode: Mode) -> Self {
70 Self {
71 mode,
72 name: crate::APP_NAME.to_string(),
73 network: NetworkConfig::default(),
74 scope: Scope::default(),
75 services: ServicesConfig::default(),
76 version: env!("CARGO_PKG_VERSION").to_string(),
77 worker: Vec::new(),
78 }
79 }
80
81 pub fn build() -> Result<Self, config::ConfigError> {
82 Self::builder_base()?.build()?.try_deserialize()
83 }
84
85 pub async fn bind(&self) -> std::io::Result<tokio::net::TcpListener> {
86 self.network().bind().await
87 }
88 pub fn init_tracing(&self) {
90 self.services().tracing().init_tracing(crate::APP_NAME);
91 }
92 pub fn debug(self) -> Self {
94 Self {
95 mode: Mode::debug(),
96 ..self
97 }
98 }
99 pub fn release(self) -> Self {
101 Self {
102 mode: Mode::release(),
103 ..self
104 }
105 }
106
107 getter! {
108 mode: Mode,
109 name: String,
110 network: NetworkConfig,
111 scope: Scope,
112 services: ServicesConfig,
113 version: String,
114 }
115
116 setwith! {
117 mode: Mode,
118 name: String,
119 scope: Scope,
120 network: NetworkConfig,
121 services: ServicesConfig,
122 version: String,
123 }
124 pub fn workers(&self) -> &[WorkerConfig] {
126 &self.worker
127 }
128 pub fn workers_mut(&mut self) -> &mut Vec<WorkerConfig> {
130 &mut self.worker
131 }
132 pub fn push_worker(&mut self, worker: WorkerConfig) {
134 self.worker.push(worker)
135 }
136 pub fn set_workdir(&mut self, workdir: impl ToString) {
138 self.scope_mut().set_workdir(workdir);
139 }
140 pub fn set_some_workdir(&mut self, workdir: Option<impl ToString>) {
142 self.scope_mut().set_some_workdir(workdir);
143 }
144 pub fn set_scope_context(&mut self, context: impl ToString) {
146 self.scope_mut().set_context(context);
147 }
148
149 pub fn set_port(&mut self, port: u16) {
150 self.network_mut().set_port(port);
151 }
152
153 pub fn set_log_level(&mut self, level: LogLevel) {
154 self.services_mut().tracing_mut().set_level(level);
155 }
156
157 fn builder_base() -> ConfigResult<ConfigBuilder> {
158 let mut builder = config::Config::builder();
160 builder = set_default(builder)?;
162 builder = add_sources(builder);
164 builder = set_overrides(builder)?;
166 Ok(builder)
168 }
169}
170
171impl Default for Settings {
172 fn default() -> Self {
173 Self::new(Mode::Debug)
174 }
175}