Skip to content

Commit

Permalink
dev: move torrent/repository to packages
Browse files Browse the repository at this point in the history
  • Loading branch information
da2ce7 committed Mar 25, 2024
1 parent 4b2d6fe commit 9a43815
Show file tree
Hide file tree
Showing 99 changed files with 2,072 additions and 1,953 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@
"evenBetterToml.formatter.trailingNewline": true,
"evenBetterToml.formatter.reorderKeys": true,
"evenBetterToml.formatter.reorderArrays": true,

}
31 changes: 17 additions & 14 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 2 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ axum = { version = "0", features = ["macros"] }
axum-client-ip = "0"
axum-extra = { version = "0", features = ["query"] }
axum-server = { version = "0", features = ["tls-rustls"] }
binascii = "0"
chrono = { version = "0", default-features = false, features = ["clock"] }
clap = { version = "4", features = ["derive", "env"] }
colored = "2"
Expand All @@ -62,14 +61,13 @@ serde_bencode = "0"
serde_bytes = "0"
serde_json = "1"
serde_repr = "0"
tdyne-peer-id = "1"
tdyne-peer-id-registry = "0"
thiserror = "1"
tokio = { version = "1", features = ["macros", "net", "rt-multi-thread", "signal", "sync"] }
torrust-tracker-configuration = { version = "3.0.0-alpha.12-develop", path = "packages/configuration" }
torrust-tracker-contrib-bencode = { version = "3.0.0-alpha.12-develop", path = "contrib/bencode" }
torrust-tracker-located-error = { version = "3.0.0-alpha.12-develop", path = "packages/located-error" }
torrust-tracker-primitives = { version = "3.0.0-alpha.12-develop", path = "packages/primitives" }
torrust-tracker-torrent-repository = { version = "3.0.0-alpha.12-develop", path = "packages/torrent-repository" }
tower-http = { version = "0", features = ["compression-full", "cors", "propagate-header", "request-id", "trace"] }
trace = "0"
tracing = "0"
Expand All @@ -91,7 +89,7 @@ members = [
"packages/located-error",
"packages/primitives",
"packages/test-helpers",
"packages/torrent-repository-benchmarks",
"packages/torrent-repository"
]

[profile.dev]
Expand Down
4 changes: 4 additions & 0 deletions cSpell.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"filesd",
"flamegraph",
"Freebox",
"Frostegård",
"gecos",
"Grcov",
"hasher",
Expand All @@ -68,6 +69,7 @@
"Intermodal",
"intervali",
"kcachegrind",
"Joakim",
"keyout",
"lcov",
"leecher",
Expand Down Expand Up @@ -96,6 +98,7 @@
"oneshot",
"ostr",
"Pando",
"peekable",
"proot",
"proto",
"Quickstart",
Expand All @@ -109,6 +112,7 @@
"reqwest",
"rerequests",
"ringbuf",
"ringsize",
"rngs",
"rosegment",
"routable",
Expand Down
7 changes: 7 additions & 0 deletions packages/configuration/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,13 @@ use thiserror::Error;
use torrust_tracker_located_error::{DynError, Located, LocatedError};
use torrust_tracker_primitives::{DatabaseDriver, TrackerMode};

#[derive(Copy, Clone, Debug, PartialEq, Default, Constructor)]
pub struct TrackerPolicy {
pub remove_peerless_torrents: bool,
pub max_peer_timeout: u32,
pub persistent_torrent_completed_stat: bool,
}

/// Information required for loading config
#[derive(Debug, Default, Clone)]
pub struct Info {
Expand Down
4 changes: 4 additions & 0 deletions packages/primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,8 @@ version.workspace = true

[dependencies]
derive_more = "0"
thiserror = "1"
binascii = "0"
serde = { version = "1", features = ["derive"] }
tdyne-peer-id = "1"
tdyne-peer-id-registry = "0"
43 changes: 43 additions & 0 deletions packages/primitives/src/announce_event.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//! Copyright (c) 2020-2023 Joakim Frostegård and The Torrust Developers
//!
//! Distributed under Apache 2.0 license

use serde::{Deserialize, Serialize};

/// Announce events. Described on the
/// [BEP 3. The `BitTorrent` Protocol Specification](https://www.bittorrent.org/beps/bep_0003.html)
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug, Serialize, Deserialize)]
pub enum AnnounceEvent {
/// The peer has started downloading the torrent.
Started,
/// The peer has ceased downloading the torrent.
Stopped,
/// The peer has completed downloading the torrent.
Completed,
/// This is one of the announcements done at regular intervals.
None,
}

