-
Notifications
You must be signed in to change notification settings - Fork 57
Expand file tree
/
Copy pathscrape.rs
More file actions
138 lines (119 loc) · 4.74 KB
/
Copy pathscrape.rs
File metadata and controls
138 lines (119 loc) · 4.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
//! The `scrape` service.
//!
//! The service is responsible for handling the `scrape` requests.
//!
//! It delegates the `scrape` logic to the [`ScrapeHandler`] and it returns the
//! [`ScrapeData`].
//!
//! It also sends an [`udp_tracker_core::statistics::event::Event`]
//! because events are specific for the UDP tracker.
use std::net::SocketAddr;
use std::ops::Range;
use std::sync::Arc;
use torrust_info_hash::InfoHash;
use torrust_net_primitives::service_binding::ServiceBinding;
use torrust_tracker_core::error::{ScrapeError, WhitelistError};
use torrust_tracker_core::scrape_handler::ScrapeHandler;
use torrust_tracker_primitives::ScrapeData;
use torrust_tracker_udp_protocol::ScrapeRequest;
use crate::connection_cookie::{ConnectionCookieError, check, gen_remote_fingerprint};
use crate::event::{ConnectionContext, Event};
/// The `ScrapeService` is responsible for handling the `scrape` requests.
///
/// The service sends an statistics event that increments:
///
/// - The number of UDP `scrape` requests handled by the UDP tracker.
pub struct ScrapeService {
scrape_handler: Arc<ScrapeHandler>,
opt_udp_stats_event_sender: crate::event::sender::Sender,
}
impl ScrapeService {
#[must_use]
pub fn new(scrape_handler: Arc<ScrapeHandler>, opt_udp_stats_event_sender: crate::event::sender::Sender) -> Self {
Self {
scrape_handler,
opt_udp_stats_event_sender,
}
}
/// It handles the `Scrape` request.
///
/// # Errors
///
/// It will return an error if cookie validation fails and `validate_cookie`
/// is `true`, or if the tracker core scrape handler returns an error.
///
/// When `validate_cookie` is `false` the connection ID is not validated.
/// The caller is responsible for any metric or event emission related to
/// the skipped validation.
pub async fn handle_scrape(
&self,
client_socket_addr: SocketAddr,
server_service_binding: ServiceBinding,
request: &ScrapeRequest,
cookie_valid_range: Range<f64>,
validate_cookie: bool,
) -> Result<ScrapeData, UdpScrapeError> {
if validate_cookie {
Self::authenticate(client_socket_addr, request, cookie_valid_range)?;
}
let scrape_data = self
.scrape_handler
.handle_scrape(&Self::convert_from_wire_info_hashes(&request.info_hashes))
.await?;
self.send_event(client_socket_addr, server_service_binding).await;
Ok(scrape_data)
}
fn authenticate(
remote_addr: SocketAddr,
request: &ScrapeRequest,
cookie_valid_range: Range<f64>,
) -> Result<f64, ConnectionCookieError> {
check(
&request.connection_id,
gen_remote_fingerprint(&remote_addr),
cookie_valid_range,
)
}
fn convert_from_wire_info_hashes(wire_info_hashes: &[torrust_tracker_udp_protocol::common::InfoHash]) -> Vec<InfoHash> {
wire_info_hashes.iter().map(|&x| InfoHash::from(x.0)).collect()
}
async fn send_event(&self, client_socket_addr: SocketAddr, server_service_binding: ServiceBinding) {
if let Some(udp_stats_event_sender) = self.opt_udp_stats_event_sender.as_deref() {
let event = Event::UdpScrape {
connection: ConnectionContext::new(client_socket_addr, server_service_binding),
};
tracing::debug!(target = crate::UDP_TRACKER_LOG_TARGET, "Sending UdpScrape event: {event:?}");
udp_stats_event_sender.send(event).await;
}
}
}
/// Errors related to scrape requests.
#[derive(thiserror::Error, Debug, Clone)]
pub enum UdpScrapeError {
/// Error returned when there was an error with the connection cookie.
#[error("Connection cookie error: {source}")]
ConnectionCookieError { source: ConnectionCookieError },
/// Error returned when there was an error with the tracker core scrape handler.
#[error("Tracker core scrape error: {source}")]
TrackerCoreScrapeError { source: ScrapeError },
/// Error returned when there was an error with the tracker core whitelist.
#[error("Tracker core whitelist error: {source}")]
TrackerCoreWhitelistError { source: WhitelistError },
}
impl From<ConnectionCookieError> for UdpScrapeError {
fn from(connection_cookie_error: ConnectionCookieError) -> Self {
Self::ConnectionCookieError {
source: connection_cookie_error,
}
}
}
impl From<ScrapeError> for UdpScrapeError {
fn from(scrape_error: ScrapeError) -> Self {
Self::TrackerCoreScrapeError { source: scrape_error }
}
}
impl From<WhitelistError> for UdpScrapeError {
fn from(whitelist_error: WhitelistError) -> Self {
Self::TrackerCoreWhitelistError { source: whitelist_error }
}
}