@@ -2,8 +2,11 @@ use std::fmt;
22use std:: path:: Path ;
33
44use confique:: Config ;
5+ #[ cfg( test) ]
6+ use trogon_nats:: NatsAuth ;
57use trogon_nats:: jetstream:: StreamMaxAge ;
6- use trogon_nats:: { NatsAuth , NatsToken , SubjectTokenViolation } ;
8+ use trogon_nats:: { NatsToken , SubjectTokenViolation } ;
9+ use trogon_service_config:: { NatsArgs , NatsConfigSection , load_config, resolve_nats} ;
710use trogon_source_discord:: config:: DiscordBotToken ;
811use trogon_source_github:: config:: GitHubWebhookSecret ;
912use trogon_source_gitlab:: config:: GitLabWebhookSecret ;
@@ -164,7 +167,7 @@ struct GatewayConfig {
164167 #[ config( nested) ]
165168 http_server : HttpServerConfig ,
166169 #[ config( nested) ]
167- nats : NatsConfig ,
170+ nats : NatsConfigSection ,
168171 #[ config( nested) ]
169172 sources : SourcesConfig ,
170173}
@@ -175,22 +178,6 @@ struct HttpServerConfig {
175178 port : u16 ,
176179}
177180
178- #[ derive( Config ) ]
179- struct NatsConfig {
180- #[ config( env = "NATS_URL" , default = "localhost:4222" ) ]
181- url : String ,
182- #[ config( env = "NATS_CREDS" ) ]
183- creds : Option < String > ,
184- #[ config( env = "NATS_NKEY" ) ]
185- nkey : Option < String > ,
186- #[ config( env = "NATS_USER" ) ]
187- user : Option < String > ,
188- #[ config( env = "NATS_PASSWORD" ) ]
189- password : Option < String > ,
190- #[ config( env = "NATS_TOKEN" ) ]
191- token : Option < String > ,
192- }
193-
194181#[ derive( Config ) ]
195182struct SourcesConfig {
196183 #[ config( nested) ]
@@ -358,17 +345,21 @@ impl ResolvedConfig {
358345 }
359346}
360347
348+ #[ cfg( test) ]
361349pub fn load ( config_path : Option < & Path > ) -> Result < ResolvedConfig , ConfigError > {
362- let mut builder = GatewayConfig :: builder ( ) ;
363- if let Some ( path) = config_path {
364- builder = builder. file ( path) ;
365- }
366- let cfg = builder. env ( ) . load ( ) . map_err ( ConfigError :: Load ) ?;
367- resolve ( cfg)
350+ load_with_overrides ( config_path, & NatsArgs :: default ( ) )
351+ }
352+
353+ pub fn load_with_overrides (
354+ config_path : Option < & Path > ,
355+ nats_overrides : & NatsArgs ,
356+ ) -> Result < ResolvedConfig , ConfigError > {
357+ let cfg = load_config :: < GatewayConfig > ( config_path) . map_err ( ConfigError :: Load ) ?;
358+ resolve ( cfg, nats_overrides)
368359}
369360
370- fn resolve ( cfg : GatewayConfig ) -> Result < ResolvedConfig , ConfigError > {
371- let nats = resolve_nats ( & cfg. nats ) ;
361+ fn resolve ( cfg : GatewayConfig , nats_overrides : & NatsArgs ) -> Result < ResolvedConfig , ConfigError > {
362+ let nats = resolve_nats ( & cfg. nats , nats_overrides ) ;
372363 let mut errors = Vec :: new ( ) ;
373364
374365 let github = resolve_github ( cfg. sources . github , & mut errors) ;
@@ -398,38 +389,6 @@ fn resolve(cfg: GatewayConfig) -> Result<ResolvedConfig, ConfigError> {
398389 } )
399390}
400391
401- fn non_empty ( opt : & Option < String > ) -> Option < & String > {
402- opt. as_ref ( ) . filter ( |s| !s. is_empty ( ) )
403- }
404-
405- fn resolve_nats ( section : & NatsConfig ) -> trogon_nats:: NatsConfig {
406- let auth = if let Some ( creds) = non_empty ( & section. creds ) {
407- NatsAuth :: Credentials ( creds. clone ( ) . into ( ) )
408- } else if let Some ( nkey) = non_empty ( & section. nkey ) {
409- NatsAuth :: NKey ( nkey. clone ( ) )
410- } else if let ( Some ( user) , Some ( password) ) =
411- ( non_empty ( & section. user ) , non_empty ( & section. password ) )
412- {
413- NatsAuth :: UserPassword {
414- user : user. clone ( ) ,
415- password : password. clone ( ) ,
416- }
417- } else if let Some ( token) = non_empty ( & section. token ) {
418- NatsAuth :: Token ( token. clone ( ) )
419- } else {
420- NatsAuth :: None
421- } ;
422-
423- let servers: Vec < String > = section
424- . url
425- . split ( ',' )
426- . map ( |s| s. trim ( ) . to_string ( ) )
427- . filter ( |s| !s. is_empty ( ) )
428- . collect ( ) ;
429-
430- trogon_nats:: NatsConfig :: new ( servers, auth)
431- }
432-
433392fn resolve_github (
434393 section : GithubConfig ,
435394 errors : & mut Vec < ConfigValidationError > ,
@@ -1721,21 +1680,47 @@ token = "mytoken"
17211680 }
17221681
17231682 #[ test]
1724- fn non_empty_filters_none ( ) {
1725- let val: Option < String > = None ;
1726- assert ! ( non_empty( & val) . is_none( ) ) ;
1727- }
1683+ fn load_with_overrides_prefers_cli_nats_values ( ) {
1684+ let toml = r#"
1685+ [nats]
1686+ url = "file1:4222,file2:4222"
1687+ token = "file-token"
1688+ "# ;
1689+ let f = write_toml ( toml) ;
1690+ let cfg = load_with_overrides (
1691+ Some ( f. path ( ) ) ,
1692+ & NatsArgs {
1693+ nats_url : Some ( "override:4222" . to_string ( ) ) ,
1694+ nats_token : Some ( "override-token" . to_string ( ) ) ,
1695+ ..Default :: default ( )
1696+ } ,
1697+ )
1698+ . expect ( "load failed" ) ;
17281699
1729- #[ test]
1730- fn non_empty_filters_empty_string ( ) {
1731- let val = Some ( String :: new ( ) ) ;
1732- assert ! ( non_empty( & val) . is_none( ) ) ;
1700+ assert_eq ! ( cfg. nats. servers, vec![ "override:4222" ] ) ;
1701+ assert ! ( matches!( cfg. nats. auth, NatsAuth :: Token ( ref token) if token == "override-token" ) ) ;
17331702 }
17341703
17351704 #[ test]
1736- fn non_empty_passes_through_nonempty ( ) {
1737- let val = Some ( "hello" . to_string ( ) ) ;
1738- assert_eq ! ( non_empty( & val) , Some ( & "hello" . to_string( ) ) ) ;
1705+ fn load_with_overrides_keeps_auth_priority ( ) {
1706+ let toml = r#"
1707+ [nats]
1708+ token = "file-token"
1709+ "# ;
1710+ let f = write_toml ( toml) ;
1711+ let cfg = load_with_overrides (
1712+ Some ( f. path ( ) ) ,
1713+ & NatsArgs {
1714+ nats_creds : Some ( "/path/to/override.creds" . to_string ( ) ) ,
1715+ nats_token : Some ( "override-token" . to_string ( ) ) ,
1716+ ..Default :: default ( )
1717+ } ,
1718+ )
1719+ . expect ( "load failed" ) ;
1720+
1721+ assert ! (
1722+ matches!( cfg. nats. auth, NatsAuth :: Credentials ( ref path) if path == std:: path:: Path :: new( "/path/to/override.creds" ) )
1723+ ) ;
17391724 }
17401725
17411726 #[ test]
0 commit comments