springtime_web_axum/
config.rs1use config::{Config, File};
8use rustc_hash::FxHashMap;
9use serde::Deserialize;
10use springtime::config::CONFIG_FILE;
11use springtime::future::{BoxFuture, FutureExt};
12use springtime_di::component_registry::conditional::unregistered_component;
13use springtime_di::instance_provider::ErrorPtr;
14use springtime_di::{component_alias, injectable, Component};
15use std::sync::Arc;
16
17pub const DEFAULT_SERVER_NAME: &str = "default";
19
20#[non_exhaustive]
22#[derive(Clone, Debug, Deserialize)]
23#[serde(default)]
24pub struct ServerConfig {
25 pub listen_address: String,
27}
28
29impl Default for ServerConfig {
30 fn default() -> Self {
31 Self {
32 listen_address: "0.0.0.0:80".to_string(),
33 }
34 }
35}
36
37#[non_exhaustive]
39#[derive(Clone, Debug, Deserialize)]
40#[serde(default)]
41pub struct WebConfig {
42 pub servers: FxHashMap<String, ServerConfig>,
46}
47
48impl Default for WebConfig {
49 fn default() -> Self {
50 Self {
51 servers: [(DEFAULT_SERVER_NAME.to_string(), Default::default())]
52 .into_iter()
53 .collect(),
54 }
55 }
56}
57
58impl WebConfig {
59 fn init_from_config() -> Result<Self, ErrorPtr> {
60 Config::builder()
61 .add_source(File::with_name(CONFIG_FILE).required(false))
62 .build()
63 .and_then(|config| config.try_deserialize::<WebConfigWrapper>())
64 .map(|config| config.web)
65 .map_err(|error| Arc::new(error) as ErrorPtr)
66 }
67}
68
69#[injectable]
72pub trait WebConfigProvider {
73 fn config(&self) -> BoxFuture<'_, Result<&WebConfig, ErrorPtr>>;
75}
76
77#[derive(Component)]
78#[component(priority = -128, condition = "unregistered_component::<dyn WebConfigProvider + Send + Sync>", constructor = "DefaultWebConfigProvider::new")]
79struct DefaultWebConfigProvider {
80 #[component(ignore)]
82 config: Result<WebConfig, ErrorPtr>,
83}
84
85#[component_alias]
86impl WebConfigProvider for DefaultWebConfigProvider {
87 fn config(&self) -> BoxFuture<'_, Result<&WebConfig, ErrorPtr>> {
88 async {
89 match &self.config {
90 Ok(config) => Ok(config),
91 Err(error) => Err(error.clone()),
92 }
93 }
94 .boxed()
95 }
96}
97
98impl DefaultWebConfigProvider {
99 fn new() -> BoxFuture<'static, Result<Self, ErrorPtr>> {
100 async {
101 Ok(Self {
102 config: WebConfig::init_from_config(),
103 })
104 }
105 .boxed()
106 }
107}
108
109#[derive(Deserialize, Default)]
110#[serde(default)]
111struct WebConfigWrapper {
112 web: WebConfig,
113}