Skip to content

Commit 69c0137

Browse files
committed
dev: add some torrent repo tests
1 parent 0bb8a5c commit 69c0137

22 files changed

+534
-135
lines changed

packages/primitives/src/announce_event.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
66

77
/// Announce events. Described on the
88
/// [BEP 3. The `BitTorrent` Protocol Specification](https://www.bittorrent.org/beps/bep_0003.html)
9-
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug, Serialize, Deserialize)]
9+
#[derive(Hash, Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
1010
pub enum AnnounceEvent {
1111
/// The peer has started downloading the torrent.
1212
Started,

packages/primitives/src/info_hash.rs

+12
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::hash::{DefaultHasher, Hash, Hasher};
12
use std::panic::Location;
23

34
use thiserror::Error;
@@ -77,6 +78,17 @@ impl std::convert::From<&[u8]> for InfoHash {
7778
}
7879
}
7980

81+
/// for testing
82+
impl std::convert::From<&DefaultHasher> for InfoHash {
83+
fn from(data: &DefaultHasher) -> InfoHash {
84+
let n = data.finish().to_le_bytes();
85+
InfoHash([
86+
n[0], n[1], n[2], n[3], n[4], n[5], n[6], n[7], n[0], n[1], n[2], n[3], n[4], n[5], n[6], n[7], n[0], n[1], n[2],
87+
n[3],
88+
])
89+
}
90+
}
91+
8092
impl std::convert::From<[u8; 20]> for InfoHash {
8193
fn from(val: [u8; 20]) -> Self {
8294
InfoHash(val)

packages/primitives/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub enum IPVersion {
3838
}
3939

4040
/// Number of bytes downloaded, uploaded or pending to download (left) by the peer.
41-
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug, Serialize, Deserialize)]
41+
#[derive(Hash, Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
4242
pub struct NumberOfBytes(pub i64);
4343

4444
/// The database management system used by the tracker.