impl AnnounceEvent {
#[inline]
#[must_use]
pub fn from_i32(i: i32) -> Self {
match i {
1 => Self::Completed,
2 => Self::Started,
3 => Self::Stopped,
_ => Self::None,
}
}

#[inline]
#[must_use]
pub fn to_i32(&self) -> i32 {
match self {
AnnounceEvent::None => 0,
AnnounceEvent::Completed => 1,
AnnounceEvent::Started => 2,
AnnounceEvent::Stopped => 3,
}
}
}
165 changes: 165 additions & 0 deletions packages/primitives/src/info_hash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
use std::panic::Location;

use thiserror::Error;

/// `BitTorrent` Info Hash v1
#[derive(PartialEq, Eq, Hash, Clone, Copy, Default, Debug)]
pub struct InfoHash(pub [u8; 20]);

pub const INFO_HASH_BYTES_LEN: usize = 20;

impl InfoHash {
/// Create a new `InfoHash` from a byte slice.
///
/// # Panics
///
/// 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
}

/// Returns the `InfoHash` internal byte array.
#[must_use]
pub fn bytes(&self) -> [u8; 20] {
self.0
}

/// Returns the `InfoHash` as a hex string.
#[must_use]
pub fn to_hex_string(&self) -> String {
self.to_string()
}
}

impl Ord for InfoHash {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.0.cmp(&other.0)
}
}

impl std::cmp::PartialOrd<InfoHash> for InfoHash {
fn partial_cmp(&self, other: &InfoHash) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}

impl std::fmt::Display for InfoHash {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut chars = [0u8; 40];
binascii::bin2hex(&self.0, &mut chars).expect("failed to hexlify");
write!(f, "{}", std::str::from_utf8(&chars).unwrap())
}
}

impl std::str::FromStr for InfoHash {
type Err = binascii::ConvertError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut i = Self([0u8; 20]);
if s.len() != 40 {
return Err(binascii::ConvertError::InvalidInputLength);
}
binascii::hex2bin(s.as_bytes(), &mut i.0)?;
Ok(i)
}
}

impl std::convert::From<&[u8]> for InfoHash {
fn from(data: &[u8]) -> InfoHash {
assert_eq!(data.len(), 20);
let mut ret = InfoHash([0u8; 20]);
ret.0.clone_from_slice(data);
ret
}
}

impl std::convert::From<[u8; 20]> for InfoHash {
fn from(val: [u8; 20]) -> Self {
InfoHash(val)
}
}

/// Errors that can occur when converting from a `Vec<u8>` to an `InfoHash`.
#[derive(Error, Debug)]
pub enum ConversionError {
/// Not enough bytes for infohash. An infohash is 20 bytes.
#[error("not enough bytes for infohash: {message} {location}")]
NotEnoughBytes {
location: &'static Location<'static>,
message: String,
},
/// Too many bytes for infohash. An infohash is 20 bytes.
#[error("too many bytes for infohash: {message} {location}")]
TooManyBytes {
location: &'static Location<'static>,
message: String,
},
}

impl TryFrom<Vec<u8>> for InfoHash {
type Error = ConversionError;

fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
if bytes.len() < INFO_HASH_BYTES_LEN {
return Err(ConversionError::NotEnoughBytes {
location: Location::caller(),
message: format! {"got {} bytes, expected {}", bytes.len(), INFO_HASH_BYTES_LEN},
});
}
if bytes.len() > INFO_HASH_BYTES_LEN {
return Err(ConversionError::TooManyBytes {
location: Location::caller(),
message: format! {"got {} bytes, expected {}", bytes.len(), INFO_HASH_BYTES_LEN},
});
}
Ok(Self::from_bytes(&bytes))
}
}

impl serde::ser::Serialize for InfoHash {
fn serialize<S: serde::ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut buffer = [0u8; 40];
let bytes_out = binascii::bin2hex(&self.0, &mut buffer).ok().unwrap();
let str_out = std::str::from_utf8(bytes_out).unwrap();
serializer.serialize_str(str_out)
}
}

impl<'de> serde::de::Deserialize<'de> for InfoHash {
fn deserialize<D: serde::de::Deserializer<'de>>(des: D) -> Result<Self, D::Error> {
des.deserialize_str(InfoHashVisitor)
}
}

struct InfoHashVisitor;

impl<'v> serde::de::Visitor<'v> for InfoHashVisitor {
type Value = InfoHash;

fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(formatter, "a 40 character long hash")
}

fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
if v.len() != 40 {
return Err(serde::de::Error::invalid_value(
serde::de::Unexpected::Str(v),
&"a 40 character long string",
));
}

let mut res = InfoHash([0u8; 20]);

if binascii::hex2bin(v.as_bytes(), &mut res.0).is_err() {
return Err(serde::de::Error::invalid_value(
serde::de::Unexpected::Str(v),
&"a hexadecimal string",
));
};
Ok(res)
}
}
Loading

0 comments on commit 9a43815

Please sign in to comment.