@@ -40,6 +40,10 @@ pub struct Config {
4040 pub geoip : Option < GeoIpConfig > ,
4141}
4242
43+ pub fn default_maxmind_edition ( ) -> Option < String > {
44+ Some ( "GeoLite2-City" . to_string ( ) )
45+ }
46+
4347impl Default for Config {
4448 fn default ( ) -> Self {
4549 Self { base_url : default_base ( ) , port : default_port ( ) , data_dir : default_data_dir ( ) , geoip : None }
@@ -49,11 +53,33 @@ impl Default for Config {
4953#[ derive( Debug , Clone , Serialize , Deserialize ) ]
5054pub struct GeoIpConfig {
5155 pub maxmind_db_path : Option < String > ,
56+ #[ serde( deserialize_with = "deserialize_option_string_from_number" ) ]
5257 pub maxmind_account_id : Option < String > ,
5358 pub maxmind_license_key : Option < String > ,
59+ #[ serde( default = "default_maxmind_edition" ) ]
5460 pub maxmind_edition : Option < String > ,
5561}
5662
63+ pub fn deserialize_option_string_from_number < ' de , D > ( deserializer : D ) -> Result < Option < String > , D :: Error >
64+ where
65+ D : serde:: Deserializer < ' de > ,
66+ {
67+ #[ derive( Deserialize ) ]
68+ #[ serde( untagged) ]
69+ enum StringOrNumber {
70+ String ( String ) ,
71+ Number ( i64 ) ,
72+ Float ( f64 ) ,
73+ }
74+
75+ match Option :: < StringOrNumber > :: deserialize ( deserializer) ? {
76+ Some ( StringOrNumber :: String ( s) ) => Ok ( Some ( s) ) ,
77+ Some ( StringOrNumber :: Number ( i) ) => Ok ( Some ( i. to_string ( ) ) ) ,
78+ Some ( StringOrNumber :: Float ( f) ) => Ok ( Some ( f. to_string ( ) ) ) ,
79+ None => Ok ( None ) ,
80+ }
81+ }
82+
5783pub static DEFAULT_CONFIG : & str = include_str ! ( "../config.example.toml" ) ;
5884
5985impl Config {
@@ -81,7 +107,7 @@ impl Config {
81107 . merge ( Env :: raw ( ) . filter_map ( |key| match key {
82108 k if !k. starts_with ( "LIWAN_" ) => None ,
83109 k if k. starts_with ( "LIWAN_MAXMIND_" ) => Some ( format ! ( "geoip.maxmind_{}" , & k[ 14 ..] ) . into ( ) ) ,
84- k => Some ( k[ 6 ..] . as_str ( ) . to_lowercase ( ) . replace ( "_" , "." ) . into ( ) ) ,
110+ k => Some ( k[ 6 ..] . as_str ( ) . to_lowercase ( ) . into ( ) ) ,
85111 } ) )
86112 . extract ( ) ?;
87113
@@ -159,6 +185,39 @@ mod test {
159185 } ) ;
160186 }
161187
188+ #[ test]
189+ fn test_default_geoip ( ) {
190+ Jail :: expect_with ( |jail| {
191+ jail. create_file (
192+ "liwan3.config.toml" ,
193+ r#"
194+ base_url = "http://localhost:8081"
195+ data_dir = "./liwan-test-data"
196+ [geoip]
197+ maxmind_db_path = "test2"
198+ "# ,
199+ ) ?;
200+
201+ let config = Config :: load ( Some ( "liwan3.config.toml" . into ( ) ) ) . expect ( "failed to load config" ) ;
202+ assert_eq ! ( config. geoip. unwrap( ) . maxmind_edition, Some ( "GeoLite2-City" . to_string( ) ) ) ;
203+ Ok ( ( ) )
204+ } ) ;
205+ }
206+
207+ #[ test]
208+ fn test_env ( ) {
209+ Jail :: expect_with ( |jail| {
210+ jail. set_env ( "LIWAN_DATA_DIR" , "/data" ) ;
211+ jail. set_env ( "LIWAN_BASE_URL" , "https://example.com" ) ;
212+ jail. set_env ( "LIWAN_MAXMIND_ACCOUNT_ID" , 123 ) ;
213+ let config = Config :: load ( None ) . expect ( "failed to load config" ) ;
214+ assert_eq ! ( config. data_dir, "/data" ) ;
215+ assert_eq ! ( config. base_url, "https://example.com" ) ;
216+ assert_eq ! ( config. geoip. unwrap( ) . maxmind_account_id, Some ( "123" . to_string( ) ) ) ;
217+ Ok ( ( ) )
218+ } ) ;
219+ }
220+
162221 #[ test]
163222 fn test_no_config ( ) {
164223 Jail :: expect_with ( |_jail| {
0 commit comments