1- use crate :: tracker:: { TorrentTracker } ;
2- use serde:: { Deserialize , Serialize } ;
31use std:: cmp:: min;
42use std:: collections:: { HashMap , HashSet } ;
3+ use std:: net:: SocketAddr ;
54use 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 ;
912
1013#[ derive( Deserialize , Debug ) ]
1114struct TorrentInfoQuery {
@@ -20,7 +23,7 @@ struct Torrent<'a> {
2023 completed : u32 ,
2124 leechers : u32 ,
2225 #[ serde( skip_serializing_if = "Option::is_none" ) ]
23- peers : Option < Vec < TorrentPeer > > ,
26+ peers : Option < Vec < & ' a TorrentPeer > > ,
2427}
2528
2629#[ derive( Serialize ) ]
@@ -52,7 +55,7 @@ enum ActionStatus<'a> {
5255
5356impl warp:: reject:: Reject for ActionStatus < ' static > { }
5457
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 {
5659 #[ derive( Deserialize ) ]
5760 struct AuthToken {
5861 token : Option < String > ,
@@ -69,7 +72,7 @@ fn authenticate(tokens: HashMap<String, String>) -> impl Filter<Extract = (), Er
6972 match token. token {
7073 Some ( token) => {
7174 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 ( ) } ) ) ;
7376 }
7477
7578 Ok ( ( ) )
@@ -81,7 +84,7 @@ fn authenticate(tokens: HashMap<String, String>) -> impl Filter<Extract = (), Er
8184 . untuple_one ( )
8285}
8386
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 = ( ) > {
8588 // GET /api/torrents?offset=:u32&limit=:u32
8689 // View torrent list
8790 let api_torrents = tracker. clone ( ) ;
@@ -131,7 +134,7 @@ pub fn build_server(tracker: Arc<TorrentTracker>) -> Server<impl Filter<Extract
131134 } )
132135 . and_then ( |tracker : Arc < TorrentTracker > | {
133136 async move {
134- let mut results = Stats {
137+ let mut results = Stats {
135138 torrents : 0 ,
136139 seeders : 0 ,
137140 completed : 0 ,
@@ -147,9 +150,11 @@ pub fn build_server(tracker: Arc<TorrentTracker>) -> Server<impl Filter<Extract
147150 udp4_scrapes_handled : 0 ,
148151 udp6_connections_handled : 0 ,
149152 udp6_announces_handled : 0 ,
150- udp6_scrapes_handled : 0
153+ udp6_scrapes_handled : 0 ,
151154 } ;
155+
152156 let db = tracker. get_torrents ( ) . await ;
157+
153158 let _: Vec < _ > = db
154159 . iter ( )
155160 . map ( |( _info_hash, torrent_entry) | {
@@ -160,7 +165,9 @@ pub fn build_server(tracker: Arc<TorrentTracker>) -> Server<impl Filter<Extract
160165 results. torrents += 1 ;
161166 } )
162167 . collect ( ) ;
168+
163169 let stats = tracker. get_stats ( ) . await ;
170+
164171 results. tcp4_connections_handled = stats. tcp4_connections_handled as u32 ;
165172 results. tcp4_announces_handled = stats. tcp4_announces_handled as u32 ;
166173 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
195202 let torrent_entry_option = db. get ( & info_hash) ;
196203
197204 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" ) )
199206 }
200207
201208 let torrent_entry = torrent_entry_option. unwrap ( ) ;
@@ -226,10 +233,10 @@ pub fn build_server(tracker: Arc<TorrentTracker>) -> Server<impl Filter<Extract
226233 } )
227234 . and_then ( |( info_hash, tracker) : ( InfoHash , Arc < TorrentTracker > ) | {
228235 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+ }
233240 }
234241 } ) ;
235242
@@ -286,13 +293,53 @@ pub fn build_server(tracker: Arc<TorrentTracker>) -> Server<impl Filter<Extract
286293 } )
287294 . and_then ( |( key, tracker) : ( String , Arc < TorrentTracker > ) | {
288295 async move {
289- match tracker. remove_auth_key ( key) . await {
296+ match tracker. remove_auth_key ( & key) . await {
290297 Ok ( _) => Ok ( warp:: reply:: json ( & ActionStatus :: Ok ) ) ,
291298 Err ( _) => Err ( warp:: reject:: custom ( ActionStatus :: Err { reason : "failed to delete key" . into ( ) } ) )
292299 }
293300 }
294301 } ) ;
295302
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+
296343 let api_routes =
297344 filters:: path:: path ( "api" )
298345 . and ( view_torrent_list
@@ -302,9 +349,17 @@ pub fn build_server(tracker: Arc<TorrentTracker>) -> Server<impl Filter<Extract
302349 . or ( add_torrent)
303350 . or ( create_key)
304351 . or ( delete_key)
352+ . or ( reload_whitelist)
353+ . or ( reload_keys)
305354 ) ;
306355
307356 let server = api_routes. and ( authenticate ( tracker. config . http_api . access_tokens . clone ( ) ) ) ;
308357
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
310365}
0 commit comments