1
- use crate :: tracker:: { TorrentTracker } ;
2
- use serde:: { Deserialize , Serialize } ;
3
1
use std:: cmp:: min;
4
2
use std:: collections:: { HashMap , HashSet } ;
3
+ use std:: net:: SocketAddr ;
5
4
use std:: sync:: Arc ;
6
- use warp:: { filters, reply, reply:: Reply , serve, Filter , Server } ;
7
- use crate :: TorrentPeer ;
8
- use super :: common:: * ;
5
+
6
+ use serde:: { Deserialize , Serialize } ;
7
+ use warp:: { Filter , filters, reply, serve} ;
8
+
9
+ use crate :: protocol:: common:: * ;
10
+ use crate :: peer:: TorrentPeer ;
11
+ use crate :: tracker:: tracker:: TorrentTracker ;
9
12
10
13
#[ derive( Deserialize , Debug ) ]
11
14
struct TorrentInfoQuery {
@@ -20,7 +23,7 @@ struct Torrent<'a> {
20
23
completed : u32 ,
21
24
leechers : u32 ,
22
25
#[ serde( skip_serializing_if = "Option::is_none" ) ]
23
- peers : Option < Vec < TorrentPeer > > ,
26
+ peers : Option < Vec < & ' a TorrentPeer > > ,
24
27
}
25
28
26
29
#[ derive( Serialize ) ]
@@ -52,7 +55,7 @@ enum ActionStatus<'a> {
52
55
53
56
impl warp:: reject:: Reject for ActionStatus < ' static > { }
54
57
55
- fn authenticate ( tokens : HashMap < String , String > ) -> impl Filter < Extract = ( ) , Error = warp:: reject:: Rejection > + Clone {
58
+ fn authenticate ( tokens : HashMap < String , String > ) -> impl Filter < Extract = ( ) , Error = warp:: reject:: Rejection > + Clone {
56
59
#[ derive( Deserialize ) ]
57
60
struct AuthToken {
58
61
token : Option < String > ,
@@ -69,7 +72,7 @@ fn authenticate(tokens: HashMap<String, String>) -> impl Filter<Extract = (), Er
69
72
match token. token {
70
73
Some ( token) => {
71
74
if !tokens. contains ( & token) {
72
- return Err ( warp:: reject:: custom ( ActionStatus :: Err { reason : "token not valid" . into ( ) } ) )
75
+ return Err ( warp:: reject:: custom ( ActionStatus :: Err { reason : "token not valid" . into ( ) } ) ) ;
73
76
}
74
77
75
78
Ok ( ( ) )
@@ -81,7 +84,7 @@ fn authenticate(tokens: HashMap<String, String>) -> impl Filter<Extract = (), Er
81
84
. untuple_one ( )
82
85
}
83
86
84
- pub fn build_server ( tracker : Arc < TorrentTracker > ) -> Server < impl Filter < Extract = impl Reply > + Clone + Send + Sync + ' static > {
87
+ pub fn start ( socket_addr : SocketAddr , tracker : Arc < TorrentTracker > ) -> impl warp :: Future < Output = ( ) > {
85
88
// GET /api/torrents?offset=:u32&limit=:u32
86
89
// View torrent list
87
90
let api_torrents = tracker. clone ( ) ;
@@ -131,7 +134,7 @@ pub fn build_server(tracker: Arc<TorrentTracker>) -> Server<impl Filter<Extract
131
134
} )
132
135
. and_then ( |tracker : Arc < TorrentTracker > | {
133
136
async move {
134
- let mut results = Stats {
137
+ let mut results = Stats {
135
138
torrents : 0 ,
136
139
seeders : 0 ,
137
140
completed : 0 ,
@@ -147,9 +150,11 @@ pub fn build_server(tracker: Arc<TorrentTracker>) -> Server<impl Filter<Extract
147
150
udp4_scrapes_handled : 0 ,
148
151
udp6_connections_handled : 0 ,
149
152
udp6_announces_handled : 0 ,
150
- udp6_scrapes_handled : 0
153
+ udp6_scrapes_handled : 0 ,
151
154
} ;
155
+
152
156
let db = tracker. get_torrents ( ) . await ;
157
+
153
158
let _: Vec < _ > = db
154
159
. iter ( )
155
160
. map ( |( _info_hash, torrent_entry) | {
@@ -160,7 +165,9 @@ pub fn build_server(tracker: Arc<TorrentTracker>) -> Server<impl Filter<Extract
160
165
results. torrents += 1 ;
161
166
} )
162
167
. collect ( ) ;
168
+
163
169
let stats = tracker. get_stats ( ) . await ;
170
+
164
171
results. tcp4_connections_handled = stats. tcp4_connections_handled as u32 ;
165
172
results. tcp4_announces_handled = stats. tcp4_announces_handled as u32 ;
166
173
results. tcp4_scrapes_handled = stats. tcp4_scrapes_handled as u32 ;
@@ -195,7 +202,7 @@ pub fn build_server(tracker: Arc<TorrentTracker>) -> Server<impl Filter<Extract
195
202
let torrent_entry_option = db. get ( & info_hash) ;
196
203
197
204
if torrent_entry_option. is_none ( ) {
198
- return Err ( warp:: reject:: custom ( ActionStatus :: Err { reason : "torrent does not exist" . into ( ) } ) )
205
+ return Result :: < _ , warp:: reject:: Rejection > :: Ok ( reply :: json ( & "torrent not known" ) )
199
206
}
200
207
201
208
let torrent_entry = torrent_entry_option. unwrap ( ) ;
@@ -226,10 +233,10 @@ pub fn build_server(tracker: Arc<TorrentTracker>) -> Server<impl Filter<Extract
226
233
} )
227
234
. and_then ( |( info_hash, tracker) : ( InfoHash , Arc < TorrentTracker > ) | {
228
235
async move {
229
- match tracker. remove_torrent_from_whitelist ( & info_hash) . await {
230
- Ok ( _) => Ok ( warp:: reply:: json ( & ActionStatus :: Ok ) ) ,
231
- Err ( _) => Err ( warp:: reject:: custom ( ActionStatus :: Err { reason : "failed to remove torrent from whitelist" . into ( ) } ) )
232
- }
236
+ match tracker. remove_torrent_from_whitelist ( & info_hash) . await {
237
+ Ok ( _) => Ok ( warp:: reply:: json ( & ActionStatus :: Ok ) ) ,
238
+ Err ( _) => Err ( warp:: reject:: custom ( ActionStatus :: Err { reason : "failed to remove torrent from whitelist" . into ( ) } ) )
239
+ }
233
240
}
234
241
} ) ;
235
242
@@ -286,13 +293,53 @@ pub fn build_server(tracker: Arc<TorrentTracker>) -> Server<impl Filter<Extract
286
293
} )
287
294
. and_then ( |( key, tracker) : ( String , Arc < TorrentTracker > ) | {
288
295
async move {
289
- match tracker. remove_auth_key ( key) . await {
296
+ match tracker. remove_auth_key ( & key) . await {
290
297
Ok ( _) => Ok ( warp:: reply:: json ( & ActionStatus :: Ok ) ) ,
291
298
Err ( _) => Err ( warp:: reject:: custom ( ActionStatus :: Err { reason : "failed to delete key" . into ( ) } ) )
292
299
}
293
300
}
294
301
} ) ;
295
302
303
+ // GET /api/whitelist/reload
304
+ // Reload whitelist
305
+ let t7 = tracker. clone ( ) ;
306
+ let reload_whitelist = filters:: method:: get ( )
307
+ . and ( filters:: path:: path ( "whitelist" ) )
308
+ . and ( filters:: path:: path ( "reload" ) )
309
+ . and ( filters:: path:: end ( ) )
310
+ . map ( move || {
311
+ let tracker = t7. clone ( ) ;
312
+ tracker
313
+ } )
314
+ . and_then ( |tracker : Arc < TorrentTracker > | {
315
+ async move {
316
+ match tracker. load_whitelist ( ) . await {
317
+ Ok ( _) => Ok ( warp:: reply:: json ( & ActionStatus :: Ok ) ) ,
318
+ Err ( _) => Err ( warp:: reject:: custom ( ActionStatus :: Err { reason : "failed to reload whitelist" . into ( ) } ) )
319
+ }
320
+ }
321
+ } ) ;
322
+
323
+ // GET /api/keys/reload
324
+ // Reload whitelist
325
+ let t8 = tracker. clone ( ) ;
326
+ let reload_keys = filters:: method:: get ( )
327
+ . and ( filters:: path:: path ( "keys" ) )
328
+ . and ( filters:: path:: path ( "reload" ) )
329
+ . and ( filters:: path:: end ( ) )
330
+ . map ( move || {
331
+ let tracker = t8. clone ( ) ;
332
+ tracker
333
+ } )
334
+ . and_then ( |tracker : Arc < TorrentTracker > | {
335
+ async move {
336
+ match tracker. load_keys ( ) . await {
337
+ Ok ( _) => Ok ( warp:: reply:: json ( & ActionStatus :: Ok ) ) ,
338
+ Err ( _) => Err ( warp:: reject:: custom ( ActionStatus :: Err { reason : "failed to reload keys" . into ( ) } ) )
339
+ }
340
+ }
341
+ } ) ;
342
+
296
343
let api_routes =
297
344
filters:: path:: path ( "api" )
298
345
. and ( view_torrent_list
@@ -302,9 +349,17 @@ pub fn build_server(tracker: Arc<TorrentTracker>) -> Server<impl Filter<Extract
302
349
. or ( add_torrent)
303
350
. or ( create_key)
304
351
. or ( delete_key)
352
+ . or ( reload_whitelist)
353
+ . or ( reload_keys)
305
354
) ;
306
355
307
356
let server = api_routes. and ( authenticate ( tracker. config . http_api . access_tokens . clone ( ) ) ) ;
308
357
309
- serve ( server)
358
+ let ( _addr, api_server) = serve ( server) . bind_with_graceful_shutdown ( socket_addr, async move {
359
+ tokio:: signal:: ctrl_c ( )
360
+ . await
361
+ . expect ( "Failed to listen to shutdown signal." ) ;
362
+ } ) ;
363
+
364
+ api_server
310
365
}
0 commit comments