11use std:: cmp:: min;
2- use std:: collections:: { HashMap , HashSet } ;
2+ use std:: collections:: { BTreeMap , HashSet } ;
33use std:: net:: SocketAddr ;
4+ use std:: str:: FromStr ;
45use std:: sync:: Arc ;
56use std:: time:: Duration ;
67
78use serde:: { Deserialize , Serialize } ;
89use warp:: { filters, reply, serve, Filter } ;
910
10- use crate :: peer :: TorrentPeer ;
11+ use crate :: errors :: settings :: ServiceSettingsError ;
1112use crate :: protocol:: common:: * ;
12- use crate :: tracker:: tracker:: TorrentTracker ;
13+ use crate :: settings:: { Service , ServiceProtocol } ;
14+ use crate :: tracker:: core:: TorrentTracker ;
15+ use crate :: tracker:: peer:: TorrentPeer ;
16+ use crate :: { check_field_is_not_empty, check_field_is_not_none} ;
17+
18+ pub type ApiTokens = BTreeMap < String , String > ;
19+
20+ #[ derive( Debug , Clone , Hash , PartialEq , Eq ) ]
21+ pub struct ApiServiceSettings {
22+ pub id : String ,
23+ pub enabled : bool ,
24+ pub display_name : String ,
25+ pub socket : SocketAddr ,
26+ pub access_tokens : ApiTokens ,
27+ }
28+
29+ impl Default for ApiServiceSettings {
30+ fn default ( ) -> Self {
31+ let mut access_tokens = BTreeMap :: new ( ) ;
32+ access_tokens. insert ( "admin" . to_string ( ) , "password" . to_string ( ) ) ;
33+
34+ Self {
35+ id : "default_api" . to_string ( ) ,
36+ enabled : false ,
37+ display_name : "HTTP API (default)" . to_string ( ) ,
38+ socket : SocketAddr :: from_str ( "127.0.0.1:1212" ) . unwrap ( ) ,
39+ access_tokens,
40+ }
41+ }
42+ }
43+
44+ impl TryFrom < ( & String , & Service ) > for ApiServiceSettings {
45+ type Error = ServiceSettingsError ;
46+
47+ fn try_from ( value : ( & String , & Service ) ) -> Result < Self , Self :: Error > {
48+ check_field_is_not_none ! ( value. 1 => ServiceSettingsError ;
49+ enabled, service) ;
50+
51+ if value. 1 . service . unwrap ( ) != ServiceProtocol :: Api {
52+ return Err ( ServiceSettingsError :: WrongService {
53+ field : "service" . to_string ( ) ,
54+ expected : ServiceProtocol :: Api ,
55+ found : value. 1 . service . unwrap ( ) ,
56+ data : value. 1 . into ( ) ,
57+ } ) ;
58+ }
59+
60+ check_field_is_not_empty ! ( value. 1 => ServiceSettingsError ;
61+ display_name: String ) ;
62+
63+ Ok ( Self {
64+ id : value. 0 . to_owned ( ) ,
65+ enabled : value. 1 . enabled . unwrap ( ) ,
66+ display_name : value. 1 . display_name . to_owned ( ) . unwrap ( ) ,
67+ socket : value. 1 . get_socket ( ) ?,
68+ access_tokens : value. 1 . get_api_tokens ( ) ?,
69+ } )
70+ }
71+ }
1372
1473#[ derive( Deserialize , Debug ) ]
1574struct TorrentInfoQuery {
@@ -56,7 +115,7 @@ enum ActionStatus<'a> {
56115
57116impl warp:: reject:: Reject for ActionStatus < ' static > { }
58117
59- fn authenticate ( tokens : HashMap < String , String > ) -> impl Filter < Extract = ( ) , Error = warp:: reject:: Rejection > + Clone {
118+ fn authenticate ( tokens : ApiTokens ) -> impl Filter < Extract = ( ) , Error = warp:: reject:: Rejection > + Clone {
60119 #[ derive( Deserialize ) ]
61120 struct AuthToken {
62121 token : Option < String > ,
@@ -87,7 +146,7 @@ fn authenticate(tokens: HashMap<String, String>) -> impl Filter<Extract = (), Er
87146 . untuple_one ( )
88147}
89148
90- pub fn start ( socket_addr : SocketAddr , tracker : Arc < TorrentTracker > ) -> impl warp:: Future < Output = ( ) > {
149+ pub fn start ( settings : & ApiServiceSettings , tracker : Arc < TorrentTracker > ) -> impl warp:: Future < Output = ( ) > {
91150 // GET /api/torrents?offset=:u32&limit=:u32
92151 // View torrent list
93152 let api_torrents = tracker. clone ( ) ;
@@ -129,10 +188,7 @@ pub fn start(socket_addr: SocketAddr, tracker: Arc<TorrentTracker>) -> impl warp
129188 let view_stats_list = filters:: method:: get ( )
130189 . and ( filters:: path:: path ( "stats" ) )
131190 . and ( filters:: path:: end ( ) )
132- . map ( move || {
133- let tracker = api_stats. clone ( ) ;
134- tracker
135- } )
191+ . map ( move || api_stats. clone ( ) )
136192 . and_then ( |tracker : Arc < TorrentTracker > | async move {
137193 let mut results = Stats {
138194 torrents : 0 ,
@@ -304,10 +360,7 @@ pub fn start(socket_addr: SocketAddr, tracker: Arc<TorrentTracker>) -> impl warp
304360 . and ( filters:: path:: path ( "whitelist" ) )
305361 . and ( filters:: path:: path ( "reload" ) )
306362 . and ( filters:: path:: end ( ) )
307- . map ( move || {
308- let tracker = t7. clone ( ) ;
309- tracker
310- } )
363+ . map ( move || t7. clone ( ) )
311364 . and_then ( |tracker : Arc < TorrentTracker > | async move {
312365 match tracker. load_whitelist ( ) . await {
313366 Ok ( _) => Ok ( warp:: reply:: json ( & ActionStatus :: Ok ) ) ,
@@ -319,15 +372,12 @@ pub fn start(socket_addr: SocketAddr, tracker: Arc<TorrentTracker>) -> impl warp
319372
320373 // GET /api/keys/reload
321374 // Reload whitelist
322- let t8 = tracker. clone ( ) ;
375+ let t8 = tracker;
323376 let reload_keys = filters:: method:: get ( )
324377 . and ( filters:: path:: path ( "keys" ) )
325378 . and ( filters:: path:: path ( "reload" ) )
326379 . and ( filters:: path:: end ( ) )
327- . map ( move || {
328- let tracker = t8. clone ( ) ;
329- tracker
330- } )
380+ . map ( move || t8. clone ( ) )
331381 . and_then ( |tracker : Arc < TorrentTracker > | async move {
332382 match tracker. load_keys ( ) . await {
333383 Ok ( _) => Ok ( warp:: reply:: json ( & ActionStatus :: Ok ) ) ,
@@ -349,9 +399,9 @@ pub fn start(socket_addr: SocketAddr, tracker: Arc<TorrentTracker>) -> impl warp
349399 . or ( reload_keys) ,
350400 ) ;
351401
352- let server = api_routes. and ( authenticate ( tracker . config . http_api . access_tokens . clone ( ) ) ) ;
402+ let server = api_routes. and ( authenticate ( settings . access_tokens . to_owned ( ) ) ) ;
353403
354- let ( _addr, api_server) = serve ( server) . bind_with_graceful_shutdown ( socket_addr , async move {
404+ let ( _addr, api_server) = serve ( server) . bind_with_graceful_shutdown ( settings . socket , async move {
355405 tokio:: signal:: ctrl_c ( ) . await . expect ( "Failed to listen to shutdown signal." ) ;
356406 } ) ;
357407
0 commit comments