Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 29b6cb8

Browse files
committedMar 20, 2024··
dev: add some torrent repo tests
1 parent b0d19b6 commit 29b6cb8

21 files changed

+510
-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/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)]
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)]
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+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
use torrust_tracker_configuration::TrackerPolicy;
2+
use torrust_tracker_primitives::info_hash::InfoHash;
3+
use torrust_tracker_primitives::pagination::Pagination;
4+
use torrust_tracker_primitives::swarm_metadata::SwarmMetadata;
5+
use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics;
6+
use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch, PersistentTorrents};
7+
use torrust_tracker_torrent_repository::repository::{Repository as _, RepositoryAsync as _};
8+
use torrust_tracker_torrent_repository::{
9+
EntrySingle, TorrentsRwLockStd, TorrentsRwLockStdMutexStd, TorrentsRwLockStdMutexTokio, TorrentsRwLockTokio,
10+
TorrentsRwLockTokioMutexStd, TorrentsRwLockTokioMutexTokio,
11+
};
12+
13+
#[derive(Debug)]
14+
pub(crate) enum Torrents {
15+
Std(TorrentsRwLockStd),
16+
StdMutexStd(TorrentsRwLockStdMutexStd),
17+
StdMutexTokio(TorrentsRwLockStdMutexTokio),
18+
Tokio(TorrentsRwLockTokio),
19+
TokioMutexStd(TorrentsRwLockTokioMutexStd),
20+
TokioMutexTokio(TorrentsRwLockTokioMutexTokio),
21+
}
22+
23+
#[allow(dead_code)]
24+
impl Torrents {
25+
pub(crate) async fn get(&self, key: &InfoHash) -> Option<EntrySingle> {
26+
match self {
27+
Torrents::Std(repo) => repo.get(key),
28+
Torrents::StdMutexStd(repo) => Some(repo.get(key)?.lock().unwrap().clone()),
29+
Torrents::StdMutexTokio(repo) => Some(repo.get(key).await?.lock().await.clone()),
30+
Torrents::Tokio(repo) => repo.get(key).await,
31+
Torrents::TokioMutexStd(repo) => Some(repo.get(key).await?.lock().unwrap().clone()),
32+
Torrents::TokioMutexTokio(repo) => Some(repo.get(key).await?.lock().await.clone()),
33+
}
34+
}
35+
pub(crate) async fn get_metrics(&self) -> TorrentsMetrics {
36+
match self {
37+
Torrents::Std(repo) => repo.get_metrics(),
38+
Torrents::StdMutexStd(repo) => repo.get_metrics(),
39+
Torrents::StdMutexTokio(repo) => repo.get_metrics().await,
40+
Torrents::Tokio(repo) => repo.get_metrics().await,
41+
Torrents::TokioMutexStd(repo) => repo.get_metrics().await,
42+
Torrents::TokioMutexTokio(repo) => repo.get_metrics().await,
43+
}
44+
}
45+
pub(crate) async fn get_paginated(&self, pagination: Option<&Pagination>) -> Vec<(InfoHash, EntrySingle)> {
46+
match self {
47+
Torrents::Std(repo) => repo.get_paginated(pagination),
48+
Torrents::StdMutexStd(repo) => repo
49+
.get_paginated(pagination)
50+
.iter()
51+
.map(|(i, t)| (*i, t.lock().expect("it should get a lock").clone()))
52+
.collect(),
53+
Torrents::StdMutexTokio(repo) => {
54+
let mut v: Vec<(InfoHash, EntrySingle)> = vec![];
55+
56+
for (i, t) in repo.get_paginated(pagination).await {
57+
v.push((i, t.lock().await.clone()));
58+
}
59+
v
60+
}
61+
Torrents::Tokio(repo) => repo.get_paginated(pagination).await,
62+
Torrents::TokioMutexStd(repo) => repo
63+
.get_paginated(pagination)
64+
.await
65+
.iter()
66+
.map(|(i, t)| (*i, t.lock().expect("it should get a lock").clone()))
67+
.collect(),
68+
Torrents::TokioMutexTokio(repo) => {
69+
let mut v: Vec<(InfoHash, EntrySingle)> = vec![];
70+
71+
for (i, t) in repo.get_paginated(pagination).await {
72+
v.push((i, t.lock().await.clone()));
73+
}
74+
v
75+
}
76+
}
77+
}
78+
pub(crate) async fn import_persistent(&self, persistent_torrents: &PersistentTorrents) {
79+
match self {
80+
Torrents::Std(repo) => repo.import_persistent(persistent_torrents),
81+
Torrents::StdMutexStd(repo) => repo.import_persistent(persistent_torrents),
82+
Torrents::StdMutexTokio(repo) => repo.import_persistent(persistent_torrents).await,
83+
Torrents::Tokio(repo) => repo.import_persistent(persistent_torrents).await,
84+
Torrents::TokioMutexStd(repo) => repo.import_persistent(persistent_torrents).await,
85+
Torrents::TokioMutexTokio(repo) => repo.import_persistent(persistent_torrents).await,
86+
}
87+
}
88+
pub(crate) async fn remove(&self, key: &InfoHash) -> Option<EntrySingle> {
89+
match self {
90+
Torrents::Std(repo) => repo.remove(key),
91+
Torrents::StdMutexStd(repo) => Some(repo.remove(key)?.lock().unwrap().clone()),
92+
Torrents::StdMutexTokio(repo) => Some(repo.remove(key).await?.lock().await.clone()),
93+
Torrents::Tokio(repo) => repo.remove(key).await,
94+
Torrents::TokioMutexStd(repo) => Some(repo.remove(key).await?.lock().unwrap().clone()),
95+
Torrents::TokioMutexTokio(repo) => Some(repo.remove(key).await?.lock().await.clone()),
96+
}
97+
}
98+
pub(crate) async fn remove_inactive_peers(&self, current_cutoff: DurationSinceUnixEpoch) {
99+
match self {
100+
Torrents::Std(repo) => repo.remove_inactive_peers(current_cutoff),
101+
Torrents::StdMutexStd(repo) => repo.remove_inactive_peers(current_cutoff),
102+
Torrents::StdMutexTokio(repo) => repo.remove_inactive_peers(current_cutoff).await,
103+
Torrents::Tokio(repo) => repo.remove_inactive_peers(current_cutoff).await,
104+
Torrents::TokioMutexStd(repo) => repo.remove_inactive_peers(current_cutoff).await,
105+
Torrents::TokioMutexTokio(repo) => repo.remove_inactive_peers(current_cutoff).await,
106+
}
107+
}
108+
pub(crate) async fn remove_peerless_torrents(&self, policy: &TrackerPolicy) {
109+
match self {
110+
Torrents::Std(repo) => repo.remove_peerless_torrents(policy),
111+
Torrents::StdMutexStd(repo) => repo.remove_peerless_torrents(policy),
112+
Torrents::StdMutexTokio(repo) => repo.remove_peerless_torrents(policy).await,
113+
Torrents::Tokio(repo) => repo.remove_peerless_torrents(policy).await,
114+
Torrents::TokioMutexStd(repo) => repo.remove_peerless_torrents(policy).await,
115+
Torrents::TokioMutexTokio(repo) => repo.remove_peerless_torrents(policy).await,
116+
}
117+
}
118+
pub(crate) async fn update_torrent_with_peer_and_get_stats(
119+
&self,
120+
info_hash: &InfoHash,
121+
peer: &peer::Peer,
122+
) -> (bool, SwarmMetadata) {
123+
match self {
124+
Torrents::Std(repo) => repo.update_torrent_with_peer_and_get_stats(info_hash, peer),
125+
Torrents::StdMutexStd(repo) => repo.update_torrent_with_peer_and_get_stats(info_hash, peer),
126+
Torrents::StdMutexTokio(repo) => repo.update_torrent_with_peer_and_get_stats(info_hash, peer).await,
127+
Torrents::Tokio(repo) => repo.update_torrent_with_peer_and_get_stats(info_hash, peer).await,
128+
Torrents::TokioMutexStd(repo) => repo.update_torrent_with_peer_and_get_stats(info_hash, peer).await,
129+
Torrents::TokioMutexTokio(repo) => repo.update_torrent_with_peer_and_get_stats(info_hash, peer).await,
130+
}
131+
}
132+
pub(crate) async fn insert(&self, info_hash: &InfoHash, torrent: EntrySingle) -> Option<EntrySingle> {
133+
match self {
134+
Torrents::Std(repo) => repo.write().insert(*info_hash, torrent),
135+
Torrents::StdMutexStd(repo) => Some(repo.write().insert(*info_hash, torrent.into())?.lock().unwrap().clone()),
136+
Torrents::StdMutexTokio(repo) => {
137+
let r = repo.write().insert(*info_hash, torrent.into());
138+
match r {
139+
Some(t) => Some(t.lock().await.clone()),
140+
None => None,
141+
}
142+
}
143+
Torrents::Tokio(repo) => repo.write().await.insert(*info_hash, torrent),
144+
Torrents::TokioMutexStd(repo) => Some(repo.write().await.insert(*info_hash, torrent.into())?.lock().unwrap().clone()),
145+
Torrents::TokioMutexTokio(repo) => Some(repo.write().await.insert(*info_hash, torrent.into())?.lock().await.clone()),
146+
}
147+
}
148+
}

