6
6
mod errors;
7
7
mod settings;
8
8
9
- use actix_web:: { http, App , HttpRequest , HttpResponse } ;
9
+ use actix_web:: { http, App , FutureResponse , HttpRequest , HttpResponse } ;
10
10
use chrono:: { DateTime , Utc } ;
11
11
use futures:: Future ;
12
12
use maxminddb:: { self , geoip2, MaxMindDBError } ;
13
13
use serde:: Serializer ;
14
14
use serde_derive:: Serialize ;
15
- use std:: { net:: IpAddr , path:: PathBuf , process} ;
15
+ use std:: fs:: File ;
16
+ use std:: io:: Read ;
17
+ use std:: { net:: IpAddr , net:: Ipv4Addr , path:: PathBuf , process} ;
16
18
17
19
use crate :: { errors:: ClassifyError , settings:: Settings } ;
18
20
19
21
#[ derive( Clone ) ]
20
22
struct State {
21
23
geoip : actix:: Addr < GeoIpActor > ,
24
+ settings : settings:: Settings ,
22
25
}
23
26
24
27
fn main ( ) {
@@ -45,11 +48,16 @@ fn main() {
45
48
} )
46
49
} ;
47
50
48
- let state = State { geoip } ;
51
+ let state = State { geoip, settings } ;
49
52
50
- let addr = format ! ( "{}:{}" , settings. host, settings. port) ;
53
+ let addr = format ! ( "{}:{}" , state . settings. host, state . settings. port) ;
51
54
let server = actix_web:: server:: new ( move || {
52
- App :: with_state ( state. clone ( ) ) . resource ( "/" , |r| r. get ( ) . f ( index) )
55
+ App :: with_state ( state. clone ( ) )
56
+ . resource ( "/" , |r| r. get ( ) . f ( index) )
57
+ // Dockerflow views
58
+ . resource ( "/__lbheartbeat__" , |r| r. get ( ) . f ( lbheartbeat) )
59
+ . resource ( "/__heartbeat__" , |r| r. get ( ) . f ( heartbeat) )
60
+ . resource ( "/__version__" , |r| r. get ( ) . f ( version) )
53
61
} )
54
62
. bind ( & addr)
55
63
. unwrap_or_else ( |err| panic ! ( format!( "Couldn't listen on {}: {}" , & addr, err) ) ) ;
@@ -190,3 +198,49 @@ fn index(req: &HttpRequest<State>) -> Box<dyn Future<Item = HttpResponse, Error
190
198
. map_err ( |err| ClassifyError :: from_source ( "Future failure" , err) ) ,
191
199
)
192
200
}
201
+
202
+ fn lbheartbeat ( _req : & HttpRequest < State > ) -> HttpResponse {
203
+ HttpResponse :: Ok ( ) . body ( "" )
204
+ }
205
+
206
+ #[ derive( Serialize ) ]
207
+ struct HeartbeatResponse {
208
+ geoip : bool ,
209
+ }
210
+
211
+ fn heartbeat ( req : & HttpRequest < State > ) -> FutureResponse < HttpResponse > {
212
+ let ip = IpAddr :: V4 ( Ipv4Addr :: new ( 1 , 2 , 3 , 4 ) ) ;
213
+
214
+ Box :: new (
215
+ req. state ( )
216
+ . geoip
217
+ . send ( CountryForIp { ip } )
218
+ . and_then ( |res| match res {
219
+ Ok ( country_info) => country_info
220
+ . and_then ( |country_info| country_info. country )
221
+ . and_then ( |country| country. iso_code )
222
+ . and_then ( |iso_code| Some ( Ok ( iso_code == "US" . to_string ( ) ) ) )
223
+ . unwrap_or ( Ok ( false ) ) ,
224
+ Err ( _) => Ok ( false ) ,
225
+ } )
226
+ . or_else ( |_| Ok ( false ) )
227
+ . and_then ( |res| {
228
+ let mut resp = match res {
229
+ true => HttpResponse :: Ok ( ) ,
230
+ false => HttpResponse :: ServiceUnavailable ( ) ,
231
+ } ;
232
+ Ok ( resp. json ( HeartbeatResponse { geoip : res } ) )
233
+ } ) ,
234
+ )
235
+ }
236
+
237
+ fn version ( req : & HttpRequest < State > ) -> HttpResponse {
238
+ let version_file = & req. state ( ) . settings . version_file ;
239
+ // Read the file or deliberately fail with a 500 if missing.
240
+ let mut file = File :: open ( version_file) . unwrap ( ) ;
241
+ let mut data = String :: new ( ) ;
242
+ file. read_to_string ( & mut data) . unwrap ( ) ;
243
+ HttpResponse :: Ok ( )
244
+ . content_type ( "application/json" )
245
+ . body ( data)
246
+ }
0 commit comments