forked from torrust/torrust-tracker
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathclient.rs
More file actions
107 lines (91 loc) · 3.17 KB
/
client.rs
File metadata and controls
107 lines (91 loc) · 3.17 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
use std::io::Cursor;
use std::sync::Arc;
use aquatic_udp_protocol::{Request, Response};
use tokio::net::UdpSocket;
use crate::shared::bit_torrent::udp::{source_address, MAX_PACKET_SIZE};
#[allow(clippy::module_name_repetitions)]
pub struct UdpClient {
pub socket: Arc<UdpSocket>,
}
impl UdpClient {
/// # Panics
///
/// Will panic if the local address can't be bound.
pub async fn bind(local_address: &str) -> Self {
let socket = UdpSocket::bind(local_address).await.unwrap();
Self {
socket: Arc::new(socket),
}
}
/// # Panics
///
/// Will panic if can't connect to the socket.
pub async fn connect(&self, remote_address: &str) {
self.socket.connect(remote_address).await.unwrap();
}
/// # Panics
///
/// Will panic if:
///
/// - Can't write to the socket.
/// - Can't send data.
pub async fn send(&self, bytes: &[u8]) -> usize {
self.socket.writable().await.unwrap();
self.socket.send(bytes).await.unwrap()
}
/// # Panics
///
/// Will panic if:
///
/// - Can't read from the socket.
/// - Can't receive data.
pub async fn receive(&self, bytes: &mut [u8]) -> usize {
self.socket.readable().await.unwrap();
self.socket.recv(bytes).await.unwrap()
}
}
/// Creates a new `UdpClient` connected to a Udp server
pub async fn new_udp_client_connected(remote_address: &str) -> UdpClient {
let port = 0; // Let OS choose an unused port.
let client = UdpClient::bind(&source_address(port)).await;
client.connect(remote_address).await;
client
}
#[allow(clippy::module_name_repetitions)]
pub struct UdpTrackerClient {
pub udp_client: UdpClient,
}
impl UdpTrackerClient {
/// # Panics
///
/// Will panic if can't write request to bytes.
pub async fn send(&self, request: Request) -> usize {
// Write request into a buffer
let request_buffer = vec![0u8; MAX_PACKET_SIZE];
let mut cursor = Cursor::new(request_buffer);
let request_data = match request.write(&mut cursor) {
Ok(()) => {
#[allow(clippy::cast_possible_truncation)]
let position = cursor.position() as usize;
let inner_request_buffer = cursor.get_ref();
// Return slice which contains written request data
&inner_request_buffer[..position]
}
Err(e) => panic!("could not write request to bytes: {e}."),
};
self.udp_client.send(request_data).await
}
/// # Panics
///
/// Will panic if can't create response from the received payload (bytes buffer).
pub async fn receive(&self) -> Response {
let mut response_buffer = [0u8; MAX_PACKET_SIZE];
let payload_size = self.udp_client.receive(&mut response_buffer).await;
Response::from_bytes(&response_buffer[..payload_size], true).unwrap()
}
}
/// Creates a new `UdpTrackerClient` connected to a Udp Tracker server
pub async fn new_udp_tracker_client_connected(remote_address: &str) -> UdpTrackerClient {
let udp_client = new_udp_client_connected(remote_address).await;
UdpTrackerClient { udp_client }
}