Skip to content

Commit

Permalink
refactor: [#1182] move structs to new mods in whitelist
Browse files Browse the repository at this point in the history
  • Loading branch information
josecelano committed Jan 15, 2025
1 parent 07f53a4 commit cc2bc7b
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 157 deletions.
88 changes: 88 additions & 0 deletions src/core/whitelist/in_memory.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use bittorrent_primitives::info_hash::InfoHash;

/// The in-memory list of allowed torrents.
#[derive(Debug, Default)]
pub struct InMemoryWhitelist {
/// The list of allowed torrents.
whitelist: tokio::sync::RwLock<std::collections::HashSet<InfoHash>>,
}

impl InMemoryWhitelist {
/// It adds a torrent from the whitelist in memory.
pub async fn add(&self, info_hash: &InfoHash) -> bool {
self.whitelist.write().await.insert(*info_hash)
}

/// It removes a torrent from the whitelist in memory.
pub async fn remove(&self, info_hash: &InfoHash) -> bool {
self.whitelist.write().await.remove(info_hash)
}

/// It checks if it contains an info-hash.
pub async fn contains(&self, info_hash: &InfoHash) -> bool {
self.whitelist.read().await.contains(info_hash)
}

/// It clears the whitelist.
pub async fn clear(&self) {
let mut whitelist = self.whitelist.write().await;
whitelist.clear();
}
}

#[cfg(test)]
mod tests {
use bittorrent_primitives::info_hash::InfoHash;

use crate::core::whitelist::in_memory::InMemoryWhitelist;

fn sample_info_hash() -> InfoHash {
"3b245504cf5f11bbdbe1201cea6a6bf45aee1bc0".parse::<InfoHash>().unwrap() // # DevSkim: ignore DS173237
}

#[tokio::test]
async fn should_allow_adding_a_new_torrent_to_the_whitelist() {
let info_hash = sample_info_hash();

let whitelist = InMemoryWhitelist::default();

whitelist.add(&info_hash).await;

assert!(whitelist.contains(&info_hash).await);
}

#[tokio::test]
async fn should_allow_removing_a_new_torrent_to_the_whitelist() {
let info_hash = sample_info_hash();

let whitelist = InMemoryWhitelist::default();

whitelist.add(&info_hash).await;
whitelist.remove(&sample_info_hash()).await;

assert!(!whitelist.contains(&info_hash).await);
}

#[tokio::test]
async fn should_allow_clearing_the_whitelist() {
let info_hash = sample_info_hash();

let whitelist = InMemoryWhitelist::default();

whitelist.add(&info_hash).await;
whitelist.clear().await;

assert!(!whitelist.contains(&info_hash).await);
}

#[tokio::test]
async fn should_allow_checking_if_an_infohash_is_whitelisted() {
let info_hash = sample_info_hash();

let whitelist = InMemoryWhitelist::default();

whitelist.add(&info_hash).await;

assert!(whitelist.contains(&info_hash).await);
}
}
166 changes: 10 additions & 156 deletions src/core/whitelist/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
pub mod in_memory;
pub mod persisted;

use std::sync::Arc;

use bittorrent_primitives::info_hash::InfoHash;
use in_memory::InMemoryWhitelist;
use persisted::DatabaseWhitelist;

use super::databases::{self, Database};

Expand All @@ -17,7 +22,7 @@ impl WhiteListManager {
#[must_use]
pub fn new(database: Arc<Box<dyn Database>>) -> Self {
Self {
in_memory_whitelist: InMemoryWhitelist::new(),
in_memory_whitelist: InMemoryWhitelist::default(),
database_whitelist: DatabaseWhitelist::new(database),
}
}
Expand All @@ -29,7 +34,7 @@ impl WhiteListManager {
///
/// Will return a `database::Error` if unable to add the `info_hash` into the whitelist database.
pub async fn add_torrent_to_whitelist(&self, info_hash: &InfoHash) -> Result<(), databases::error::Error> {
self.database_whitelist.add_torrent_to_database_whitelist(info_hash)?;
self.database_whitelist.add(info_hash)?;
self.in_memory_whitelist.add(info_hash).await;
Ok(())
}
Expand All @@ -41,7 +46,7 @@ impl WhiteListManager {
///
/// Will return a `database::Error` if unable to remove the `info_hash` from the whitelist database.
pub async fn remove_torrent_from_whitelist(&self, info_hash: &InfoHash) -> Result<(), databases::error::Error> {
self.database_whitelist.remove_torrent_from_database_whitelist(info_hash)?;
self.database_whitelist.remove(info_hash)?;
self.in_memory_whitelist.remove(info_hash).await;
Ok(())
}
Expand All @@ -52,7 +57,7 @@ impl WhiteListManager {
///
/// Will return a `database::Error` if unable to remove the `info_hash` from the whitelist database.
pub fn remove_torrent_from_database_whitelist(&self, info_hash: &InfoHash) -> Result<(), databases::error::Error> {
self.database_whitelist.remove_torrent_from_database_whitelist(info_hash)
self.database_whitelist.remove(info_hash)
}

/// It adds a torrent from the whitelist in memory.
Expand All @@ -76,7 +81,7 @@ impl WhiteListManager {
///
/// Will return a `database::Error` if unable to load the list whitelisted `info_hash`s from the database.
pub async fn load_whitelist_from_database(&self) -> Result<(), databases::error::Error> {
let whitelisted_torrents_from_database = self.database_whitelist.load_whitelist_from_database()?;
let whitelisted_torrents_from_database = self.database_whitelist.load_from_database()?;

self.in_memory_whitelist.clear().await;

Expand All @@ -87,154 +92,3 @@ impl WhiteListManager {
Ok(())
}
}

/// The in-memory list of allowed torrents.
struct InMemoryWhitelist {
/// The list of allowed torrents.
whitelist: tokio::sync::RwLock<std::collections::HashSet<InfoHash>>,
}

impl InMemoryWhitelist {
pub fn new() -> Self {
Self {
whitelist: tokio::sync::RwLock::new(std::collections::HashSet::new()),
}
}

/// It adds a torrent from the whitelist in memory.
pub async fn add(&self, info_hash: &InfoHash) -> bool {
self.whitelist.write().await.insert(*info_hash)
}

/// It removes a torrent from the whitelist in memory.
pub async fn remove(&self, info_hash: &InfoHash) -> bool {
self.whitelist.write().await.remove(info_hash)
}

/// It checks if it contains an info-hash.
pub async fn contains(&self, info_hash: &InfoHash) -> bool {
self.whitelist.read().await.contains(info_hash)
}

/// It clears the whitelist.
pub async fn clear(&self) {
let mut whitelist = self.whitelist.write().await;
whitelist.clear();
}
}

/// The persisted list of allowed torrents.
struct DatabaseWhitelist {
/// A database driver implementation: [`Sqlite3`](crate::core::databases::sqlite)
/// or [`MySQL`](crate::core::databases::mysql)
database: Arc<Box<dyn Database>>,
}

impl DatabaseWhitelist {
#[must_use]
pub fn new(database: Arc<Box<dyn Database>>) -> Self {
Self { database }
}

/// It adds a torrent to the whitelist if it has not been whitelisted previously
fn add_torrent_to_database_whitelist(&self, info_hash: &InfoHash) -> Result<(), databases::error::Error> {
let is_whitelisted = self.database.is_info_hash_whitelisted(*info_hash)?;

if is_whitelisted {
return Ok(());
}

self.database.add_info_hash_to_whitelist(*info_hash)?;

Ok(())
}

/// It removes a torrent from the whitelist in the database.
///
/// # Errors
///
/// Will return a `database::Error` if unable to remove the `info_hash` from the whitelist database.
pub fn remove_torrent_from_database_whitelist(&self, info_hash: &InfoHash) -> Result<(), databases::error::Error> {
let is_whitelisted = self.database.is_info_hash_whitelisted(*info_hash)?;

if !is_whitelisted {
return Ok(());
}

self.database.remove_info_hash_from_whitelist(*info_hash)?;

Ok(())
}

/// It loads the whitelist from the database.
///
/// # Errors
///
/// Will return a `database::Error` if unable to load the list whitelisted `info_hash`s from the database.
pub fn load_whitelist_from_database(&self) -> Result<Vec<InfoHash>, databases::error::Error> {
self.database.load_whitelist()
}
}

#[cfg(test)]
mod tests {
use bittorrent_primitives::info_hash::InfoHash;

fn sample_info_hash() -> InfoHash {
"3b245504cf5f11bbdbe1201cea6a6bf45aee1bc0".parse::<InfoHash>().unwrap() // # DevSkim: ignore DS173237
}

mod in_memory_whitelist {

use crate::core::whitelist::tests::sample_info_hash;
use crate::core::whitelist::InMemoryWhitelist;

#[tokio::test]
async fn should_allow_adding_a_new_torrent_to_the_whitelist() {
let info_hash = sample_info_hash();

let whitelist = InMemoryWhitelist::new();

whitelist.add(&info_hash).await;

assert!(whitelist.contains(&info_hash).await);
}

#[tokio::test]
async fn should_allow_removing_a_new_torrent_to_the_whitelist() {
let info_hash = sample_info_hash();

let whitelist = InMemoryWhitelist::new();

whitelist.add(&info_hash).await;
whitelist.remove(&sample_info_hash()).await;

assert!(!whitelist.contains(&info_hash).await);
}

#[tokio::test]
async fn should_allow_clearing_the_whitelist() {
let info_hash = sample_info_hash();

let whitelist = InMemoryWhitelist::new();

whitelist.add(&info_hash).await;
whitelist.clear().await;

assert!(!whitelist.contains(&info_hash).await);
}

#[tokio::test]
async fn should_allow_checking_if_an_infohash_is_whitelisted() {
let info_hash = sample_info_hash();

let whitelist = InMemoryWhitelist::new();

whitelist.add(&info_hash).await;

assert!(whitelist.contains(&info_hash).await);
}
}

mod database_whitelist {}
}
62 changes: 62 additions & 0 deletions src/core/whitelist/persisted.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use std::sync::Arc;

use bittorrent_primitives::info_hash::InfoHash;

use super::databases::{self, Database};

/// The persisted list of allowed torrents.
pub struct DatabaseWhitelist {
/// A database driver implementation: [`Sqlite3`](crate::core::databases::sqlite)
/// or [`MySQL`](crate::core::databases::mysql)
database: Arc<Box<dyn Database>>,
}

impl DatabaseWhitelist {
#[must_use]
pub fn new(database: Arc<Box<dyn Database>>) -> Self {
Self { database }
}

/// It adds a torrent to the whitelist if it has not been whitelisted previously
///
/// # Errors
///
/// Will return a `database::Error` if unable to add the `info_hash` to the whitelist database.
pub fn add(&self, info_hash: &InfoHash) -> Result<(), databases::error::Error> {
let is_whitelisted = self.database.is_info_hash_whitelisted(*info_hash)?;

if is_whitelisted {
return Ok(());
}

self.database.add_info_hash_to_whitelist(*info_hash)?;

Ok(())
}

/// It removes a torrent from the whitelist in the database.
///
/// # Errors
///
/// Will return a `database::Error` if unable to remove the `info_hash` from the whitelist database.
pub fn remove(&self, info_hash: &InfoHash) -> Result<(), databases::error::Error> {
let is_whitelisted = self.database.is_info_hash_whitelisted(*info_hash)?;

if !is_whitelisted {
return Ok(());
}

self.database.remove_info_hash_from_whitelist(*info_hash)?;

Ok(())
}

/// It loads the whitelist from the database.
///
/// # Errors
///
/// Will return a `database::Error` if unable to load the list whitelisted `info_hash`s from the database.
pub fn load_from_database(&self) -> Result<Vec<InfoHash>, databases::error::Error> {
self.database.load_whitelist()
}
}
5 changes: 4 additions & 1 deletion src/servers/udp/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1391,7 +1391,10 @@ mod tests {

add_a_seeder(tracker.clone(), &remote_addr, &info_hash).await;

tracker.whitelist_manager.add_torrent_to_memory_whitelist(&info_hash.0.into()).await;
tracker
.whitelist_manager
.add_torrent_to_memory_whitelist(&info_hash.0.into())
.await;

let request = build_scrape_request(&remote_addr, &info_hash);

Expand Down

0 comments on commit cc2bc7b

Please sign in to comment.