Skip to content

Commit 72d0678

Browse files
committed
dev: move torrent/repository to packages
1 parent bec17b3 commit 72d0678

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+1127
-962
lines changed

.vscode/settings.json

+5
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,9 @@
3131
"evenBetterToml.formatter.trailingNewline": true,
3232
"evenBetterToml.formatter.reorderKeys": true,
3333
"evenBetterToml.formatter.reorderArrays": true,
34+
"rust-analyzer.linkedProjects": [
35+
"./packages/torrent-repository/Cargo.toml",
36+
"./packages/primitives/Cargo.toml",
37+
"./packages/primitives/Cargo.toml"
38+
],
3439
}

Cargo.lock

+19-11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ torrust-tracker-configuration = { version = "3.0.0-alpha.12-develop", path = "pa
6868
torrust-tracker-contrib-bencode = { version = "3.0.0-alpha.12-develop", path = "contrib/bencode" }
6969
torrust-tracker-located-error = { version = "3.0.0-alpha.12-develop", path = "packages/located-error" }
7070
torrust-tracker-primitives = { version = "3.0.0-alpha.12-develop", path = "packages/primitives" }
71+
torrust-tracker-torrent-repository = { version = "3.0.0-alpha.12-develop", path = "packages/torrent-repository" }
7172
tower-http = { version = "0", features = ["compression-full"] }
7273
uuid = { version = "1", features = ["v4"] }
7374
colored = "2.1.0"
@@ -93,7 +94,7 @@ members = [
9394
"packages/located-error",
9495
"packages/primitives",
9596
"packages/test-helpers",
96-
"packages/torrent-repository-benchmarks",
97+
"packages/torrent-repository"
9798
]
9899

99100
[profile.dev]

cSpell.json

+5
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"elif",
4747
"filesd",
4848
"Freebox",
49+
"Frostegård",
4950
"gecos",
5051
"Grcov",
5152
"hasher",
@@ -61,6 +62,7 @@
6162
"infoschema",
6263
"Intermodal",
6364
"intervali",
65+
"Joakim",
6466
"keyout",
6567
"lcov",
6668
"leecher",
@@ -89,6 +91,7 @@
8991
"oneshot",
9092
"ostr",
9193
"Pando",
94+
"peekable",
9295
"proot",
9396
"proto",
9497
"Quickstart",
@@ -101,6 +104,7 @@
101104
"reqwest",
102105
"rerequests",
103106
"ringbuf",
107+
"ringsize",
104108
"rngs",
105109
"routable",
106110
"rusqlite",
@@ -119,6 +123,7 @@
119123
"Swatinem",
120124
"Swiftbit",
121125
"taiki",
126+
"tdyne",
122127
"tempfile",
123128
"thiserror",
124129
"tlsv",

packages/configuration/src/lib.rs

+7
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,13 @@ use thiserror::Error;
243243
use torrust_tracker_located_error::{DynError, Located, LocatedError};
244244
use torrust_tracker_primitives::{DatabaseDriver, TrackerMode};
245245

246+
#[derive(Copy, Clone, Debug, PartialEq, Default, Constructor)]
247+
pub struct TrackerPolicy {
248+
pub remove_peerless_torrents: bool,
249+
pub max_peer_timeout: u32,
250+
pub persistent_torrent_completed_stat: bool,
251+
}
252+
246253
/// Information required for loading config
247254
#[derive(Debug, Default, Clone)]
248255
pub struct Info {

packages/primitives/Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,8 @@ version.workspace = true
1616

1717
[dependencies]
1818
derive_more = "0"
19+
thiserror = "1"
20+
binascii = "0"
1921
serde = { version = "1", features = ["derive"] }
22+
tdyne-peer-id = "1"
23+
tdyne-peer-id-registry = "0"
+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//! Copyright (c) 2020-2023 Joakim Frostegård and The Torrust Developers
2+
//!
3+
//! Distributed under Apache 2.0 license
4+
5+
use serde::{Deserialize, Serialize};
6+
7+
/// Announce events. Described on the
8+
/// [BEP 3. The `BitTorrent` Protocol Specification](https://www.bittorrent.org/beps/bep_0003.html)
9+
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug, Serialize, Deserialize)]
10+
pub enum AnnounceEvent {
11+
/// The peer has started downloading the torrent.
12+
Started,
13+
/// The peer has ceased downloading the torrent.
14+
Stopped,
15+
/// The peer has completed downloading the torrent.
16+
Completed,
17+
/// This is one of the announcements done at regular intervals.
18+
None,
19+
}
20+
21+
impl AnnounceEvent {
22+
#[inline]
23+
#[must_use]
24+
pub fn from_i32(i: i32) -> Self {
25+
match i {
26+
1 => Self::Completed,
27+
2 => Self::Started,
28+
3 => Self::Stopped,
29+
_ => Self::None,
30+
}
31+
}
32+
33+
#[inline]
34+
#[must_use]
35+
pub fn to_i32(&self) -> i32 {
36+
match self {
37+
AnnounceEvent::None => 0,
38+
AnnounceEvent::Completed => 1,
39+
AnnounceEvent::Started => 2,
40+
AnnounceEvent::Stopped => 3,
41+
}
42+
}
43+
}

packages/primitives/src/info_hash.rs

