Skip to content

Commit bbfca2c

Browse files
committed
feat: [#639] Tracker Checker. Check UDP trackers
This is the first working implementation. WIP. TODO: - Refactor: reorganize code: big functions, etc. - Bugs: if the UDP server is down the checker waits forever. Probably there is a missing timeout for the connection request. And in general for all requests.
1 parent 661b521 commit bbfca2c

File tree

1 file changed

+72
-44
lines changed

1 file changed

+72
-44
lines changed

src/console/clients/checker/service.rs

+72-44
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,25 @@ use std::str::FromStr;
33
use std::sync::Arc;
44
use std::time::Duration;
55

6+
use aquatic_udp_protocol::{Port, TransactionId};
67
use colored::Colorize;
8+
use hex_literal::hex;
79
use log::debug;
810
use reqwest::{Client as HttpClient, Url};
911

1012
use super::config::Configuration;
1113
use super::console::Console;
1214
use crate::console::clients::checker::printer::Printer;
15+
use crate::console::clients::udp::checker;
1316
use crate::shared::bit_torrent::info_hash::InfoHash;
1417
use crate::shared::bit_torrent::tracker::http::client::requests::announce::QueryBuilder;
1518
use crate::shared::bit_torrent::tracker::http::client::responses::announce::Announce;
1619
use crate::shared::bit_torrent::tracker::http::client::responses::scrape;
1720
use crate::shared::bit_torrent::tracker::http::client::{requests, Client};
1821

22+
const ASSIGNED_BY_OS: u16 = 0;
23+
const RANDOM_TRANSACTION_ID: i32 = -888_840_697;
24+
1925
pub struct Service {
2026
pub(crate) config: Arc<Configuration>,
2127
pub(crate) console: Console,
@@ -25,7 +31,7 @@ pub type CheckResult = Result<(), CheckError>;
2531

2632
#[derive(Debug)]
2733
pub enum CheckError {
28-
UdpError,
34+
UdpError { socket_addr: SocketAddr },
2935
HttpError { url: Url },
3036
HealthCheckError { url: Url },
3137
}
@@ -54,37 +60,63 @@ impl Service {
5460
for udp_tracker in &self.config.udp_trackers {
5561
let colored_tracker_url = udp_tracker.to_string().yellow();
5662

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));
75105
}
76106

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));
88120
}
89121
}
90122
}
@@ -99,7 +131,7 @@ impl Service {
99131
Ok(()) => {
100132
check_results.push(Ok(()));
101133
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));
103135
}
104136
Err(err) => {
105137
check_results.push(Err(err));
@@ -112,7 +144,7 @@ impl Service {
112144
Ok(()) => {
113145
check_results.push(Ok(()));
114146
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));
116148
}
117149
Err(err) => {
118150
check_results.push(Err(err));
@@ -134,22 +166,14 @@ impl Service {
134166
}
135167
}
136168

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-
149169
async fn check_http_announce(&self, tracker_url: &Url) -> Result<(), CheckError> {
150170
let info_hash_str = "9c38422213e30bff212b30c360d26f9a02136422".to_string(); // # DevSkim: ignore DS173237
151171
let info_hash = InfoHash::from_str(&info_hash_str).expect("a valid info-hash is required");
152172

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.
153177
let response = Client::new(tracker_url.clone())
154178
.announce(&QueryBuilder::with_default_values().with_info_hash(&info_hash).query())
155179
.await;
@@ -174,6 +198,10 @@ impl Service {
174198
let info_hashes: Vec<String> = vec!["9c38422213e30bff212b30c360d26f9a02136422".to_string()]; // # DevSkim: ignore DS173237
175199
let query = requests::scrape::Query::try_from(info_hashes).expect("a valid array of info-hashes is required");
176200

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.
177205
let response = Client::new(url.clone()).scrape(&query).await;
178206

179207
if let Ok(body) = response.bytes().await {

0 commit comments

Comments
 (0)