Merge branch 'add_getters' into 'main' add news getters See merge request ebii/rustwarden!1
Eric BOUHANA <eric@ebii.fr> committé le 2026-03-25 21:22
8c735fcabea1b48e83fe9012c16bec3f641f0ce1
2 parent(s)
2 fichiers modifiés
+102
-11
M
crates/rustwarden-core/src/app.rs
+50
-0
@@ -39,9 +39,16 @@ use crate::services::app_settings_service::AppSettingsService;
| 39 | 39 | use crate::services::default_admin_service; |
| 40 | 40 | |
| 41 | 41 | /// A fully configured Rustwarden application ready to run. |
| 42 | +/// | |
| 43 | +/// After `build()`, getters expose internal resources (DB, config, i18n) | |
| 44 | +/// so consumer apps can run migrations, seed data, or translate messages | |
| 45 | +/// before calling `run()`. | |
| 42 | 46 | pub struct RustwardenApp { |
| 43 | 47 | router: Router, |
| 44 | 48 | address: String, |
| 49 | + db: DatabaseConnection, | |
| 50 | + auth_config: Arc<AuthConfig>, | |
| 51 | + i18n: Arc<I18nService>, | |
| 45 | 52 | } |
| 46 | 53 | |
| 47 | 54 | impl RustwardenApp { |
@@ -50,6 +57,43 @@ impl RustwardenApp {
| 50 | 57 | RustwardenBuilder::default() |
| 51 | 58 | } |
| 52 | 59 | |
| 60 | + /// Access the database connection (pool) used by the framework. | |
| 61 | + /// | |
| 62 | + /// Allows consumer apps to run business migrations, seed data, or | |
| 63 | + /// execute queries on the same connection pool as the framework. | |
| 64 | + /// | |
| 65 | + /// # Examples | |
| 66 | + /// | |
| 67 | + /// ```rust,ignore | |
| 68 | + /// let app = RustwardenApp::builder().from_env().build().await?; | |
| 69 | + /// my_app::migrations::run_migrations(app.database()).await?; | |
| 70 | + /// app.run().await | |
| 71 | + /// ``` | |
| 72 | + pub fn database(&self) -> &DatabaseConnection { | |
| 73 | + &self.db | |
| 74 | + } | |
| 75 | + | |
| 76 | + /// Access the authentication configuration. | |
| 77 | + /// | |
| 78 | + /// Exposes JWT settings, session timeouts, rate limits, and cookie | |
| 79 | + /// configuration for consumer app logic that depends on auth parameters. | |
| 80 | + pub fn auth_config(&self) -> &AuthConfig { | |
| 81 | + &self.auth_config | |
| 82 | + } | |
| 83 | + | |
| 84 | + /// Access the i18n translation service. | |
| 85 | + /// | |
| 86 | + /// Allows consumer apps to translate messages in non-handler code | |
| 87 | + /// (cron tasks, seeding, CLI) or load additional translations after build. | |
| 88 | + pub fn i18n_service(&self) -> &Arc<I18nService> { | |
| 89 | + &self.i18n | |
| 90 | + } | |
| 91 | + | |
| 92 | + /// Server bind address (e.g. "0.0.0.0:3000"). | |
| 93 | + pub fn address(&self) -> &str { | |
| 94 | + &self.address | |
| 95 | + } | |
| 96 | + | |
| 53 | 97 | /// Get the assembled router (for advanced usage, e.g. testing). |
| 54 | 98 | pub fn into_router(self) -> Router { |
| 55 | 99 | self.router |
@@ -370,9 +414,12 @@ impl RustwardenBuilder {
| 370 | 414 | let default = self.default_locale.clone(); |
| 371 | 415 | let db_for_admin = db.clone(); |
| 372 | 416 | let db_for_auth = db.clone(); |
| 417 | + let db_for_app = db.clone(); // Retained for getter access after build | |
| 373 | 418 | |
| 374 | 419 | let hooks = self.hooks.clone(); |
| 375 | 420 | let db_for_ext = db.clone(); |
| 421 | + let i18n_for_app = i18n_service.clone(); // Retained for getter access after build | |
| 422 | + let auth_config_for_app = auth_config.clone(); // Retained for getter access after build | |
| 376 | 423 | let app = router.with_state(db).layer( |
| 377 | 424 | ServiceBuilder::new() |
| 378 | 425 | .layer(axum::middleware::from_fn(security_headers_middleware)) |
@@ -403,6 +450,9 @@ impl RustwardenBuilder {
| 403 | 450 | Ok(RustwardenApp { |
| 404 | 451 | router: app, |
| 405 | 452 | address, |
| 453 | + db: db_for_app, | |
| 454 | + auth_config: auth_config_for_app, | |
| 455 | + i18n: i18n_for_app, | |
| 406 | 456 | }) |
| 407 | 457 | } |
| 408 | 458 |
M
docs/project_rustwarden_db_getter.md
+52
-11
@@ -1,15 +1,15 @@
| 1 | 1 | --- |
| 2 | 2 | name: Rustwarden DB getter improvement |
| 3 | -description: RustwardenApp manque d'un getter database() — workaround actuel dans main.rs, amelioration upstream a envisager | |
| 3 | +description: RustwardenApp manque de getters (database, auth_config, i18n_service, address) — amelioration upstream | |
| 4 | 4 | type: project |
| 5 | 5 | --- |
| 6 | 6 | |
| 7 | 7 | # Specification : Exposition de getters sur `RustwardenApp` |
| 8 | 8 | |
| 9 | -**Version** : 1.0 | |
| 9 | +**Version** : 1.1 | |
| 10 | 10 | **Date** : 2026-03-25 |
| 11 | 11 | **Composant** : `rustwarden-core` (crate framework) |
| 12 | -**Statut** : Proposition | |
| 12 | +**Statut** : Implemente | |
| 13 | 13 | |
| 14 | 14 | --- |
| 15 | 15 |
@@ -67,6 +67,7 @@ pub struct RustwardenApp {
| 67 | 67 | address: String, |
| 68 | 68 | db: DatabaseConnection, // Nouveau |
| 69 | 69 | auth_config: Arc<AuthConfig>, // Nouveau |
| 70 | + i18n: Arc<I18nService>, // Nouveau | |
| 70 | 71 | } |
| 71 | 72 | ``` |
| 72 | 73 |
@@ -81,6 +82,7 @@ Ok(RustwardenApp {
| 81 | 82 | address, |
| 82 | 83 | db: db_for_app, |
| 83 | 84 | auth_config, |
| 85 | + i18n: i18n_service.clone(), | |
| 84 | 86 | }) |
| 85 | 87 | ``` |
| 86 | 88 |
@@ -101,6 +103,15 @@ impl RustwardenApp {
| 101 | 103 | &self.auth_config |
| 102 | 104 | } |
| 103 | 105 | |
| 106 | + /// Acces au service d'internationalisation. | |
| 107 | + /// | |
| 108 | + /// Permet aux consommateurs de traduire des messages dans du code | |
| 109 | + /// non-handler (taches cron, seeding, CLI) ou de charger des | |
| 110 | + /// traductions supplementaires apres build. | |
| 111 | + pub fn i18n_service(&self) -> &Arc<I18nService> { | |
| 112 | + &self.i18n | |
| 113 | + } | |
| 114 | + | |
| 104 | 115 | /// Adresse de bind du serveur (ex: "0.0.0.0:3000"). |
| 105 | 116 | pub fn address(&self) -> &str { |
| 106 | 117 | &self.address |
@@ -131,9 +142,19 @@ app.run().await
| 131 | 142 | |
| 132 | 143 | Plus besoin de `create_connection()` ni de `.clone()` dans le main. |
| 133 | 144 | |
| 134 | -## 4. Analyse des risques | |
| 145 | +## 4. Getters evalues et rejetes | |
| 135 | 146 | |
| 136 | -### 4.1 Risques du changement | |
| 147 | +| Getter | Raison du rejet | | |
| 148 | +|--------|----------------| | |
| 149 | +| `config()` (generique) | Il n'existe pas de struct `AppConfig` unifiee. `ServerConfig`, `EmailConfig`, `AuthConfig` sont des structs distinctes chargees a des moments differents. Des getters specifiques sont plus explicites. | | |
| 150 | +| `state()` | Le "state" Axum du router est `DatabaseConnection`. Exposer `state()` serait redondant avec `database()` et fuiterait un detail d'implementation Axum. | | |
| 151 | +| `hooks()` | Les hooks sont passes au builder par le consommateur lui-meme — il les possede deja. Les re-exposer n'apporte rien. | | |
| 152 | +| `router()` (ref) | `into_router()` existe deja (consomme `self`). Un `&Router` immutable est inutile — on ne peut rien en faire sans le posseder. | | |
| 153 | +| `session_layer()` | Detail d'implementation interne du middleware stack. Le consommateur n'a jamais besoin de manipuler le session layer directement. | | |
| 154 | + | |
| 155 | +## 5. Analyse des risques | |
| 156 | + | |
| 157 | +### 5.1 Risques du changement | |
| 137 | 158 | |
| 138 | 159 | | Risque | Severite | Mitigation | |
| 139 | 160 | |--------|----------|------------| |
@@ -143,7 +164,7 @@ Plus besoin de `create_connection()` ni de `.clone()` dans le main.
| 143 | 164 | | **Utilisation apres `run()`** | Nulle | `run()` consomme `self` (`self`, pas `&self`). Apres `run()`, l'app n'existe plus — aucun risque d'acces concurrent via le getter. | |
| 144 | 165 | | **Acces DB entre `build()` et `run()`** | Faible | Fenetre d'acces intentionnelle et utile (migrations metier, seeding). Les taches de fond (email queue, JWT cleanup) tournent deja dans cette fenetre via des `tokio::spawn` — pas de nouveau risque. | |
| 145 | 166 | |
| 146 | -### 4.2 Risques de NE PAS faire le changement | |
| 167 | +### 5.2 Risques de NE PAS faire le changement | |
| 147 | 168 | |
| 148 | 169 | | Risque | Severite | Impact | |
| 149 | 170 | |--------|----------|--------| |
@@ -152,7 +173,7 @@ Plus besoin de `create_connection()` ni de `.clone()` dans le main.
| 152 | 173 | | **Impossibilite de migrer apres build** | Moyenne | Le pattern actuel force a migrer AVANT `build()`. Les consommateurs qui veulent `auto_migrate(true)` pour les tables framework mais ensuite migrer leurs propres tables ne peuvent pas le faire proprement. | |
| 153 | 174 | | **Framework non idiomatique** | Faible | Le builder pattern en Rust expose generalement des getters sur le produit construit. L'absence degrade l'ergonomie et la credibilite du framework. | |
| 154 | 175 | |
| 155 | -## 5. Avantages | |
| 176 | +## 6. Avantages | |
| 156 | 177 | |
| 157 | 178 | | Avantage | Impact | |
| 158 | 179 | |----------|--------| |
@@ -163,7 +184,7 @@ Plus besoin de `create_connection()` ni de `.clone()` dans le main.
| 163 | 184 | | **Testabilite** | Les tests d'integration peuvent `app.database()` pour setup/teardown les donnees sans reconstruire une connexion | |
| 164 | 185 | | **Extensibilite future** | Ouvre la voie a d'autres getters (`i18n_service()`, `hooks()`) sans repenser l'architecture | |
| 165 | 186 | |
| 166 | -## 6. Retrocompatibilite | |
| 187 | +## 7. Retrocompatibilite | |
| 167 | 188 | |
| 168 | 189 | | Composant | Impact | |
| 169 | 190 | |-----------|--------| |
@@ -175,20 +196,40 @@ Plus besoin de `create_connection()` ni de `.clone()` dans le main.
| 175 | 196 | | Prelude | Aucun changement requis — `RustwardenApp` est deja exporte | |
| 176 | 197 | | CLI wizard templates | Aucun changement requis — le code genere peut adopter le nouveau pattern progressivement | |
| 177 | 198 | |
| 178 | -## 7. Fichiers impactes | |
| 199 | +## 8. Fichiers impactes | |
| 179 | 200 | |
| 180 | 201 | | Fichier | Modification | |
| 181 | 202 | |---------|-------------| |
| 182 | -| `crates/rustwarden-core/src/app.rs` | Ajout de `db` et `auth_config` dans `RustwardenApp`, getters, clone dans `build()` | | |
| 203 | +| `crates/rustwarden-core/src/app.rs` | Ajout de `db`, `auth_config`, `i18n` dans `RustwardenApp`, 4 getters, clones dans `build()` | | |
| 183 | 204 | |
| 184 | 205 | Un seul fichier impacte. Aucune migration, aucun changement de dependance. |
| 185 | 206 | |
| 186 | -## 8. Criteres d'acceptation | |
| 207 | +## 9. Criteres d'acceptation | |
| 187 | 208 | |
| 188 | 209 | - [ ] `app.database()` retourne `&DatabaseConnection` fonctionnelle apres `build()` |
| 189 | 210 | - [ ] `app.auth_config()` retourne `&AuthConfig` fonctionnelle apres `build()` |
| 211 | +- [ ] `app.i18n_service()` retourne `&Arc<I18nService>` fonctionnelle apres `build()` | |
| 190 | 212 | - [ ] `app.address()` retourne l'adresse de bind |
| 191 | 213 | - [ ] Les projets consommateurs existants compilent sans modification |
| 192 | 214 | - [ ] Le pattern `builder().database(db).build()` continue de fonctionner (retrocompat) |
| 193 | 215 | - [ ] `cargo clippy -- -D warnings` passe sans avertissement |
| 194 | 216 | - [ ] `cargo test` — les tests existants passent sans modification |
| 217 | + | |
| 218 | +Resume des changements : | |
| 219 | + | |
| 220 | +Spec mise a jour (project_rustwarden_db_getter.md) — version 1.1 avec : | |
| 221 | + | |
| 222 | +i18n_service() ajoute aux getters proposes | |
| 223 | +Section 4 "Getters evalues et rejetes" (config(), state(), hooks(), router(), session_layer()) | |
| 224 | +Numerotation et criteres d'acceptation mis a jour | |
| 225 | +Implementation dans app.rs : | |
| 226 | + | |
| 227 | +RustwardenApp stocke maintenant db, auth_config, i18n en plus du router et address | |
| 228 | +4 getters publics documentes : database(), auth_config(), i18n_service(), address() | |
| 229 | +Les clones sont places juste avant la consommation dans les layers (cout negligeable — Arc et DatabaseConnection sont des copies de pointeurs) | |
| 230 | +Les projets consommateurs peuvent maintenant ecrire : | |
| 231 | + | |
| 232 | + | |
| 233 | +let app = RustwardenApp::builder().from_env().auto_migrate(true).build().await?; | |
| 234 | +my_app::migrations::run_migrations(app.database()).await?; | |
| 235 | +app.run().await | |
| 235 | < \ No newline at end of file |
GitRust