torrust_tracker/servers/http/v1/services/
scrape.rs1use std::net::IpAddr;
12use std::sync::Arc;
13
14use torrust_tracker_primitives::info_hash::InfoHash;
15
16use crate::core::{statistics, ScrapeData, Tracker};
17
18pub async fn invoke(tracker: &Arc<Tracker>, info_hashes: &Vec<InfoHash>, original_peer_ip: &IpAddr) -> ScrapeData {
29 let scrape_data = tracker.scrape(info_hashes).await;
30
31 send_scrape_event(original_peer_ip, tracker).await;
32
33 scrape_data
34}
35
36pub async fn fake(tracker: &Arc<Tracker>, info_hashes: &Vec<InfoHash>, original_peer_ip: &IpAddr) -> ScrapeData {
43 send_scrape_event(original_peer_ip, tracker).await;
44
45 ScrapeData::zeroed(info_hashes)
46}
47
48async fn send_scrape_event(original_peer_ip: &IpAddr, tracker: &Arc<Tracker>) {
49 match original_peer_ip {
50 IpAddr::V4(_) => {
51 tracker.send_stats_event(statistics::Event::Tcp4Scrape).await;
52 }
53 IpAddr::V6(_) => {
54 tracker.send_stats_event(statistics::Event::Tcp6Scrape).await;
55 }
56 }
57}
58
59#[cfg(test)]
60mod tests {
61
62 use std::net::{IpAddr, Ipv4Addr, SocketAddr};
63
64 use aquatic_udp_protocol::{AnnounceEvent, NumberOfBytes, PeerId};
65 use torrust_tracker_primitives::info_hash::InfoHash;
66 use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch};
67 use torrust_tracker_test_helpers::configuration;
68
69 use crate::core::services::tracker_factory;
70 use crate::core::Tracker;
71
72 fn public_tracker() -> Tracker {
73 tracker_factory(&configuration::ephemeral_public())
74 }
75
76 fn sample_info_hashes() -> Vec<InfoHash> {
77 vec![sample_info_hash()]
78 }
79
80 fn sample_info_hash() -> InfoHash {
81 "3b245504cf5f11bbdbe1201cea6a6bf45aee1bc0".parse::<InfoHash>().unwrap()
82 }
83
84 fn sample_peer() -> peer::Peer {
85 peer::Peer {
86 peer_id: PeerId(*b"-qB00000000000000000"),
87 peer_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(126, 0, 0, 1)), 8080),
88 updated: DurationSinceUnixEpoch::new(1_669_397_478_934, 0),
89 uploaded: NumberOfBytes::new(0),
90 downloaded: NumberOfBytes::new(0),
91 left: NumberOfBytes::new(0),
92 event: AnnounceEvent::Started,
93 }
94 }
95
96 mod with_real_data {
97
98 use std::future;
99 use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
100 use std::sync::Arc;
101
102 use mockall::predicate::eq;
103 use torrust_tracker_primitives::swarm_metadata::SwarmMetadata;
104 use torrust_tracker_test_helpers::configuration;
105
106 use crate::core::{statistics, PeersWanted, ScrapeData, Tracker};
107 use crate::servers::http::v1::services::scrape::invoke;
108 use crate::servers::http::v1::services::scrape::tests::{
109 public_tracker, sample_info_hash, sample_info_hashes, sample_peer,
110 };
111
112 #[tokio::test]
113 async fn it_should_return_the_scrape_data_for_a_torrent() {
114 let tracker = Arc::new(public_tracker());
115
116 let info_hash = sample_info_hash();
117 let info_hashes = vec![info_hash];
118
119 let mut peer = sample_peer();
121 let original_peer_ip = peer.ip();
122 tracker.announce(&info_hash, &mut peer, &original_peer_ip, &PeersWanted::All);
123
124 let scrape_data = invoke(&tracker, &info_hashes, &original_peer_ip).await;
125
126 let mut expected_scrape_data = ScrapeData::empty();
127 expected_scrape_data.add_file(
128 &info_hash,
129 SwarmMetadata {
130 complete: 1,
131 downloaded: 0,
132 incomplete: 0,
133 },
134 );
135
136 assert_eq!(scrape_data, expected_scrape_data);
137 }
138
139 #[tokio::test]
140 async fn it_should_send_the_tcp_4_scrape_event_when_the_peer_uses_ipv4() {
141 let mut stats_event_sender_mock = statistics::MockEventSender::new();
142 stats_event_sender_mock
143 .expect_send_event()
144 .with(eq(statistics::Event::Tcp4Scrape))
145 .times(1)
146 .returning(|_| Box::pin(future::ready(Some(Ok(())))));
147 let stats_event_sender = Box::new(stats_event_sender_mock);
148
149 let tracker = Arc::new(
150 Tracker::new(
151 &configuration::ephemeral().core,
152 Some(stats_event_sender),
153 statistics::Repo::new(),
154 )
155 .unwrap(),
156 );
157
158 let peer_ip = IpAddr::V4(Ipv4Addr::new(126, 0, 0, 1));
159
160 invoke(&tracker, &sample_info_hashes(), &peer_ip).await;
161 }
162
163 #[tokio::test]
164 async fn it_should_send_the_tcp_6_scrape_event_when_the_peer_uses_ipv6() {
165 let mut stats_event_sender_mock = statistics::MockEventSender::new();
166 stats_event_sender_mock
167 .expect_send_event()
168 .with(eq(statistics::Event::Tcp6Scrape))
169 .times(1)
170 .returning(|_| Box::pin(future::ready(Some(Ok(())))));
171 let stats_event_sender = Box::new(stats_event_sender_mock);
172
173 let tracker = Arc::new(
174 Tracker::new(
175 &configuration::ephemeral().core,
176 Some(stats_event_sender),
177 statistics::Repo::new(),
178 )
179 .unwrap(),
180 );
181
182 let peer_ip = IpAddr::V6(Ipv6Addr::new(0x6969, 0x6969, 0x6969, 0x6969, 0x6969, 0x6969, 0x6969, 0x6969));
183
184 invoke(&tracker, &sample_info_hashes(), &peer_ip).await;
185 }
186 }
187
188 mod with_zeroed_data {
189
190 use std::future;
191 use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
192 use std::sync::Arc;
193
194 use mockall::predicate::eq;
195 use torrust_tracker_test_helpers::configuration;
196
197 use crate::core::{statistics, PeersWanted, ScrapeData, Tracker};
198 use crate::servers::http::v1::services::scrape::fake;
199 use crate::servers::http::v1::services::scrape::tests::{
200 public_tracker, sample_info_hash, sample_info_hashes, sample_peer,
201 };
202
203 #[tokio::test]
204 async fn it_should_always_return_the_zeroed_scrape_data_for_a_torrent() {
205 let tracker = Arc::new(public_tracker());
206
207 let info_hash = sample_info_hash();
208 let info_hashes = vec![info_hash];
209
210 let mut peer = sample_peer();
212 let original_peer_ip = peer.ip();
213 tracker.announce(&info_hash, &mut peer, &original_peer_ip, &PeersWanted::All);
214
215 let scrape_data = fake(&tracker, &info_hashes, &original_peer_ip).await;
216
217 let expected_scrape_data = ScrapeData::zeroed(&info_hashes);
218
219 assert_eq!(scrape_data, expected_scrape_data);
220 }
221
222 #[tokio::test]
223 async fn it_should_send_the_tcp_4_scrape_event_when_the_peer_uses_ipv4() {
224 let mut stats_event_sender_mock = statistics::MockEventSender::new();
225 stats_event_sender_mock
226 .expect_send_event()
227 .with(eq(statistics::Event::Tcp4Scrape))
228 .times(1)
229 .returning(|_| Box::pin(future::ready(Some(Ok(())))));
230 let stats_event_sender = Box::new(stats_event_sender_mock);
231
232 let tracker = Arc::new(
233 Tracker::new(
234 &configuration::ephemeral().core,
235 Some(stats_event_sender),
236 statistics::Repo::new(),
237 )
238 .unwrap(),
239 );
240
241 let peer_ip = IpAddr::V4(Ipv4Addr::new(126, 0, 0, 1));
242
243 fake(&tracker, &sample_info_hashes(), &peer_ip).await;
244 }
245
246 #[tokio::test]
247 async fn it_should_send_the_tcp_6_scrape_event_when_the_peer_uses_ipv6() {
248 let mut stats_event_sender_mock = statistics::MockEventSender::new();
249 stats_event_sender_mock
250 .expect_send_event()
251 .with(eq(statistics::Event::Tcp6Scrape))
252 .times(1)
253 .returning(|_| Box::pin(future::ready(Some(Ok(())))));
254 let stats_event_sender = Box::new(stats_event_sender_mock);
255
256 let tracker = Arc::new(
257 Tracker::new(
258 &configuration::ephemeral().core,
259 Some(stats_event_sender),
260 statistics::Repo::new(),
261 )
262 .unwrap(),
263 );
264
265 let peer_ip = IpAddr::V6(Ipv6Addr::new(0x6969, 0x6969, 0x6969, 0x6969, 0x6969, 0x6969, 0x6969, 0x6969));
266
267 fake(&tracker, &sample_info_hashes(), &peer_ip).await;
268 }
269 }
270}