From 8d4b6f8f389b0e32d829a03be06fda4c4fa5e67d Mon Sep 17 00:00:00 2001 From: Cameron Garnham Date: Sat, 13 Jul 2024 14:59:46 +0200 Subject: [PATCH] dev: use aquatic_udp_protocol InfoHash inside our type --- Cargo.lock | 2 + packages/primitives/Cargo.toml | 2 + packages/primitives/src/info_hash.rs | 64 +++++++++++++++---- .../benches/helpers/asyn.rs | 12 ++-- .../benches/helpers/sync.rs | 12 ++-- .../benches/helpers/utils.rs | 2 +- src/console/clients/checker/checks/udp.rs | 7 +- src/servers/http/v1/responses/scrape.rs | 2 +- src/servers/udp/handlers.rs | 6 +- 9 files changed, 74 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 889a6a5d7..fd5491781 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3962,12 +3962,14 @@ dependencies = [ name = "torrust-tracker-primitives" version = "3.0.0-alpha.12-develop" dependencies = [ + "aquatic_udp_protocol", "binascii", "derive_more", "serde", "tdyne-peer-id", "tdyne-peer-id-registry", "thiserror", + "zerocopy", ] [[package]] diff --git a/packages/primitives/Cargo.toml b/packages/primitives/Cargo.toml index 174750fbb..05981b3a8 100644 --- a/packages/primitives/Cargo.toml +++ b/packages/primitives/Cargo.toml @@ -15,9 +15,11 @@ rust-version.workspace = true version.workspace = true [dependencies] +aquatic_udp_protocol = "0" binascii = "0" derive_more = "0" serde = { version = "1", features = ["derive"] } tdyne-peer-id = "1" tdyne-peer-id-registry = "0" thiserror = "1" +zerocopy = "0" diff --git a/packages/primitives/src/info_hash.rs b/packages/primitives/src/info_hash.rs index a07cc41a2..57dfd90e5 100644 --- a/packages/primitives/src/info_hash.rs +++ b/packages/primitives/src/info_hash.rs @@ -1,11 +1,15 @@ use std::hash::{DefaultHasher, Hash, Hasher}; +use std::ops::{Deref, DerefMut}; use std::panic::Location; use thiserror::Error; +use zerocopy::FromBytes; /// `BitTorrent` Info Hash v1 -#[derive(PartialEq, Eq, Hash, Clone, Copy, Default, Debug)] -pub struct InfoHash(pub [u8; 20]); +#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] +pub struct InfoHash { + data: aquatic_udp_protocol::InfoHash, +} pub const INFO_HASH_BYTES_LEN: usize = 20; @@ -17,10 +21,9 @@ impl InfoHash { /// Will panic if byte slice does not contains the exact amount of bytes need for the `InfoHash`. #[must_use] pub fn from_bytes(bytes: &[u8]) -> Self { - assert_eq!(bytes.len(), INFO_HASH_BYTES_LEN); - let mut ret = Self([0u8; INFO_HASH_BYTES_LEN]); - ret.0.clone_from_slice(bytes); - ret + let data = aquatic_udp_protocol::InfoHash::read_from(bytes).expect("it should have the exact amount of bytes"); + + Self { data } } /// Returns the `InfoHash` internal byte array. @@ -36,6 +39,34 @@ impl InfoHash { } } +impl Default for InfoHash { + fn default() -> Self { + Self { + data: aquatic_udp_protocol::InfoHash(Default::default()), + } + } +} + +impl From for InfoHash { + fn from(data: aquatic_udp_protocol::InfoHash) -> Self { + Self { data } + } +} + +impl Deref for InfoHash { + type Target = aquatic_udp_protocol::InfoHash; + + fn deref(&self) -> &Self::Target { + &self.data + } +} + +impl DerefMut for InfoHash { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.data + } +} + impl Ord for InfoHash { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.0.cmp(&other.0) @@ -60,7 +91,7 @@ impl std::str::FromStr for InfoHash { type Err = binascii::ConvertError; fn from_str(s: &str) -> Result { - let mut i = Self([0u8; 20]); + let mut i = Self::default(); if s.len() != 40 { return Err(binascii::ConvertError::InvalidInputLength); } @@ -72,7 +103,7 @@ impl std::str::FromStr for InfoHash { impl std::convert::From<&[u8]> for InfoHash { fn from(data: &[u8]) -> InfoHash { assert_eq!(data.len(), 20); - let mut ret = InfoHash([0u8; 20]); + let mut ret = Self::default(); ret.0.clone_from_slice(data); ret } @@ -82,23 +113,28 @@ impl std::convert::From<&[u8]> for InfoHash { impl std::convert::From<&DefaultHasher> for InfoHash { fn from(data: &DefaultHasher) -> InfoHash { let n = data.finish().to_le_bytes(); - InfoHash([ + let bytes = [ 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], n[3], - ]) + ]; + let data = aquatic_udp_protocol::InfoHash(bytes); + Self { data } } } impl std::convert::From<&i32> for InfoHash { fn from(n: &i32) -> InfoHash { let n = n.to_le_bytes(); - InfoHash([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, n[0], n[1], n[2], n[3]]) + let bytes = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, n[0], n[1], n[2], n[3]]; + let data = aquatic_udp_protocol::InfoHash(bytes); + Self { data } } } impl std::convert::From<[u8; 20]> for InfoHash { - fn from(val: [u8; 20]) -> Self { - InfoHash(val) + fn from(bytes: [u8; 20]) -> Self { + let data = aquatic_udp_protocol::InfoHash(bytes); + Self { data } } } @@ -171,7 +207,7 @@ impl<'v> serde::de::Visitor<'v> for InfoHashVisitor { )); } - let mut res = InfoHash([0u8; 20]); + let mut res = InfoHash::default(); if binascii::hex2bin(v.as_bytes(), &mut res.0).is_err() { return Err(serde::de::Error::invalid_value( diff --git a/packages/torrent-repository/benches/helpers/asyn.rs b/packages/torrent-repository/benches/helpers/asyn.rs index 1c6d9d915..08862abc8 100644 --- a/packages/torrent-repository/benches/helpers/asyn.rs +++ b/packages/torrent-repository/benches/helpers/asyn.rs @@ -16,7 +16,7 @@ where for _ in 0..samples { let torrent_repository = V::default(); - let info_hash = InfoHash([0; 20]); + let info_hash = InfoHash::default(); torrent_repository.upsert_peer(&info_hash, &DEFAULT_PEER).await; @@ -33,13 +33,13 @@ where Arc: Clone + Send + Sync + 'static, { let torrent_repository = Arc::::default(); - let info_hash: &'static InfoHash = &InfoHash([0; 20]); + let info_hash = InfoHash::default(); let handles = FuturesUnordered::new(); // Add the torrent/peer to the torrent repository - torrent_repository.upsert_peer(info_hash, &DEFAULT_PEER).await; + torrent_repository.upsert_peer(&info_hash, &DEFAULT_PEER).await; - torrent_repository.get_swarm_metadata(info_hash).await; + torrent_repository.get_swarm_metadata(&info_hash).await; let start = Instant::now(); @@ -47,9 +47,9 @@ where let torrent_repository_clone = torrent_repository.clone(); let handle = runtime.spawn(async move { - torrent_repository_clone.upsert_peer(info_hash, &DEFAULT_PEER).await; + torrent_repository_clone.upsert_peer(&info_hash, &DEFAULT_PEER).await; - torrent_repository_clone.get_swarm_metadata(info_hash).await; + torrent_repository_clone.get_swarm_metadata(&info_hash).await; if let Some(sleep_time) = sleep { let start_time = std::time::Instant::now(); diff --git a/packages/torrent-repository/benches/helpers/sync.rs b/packages/torrent-repository/benches/helpers/sync.rs index 63fccfc77..77055911d 100644 --- a/packages/torrent-repository/benches/helpers/sync.rs +++ b/packages/torrent-repository/benches/helpers/sync.rs @@ -18,7 +18,7 @@ where for _ in 0..samples { let torrent_repository = V::default(); - let info_hash = InfoHash([0; 20]); + let info_hash = InfoHash::default(); torrent_repository.upsert_peer(&info_hash, &DEFAULT_PEER); @@ -35,13 +35,13 @@ where Arc: Clone + Send + Sync + 'static, { let torrent_repository = Arc::::default(); - let info_hash: &'static InfoHash = &InfoHash([0; 20]); + let info_hash = InfoHash::default(); let handles = FuturesUnordered::new(); // Add the torrent/peer to the torrent repository - torrent_repository.upsert_peer(info_hash, &DEFAULT_PEER); + torrent_repository.upsert_peer(&info_hash, &DEFAULT_PEER); - torrent_repository.get_swarm_metadata(info_hash); + torrent_repository.get_swarm_metadata(&info_hash); let start = Instant::now(); @@ -49,9 +49,9 @@ where let torrent_repository_clone = torrent_repository.clone(); let handle = runtime.spawn(async move { - torrent_repository_clone.upsert_peer(info_hash, &DEFAULT_PEER); + torrent_repository_clone.upsert_peer(&info_hash, &DEFAULT_PEER); - torrent_repository_clone.get_swarm_metadata(info_hash); + torrent_repository_clone.get_swarm_metadata(&info_hash); if let Some(sleep_time) = sleep { let start_time = std::time::Instant::now(); diff --git a/packages/torrent-repository/benches/helpers/utils.rs b/packages/torrent-repository/benches/helpers/utils.rs index 170194806..2f912a5c0 100644 --- a/packages/torrent-repository/benches/helpers/utils.rs +++ b/packages/torrent-repository/benches/helpers/utils.rs @@ -30,7 +30,7 @@ pub fn generate_unique_info_hashes(size: usize) -> Vec { bytes[2] = ((i >> 16) & 0xFF) as u8; bytes[3] = ((i >> 24) & 0xFF) as u8; - let info_hash = InfoHash(bytes); + let info_hash = InfoHash::from_bytes(&bytes); result.insert(info_hash); } diff --git a/src/console/clients/checker/checks/udp.rs b/src/console/clients/checker/checks/udp.rs index dd4d5e639..dd9afa47c 100644 --- a/src/console/clients/checker/checks/udp.rs +++ b/src/console/clients/checker/checks/udp.rs @@ -4,7 +4,6 @@ use std::time::Duration; use aquatic_udp_protocol::TransactionId; use hex_literal::hex; use serde::Serialize; -use torrust_tracker_primitives::info_hash::InfoHash; use crate::console::clients::udp::checker::Client; use crate::console::clients::udp::Error; @@ -29,7 +28,7 @@ pub async fn run(udp_trackers: Vec, timeout: Duration) -> Vec, timeout: Duration) -> Vec, timeout: Duration) -> Vec ScrapeData { - let info_hash = InfoHash([0x69; 20]); + let info_hash = InfoHash::from_bytes(&[0x69; 20]); let mut scrape_data = ScrapeData::empty(); scrape_data.add_file( &info_hash, diff --git a/src/servers/udp/handlers.rs b/src/servers/udp/handlers.rs index e37179b4b..7eb07bc8d 100644 --- a/src/servers/udp/handlers.rs +++ b/src/servers/udp/handlers.rs @@ -151,7 +151,7 @@ pub async fn handle_announce( check(&remote_addr, &from_connection_id(&announce_request.connection_id))?; - let info_hash = InfoHash(announce_request.info_hash.0); + let info_hash = announce_request.info_hash.into(); let remote_client_ip = remote_addr.ip(); // Authorization @@ -240,9 +240,9 @@ pub async fn handle_scrape(remote_addr: SocketAddr, request: &ScrapeRequest, tra debug!("udp scrape request: {:#?}", request); // Convert from aquatic infohashes - let mut info_hashes = vec![]; + let mut info_hashes: Vec = vec![]; for info_hash in &request.info_hashes { - info_hashes.push(InfoHash(info_hash.0)); + info_hashes.push((*info_hash).into()); } let scrape_data = if tracker.requires_authentication() {