11use core:: panic;
22use std:: env;
3+ use std:: fmt:: { Display , Formatter , Result } ;
34use std:: net:: { IpAddr , Ipv4Addr , SocketAddr } ;
45use std:: sync:: Arc ;
56
67use aquatic_udp_protocol:: { AnnounceEvent , NumberOfBytes } ;
78use reqwest:: Response ;
8- use torrust_tracker:: api:: resource:: auth_key:: AuthKey ;
9- use torrust_tracker:: api:: resource:: stats:: Stats ;
10- use torrust_tracker:: api:: resource:: torrent:: { self , Torrent } ;
119use torrust_tracker:: config:: Configuration ;
1210use torrust_tracker:: jobs:: tracker_api;
1311use torrust_tracker:: protocol:: clock:: DurationSinceUnixEpoch ;
@@ -51,14 +49,21 @@ pub fn tracker_configuration() -> Arc<Configuration> {
5149#[ derive( Clone ) ]
5250pub struct ConnectionInfo {
5351 pub bind_address : String ,
54- pub api_token : String ,
52+ pub api_token : Option < String > ,
5553}
5654
5755impl ConnectionInfo {
58- pub fn new ( bind_address : & str , api_token : & str ) -> Self {
56+ pub fn authenticated ( bind_address : & str , api_token : & str ) -> Self {
5957 Self {
6058 bind_address : bind_address. to_string ( ) ,
61- api_token : api_token. to_string ( ) ,
59+ api_token : Some ( api_token. to_string ( ) ) ,
60+ }
61+ }
62+
63+ pub fn anonymous ( bind_address : & str ) -> Self {
64+ Self {
65+ bind_address : bind_address. to_string ( ) ,
66+ api_token : None ,
6267 }
6368 }
6469}
@@ -73,7 +78,7 @@ pub async fn start_custom_api_server(configuration: Arc<Configuration>) -> Serve
7378}
7479
7580async fn start ( configuration : Arc < Configuration > ) -> Server {
76- let connection_info = ConnectionInfo :: new (
81+ let connection_info = ConnectionInfo :: authenticated (
7782 & configuration. http_api . bind_address . clone ( ) ,
7883 & configuration. http_api . access_tokens . get_key_value ( "admin" ) . unwrap ( ) . 1 . clone ( ) ,
7984 ) ;
@@ -117,6 +122,10 @@ impl Server {
117122 self . connection_info . clone ( )
118123 }
119124
125+ pub fn get_bind_address ( & self ) -> String {
126+ self . connection_info . bind_address . clone ( )
127+ }
128+
120129 /// Add a torrent to the tracker
121130 pub async fn add_torrent ( & self , info_hash : & InfoHash , peer : & Peer ) {
122131 self . tracker . update_torrent_with_peer_and_get_stats ( info_hash, peer) . await ;
@@ -127,53 +136,168 @@ pub struct Client {
127136 connection_info : ConnectionInfo ,
128137}
129138
139+ type ReqwestQuery = Vec < ReqwestQueryParam > ;
140+ type ReqwestQueryParam = ( String , String ) ;
141+
142+ #[ derive( Default , Debug ) ]
143+ pub struct Query {
144+ params : Vec < QueryParam > ,
145+ }
146+
147+ impl Query {
148+ pub fn empty ( ) -> Self {
149+ Self { params : vec ! [ ] }
150+ }
151+
152+ pub fn params ( params : Vec < QueryParam > ) -> Self {
153+ Self { params }
154+ }
155+
156+ pub fn add_param ( & mut self , param : QueryParam ) {
157+ self . params . push ( param) ;
158+ }
159+
160+ fn with_token ( token : & str ) -> Self {
161+ Self {
162+ params : vec ! [ QueryParam :: new( "token" , token) ] ,
163+ }
164+ }
165+ }
166+
167+ impl From < Query > for ReqwestQuery {
168+ fn from ( url_search_params : Query ) -> Self {
169+ url_search_params
170+ . params
171+ . iter ( )
172+ . map ( |param| ReqwestQueryParam :: from ( ( * param) . clone ( ) ) )
173+ . collect ( )
174+ }
175+ }
176+
177+ #[ derive( Clone , Debug ) ]
178+ pub struct QueryParam {
179+ name : UrlEncoded ,
180+ value : UrlEncoded ,
181+ }
182+
183+ impl QueryParam {
184+ pub fn new ( name : & str , value : & str ) -> Self {
185+ Self {
186+ name : UrlEncoded :: new ( name) ,
187+ value : UrlEncoded :: new ( value) ,
188+ }
189+ }
190+ }
191+
192+ impl From < QueryParam > for ReqwestQueryParam {
193+ fn from ( param : QueryParam ) -> Self {
194+ ( param. name . to_string ( ) , param. value . to_string ( ) )
195+ }
196+ }
197+
198+ #[ derive( Clone , Debug ) ]
199+ pub struct UrlEncoded {
200+ value : String ,
201+ }
202+
203+ impl UrlEncoded {
204+ fn new ( value : & str ) -> Self {
205+ Self {
206+ value : value. to_string ( ) , // todo encode
207+ }
208+ }
209+ }
210+
211+ impl Display for UrlEncoded {
212+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> Result {
213+ write ! ( f, "{}" , self . value)
214+ }
215+ }
216+
130217impl Client {
131218 pub fn new ( connection_info : ConnectionInfo ) -> Self {
132219 Self { connection_info }
133220 }
134221
135- pub async fn generate_auth_key ( & self , seconds_valid : i32 ) -> AuthKey {
136- self . post ( & format ! ( "key/{}" , & seconds_valid) ) . await . json ( ) . await . unwrap ( )
222+ pub async fn generate_auth_key ( & self , seconds_valid : i32 ) -> Response {
223+ self . post ( & format ! ( "key/{}" , & seconds_valid) ) . await
224+ }
225+
226+ pub async fn delete_auth_key ( & self , key : & str ) -> Response {
227+ self . delete ( & format ! ( "key/{}" , & key) ) . await
228+ }
229+
230+ pub async fn reload_keys ( & self ) -> Response {
231+ self . get ( "keys/reload" , Query :: default ( ) ) . await
137232 }
138233
139234 pub async fn whitelist_a_torrent ( & self , info_hash : & str ) -> Response {
140235 self . post ( & format ! ( "whitelist/{}" , & info_hash) ) . await
141236 }
142237
143- pub async fn get_torrent ( & self , info_hash : & str ) -> Torrent {
144- self . get ( & format ! ( "torrent/{}" , & info_hash) )
145- . await
146- . json :: < Torrent > ( )
147- . await
148- . unwrap ( )
238+ pub async fn remove_torrent_from_whitelist ( & self , info_hash : & str ) -> Response {
239+ self . delete ( & format ! ( "whitelist/{}" , & info_hash) ) . await
149240 }
150241
151- pub async fn get_torrents ( & self ) -> Vec < torrent :: ListItem > {
152- self . get ( "torrents" ) . await . json :: < Vec < torrent :: ListItem > > ( ) . await . unwrap ( )
242+ pub async fn reload_whitelist ( & self ) -> Response {
243+ self . get ( "whitelist/reload" , Query :: default ( ) ) . await
153244 }
154245
155- pub async fn get_tracker_statistics ( & self ) -> Stats {
156- self . get ( "stats" ) . await . json :: < Stats > ( ) . await . unwrap ( )
246+ pub async fn get_torrent ( & self , info_hash : & str ) -> Response {
247+ self . get ( & format ! ( "torrent/{}" , & info_hash ) , Query :: default ( ) ) . await
157248 }
158249
159- async fn get ( & self , path : & str ) -> Response {
250+ pub async fn get_torrents ( & self , params : Query ) -> Response {
251+ self . get ( "torrents" , params) . await
252+ }
253+
254+ pub async fn get_tracker_statistics ( & self ) -> Response {
255+ self . get ( "stats" , Query :: default ( ) ) . await
256+ }
257+
258+ async fn get ( & self , path : & str , params : Query ) -> Response {
259+ let mut query: Query = params;
260+
261+ if let Some ( token) = & self . connection_info . api_token {
262+ query. add_param ( QueryParam :: new ( "token" , token) ) ;
263+ } ;
264+
160265 reqwest:: Client :: builder ( )
161266 . build ( )
162267 . unwrap ( )
163- . get ( self . url ( path) )
268+ . get ( self . base_url ( path) )
269+ . query ( & ReqwestQuery :: from ( query) )
164270 . send ( )
165271 . await
166272 . unwrap ( )
167273 }
168274
169275 async fn post ( & self , path : & str ) -> Response {
170- reqwest:: Client :: new ( ) . post ( self . url ( path) . clone ( ) ) . send ( ) . await . unwrap ( )
276+ reqwest:: Client :: new ( )
277+ . post ( self . base_url ( path) . clone ( ) )
278+ . query ( & ReqwestQuery :: from ( self . query_with_token ( ) ) )
279+ . send ( )
280+ . await
281+ . unwrap ( )
171282 }
172283
173- fn url ( & self , path : & str ) -> String {
174- format ! (
175- "http://{}/api/{path}?token={}" ,
176- & self . connection_info. bind_address, & self . connection_info. api_token
177- )
284+ async fn delete ( & self , path : & str ) -> Response {
285+ reqwest:: Client :: new ( )
286+ . delete ( self . base_url ( path) . clone ( ) )
287+ . query ( & ReqwestQuery :: from ( self . query_with_token ( ) ) )
288+ . send ( )
289+ . await
290+ . unwrap ( )
291+ }
292+
293+ fn base_url ( & self , path : & str ) -> String {
294+ format ! ( "http://{}/api/{path}" , & self . connection_info. bind_address)
295+ }
296+
297+ fn query_with_token ( & self ) -> Query {
298+ match & self . connection_info . api_token {
299+ Some ( token) => Query :: with_token ( token) ,
300+ None => Query :: default ( ) ,
301+ }
178302 }
179303}
0 commit comments