@@ -3,19 +3,25 @@ use std::str::FromStr;
3
3
use std:: sync:: Arc ;
4
4
use std:: time:: Duration ;
5
5
6
+ use aquatic_udp_protocol:: { Port , TransactionId } ;
6
7
use colored:: Colorize ;
8
+ use hex_literal:: hex;
7
9
use log:: debug;
8
10
use reqwest:: { Client as HttpClient , Url } ;
9
11
10
12
use super :: config:: Configuration ;
11
13
use super :: console:: Console ;
12
14
use crate :: console:: clients:: checker:: printer:: Printer ;
15
+ use crate :: console:: clients:: udp:: checker;
13
16
use crate :: shared:: bit_torrent:: info_hash:: InfoHash ;
14
17
use crate :: shared:: bit_torrent:: tracker:: http:: client:: requests:: announce:: QueryBuilder ;
15
18
use crate :: shared:: bit_torrent:: tracker:: http:: client:: responses:: announce:: Announce ;
16
19
use crate :: shared:: bit_torrent:: tracker:: http:: client:: responses:: scrape;
17
20
use crate :: shared:: bit_torrent:: tracker:: http:: client:: { requests, Client } ;
18
21
22
+ const ASSIGNED_BY_OS : u16 = 0 ;
23
+ const RANDOM_TRANSACTION_ID : i32 = -888_840_697 ;
24
+
19
25
pub struct Service {
20
26
pub ( crate ) config : Arc < Configuration > ,
21
27
pub ( crate ) console : Console ,
@@ -25,7 +31,7 @@ pub type CheckResult = Result<(), CheckError>;
25
31
26
32
#[ derive( Debug ) ]
27
33
pub enum CheckError {
28
- UdpError ,
34
+ UdpError { socket_addr : SocketAddr } ,
29
35
HttpError { url : Url } ,
30
36
HealthCheckError { url : Url } ,
31
37
}
@@ -54,37 +60,63 @@ impl Service {
54
60
for udp_tracker in & self . config . udp_trackers {
55
61
let colored_tracker_url = udp_tracker. to_string ( ) . yellow ( ) ;
56
62
57
- /* todo:
58
- - Initialize the UDP client
59
- - Pass the connected client the the check function
60
- - Connect to the tracker
61
- - Make the request (announce or scrape)
62
- */
63
-
64
- match self . check_udp_announce ( udp_tracker) . await {
65
- Ok ( ( ) ) => {
66
- check_results. push ( Ok ( ( ) ) ) ;
67
- self . console
68
- . println ( & format ! ( "{} - Announce at {} is OK" , "✓" . green( ) , colored_tracker_url) ) ;
69
- }
70
- Err ( err) => {
71
- check_results. push ( Err ( err) ) ;
72
- self . console
73
- . println ( & format ! ( "{} - Announce at {} is failing" , "✗" . red( ) , colored_tracker_url) ) ;
74
- }
63
+ let transaction_id = TransactionId ( RANDOM_TRANSACTION_ID ) ;
64
+
65
+ let mut client = checker:: Client :: default ( ) ;
66
+
67
+ let Ok ( bound_to) = client. bind_and_connect ( ASSIGNED_BY_OS , udp_tracker) . await else {
68
+ check_results. push ( Err ( CheckError :: UdpError {
69
+ socket_addr : * udp_tracker,
70
+ } ) ) ;
71
+ self . console
72
+ . println ( & format ! ( "{} - Can't connect to socket {}" , "✗" . red( ) , colored_tracker_url) ) ;
73
+ break ;
74
+ } ;
75
+
76
+ let Ok ( connection_id) = client. send_connection_request ( transaction_id) . await else {
77
+ check_results. push ( Err ( CheckError :: UdpError {
78
+ socket_addr : * udp_tracker,
79
+ } ) ) ;
80
+ self . console . println ( & format ! (
81
+ "{} - Can't make tracker connection request to {}" ,
82
+ "✗" . red( ) ,
83
+ colored_tracker_url
84
+ ) ) ;
85
+ break ;
86
+ } ;
87
+
88
+ let info_hash = InfoHash ( hex ! ( "9c38422213e30bff212b30c360d26f9a02136422" ) ) ; // # DevSkim: ignore DS173237
89
+
90
+ if ( client
91
+ . send_announce_request ( connection_id, transaction_id, info_hash, Port ( bound_to. port ( ) ) )
92
+ . await )
93
+ . is_ok ( )
94
+ {
95
+ check_results. push ( Ok ( ( ) ) ) ;
96
+ self . console
97
+ . println ( & format ! ( "{} - Announce at {} is OK" , "✓" . green( ) , colored_tracker_url) ) ;
98
+ } else {
99
+ let err = CheckError :: UdpError {
100
+ socket_addr : * udp_tracker,
101
+ } ;
102
+ check_results. push ( Err ( err) ) ;
103
+ self . console
104
+ . println ( & format ! ( "{} - Announce at {} is failing" , "✗" . red( ) , colored_tracker_url) ) ;
75
105
}
76
106
77
- match self . check_udp_scrape ( udp_tracker) . await {
78
- Ok ( ( ) ) => {
79
- check_results. push ( Ok ( ( ) ) ) ;
80
- self . console
81
- . println ( & format ! ( "{} - Scrape at {} is OK" , "✓" . green( ) , colored_tracker_url) ) ;
82
- }
83
- Err ( err) => {
84
- check_results. push ( Err ( err) ) ;
85
- self . console
86
- . println ( & format ! ( "{} - Scrape at {} is failing" , "✗" . red( ) , colored_tracker_url) ) ;
87
- }
107
+ let info_hashes = vec ! [ InfoHash ( hex!( "9c38422213e30bff212b30c360d26f9a02136422" ) ) ] ; // # DevSkim: ignore DS173237
108
+
109
+ if ( client. send_scrape_request ( connection_id, transaction_id, info_hashes) . await ) . is_ok ( ) {
110
+ check_results. push ( Ok ( ( ) ) ) ;
111
+ self . console
112
+ . println ( & format ! ( "{} - Announce at {} is OK" , "✓" . green( ) , colored_tracker_url) ) ;
113
+ } else {
114
+ let err = CheckError :: UdpError {
115
+ socket_addr : * udp_tracker,
116
+ } ;
117
+ check_results. push ( Err ( err) ) ;
118
+ self . console
119
+ . println ( & format ! ( "{} - Announce at {} is failing" , "✗" . red( ) , colored_tracker_url) ) ;
88
120
}
89
121
}
90
122
}
@@ -99,7 +131,7 @@ impl Service {
99
131
Ok ( ( ) ) => {
100
132
check_results. push ( Ok ( ( ) ) ) ;
101
133
self . console
102
- . println ( & format ! ( "{} - Announce at {} is OK (TODO) " , "✓" . green( ) , colored_tracker_url) ) ;
134
+ . println ( & format ! ( "{} - Announce at {} is OK" , "✓" . green( ) , colored_tracker_url) ) ;
103
135
}
104
136
Err ( err) => {
105
137
check_results. push ( Err ( err) ) ;
@@ -112,7 +144,7 @@ impl Service {
112
144
Ok ( ( ) ) => {
113
145
check_results. push ( Ok ( ( ) ) ) ;
114
146
self . console
115
- . println ( & format ! ( "{} - Scrape at {} is OK (TODO) " , "✓" . green( ) , colored_tracker_url) ) ;
147
+ . println ( & format ! ( "{} - Scrape at {} is OK" , "✓" . green( ) , colored_tracker_url) ) ;
116
148
}
117
149
Err ( err) => {
118
150
check_results. push ( Err ( err) ) ;
@@ -134,22 +166,14 @@ impl Service {
134
166
}
135
167
}
136
168
137
- #[ allow( clippy:: unused_async) ]
138
- async fn check_udp_announce ( & self , tracker_socket_addr : & SocketAddr ) -> Result < ( ) , CheckError > {
139
- debug ! ( "{tracker_socket_addr}" ) ;
140
- Ok ( ( ) )
141
- }
142
-
143
- #[ allow( clippy:: unused_async) ]
144
- async fn check_udp_scrape ( & self , tracker_socket_addr : & SocketAddr ) -> Result < ( ) , CheckError > {
145
- debug ! ( "{tracker_socket_addr}" ) ;
146
- Ok ( ( ) )
147
- }
148
-
149
169
async fn check_http_announce ( & self , tracker_url : & Url ) -> Result < ( ) , CheckError > {
150
170
let info_hash_str = "9c38422213e30bff212b30c360d26f9a02136422" . to_string ( ) ; // # DevSkim: ignore DS173237
151
171
let info_hash = InfoHash :: from_str ( & info_hash_str) . expect ( "a valid info-hash is required" ) ;
152
172
173
+ // todo: HTTP request could panic.For example, if the server is not accessible.
174
+ // We should change the client to catch that error and return a `CheckError`.
175
+ // Otherwise the checking process will stop. The idea is to process all checks
176
+ // and return a final report.
153
177
let response = Client :: new ( tracker_url. clone ( ) )
154
178
. announce ( & QueryBuilder :: with_default_values ( ) . with_info_hash ( & info_hash) . query ( ) )
155
179
. await ;
@@ -174,6 +198,10 @@ impl Service {
174
198
let info_hashes: Vec < String > = vec ! [ "9c38422213e30bff212b30c360d26f9a02136422" . to_string( ) ] ; // # DevSkim: ignore DS173237
175
199
let query = requests:: scrape:: Query :: try_from ( info_hashes) . expect ( "a valid array of info-hashes is required" ) ;
176
200
201
+ // todo: HTTP request could panic.For example, if the server is not accessible.
202
+ // We should change the client to catch that error and return a `CheckError`.
203
+ // Otherwise the checking process will stop. The idea is to process all checks
204
+ // and return a final report.
177
205
let response = Client :: new ( url. clone ( ) ) . scrape ( & query) . await ;
178
206
179
207
if let Ok ( body) = response. bytes ( ) . await {
0 commit comments