@@ -65,8 +65,6 @@ use zbus::MatchRule;
65
65
use super :: prelude:: * ;
66
66
use crate :: util:: { country_flag_from_iso_code, new_system_dbus_connection} ;
67
67
68
- const API_ENDPOINT : & str = "https://ipapi.co/json/" ;
69
-
70
68
#[ derive( Deserialize , Debug , SmartDefault ) ]
71
69
#[ serde( deny_unknown_fields, default ) ]
72
70
pub struct Config {
@@ -137,40 +135,75 @@ pub async fn run(config: &Config, api: &CommonApi) -> Result<()> {
137
135
} ;
138
136
139
137
loop {
140
- let fetch_info = || IPAddressInfo :: new ( client ) ;
138
+ let fetch_info = || api . find_ip_location ( client , Duration :: from_secs ( 0 ) ) ;
141
139
let info = fetch_info. retry ( ExponentialBuilder :: default ( ) ) . await ?;
142
140
143
141
let mut values = map ! {
144
142
"ip" => Value :: text( info. ip) ,
145
- "version" => Value :: text( info. version) ,
146
143
"city" => Value :: text( info. city) ,
147
- "region" => Value :: text( info. region) ,
148
- "region_code" => Value :: text( info. region_code) ,
149
- "country" => Value :: text( info. country) ,
150
- "country_name" => Value :: text( info. country_name) ,
151
- "country_flag" => Value :: text( country_flag_from_iso_code( & info. country_code) ) ,
152
- "country_code" => Value :: text( info. country_code) ,
153
- "country_code_iso3" => Value :: text( info. country_code_iso3) ,
154
- "country_capital" => Value :: text( info. country_capital) ,
155
- "country_tld" => Value :: text( info. country_tld) ,
156
- "continent_code" => Value :: text( info. continent_code) ,
157
144
"latitude" => Value :: number( info. latitude) ,
158
145
"longitude" => Value :: number( info. longitude) ,
159
- "timezone" => Value :: text( info. timezone) ,
160
- "utc_offset" => Value :: text( info. utc_offset) ,
161
- "country_calling_code" => Value :: text( info. country_calling_code) ,
162
- "currency" => Value :: text( info. currency) ,
163
- "currency_name" => Value :: text( info. currency_name) ,
164
- "languages" => Value :: text( info. languages) ,
165
- "country_area" => Value :: number( info. country_area) ,
166
- "country_population" => Value :: number( info. country_population) ,
167
- "asn" => Value :: text( info. asn) ,
168
- "org" => Value :: text( info. org) ,
169
146
} ;
170
- info. postal
171
- . map ( |x| values. insert ( "postal" . into ( ) , Value :: text ( x) ) ) ;
172
- if info. in_eu {
173
- values. insert ( "in_eu" . into ( ) , Value :: flag ( ) ) ;
147
+
148
+ macro_rules! map_push_if_some { ( $( $key: ident: $type: ident) ,* $( , ) ?) => {
149
+ $( {
150
+ let key = stringify!( $key) ;
151
+ if let Some ( value) = info. $key {
152
+ values. insert( key. into( ) , Value :: $type( value) ) ;
153
+ } else if format. contains_key( key) {
154
+ return Err ( Error :: new( format!(
155
+ "The format string contains '{key}', but the {key} field is not provided by {} (an api key may be required)" ,
156
+ api. locator_name( )
157
+ ) ) ) ;
158
+ }
159
+ } ) *
160
+ } }
161
+
162
+ map_push_if_some ! (
163
+ version: text,
164
+ region: text,
165
+ region_code: text,
166
+ country: text,
167
+ country_name: text,
168
+ country_code_iso3: text,
169
+ country_capital: text,
170
+ country_tld: text,
171
+ continent_code: text,
172
+ postal: text,
173
+ timezone: text,
174
+ utc_offset: text,
175
+ country_calling_code: text,
176
+ currency: text,
177
+ currency_name: text,
178
+ languages: text,
179
+ country_area: number,
180
+ country_population: number,
181
+ asn: text,
182
+ org: text,
183
+ ) ;
184
+
185
+ if let Some ( country_code) = info. country_code {
186
+ values. insert (
187
+ "country_flag" . into ( ) ,
188
+ Value :: text ( country_flag_from_iso_code ( & country_code) ) ,
189
+ ) ;
190
+ values. insert ( "country_code" . into ( ) , Value :: text ( country_code) ) ;
191
+ } else if format. contains_key ( "country_code" ) || format. contains_key ( "country_flag" ) {
192
+ return Err ( Error :: new ( format ! (
193
+ "The format string contains 'country_code' or 'country_flag', but the country_code field is not provided by {}" ,
194
+ api. locator_name( )
195
+ ) ) ) ;
196
+ }
197
+
198
+ if let Some ( in_eu) = info. in_eu {
199
+ if in_eu {
200
+ values. insert ( "in_eu" . into ( ) , Value :: flag ( ) ) ;
201
+ }
202
+ } else if format. contains_key ( "in_eu" ) {
203
+ return Err ( Error :: new ( format ! (
204
+ "The format string contains 'in_eu', but the in_eu field is not provided by {}" ,
205
+ api. locator_name( )
206
+ ) ) ) ;
174
207
}
175
208
176
209
let mut widget = Widget :: new ( ) . with_format ( format. clone ( ) ) ;
@@ -189,54 +222,3 @@ pub async fn run(config: &Config, api: &CommonApi) -> Result<()> {
189
222
}
190
223
}
191
224
}
192
-
193
- #[ derive( Deserialize , Default ) ]
194
- #[ serde( default ) ]
195
- struct IPAddressInfo {
196
- error : bool ,
197
- reason : String ,
198
- ip : String ,
199
- version : String ,
200
- city : String ,
201
- region : String ,
202
- region_code : String ,
203
- country : String ,
204
- country_name : String ,
205
- country_code : String ,
206
- country_code_iso3 : String ,
207
- country_capital : String ,
208
- country_tld : String ,
209
- continent_code : String ,
210
- in_eu : bool ,
211
- postal : Option < String > ,
212
- latitude : f64 ,
213
- longitude : f64 ,
214
- timezone : String ,
215
- utc_offset : String ,
216
- country_calling_code : String ,
217
- currency : String ,
218
- currency_name : String ,
219
- languages : String ,
220
- country_area : f64 ,
221
- country_population : f64 ,
222
- asn : String ,
223
- org : String ,
224
- }
225
-
226
- impl IPAddressInfo {
227
- async fn new ( client : & reqwest:: Client ) -> Result < Self > {
228
- let info: Self = client
229
- . get ( API_ENDPOINT )
230
- . send ( )
231
- . await
232
- . error ( "Failed to request current location" ) ?
233
- . json :: < Self > ( )
234
- . await
235
- . error ( "Failed to parse JSON" ) ?;
236
- if info. error {
237
- Err ( Error :: new ( info. reason ) )
238
- } else {
239
- Ok ( info)
240
- }
241
- }
242
- }
0 commit comments