Skip to content

Commit 29b0f43

Browse files
committed
docs: [#1261] review docs for tracker-core package
1 parent 74d0d28 commit 29b0f43

File tree

9 files changed

+545
-363
lines changed

9 files changed

+545
-363
lines changed

packages/http-protocol/src/v1/query.rs

+7
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,13 @@ mod tests {
249249
assert_eq!(query.get_param("param2"), Some("value2".to_string()));
250250
}
251251

252+
#[test]
253+
fn should_ignore_duplicate_param_values_when_asked_to_return_only_one_value() {
254+
let query = Query::from(vec![("param1", "value1"), ("param1", "value2")]);
255+
256+
assert_eq!(query.get_param("param1"), Some("value1".to_string()));
257+
}
258+
252259
#[test]
253260
fn should_fail_parsing_an_invalid_query_string() {
254261
let invalid_raw_query = "name=value=value";

packages/tracker-core/src/announce_handler.rs

+84
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,87 @@
1+
//! Announce handler.
2+
//!
3+
//! Handling `announce` requests is the most important task for a `BitTorrent` tracker.
4+
//!
5+
//! A `BitTorrent` swarm is a network of peers that are all trying to download the same torrent.
6+
//! When a peer wants to find other peers it announces itself to the swarm via the tracker.
7+
//! The peer sends its data to the tracker so that the tracker can add it to the swarm.
8+
//! The tracker responds to the peer with the list of other peers in the swarm so that
9+
//! the peer can contact them to start downloading pieces of the file from them.
10+
//!
11+
//! Once you have instantiated the `AnnounceHandler` you can `announce` a new [`peer::Peer`](torrust_tracker_primitives) with:
12+
//!
13+
//! ```rust,no_run
14+
//! use std::net::SocketAddr;
15+
//! use std::net::IpAddr;
16+
//! use std::net::Ipv4Addr;
17+
//! use std::str::FromStr;
18+
//!
19+
//! use aquatic_udp_protocol::{AnnounceEvent, NumberOfBytes, PeerId};
20+
//! use torrust_tracker_primitives::DurationSinceUnixEpoch;
21+
//! use torrust_tracker_primitives::peer;
22+
//! use bittorrent_primitives::info_hash::InfoHash;
23+
//!
24+
//! let info_hash = InfoHash::from_str("3b245504cf5f11bbdbe1201cea6a6bf45aee1bc0").unwrap();
25+
//!
26+
//! let peer = peer::Peer {
27+
//! peer_id: PeerId(*b"-qB00000000000000001"),
28+
//! peer_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(126, 0, 0, 1)), 8081),
29+
//! updated: DurationSinceUnixEpoch::new(1_669_397_478_934, 0),
30+
//! uploaded: NumberOfBytes::new(0),
31+
//! downloaded: NumberOfBytes::new(0),
32+
//! left: NumberOfBytes::new(0),
33+
//! event: AnnounceEvent::Completed,
34+
//! };
35+
//!
36+
//! let peer_ip = IpAddr::V4(Ipv4Addr::from_str("126.0.0.1").unwrap());
37+
//! ```
38+
//!
39+
//! ```text
40+
//! let announce_data = announce_handler.announce(&info_hash, &mut peer, &peer_ip).await;
41+
//! ```
42+
//!
43+
//! The `Tracker` returns the list of peers for the torrent with the infohash `3b245504cf5f11bbdbe1201cea6a6bf45aee1bc0`,
44+
//! filtering out the peer that is making the `announce` request.
45+
//!
46+
//! > **NOTICE**: that the peer argument is mutable because the `Tracker` can change the peer IP if the peer is using a loopback IP.
47+
//!
48+
//! The `peer_ip` argument is the resolved peer ip. It's a common practice that trackers ignore the peer ip in the `announce` request params,
49+
//! and resolve the peer ip using the IP of the client making the request. As the tracker is a domain service, the peer IP must be provided
50+
//! for the `Tracker` user, which is usually a higher component with access the the request metadata, for example, connection data, proxy headers,
51+
//! etcetera.
52+
//!
53+
//! The returned struct is:
54+
//!
55+
//! ```rust,no_run
56+
//! use torrust_tracker_primitives::peer;
57+
//! use torrust_tracker_configuration::AnnouncePolicy;
58+
//!
59+
//! pub struct AnnounceData {
60+
//! pub peers: Vec<peer::Peer>,
61+
//! pub swarm_stats: SwarmMetadata,
62+
//! pub policy: AnnouncePolicy, // the tracker announce policy.
63+
//! }
64+
//!
65+
//! pub struct SwarmMetadata {
66+
//! pub completed: u32, // The number of peers that have ever completed downloading
67+
//! pub seeders: u32, // The number of active peers that have completed downloading (seeders)
68+
//! pub leechers: u32, // The number of active peers that have not completed downloading (leechers)
69+
//! }
70+
//!
71+
//! // Core tracker configuration
72+
//! pub struct AnnounceInterval {
73+
//! // ...
74+
//! pub interval: u32, // Interval in seconds that the client should wait between sending regular announce requests to the tracker
75+
//! pub interval_min: u32, // Minimum announce interval. Clients must not reannounce more frequently than this
76+
//! // ...
77+
//! }
78+
//! ```
79+
//!
80+
//! Refer to `BitTorrent` BEPs and other sites for more information about the `announce` request:
81+
//!
82+
//! - [BEP 3. The `BitTorrent` Protocol Specification](https://www.bittorrent.org/beps/bep_0003.html)
83+
//! - [BEP 23. Tracker Returns Compact Peer Lists](https://www.bittorrent.org/beps/bep_0023.html)
84+
//! - [Vuze docs](https://wiki.vuze.com/w/Announce)
185
use std::net::IpAddr;
286
use std::sync::Arc;
387

packages/tracker-core/src/authentication/handler.rs

+93-48
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
//! This module implements the `KeysHandler` service
2+
//!
3+
//! It's responsible for managing authentication keys for the `BitTorrent` tracker.
4+
//!
5+
//! The service handles both persistent and in-memory storage of peer keys, and
6+
//! supports adding new keys (either pre-generated or randomly created),
7+
//! removing keys, and loading keys from the database into memory. Keys can be
8+
//! either permanent or expire after a configurable duration per key.
19
use std::sync::Arc;
210
use std::time::Duration;
311

@@ -11,29 +19,44 @@ use super::{key, CurrentClock, Key, PeerKey};
1119
use crate::databases;
1220
use crate::error::PeerKeyError;
1321

14-
/// This type contains the info needed to add a new tracker key.
22+
/// Contains the information needed to add a new tracker key.
1523
///
16-
/// You can upload a pre-generated key or let the app to generate a new one.
17-
/// You can also set an expiration date or leave it empty (`None`) if you want
18-
/// to create a permanent key that does not expire.
24+
/// A new key can either be a pre-generated key provided by the user or can be
25+
/// randomly generated by the application. Additionally, the key may be set to
26+
/// expire after a certain number of seconds, or be permanent (if no expiration
27+
/// is specified).
1928
#[derive(Debug)]
2029
pub struct AddKeyRequest {
21-
/// The pre-generated key. Use `None` to generate a random key.
30+
/// The pre-generated key as a string. If `None` the service will generate a
31+
/// random key.
2232
pub opt_key: Option<String>,
2333

24-
/// How long the key will be valid in seconds. Use `None` for permanent keys.
34+
/// The duration (in seconds) for which the key is valid. Use `None` for
35+
/// permanent keys.
2536
pub opt_seconds_valid: Option<u64>,
2637
}
2738

39+
/// The `KeysHandler` service manages the creation, addition, removal, and loading
40+
/// of authentication keys for the tracker.
41+
///
42+
/// It uses both a persistent (database) repository and an in-memory repository
43+
/// to manage keys.
2844
pub struct KeysHandler {
29-
/// The database repository for the authentication keys.
45+
/// The database repository for storing authentication keys persistently.
3046
db_key_repository: Arc<DatabaseKeyRepository>,
3147

32-
/// In-memory implementation of the authentication key repository.
48+
/// The in-memory repository for caching authentication keys.
3349
in_memory_key_repository: Arc<InMemoryKeyRepository>,
3450
}
3551

3652
impl KeysHandler {
53+
/// Creates a new instance of the `KeysHandler` service.
54+
///
55+
/// # Parameters
56+
///
57+
/// - `db_key_repository`: A shared reference to the database key repository.
58+
/// - `in_memory_key_repository`: A shared reference to the in-memory key
59+
/// repository.
3760
#[must_use]
3861
pub fn new(db_key_repository: &Arc<DatabaseKeyRepository>, in_memory_key_repository: &Arc<InMemoryKeyRepository>) -> Self {
3962
Self {
@@ -42,18 +65,24 @@ impl KeysHandler {
4265
}
4366
}
4467

45-
/// Adds new peer keys to the tracker.
68+
/// Adds a new peer key to the tracker.
69+
///
70+
/// The key may be pre-generated or generated on-the-fly.
71+
///
72+
/// Depending on whether an expiration duration is specified, the key will
73+
/// be either expiring or permanent.
4674
///
47-
/// Keys can be pre-generated or randomly created. They can also be
48-
/// permanent or expire.
75+
/// # Parameters
76+
///
77+
/// - `add_key_req`: The request containing options for key creation.
4978
///
5079
/// # Errors
5180
///
52-
/// Will return an error if:
81+
/// Returns an error if:
5382
///
54-
/// - The key duration overflows the duration type maximum value.
83+
/// - The provided key duration exceeds the maximum allowed value.
5584
/// - The provided pre-generated key is invalid.
56-
/// - The key could not been persisted due to database issues.
85+
/// - There is an error persisting the key in the database.
5786
pub async fn add_peer_key(&self, add_key_req: AddKeyRequest) -> Result<PeerKey, PeerKeyError> {
5887
if let Some(pre_existing_key) = add_key_req.opt_key {
5988
// Pre-generated key
@@ -125,29 +154,31 @@ impl KeysHandler {
125154
}
126155
}
127156

128-
/// It generates a new permanent authentication key.
157+
/// Generates a new permanent authentication key.
129158
///
130-
/// Authentication keys are used by HTTP trackers.
159+
/// Permanent keys do not expire.
131160
///
132161
/// # Errors
133162
///
134-
/// Will return a `database::Error` if unable to add the `auth_key` to the database.
163+
/// Returns a `databases::error::Error` if the key cannot be persisted in
164+
/// the database.
135165
pub(crate) async fn generate_permanent_peer_key(&self) -> Result<PeerKey, databases::error::Error> {
136166
self.generate_expiring_peer_key(None).await
137167
}
138168

139-
/// It generates a new expiring authentication key.
169+
/// Generates a new authentication key with an optional expiration lifetime.
140170
///
141-
/// Authentication keys are used by HTTP trackers.
171+
/// If a `lifetime` is provided, the generated key will expire after that
172+
/// duration. The new key is stored both in the database and in memory.
142173
///
143-
/// # Errors
174+
/// # Parameters
144175
///
145-
/// Will return a `database::Error` if unable to add the `auth_key` to the database.
176+
/// - `lifetime`: An optional duration specifying how long the key is valid.
146177
///
147-
/// # Arguments
178+
/// # Errors
148179
///
149-
/// * `lifetime` - The duration in seconds for the new key. The key will be
150-
/// no longer valid after `lifetime` seconds.
180+
/// Returns a `databases::error::Error` if there is an issue adding the key
181+
/// to the database.
151182
pub async fn generate_expiring_peer_key(&self, lifetime: Option<Duration>) -> Result<PeerKey, databases::error::Error> {
152183
let peer_key = key::generate_key(lifetime);
153184

@@ -158,36 +189,36 @@ impl KeysHandler {
158189
Ok(peer_key)
159190
}
160191

161-
/// It adds a pre-generated permanent authentication key.
192+
/// Adds a pre-generated permanent authentication key.
162193
///
163-
/// Authentication keys are used by HTTP trackers.
194+
/// Internally, this calls `add_expiring_peer_key` with no expiration.
164195
///
165-
/// # Errors
196+
/// # Parameters
166197
///
167-
/// Will return a `database::Error` if unable to add the `auth_key` to the
168-
/// database. For example, if the key already exist.
198+
/// - `key`: The pre-generated key.
169199
///
170-
/// # Arguments
200+
/// # Errors
171201
///
172-
/// * `key` - The pre-generated key.
202+
/// Returns a `databases::error::Error` if there is an issue persisting the
203+
/// key.
173204
pub(crate) async fn add_permanent_peer_key(&self, key: Key) -> Result<PeerKey, databases::error::Error> {
174205
self.add_expiring_peer_key(key, None).await
175206
}
176207

177-
/// It adds a pre-generated authentication key.
208+
/// Adds a pre-generated authentication key with an optional expiration.
178209
///
179-
/// Authentication keys are used by HTTP trackers.
210+
/// The key is stored in both the database and the in-memory repository.
180211
///
181-
/// # Errors
212+
/// # Parameters
182213
///
183-
/// Will return a `database::Error` if unable to add the `auth_key` to the
184-
/// database. For example, if the key already exist.
214+
/// - `key`: The pre-generated key.
215+
/// - `valid_until`: An optional timestamp (as a duration since the Unix
216+
/// epoch) after which the key expires.
185217
///
186-
/// # Arguments
218+
/// # Errors
187219
///
188-
/// * `key` - The pre-generated key.
189-
/// * `lifetime` - The duration in seconds for the new key. The key will be
190-
/// no longer valid after `lifetime` seconds.
220+
/// Returns a `databases::error::Error` if there is an issue adding the key
221+
/// to the database.
191222
pub(crate) async fn add_expiring_peer_key(
192223
&self,
193224
key: Key,
@@ -205,11 +236,18 @@ impl KeysHandler {
205236
Ok(peer_key)
206237
}
207238

208-
/// It removes an authentication key.
239+
/// Removes an authentication key.
240+
///
241+
/// The key is removed from both the database and the in-memory repository.
242+
///
243+
/// # Parameters
244+
///
245+
/// - `key`: A reference to the key to be removed.
209246
///
210247
/// # Errors
211248
///
212-
/// Will return a `database::Error` if unable to remove the `key` to the database.
249+
/// Returns a `databases::error::Error` if the key cannot be removed from
250+
/// the database.
213251
pub async fn remove_peer_key(&self, key: &Key) -> Result<(), databases::error::Error> {
214252
self.db_key_repository.remove(key)?;
215253

@@ -218,19 +256,26 @@ impl KeysHandler {
218256
Ok(())
219257
}
220258

221-
/// It removes an authentication key from memory.
259+
/// Removes an authentication key from the in-memory repository.
260+
///
261+
/// This function does not interact with the database.
262+
///
263+
/// # Parameters
264+
///
265+
/// - `key`: A reference to the key to be removed.
222266
pub(crate) async fn remove_in_memory_auth_key(&self, key: &Key) {
223267
self.in_memory_key_repository.remove(key).await;
224268
}
225269

226-
/// The `Tracker` stores the authentication keys in memory and in the
227-
/// database. In case you need to restart the `Tracker` you can load the
228-
/// keys from the database into memory with this function. Keys are
229-
/// automatically stored in the database when they are generated.
270+
/// Loads all authentication keys from the database into the in-memory
271+
/// repository.
272+
///
273+
/// This is useful during tracker startup to ensure that all persisted keys
274+
/// are available in memory.
230275
///
231276
/// # Errors
232277
///
233-
/// Will return a `database::Error` if unable to `load_keys` from the database.
278+
/// Returns a `databases::error::Error` if there is an issue loading the keys from the database.
234279
pub async fn load_peer_keys_from_database(&self) -> Result<(), databases::error::Error> {
235280
let keys_from_database = self.db_key_repository.load_keys()?;
236281

packages/tracker-core/src/authentication/key/peer_key.rs

+32-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
//! Authentication keys for private trackers.
2+
//!
3+
//! This module defines the types and functionality for managing authentication
4+
//! keys used by the tracker. These keys, represented by the `Key` and `PeerKey`
5+
//! types, are essential for authenticating peers in private tracker
6+
//! environments.
7+
//!
8+
//! A `Key` is a 32-character alphanumeric token, while a `PeerKey` couples a
9+
//! `Key` with an optional expiration timestamp. If the expiration is set (via
10+
//! `valid_until`), the key will become invalid after that time.
111
use std::str::FromStr;
212
use std::time::Duration;
313

@@ -11,8 +21,28 @@ use torrust_tracker_primitives::DurationSinceUnixEpoch;
1121

1222
use super::AUTH_KEY_LENGTH;
1323

14-
/// An authentication key which can potentially have an expiration time.
15-
/// After that time is will automatically become invalid.
24+
/// A peer authentication key with an optional expiration time.
25+
///
26+
/// A `PeerKey` associates a generated `Key` (a 32-character alphanumeric string)
27+
/// with an optional expiration timestamp (`valid_until`). If `valid_until` is
28+
/// `None`, the key is considered permanent.
29+
///
30+
/// # Example
31+
///
32+
/// ```rust
33+
/// use std::time::Duration;
34+
/// use bittorrent_tracker_core::authentication::key::peer_key::{Key, PeerKey};
35+
///
36+
/// let expiring_key = PeerKey {
37+
/// key: Key::random(),
38+
/// valid_until: Some(Duration::from_secs(3600)), // Expires in 1 hour
39+
/// };
40+
///
41+
/// let permanent_key = PeerKey {
42+
/// key: Key::random(),
43+
/// valid_until: None,
44+
/// };
45+
/// ```
1646
#[derive(Serialize, Deserialize, Debug, Clone)]
1747
pub struct PeerKey {
1848
/// Random 32-char string. For example: `YZSl4lMZupRuOpSRC3krIKR5BPB14nrJ`

0 commit comments

Comments
 (0)