torrust_tracker/console/clients/udp/
checker.rs1use std::net::{Ipv4Addr, SocketAddr};
2use std::num::NonZeroU16;
3use std::time::Duration;
4
5use aquatic_udp_protocol::common::InfoHash;
6use aquatic_udp_protocol::{
7 AnnounceActionPlaceholder, AnnounceEvent, AnnounceRequest, ConnectRequest, ConnectionId, NumberOfBytes, NumberOfPeers,
8 PeerId, PeerKey, Port, Response, ScrapeRequest, TransactionId,
9};
10use torrust_tracker_primitives::info_hash::InfoHash as TorrustInfoHash;
11
12use super::Error;
13use crate::shared::bit_torrent::tracker::udp::client::UdpTrackerClient;
14
15#[derive(Debug)]
17pub struct Client {
18 client: UdpTrackerClient,
19}
20
21impl Client {
22 pub async fn new(remote_addr: SocketAddr, timeout: Duration) -> Result<Self, Error> {
29 let client = UdpTrackerClient::new(remote_addr, timeout)
30 .await
31 .map_err(|err| Error::UnableToBindAndConnect { remote_addr, err })?;
32
33 Ok(Self { client })
34 }
35
36 pub fn local_addr(&self) -> std::io::Result<SocketAddr> {
42 self.client.client.socket.local_addr()
43 }
44
45 pub async fn send_connection_request(&self, transaction_id: TransactionId) -> Result<ConnectionId, Error> {
59 tracing::debug!("Sending connection request with transaction id: {transaction_id:#?}");
60
61 let connect_request = ConnectRequest { transaction_id };
62
63 let _ = self
64 .client
65 .send(connect_request.into())
66 .await
67 .map_err(|err| Error::UnableToSendConnectionRequest { err })?;
68
69 let response = self
70 .client
71 .receive()
72 .await
73 .map_err(|err| Error::UnableToReceiveConnectResponse { err })?;
74
75 match response {
76 Response::Connect(connect_response) => Ok(connect_response.connection_id),
77 _ => Err(Error::UnexpectedConnectionResponse { response }),
78 }
79 }
80
81 pub async fn send_announce_request(
92 &self,
93 transaction_id: TransactionId,
94 connection_id: ConnectionId,
95 info_hash: TorrustInfoHash,
96 ) -> Result<Response, Error> {
97 tracing::debug!("Sending announce request with transaction id: {transaction_id:#?}");
98
99 let port = NonZeroU16::new(
100 self.client
101 .client
102 .socket
103 .local_addr()
104 .expect("it should get the local address")
105 .port(),
106 )
107 .expect("it should no be zero");
108
109 let announce_request = AnnounceRequest {
110 connection_id,
111 action_placeholder: AnnounceActionPlaceholder::default(),
112 transaction_id,
113 info_hash: InfoHash(info_hash.bytes()),
114 peer_id: PeerId(*b"-qB00000000000000001"),
115 bytes_downloaded: NumberOfBytes(0i64.into()),
116 bytes_uploaded: NumberOfBytes(0i64.into()),
117 bytes_left: NumberOfBytes(0i64.into()),
118 event: AnnounceEvent::Started.into(),
119 ip_address: Ipv4Addr::new(0, 0, 0, 0).into(),
120 key: PeerKey::new(0i32),
121 peers_wanted: NumberOfPeers(1i32.into()),
122 port: Port::new(port),
123 };
124
125 let _ = self
126 .client
127 .send(announce_request.into())
128 .await
129 .map_err(|err| Error::UnableToSendAnnounceRequest { err })?;
130
131 let response = self
132 .client
133 .receive()
134 .await
135 .map_err(|err| Error::UnableToReceiveAnnounceResponse { err })?;
136
137 Ok(response)
138 }
139
140 pub async fn send_scrape_request(
147 &self,
148 connection_id: ConnectionId,
149 transaction_id: TransactionId,
150 info_hashes: &[TorrustInfoHash],
151 ) -> Result<Response, Error> {
152 tracing::debug!("Sending scrape request with transaction id: {transaction_id:#?}");
153
154 let scrape_request = ScrapeRequest {
155 connection_id,
156 transaction_id,
157 info_hashes: info_hashes
158 .iter()
159 .map(|torrust_info_hash| InfoHash(torrust_info_hash.bytes()))
160 .collect(),
161 };
162
163 let _ = self
164 .client
165 .send(scrape_request.into())
166 .await
167 .map_err(|err| Error::UnableToSendScrapeRequest { err })?;
168
169 let response = self
170 .client
171 .receive()
172 .await
173 .map_err(|err| Error::UnableToReceiveScrapeResponse { err })?;
174
175 Ok(response)
176 }
177}