1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
//! A request-scoped configuration snapshot for Loco.
//!
//! ```no_run
//! use dynamic_config_loco::{sections, Config, DynamicConfig};
//! use loco_rs::prelude::*;
//! # use dynamic_config::dynamic_config;
//! # use serde::Deserialize;
//! # #[dynamic_config] #[derive(Deserialize)] struct Server { port: u16 }
//! # #[dynamic_config] #[derive(Deserialize)] struct Features { cache: bool }
//! # struct App;
//!
//! # impl App {
//! async fn initializers(_ctx: &AppContext) -> Result<Vec<Box<dyn Initializer>>> {
//! Ok(vec![Box::new(DynamicConfig::new(sections![Server, Features]))])
//! }
//! # }
//! ```
//!
//! ```no_run
//! # use dynamic_config_loco::Config;
//! # use loco_rs::prelude::*;
//! # struct Server { port: u16 }
//! # struct Features { cache: bool }
//! async fn index(
//! Config(server): Config<Server>,
//! Config(features): Config<Features>,
//! ) -> Result<Response> {
//! // One reading, taken when the request began. `Sections::take`
//! // retries if a reload lands mid-read, so these two cannot be
//! // different generations.
//! format::text(&format!("{} {}", server.port, features.cache))
//! }
//! ```
//!
//! # What this crate is
//!
//! Loco is axum underneath, so the layer and the extractor are
//! [`dynamic-config-axum`](https://docs.rs/dynamic-config-axum)'s, re-exported
//! here unchanged. What Loco adds is a place to register one — the
//! [`Initializer`] trait — and that registration is all this crate is.
//!
//! Writing it by hand is three lines in your own initializer, and doing so
//! is fine. This crate exists so that it is one line in `initializers`, and
//! so that there is somewhere to write down the two things below.
//!
//! # Loco's own configuration is a different thing
//!
//! Loco reads `config/development.yaml` into `ctx.config` at boot, and that
//! is where the database URL, the worker mode and the server port live.
//! None of it reloads, and none of it should: Loco binds its listener and
//! builds its connection pool from those values once.
//!
//! This crate is for the *other* half — the settings an operator changes
//! while the service runs. Keep them in their own file with their own
//! `#[dynamic_config]` sections, and leave `ctx.config` to Loco.
//!
//! # What this crate does not do
//!
//! It does not load configuration, watch files, or own a [`WatchHandle`].
//! Loco's `Hooks::boot` is where a service does that, before the router
//! exists.
//!
//! [`WatchHandle`]: https://docs.rs/dynamic-config/latest/dynamic_config/watch/struct.WatchHandle.html
use async_trait;
use Sections;
use ;
use Result;
// `axum::Router` itself: Loco's `AxumRouter` is a private alias for it
// inside `loco_rs::app`, so the trait's signature is spelled here the way
// the compiler sees it.
use Router as AxumRouter;
pub use ;
pub use ;
/// The initializer that puts one reading on every request.
///
/// ```no_run
/// # use dynamic_config_loco::{DynamicConfig, ConfigSections};
/// # use loco_rs::app::Initializer;
/// let initializers: Vec<Box<dyn Initializer>> =
/// vec![Box::new(DynamicConfig::new(ConfigSections::new()))];
/// ```
///
/// Loco calls [`after_routes`](Initializer::after_routes) once, with the
/// router it has built, and this adds the layer to it — so every route the
/// application declares is covered, including the ones Loco adds itself.