‎packages/torrent-repository/tests/entry/mod.rs

+2-84
Original file line numberDiff line numberDiff line change
@@ -9,95 +9,13 @@ use torrust_tracker_clock::clock::{self, Time as _};
99
use torrust_tracker_configuration::{TrackerPolicy, TORRENT_PEERS_LIMIT};
1010
use torrust_tracker_primitives::announce_event::AnnounceEvent;
1111
use torrust_tracker_primitives::peer::Peer;
12-
use torrust_tracker_primitives::swarm_metadata::SwarmMetadata;
13-
use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch, NumberOfBytes};
14-
use torrust_tracker_torrent_repository::entry::{Entry, EntryAsync, EntrySync};
12+
use torrust_tracker_primitives::{peer, NumberOfBytes};
1513
use torrust_tracker_torrent_repository::{EntryMutexStd, EntryMutexTokio, EntrySingle};
1614

15+
use crate::common::torrent::Torrent;
1716
use crate::common::torrent_peer_builder::{a_completed_peer, a_started_peer};
1817
use crate::CurrentClock;
1918

20-
#[derive(Debug)]
21-
pub enum Torrent {
22-
Single(EntrySingle),
23-
MutexStd(EntryMutexStd),
24-
MutexTokio(EntryMutexTokio),
25-
}
26-
27-
impl Torrent {
28-
async fn get_stats(&self) -> SwarmMetadata {
29-
match self {
30-
Torrent::Single(entry) => entry.get_stats(),
31-
Torrent::MutexStd(entry) => entry.get_stats(),
32-
Torrent::MutexTokio(entry) => entry.clone().get_stats().await,
33-
}
34-
}
35-
36-
async fn is_good(&self, policy: &TrackerPolicy) -> bool {
37-
match self {
38-
Torrent::Single(entry) => entry.is_good(policy),
39-
Torrent::MutexStd(entry) => entry.is_good(policy),
40-
Torrent::MutexTokio(entry) => entry.clone().is_good(policy).await,
41-
}
42-
}
43-
44-
async fn peers_is_empty(&self) -> bool {
45-
match self {
46-
Torrent::Single(entry) => entry.peers_is_empty(),
47-
Torrent::MutexStd(entry) => entry.peers_is_empty(),
48-
Torrent::MutexTokio(entry) => entry.clone().peers_is_empty().await,
49-
}
50-
}
51-
52-
async fn get_peers_len(&self) -> usize {
53-
match self {
54-
Torrent::Single(entry) => entry.get_peers_len(),
55-
Torrent::MutexStd(entry) => entry.get_peers_len(),
56-
Torrent::MutexTokio(entry) => entry.clone().get_peers_len().await,
57-
}
58-
}
59-
60-
async fn get_peers(&self, limit: Option<usize>) -> Vec<Arc<peer::Peer>> {
61-
match self {
62-
Torrent::Single(entry) => entry.get_peers(limit),
63-
Torrent::MutexStd(entry) => entry.get_peers(limit),
64-
Torrent::MutexTokio(entry) => entry.clone().get_peers(limit).await,
65-
}
66-
}
67-
68-
async fn get_peers_for_peer(&self, client: &peer::Peer, limit: Option<usize>) -> Vec<Arc<peer::Peer>> {
69-
match self {
70-
Torrent::Single(entry) => entry.get_peers_for_peer(client, limit),
71-
Torrent::MutexStd(entry) => entry.get_peers_for_peer(client, limit),
72-
Torrent::MutexTokio(entry) => entry.clone().get_peers_for_peer(client, limit).await,
73-
}
74-
}
75-
76-
async fn insert_or_update_peer(&mut self, peer: &peer::Peer) -> bool {
77-
match self {
78-
Torrent::Single(entry) => entry.insert_or_update_peer(peer),
79-
Torrent::MutexStd(entry) => entry.insert_or_update_peer(peer),
80-
Torrent::MutexTokio(entry) => entry.clone().insert_or_update_peer(peer).await,
81-
}
82-
}
83-
84-
async fn insert_or_update_peer_and_get_stats(&mut self, peer: &peer::Peer) -> (bool, SwarmMetadata) {
85-
match self {
86-
Torrent::Single(entry) => entry.insert_or_update_peer_and_get_stats(peer),
87-
Torrent::MutexStd(entry) => entry.insert_or_update_peer_and_get_stats(peer),
88-
Torrent::MutexTokio(entry) => entry.clone().insert_or_update_peer_and_get_stats(peer).await,
89-
}
90-
}
91-
92-
async fn remove_inactive_peers(&mut self, current_cutoff: DurationSinceUnixEpoch) {
93-
match self {
94-
Torrent::Single(entry) => entry.remove_inactive_peers(current_cutoff),
95-
Torrent::MutexStd(entry) => entry.remove_inactive_peers(current_cutoff),
96-
Torrent::MutexTokio(entry) => entry.clone().remove_inactive_peers(current_cutoff).await,
97-
}
98-
}
99-
}
100-
10119
#[fixture]
10220
async fn single_empty() -> (Torrent, Peer) {
10321
(Torrent::Single(EntrySingle::default()), a_started_peer())
Original file line numberDiff line numberDiff line change
@@ -1 +1,182 @@
1+
use rstest::{fixture, rstest};
2+
use torrust_tracker_primitives::info_hash::InfoHash;
3+
use torrust_tracker_torrent_repository::entry::Entry as _;
4+
use torrust_tracker_torrent_repository::repository::{RwLockStd, RwLockTokio};
5+
use torrust_tracker_torrent_repository::EntrySingle;
16

7+
use crate::common::torrent_peer_builder::a_started_peer;
8+
use crate::common::torrents::Torrents;
9+
10+
#[fixture]
11+
fn standard() -> Torrents {
12+
Torrents::Std(RwLockStd::default())
13+
}
14+
#[fixture]
15+
fn standard_mutex() -> Torrents {
16+
Torrents::StdMutexStd(RwLockStd::default())
17+
}
18+
19+
#[fixture]
20+
fn standard_tokio() -> Torrents {
21+
Torrents::StdMutexTokio(RwLockStd::default())
22+
}
23+
24+
#[fixture]
25+
fn tokio_std() -> Torrents {
26+
Torrents::Tokio(RwLockTokio::default())
27+
}
28+
#[fixture]
29+
fn tokio_mutex() -> Torrents {
30+
Torrents::TokioMutexStd(RwLockTokio::default())
31+
}
32+
33+
#[fixture]
34+
fn tokio_tokio() -> Torrents {
35+
Torrents::TokioMutexTokio(RwLockTokio::default())
36+
}
37+
38+
#[fixture]
39+
fn empty() -> Option<EntrySingle> {
40+
None
41+
}
42+
43+
#[fixture]
44+
#[allow(clippy::unnecessary_wraps)]
45+
fn default() -> Option<EntrySingle> {
46+
Some(EntrySingle::default())
47+
}
48+
49+
#[fixture]
50+
#[allow(clippy::unnecessary_wraps)]
51+
fn started() -> Option<EntrySingle> {
52+
let mut torrent = EntrySingle::default();
53+
let peer = a_started_peer();
54+
torrent.insert_or_update_peer(&peer);
55+
Some(torrent)
56+
}
57+
58+
type Repo = (Torrents, Option<(InfoHash, EntrySingle)>);
59+
60+
#[fixture]
61+
async fn make(#[default(empty())] torrent: Option<EntrySingle>, #[default(standard())] repo: Torrents) -> Repo {
62+
let info_hash = InfoHash::default();
63+
64+
if let Some(torrent) = torrent {
65+
repo.insert(&info_hash, torrent.clone()).await;
66+
67+
(repo, Some((info_hash, torrent)))
68+
} else {
69+
(repo, None)
70+
}
71+
}
72+
73+
#[rstest]
74+
#[case::empty_standard(make(empty(), standard()))]
75+
#[case::empty_standard_mutex(make(empty(), standard_mutex()))]
76+
#[case::empty_standard_tokio(make(empty(), standard_tokio()))]
77+
#[case::empty_tokio_std(make(empty(), tokio_std()))]
78+
#[case::empty_tokio_mutex(make(empty(), tokio_mutex()))]
79+
#[case::empty_tokio_tokio(make(empty(), tokio_tokio()))]
80+
#[case::default_standard(make(default(), standard()))]
81+
#[case::default_standard_mutex(make(default(), standard_mutex()))]
82+
#[case::default_standard_tokio(make(default(), standard_tokio()))]
83+
#[case::default_tokio_std(make(default(), tokio_std()))]
84+
#[case::default_tokio_mutex(make(default(), tokio_mutex()))]
85+
#[case::default_tokio_tokio(make(default(), tokio_tokio()))]
86+
#[case::started_standard(make(started(), standard()))]
87+
#[case::started_standard_mutex(make(started(), standard_mutex()))]
88+
#[case::started_standard_tokio(make(started(), standard_tokio()))]
89+
#[case::started_tokio_std(make(started(), tokio_std()))]
90+
#[case::started_tokio_mutex(make(started(), tokio_mutex()))]
91+
#[case::started_tokio_tokio(make(started(), tokio_tokio()))]
92+
#[tokio::test]
93+
async fn it_should_get_a_torrent_entry(
94+
#[future]
95+
#[case]
96+
repo: Repo,
97+
) {
98+
let (repo, maybe) = repo.await;
99+
100+
if let Some((info_hash, torrent)) = maybe {
101+
assert_eq!(repo.get(&info_hash).await, Some(torrent));
102+
} else {
103+
assert_eq!(repo.get(&InfoHash::default()).await, None);
104+
}
105+
}
106+
107+
#[rstest]
108+
#[case::empty_standard(make(empty(), standard()))]
109+
#[case::empty_standard_mutex(make(empty(), standard_mutex()))]
110+
#[case::empty_standard_tokio(make(empty(), standard_tokio()))]
111+
#[case::empty_tokio_std(make(empty(), tokio_std()))]
112+
#[case::empty_tokio_mutex(make(empty(), tokio_mutex()))]
113+
#[case::empty_tokio_tokio(make(empty(), tokio_tokio()))]
114+
#[case::default_standard(make(default(), standard()))]
115+
#[case::default_standard_mutex(make(default(), standard_mutex()))]
116+
#[case::default_standard_tokio(make(default(), standard_tokio()))]
117+
#[case::default_tokio_std(make(default(), tokio_std()))]
118+
#[case::default_tokio_mutex(make(default(), tokio_mutex()))]
119+
#[case::default_tokio_tokio(make(default(), tokio_tokio()))]
120+
#[case::started_standard(make(started(), standard()))]
121+
#[case::started_standard_mutex(make(started(), standard_mutex()))]
122+
#[case::started_standard_tokio(make(started(), standard_tokio()))]
123+
#[case::started_tokio_std(make(started(), tokio_std()))]
124+
#[case::started_tokio_mutex(make(started(), tokio_mutex()))]
125+
#[case::started_tokio_tokio(make(started(), tokio_tokio()))]
126+
#[tokio::test]
127+
async fn it_should_get_entries(
128+
#[future]
129+
#[case]
130+
repo: Repo,
131+
) {
132+
let (repo, maybe) = repo.await;
133+
134+
if let Some((info_hash, torrent)) = maybe {
135+
assert_eq!(repo.get_paginated(None).await[0], (info_hash, torrent));
136+
} else {
137+
assert!(repo.get_paginated(None).await.is_empty());
138+
}
139+
}
140+
141+
#[rstest]
142+
#[case::empty_standard(make(empty(), standard()))]
143+
#[case::empty_standard_mutex(make(empty(), standard_mutex()))]
144+
#[case::empty_standard_tokio(make(empty(), standard_tokio()))]
145+
#[case::empty_tokio_std(make(empty(), tokio_std()))]
146+
#[case::empty_tokio_mutex(make(empty(), tokio_mutex()))]
147+
#[case::empty_tokio_tokio(make(empty(), tokio_tokio()))]
148+
#[case::default_standard(make(default(), standard()))]
149+
#[case::default_standard_mutex(make(default(), standard_mutex()))]
150+
#[case::default_standard_tokio(make(default(), standard_tokio()))]
151+
#[case::default_tokio_std(make(default(), tokio_std()))]
152+
#[case::default_tokio_mutex(make(default(), tokio_mutex()))]
153+
#[case::default_tokio_tokio(make(default(), tokio_tokio()))]
154+
#[case::started_standard(make(started(), standard()))]
155+
#[case::started_standard_mutex(make(started(), standard_mutex()))]
156+
#[case::started_standard_tokio(make(started(), standard_tokio()))]
157+
#[case::started_tokio_std(make(started(), tokio_std()))]
158+
#[case::started_tokio_mutex(make(started(), tokio_mutex()))]
159+
#[case::started_tokio_tokio(make(started(), tokio_tokio()))]
160+
#[tokio::test]
161+
async fn it_should_get_metrics(
162+
#[future]
163+
#[case]
164+
repo: Repo,
165+
) {
166+
use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics;
167+
168+
let (repo, maybe) = repo.await;
169+
170+
let expected = if let Some((_, torrent)) = maybe {
171+
TorrentsMetrics {
172+
torrents: 1,
173+
incomplete: u64::from(torrent.get_stats().incomplete),
174+
complete: u64::from(torrent.get_stats().complete),
175+
downloaded: u64::from(torrent.get_stats().downloaded),
176+
}
177+
} else {
178+
TorrentsMetrics::default()
179+
};
180+
181+
assert_eq!(repo.get_metrics().await, expected);
182+
}

‎src/core/mod.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -1115,9 +1115,9 @@ mod tests {
11151115
assert_eq!(
11161116
torrents_metrics,
11171117
TorrentsMetrics {
1118-
seeders: 0,
1119-
completed: 0,
1120-
leechers: 0,
1118+
complete: 0,
1119+
downloaded: 0,
1120+
incomplete: 0,
11211121
torrents: 0
11221122
}
11231123
);
@@ -1164,9 +1164,9 @@ mod tests {
11641164
assert_eq!(
11651165
torrent_metrics,
11661166
TorrentsMetrics {
1167-
seeders: 0,
1168-
completed: 0,
1169-
leechers: 1,
1167+
complete: 0,
1168+
downloaded: 0,
1169+
incomplete: 1,
11701170
torrents: 1,
11711171
}
11721172
);
@@ -1191,9 +1191,9 @@ mod tests {
11911191
assert_eq!(
11921192
(torrent_metrics),
11931193
(TorrentsMetrics {
1194-
seeders: 0,
1195-
completed: 0,
1196-
leechers: 1_000_000,
1194+
complete: 0,
1195+
downloaded: 0,
1196+
incomplete: 1_000_000,
11971197
torrents: 1_000_000,
11981198
}),
11991199
"{result_a:?} {result_b:?}"

‎src/servers/apis/v1/context/stats/resources.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ impl From<TrackerMetrics> for Stats {
5050
fn from(metrics: TrackerMetrics) -> Self {
5151
Self {
5252
torrents: metrics.torrents_metrics.torrents,
53-
seeders: metrics.torrents_metrics.seeders,
54-
completed: metrics.torrents_metrics.completed,
55-
leechers: metrics.torrents_metrics.leechers,
53+
seeders: metrics.torrents_metrics.complete,
54+
completed: metrics.torrents_metrics.downloaded,
55+
leechers: metrics.torrents_metrics.incomplete,
5656
tcp4_connections_handled: metrics.protocol_metrics.tcp4_connections_handled,
5757
tcp4_announces_handled: metrics.protocol_metrics.tcp4_announces_handled,
5858
tcp4_scrapes_handled: metrics.protocol_metrics.tcp4_scrapes_handled,
@@ -82,9 +82,9 @@ mod tests {
8282
assert_eq!(
8383
Stats::from(TrackerMetrics {
8484
torrents_metrics: TorrentsMetrics {
85-
seeders: 1,
86-
completed: 2,
87-
leechers: 3,
85+
complete: 1,
86+
downloaded: 2,
87+
incomplete: 3,
8888
torrents: 4
8989
},
9090
protocol_metrics: Metrics {

0 commit comments

Comments
 (0)
Please sign in to comment.