+165
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
use std::panic::Location;
2+
3+
use thiserror::Error;
4+
5+
/// `BitTorrent` Info Hash v1
6+
#[derive(PartialEq, Eq, Hash, Clone, Copy, Default, Debug)]
7+
pub struct InfoHash(pub [u8; 20]);
8+
9+
pub const INFO_HASH_BYTES_LEN: usize = 20;
10+
11+
impl InfoHash {
12+
/// Create a new `InfoHash` from a byte slice.
13+
///
14+
/// # Panics
15+
///
16+
/// Will panic if byte slice does not contains the exact amount of bytes need for the `InfoHash`.
17+
#[must_use]
18+
pub fn from_bytes(bytes: &[u8]) -> Self {
19+
assert_eq!(bytes.len(), INFO_HASH_BYTES_LEN);
20+
let mut ret = Self([0u8; INFO_HASH_BYTES_LEN]);
21+
ret.0.clone_from_slice(bytes);
22+
ret
23+
}
24+
25+
/// Returns the `InfoHash` internal byte array.
26+
#[must_use]
27+
pub fn bytes(&self) -> [u8; 20] {
28+
self.0
29+
}
30+
31+
/// Returns the `InfoHash` as a hex string.
32+
#[must_use]
33+
pub fn to_hex_string(&self) -> String {
34+
self.to_string()
35+
}
36+
}
37+
38+
impl Ord for InfoHash {
39+
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
40+
self.0.cmp(&other.0)
41+
}
42+
}
43+
44+
impl std::cmp::PartialOrd<InfoHash> for InfoHash {
45+
fn partial_cmp(&self, other: &InfoHash) -> Option<std::cmp::Ordering> {
46+
Some(self.cmp(other))
47+
}
48+
}
49+
50+
impl std::fmt::Display for InfoHash {
51+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52+
let mut chars = [0u8; 40];
53+
binascii::bin2hex(&self.0, &mut chars).expect("failed to hexlify");
54+
write!(f, "{}", std::str::from_utf8(&chars).unwrap())
55+
}
56+
}
57+
58+
impl std::str::FromStr for InfoHash {
59+
type Err = binascii::ConvertError;
60+
61+
fn from_str(s: &str) -> Result<Self, Self::Err> {
62+
let mut i = Self([0u8; 20]);
63+
if s.len() != 40 {
64+
return Err(binascii::ConvertError::InvalidInputLength);
65+
}
66+
binascii::hex2bin(s.as_bytes(), &mut i.0)?;
67+
Ok(i)
68+
}
69+
}
70+
71+
impl std::convert::From<&[u8]> for InfoHash {
72+
fn from(data: &[u8]) -> InfoHash {
73+
assert_eq!(data.len(), 20);
74+
let mut ret = InfoHash([0u8; 20]);
75+
ret.0.clone_from_slice(data);
76+
ret
77+
}
78+
}
79+
80+
impl std::convert::From<[u8; 20]> for InfoHash {
81+
fn from(val: [u8; 20]) -> Self {
82+
InfoHash(val)
83+
}
84+
}
85+
86+
/// Errors that can occur when converting from a `Vec<u8>` to an `InfoHash`.
87+
#[derive(Error, Debug)]
88+
pub enum ConversionError {
89+
/// Not enough bytes for infohash. An infohash is 20 bytes.
90+
#[error("not enough bytes for infohash: {message} {location}")]
91+
NotEnoughBytes {
92+
location: &'static Location<'static>,
93+
message: String,
94+
},
95+
/// Too many bytes for infohash. An infohash is 20 bytes.
96+
#[error("too many bytes for infohash: {message} {location}")]
97+
TooManyBytes {
98+
location: &'static Location<'static>,
99+
message: String,
100+
},
101+
}
102+
103+
impl TryFrom<Vec<u8>> for InfoHash {
104+
type Error = ConversionError;
105+
106+
fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
107+
if bytes.len() < INFO_HASH_BYTES_LEN {
108+
return Err(ConversionError::NotEnoughBytes {
109+
location: Location::caller(),
110+
message: format! {"got {} bytes, expected {}", bytes.len(), INFO_HASH_BYTES_LEN},
111+
});
112+
}
113+
if bytes.len() > INFO_HASH_BYTES_LEN {
114+
return Err(ConversionError::TooManyBytes {
115+
location: Location::caller(),
116+
message: format! {"got {} bytes, expected {}", bytes.len(), INFO_HASH_BYTES_LEN},
117+
});
118+
}
119+
Ok(Self::from_bytes(&bytes))
120+
}
121+
}
122+
123+
impl serde::ser::Serialize for InfoHash {
124+
fn serialize<S: serde::ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
125+
let mut buffer = [0u8; 40];
126+
let bytes_out = binascii::bin2hex(&self.0, &mut buffer).ok().unwrap();
127+
let str_out = std::str::from_utf8(bytes_out).unwrap();
128+
serializer.serialize_str(str_out)
129+
}
130+
}
131+
132+
impl<'de> serde::de::Deserialize<'de> for InfoHash {
133+
fn deserialize<D: serde::de::Deserializer<'de>>(des: D) -> Result<Self, D::Error> {
134+
des.deserialize_str(InfoHashVisitor)
135+
}
136+
}
137+
138+
struct InfoHashVisitor;
139+
140+
impl<'v> serde::de::Visitor<'v> for InfoHashVisitor {
141+
type Value = InfoHash;
142+
143+
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
144+
write!(formatter, "a 40 character long hash")
145+
}
146+
147+
fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
148+
if v.len() != 40 {
149+
return Err(serde::de::Error::invalid_value(
150+
serde::de::Unexpected::Str(v),
151+
&"a 40 character long string",
152+
));
153+
}
154+
155+
let mut res = InfoHash([0u8; 20]);
156+
157+
if binascii::hex2bin(v.as_bytes(), &mut res.0).is_err() {
158+
return Err(serde::de::Error::invalid_value(
159+
serde::de::Unexpected::Str(v),
160+
&"a hexadecimal string",
161+
));
162+
};
163+
Ok(res)
164+
}
165+
}

0 commit comments

Comments
 (0)