packages/primitives/src/peer.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ use crate::{ser_unix_time_value, DurationSinceUnixEpoch, IPVersion, NumberOfByte
5151
/// event: AnnounceEvent::Started,
5252
/// };
5353
/// ```
54-
#[derive(PartialEq, Eq, Debug, Clone, Serialize, Copy)]
54+
#[derive(Debug, Clone, Serialize, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
5555
pub struct Peer {
5656
/// ID used by the downloader peer
5757
pub peer_id: Id,

packages/primitives/src/torrent_metrics.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,20 @@ use std::ops::AddAssign;
66
#[derive(Copy, Clone, Debug, PartialEq, Default)]
77
pub struct TorrentsMetrics {
88
/// Total number of seeders for all torrents
9-
pub seeders: u64,
9+
pub complete: u64,
1010
/// Total number of peers that have ever completed downloading for all torrents.
11-
pub completed: u64,
11+
pub downloaded: u64,
1212
/// Total number of leechers for all torrents.
13-
pub leechers: u64,
13+
pub incomplete: u64,
1414
/// Total number of torrents.
1515
pub torrents: u64,
1616
}
1717

1818
impl AddAssign for TorrentsMetrics {
1919
fn add_assign(&mut self, rhs: Self) {
20-
self.seeders += rhs.seeders;
21-
self.completed += rhs.completed;
22-
self.leechers += rhs.leechers;
20+
self.complete += rhs.complete;
21+
self.downloaded += rhs.downloaded;
22+
self.incomplete += rhs.incomplete;
2323
self.torrents += rhs.torrents;
2424
}
2525
}

packages/torrent-repository/src/entry/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ pub trait EntryAsync {
8686
/// This is the tracker entry for a given torrent and contains the swarm data,
8787
/// that's the list of all the peers trying to download the same torrent.
8888
/// The tracker keeps one entry like this for every torrent.
89-
#[derive(Clone, Debug, Default)]
89+
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
9090
pub struct Torrent {
9191
/// The swarm: a network of peers that are all trying to download the torrent associated to this entry
9292
// #[serde(skip)]

packages/torrent-repository/src/entry/mutex_std.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use torrust_tracker_primitives::swarm_metadata::SwarmMetadata;
55
use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch};
66

77
use super::{Entry, EntrySync};
8-
use crate::EntryMutexStd;
8+
use crate::{EntryMutexStd, EntrySingle};
99

1010
impl EntrySync for EntryMutexStd {
1111
fn get_stats(&self) -> SwarmMetadata {
@@ -48,3 +48,9 @@ impl EntrySync for EntryMutexStd {
4848
.remove_inactive_peers(current_cutoff);
4949
}
5050
}
51+
52+
impl From<EntrySingle> for EntryMutexStd {
53+
fn from(entry: EntrySingle) -> Self {
54+
Arc::new(std::sync::Mutex::new(entry))
55+
}
56+
}

packages/torrent-repository/src/entry/mutex_tokio.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use torrust_tracker_primitives::swarm_metadata::SwarmMetadata;
55
use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch};
66

77
use super::{Entry, EntryAsync};
8-
use crate::EntryMutexTokio;
8+
use crate::{EntryMutexTokio, EntrySingle};
99

1010
impl EntryAsync for EntryMutexTokio {
1111
async fn get_stats(&self) -> SwarmMetadata {
@@ -44,3 +44,9 @@ impl EntryAsync for EntryMutexTokio {
4444
self.lock().await.remove_inactive_peers(current_cutoff);
4545
}
4646
}
47+
48+
impl From<EntrySingle> for EntryMutexTokio {
49+
fn from(entry: EntrySingle) -> Self {
50+
Arc::new(tokio::sync::Mutex::new(entry))
51+
}
52+
}

packages/torrent-repository/src/repository/mod.rs

+32-6
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ pub mod rw_lock_tokio;
1212
pub mod rw_lock_tokio_mutex_std;
1313
pub mod rw_lock_tokio_mutex_tokio;
1414

15-
pub trait Repository<T>: Default + 'static {
15+
use std::fmt::Debug;
16+
17+
pub trait Repository<T>: Debug + Default + Sized + 'static {
1618
fn get(&self, key: &InfoHash) -> Option<T>;
1719
fn get_metrics(&self) -> TorrentsMetrics;
1820
fn get_paginated(&self, pagination: Option<&Pagination>) -> Vec<(InfoHash, T)>;
@@ -24,7 +26,7 @@ pub trait Repository<T>: Default + 'static {
2426
}
2527

2628
#[allow(clippy::module_name_repetitions)]
27-
pub trait RepositoryAsync<T>: Default + 'static {
29+
pub trait RepositoryAsync<T>: Debug + Default + Sized + 'static {
2830
fn get(&self, key: &InfoHash) -> impl std::future::Future<Output = Option<T>> + Send;
2931
fn get_metrics(&self) -> impl std::future::Future<Output = TorrentsMetrics> + Send;
3032
fn get_paginated(&self, pagination: Option<&Pagination>) -> impl std::future::Future<Output = Vec<(InfoHash, T)>> + Send;
@@ -39,12 +41,36 @@ pub trait RepositoryAsync<T>: Default + 'static {
3941
) -> impl std::future::Future<Output = (bool, SwarmMetadata)> + Send;
4042
}
4143

42-
#[derive(Default)]
44+
#[derive(Default, Debug)]
45+
pub struct RwLockStd<T> {
46+
torrents: std::sync::RwLock<std::collections::BTreeMap<InfoHash, T>>,
47+
}
48+
49+
#[derive(Default, Debug)]
4350
pub struct RwLockTokio<T> {
4451
torrents: tokio::sync::RwLock<std::collections::BTreeMap<InfoHash, T>>,
4552
}
4653

47-
#[derive(Default)]
48-
pub struct RwLockStd<T> {
49-
torrents: std::sync::RwLock<std::collections::BTreeMap<InfoHash, T>>,
54+
impl<T> RwLockStd<T> {
55+
/// # Panics
56+
///
57+
/// Panics if unable to get a lock.
58+
pub fn write(
59+
&self,
60+
) -> std::sync::RwLockWriteGuard<'_, std::collections::BTreeMap<torrust_tracker_primitives::info_hash::InfoHash, T>> {
61+
self.torrents.write().expect("it should get lock")
62+
}
63+
}
64+
65+
impl<T> RwLockTokio<T> {
66+
pub fn write(
67+
&self,
68+
) -> impl std::future::Future<
69+
Output = tokio::sync::RwLockWriteGuard<
70+
'_,
71+
std::collections::BTreeMap<torrust_tracker_primitives::info_hash::InfoHash, T>,
72+
>,
73+
> {
74+
self.torrents.write()
75+
}
5076
}

packages/torrent-repository/src/repository/rw_lock_std.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ where
4949

5050
for entry in self.get_torrents().values() {
5151
let stats = entry.get_stats();
52-
metrics.seeders += u64::from(stats.complete);
53-
metrics.completed += u64::from(stats.downloaded);
54-
metrics.leechers += u64::from(stats.incomplete);
52+
metrics.complete += u64::from(stats.complete);
53+
metrics.downloaded += u64::from(stats.downloaded);
54+
metrics.incomplete += u64::from(stats.incomplete);
5555
metrics.torrents += 1;
5656
}
5757

packages/torrent-repository/src/repository/rw_lock_std_mutex_std.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ where
5757

5858
for entry in self.get_torrents().values() {
5959
let stats = entry.lock().expect("it should get a lock").get_stats();
60-
metrics.seeders += u64::from(stats.complete);
61-
metrics.completed += u64::from(stats.downloaded);
62-
metrics.leechers += u64::from(stats.incomplete);
60+
metrics.complete += u64::from(stats.complete);
61+
metrics.downloaded += u64::from(stats.downloaded);
62+
metrics.incomplete += u64::from(stats.incomplete);
6363
metrics.torrents += 1;
6464
}
6565

packages/torrent-repository/src/repository/rw_lock_std_mutex_tokio.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,9 @@ where
7575

7676
for entry in entries {
7777
let stats = entry.lock().await.get_stats();
78-
metrics.seeders += u64::from(stats.complete);
79-
metrics.completed += u64::from(stats.downloaded);
80-
metrics.leechers += u64::from(stats.incomplete);
78+
metrics.complete += u64::from(stats.complete);
79+
metrics.downloaded += u64::from(stats.downloaded);
80+
metrics.incomplete += u64::from(stats.incomplete);
8181
metrics.torrents += 1;
8282
}
8383

packages/torrent-repository/src/repository/rw_lock_tokio.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ where
6464

6565
for entry in self.get_torrents().await.values() {
6666
let stats = entry.get_stats();
67-
metrics.seeders += u64::from(stats.complete);
68-
metrics.completed += u64::from(stats.downloaded);
69-
metrics.leechers += u64::from(stats.incomplete);
67+
metrics.complete += u64::from(stats.complete);
68+
metrics.downloaded += u64::from(stats.downloaded);
69+
metrics.incomplete += u64::from(stats.incomplete);
7070
metrics.torrents += 1;
7171
}
7272

packages/torrent-repository/src/repository/rw_lock_tokio_mutex_std.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ where
7272

7373
for entry in self.get_torrents().await.values() {
7474
let stats = entry.get_stats();
75-
metrics.seeders += u64::from(stats.complete);
76-
metrics.completed += u64::from(stats.downloaded);
77-
metrics.leechers += u64::from(stats.incomplete);
75+
metrics.complete += u64::from(stats.complete);
76+
metrics.downloaded += u64::from(stats.downloaded);
77+
metrics.incomplete += u64::from(stats.incomplete);
7878
metrics.torrents += 1;
7979
}
8080

packages/torrent-repository/src/repository/rw_lock_tokio_mutex_tokio.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ where
7272

7373
for entry in self.get_torrents().await.values() {
7474
let stats = entry.get_stats().await;
75-
metrics.seeders += u64::from(stats.complete);
76-
metrics.completed += u64::from(stats.downloaded);
77-
metrics.leechers += u64::from(stats.incomplete);
75+
metrics.complete += u64::from(stats.complete);
76+
metrics.downloaded += u64::from(stats.downloaded);
77+
metrics.incomplete += u64::from(stats.incomplete);
7878
metrics.torrents += 1;
7979
}
8080

Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1+
pub mod torrent;
12
pub mod torrent_peer_builder;
3+
pub mod torrents;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
use std::sync::Arc;
2+
3+
use torrust_tracker_configuration::TrackerPolicy;
4+
use torrust_tracker_primitives::swarm_metadata::SwarmMetadata;
5+
use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch};
6+
use torrust_tracker_torrent_repository::entry::{Entry as _, EntryAsync as _, EntrySync as _};
7+
use torrust_tracker_torrent_repository::{EntryMutexStd, EntryMutexTokio, EntrySingle};
8+
9+
#[derive(Debug)]
10+
pub(crate) enum Torrent {
11+
Single(EntrySingle),
12+
MutexStd(EntryMutexStd),
13+
MutexTokio(EntryMutexTokio),
14+
}
15+
16+
impl Torrent {
17+
pub(crate) async fn get_stats(&self) -> SwarmMetadata {
18+
match self {
19+
Torrent::Single(entry) => entry.get_stats(),
20+
Torrent::MutexStd(entry) => entry.get_stats(),
21+
Torrent::MutexTokio(entry) => entry.clone().get_stats().await,
22+
}
23+
}
24+
25+
pub(crate) async fn is_good(&self, policy: &TrackerPolicy) -> bool {
26+
match self {
27+
Torrent::Single(entry) => entry.is_good(policy),
28+
Torrent::MutexStd(entry) => entry.is_good(policy),
29+
Torrent::MutexTokio(entry) => entry.clone().is_good(policy).await,
30+
}
31+
}
32+
33+
pub(crate) async fn peers_is_empty(&self) -> bool {
34+
match self {
35+
Torrent::Single(entry) => entry.peers_is_empty(),
36+
Torrent::MutexStd(entry) => entry.peers_is_empty(),
37+
Torrent::MutexTokio(entry) => entry.clone().peers_is_empty().await,
38+
}
39+
}
40+
41+
pub(crate) async fn get_peers_len(&self) -> usize {
42+
match self {
43+
Torrent::Single(entry) => entry.get_peers_len(),
44+
Torrent::MutexStd(entry) => entry.get_peers_len(),
45+
Torrent::MutexTokio(entry) => entry.clone().get_peers_len().await,
46+
}
47+
}
48+
49+
pub(crate) async fn get_peers(&self, limit: Option<usize>) -> Vec<Arc<peer::Peer>> {
50+
match self {
51+
Torrent::Single(entry) => entry.get_peers(limit),
52+
Torrent::MutexStd(entry) => entry.get_peers(limit),
53+
Torrent::MutexTokio(entry) => entry.clone().get_peers(limit).await,
54+
}
55+
}
56+
57+
pub(crate) async fn get_peers_for_peer(&self, client: &peer::Peer, limit: Option<usize>) -> Vec<Arc<peer::Peer>> {
58+
match self {
59+
Torrent::Single(entry) => entry.get_peers_for_peer(client, limit),
60+
Torrent::MutexStd(entry) => entry.get_peers_for_peer(client, limit),
61+
Torrent::MutexTokio(entry) => entry.clone().get_peers_for_peer(client, limit).await,
62+
}
63+
}
64+
65+
pub(crate) async fn insert_or_update_peer(&mut self, peer: &peer::Peer) -> bool {
66+
match self {
67+
Torrent::Single(entry) => entry.insert_or_update_peer(peer),
68+
Torrent::MutexStd(entry) => entry.insert_or_update_peer(peer),
69+
Torrent::MutexTokio(entry) => entry.clone().insert_or_update_peer(peer).await,
70+
}
71+
}
72+
73+
pub(crate) async fn insert_or_update_peer_and_get_stats(&mut self, peer: &peer::Peer) -> (bool, SwarmMetadata) {
74+
match self {
75+
Torrent::Single(entry) => entry.insert_or_update_peer_and_get_stats(peer),
76+
Torrent::MutexStd(entry) => entry.insert_or_update_peer_and_get_stats(peer),
77+
Torrent::MutexTokio(entry) => entry.clone().insert_or_update_peer_and_get_stats(peer).await,
78+
}
79+
}
80+
81+
pub(crate) async fn remove_inactive_peers(&mut self, current_cutoff: DurationSinceUnixEpoch) {
82+
match self {
83+
Torrent::Single(entry) => entry.remove_inactive_peers(current_cutoff),
84+
Torrent::MutexStd(entry) => entry.remove_inactive_peers(current_cutoff),
85+
Torrent::MutexTokio(entry) => entry.clone().remove_inactive_peers(current_cutoff).await,
86+
}
87+
}
88+
}

0 commit comments

Comments
 (0)