Skip to content

Commit

Permalink
code restructure
Browse files Browse the repository at this point in the history
  • Loading branch information
ishaan26 committed Dec 31, 2024
1 parent a04a34d commit 6b0867b
Show file tree
Hide file tree
Showing 7 changed files with 202 additions and 117 deletions.
78 changes: 73 additions & 5 deletions zung_parsers/src/bencode/value.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
use serde::{
de::Visitor,
ser::{SerializeMap, SerializeSeq},
Serialize, Serializer,
Deserialize, Serialize, Serializer,
};

use std::{
collections::HashMap,
fmt::{self},
};
use std::{collections::HashMap, fmt};

/// Representation of Bencode values in Rust.
#[derive(Debug, Clone, PartialEq)]
Expand Down Expand Up @@ -71,6 +69,76 @@ impl Serialize for Value {
}
}

impl<'de> Deserialize<'de> for Value {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{

Check warning on line 76 in zung_parsers/src/bencode/value.rs

View check run for this annotation

Codecov / codecov/patch

zung_parsers/src/bencode/value.rs#L73-L76

Added lines #L73 - L76 were not covered by tests
struct ValueVisitor;

impl<'de> Visitor<'de> for ValueVisitor {
type Value = Value;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a bencode value")
}

Check warning on line 84 in zung_parsers/src/bencode/value.rs

View check run for this annotation

Codecov / codecov/patch

zung_parsers/src/bencode/value.rs#L82-L84

Added lines #L82 - L84 were not covered by tests

fn visit_i64<E>(self, value: i64) -> Result<Value, E>
where
E: serde::de::Error,
{
Ok(Value::Integer(value))
}

Check warning on line 91 in zung_parsers/src/bencode/value.rs

View check run for this annotation

Codecov / codecov/patch

zung_parsers/src/bencode/value.rs#L86-L91

Added lines #L86 - L91 were not covered by tests

fn visit_str<E>(self, value: &str) -> Result<Value, E>
where
E: serde::de::Error,
{
Ok(Value::String(value.to_owned()))
}

Check warning on line 98 in zung_parsers/src/bencode/value.rs

View check run for this annotation

Codecov / codecov/patch

zung_parsers/src/bencode/value.rs#L93-L98

Added lines #L93 - L98 were not covered by tests

fn visit_bytes<E>(self, value: &[u8]) -> Result<Value, E>
where
E: serde::de::Error,
{
// Try to convert to UTF-8 string first
match std::str::from_utf8(value) {
Ok(s) => Ok(Value::String(s.to_owned())),
Err(_) => Ok(Value::Bytes(value.to_vec())),

Check warning on line 107 in zung_parsers/src/bencode/value.rs

View check run for this annotation

Codecov / codecov/patch

zung_parsers/src/bencode/value.rs#L100-L107

Added lines #L100 - L107 were not covered by tests
}
}

Check warning on line 109 in zung_parsers/src/bencode/value.rs

View check run for this annotation

Codecov / codecov/patch

zung_parsers/src/bencode/value.rs#L109

Added line #L109 was not covered by tests

fn visit_seq<A>(self, mut seq: A) -> Result<Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
let mut values = Vec::new();

Check warning on line 115 in zung_parsers/src/bencode/value.rs

View check run for this annotation

Codecov / codecov/patch

zung_parsers/src/bencode/value.rs#L111-L115

Added lines #L111 - L115 were not covered by tests

while let Some(value) = seq.next_element()? {
values.push(value);
}

Check warning on line 119 in zung_parsers/src/bencode/value.rs

View check run for this annotation

Codecov / codecov/patch

zung_parsers/src/bencode/value.rs#L117-L119

Added lines #L117 - L119 were not covered by tests

Ok(Value::List(values))
}

Check warning on line 122 in zung_parsers/src/bencode/value.rs

View check run for this annotation

Codecov / codecov/patch

zung_parsers/src/bencode/value.rs#L121-L122

Added lines #L121 - L122 were not covered by tests

fn visit_map<M>(self, mut access: M) -> Result<Value, M::Error>
where
M: serde::de::MapAccess<'de>,
{
let mut map = HashMap::new();

Check warning on line 128 in zung_parsers/src/bencode/value.rs

View check run for this annotation

Codecov / codecov/patch

zung_parsers/src/bencode/value.rs#L124-L128

Added lines #L124 - L128 were not covered by tests

while let Some((key, value)) = access.next_entry()? {
map.insert(key, value);
}

Check warning on line 132 in zung_parsers/src/bencode/value.rs

View check run for this annotation

Codecov / codecov/patch

zung_parsers/src/bencode/value.rs#L130-L132

Added lines #L130 - L132 were not covered by tests

Ok(Value::Dictionary(map))
}

Check warning on line 135 in zung_parsers/src/bencode/value.rs

View check run for this annotation

Codecov / codecov/patch

zung_parsers/src/bencode/value.rs#L134-L135

Added lines #L134 - L135 were not covered by tests
}

deserializer.deserialize_any(ValueVisitor)
}

Check warning on line 139 in zung_parsers/src/bencode/value.rs

View check run for this annotation

Codecov / codecov/patch

zung_parsers/src/bencode/value.rs#L138-L139

Added lines #L138 - L139 were not covered by tests
}

pub enum ValueInput<'a> {
Str(&'a str),
Bytes(&'a [u8]),
Expand Down
5 changes: 3 additions & 2 deletions zung_torrent/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ default = ["client"]
client = ["dep:colored", "dep:human_bytes"]

[dependencies]

colored = { version = "2.2.0", optional = true }
anyhow = "1.0.94"
bytes = { version = "1.9.0", features = ["serde"] }
clap = { version = "4.5.23", features = ["derive"] }
Expand All @@ -24,9 +26,8 @@ rayon = "1.10.0"
indexmap = "2.7.0"
rand = "0.8.5"
tokio = { version = "1.42.0", features = ["full"] }

colored = { version = "2.2.0", optional = true }
human_bytes = { version = "0.4.3", optional = true }
reqwest = "0.12.11"


serde = { version = "1.0.216", features = ["derive"] }
Expand Down
18 changes: 3 additions & 15 deletions zung_torrent/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ pub mod sources;

pub use client::Client;
pub use client::PeerID;
use colored::Colorize;
use futures::StreamExt;
use meta_info::MetaInfo;

use clap::{Args, Subcommand};
Expand Down Expand Up @@ -74,23 +72,13 @@ impl TorrentArgs {
}
TorrentCommands::Test { file } => {
let torrent = Client::new(file)?;
let mut list = torrent
let list = torrent
.sources()
.tracker_requests(torrent.info_hash().as_encoded(), torrent.peer_id())
.await
.unwrap();

// Waits for ALL futures to complete
while let Some(result) = list.next().await {
match result {
Ok(a) => match a {
Ok(a) => println!("Connected! {}", a.to_url().unwrap().green()),
Err(e) => println!("{}", e.to_string().red()),
},
Err(e) => {
println!("{}", e.to_string().red())
}
}
}
println!("{list:#?}");
}
}

Expand Down
37 changes: 20 additions & 17 deletions zung_torrent/src/sources/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ use crate::{
PeerID,
};

use anyhow::Result;
use futures::stream::FuturesUnordered;
use tokio::task::JoinHandle;
use futures::StreamExt;

mod http_seeders;
mod trackers;
Expand Down Expand Up @@ -113,13 +111,11 @@ impl<'a> DownloadSources<'a> {
/// }
/// # }
/// ```
pub fn trackers(&self) -> Option<&TrackerList> {
if let Self::Trackers { tracker_list } = self {
Some(tracker_list)
} else if let Self::Hybrid { tracker_list, .. } = self {
Some(tracker_list)
} else {
None
pub fn tracker_list(&self) -> Option<&TrackerList> {
match self {
DownloadSources::Trackers { tracker_list }

Check warning on line 116 in zung_torrent/src/sources/mod.rs

View check run for this annotation

Codecov / codecov/patch

zung_torrent/src/sources/mod.rs#L116

Added line #L116 was not covered by tests
| DownloadSources::Hybrid { tracker_list, .. } => Some(tracker_list),
DownloadSources::HttpSeeders { .. } => None,

Check warning on line 118 in zung_torrent/src/sources/mod.rs

View check run for this annotation

Codecov / codecov/patch

zung_torrent/src/sources/mod.rs#L118

Added line #L118 was not covered by tests
}
}

Expand Down Expand Up @@ -189,17 +185,24 @@ impl<'a> DownloadSources<'a> {
matches!(self, Self::Hybrid { .. })
}

pub fn tracker_requests(
pub async fn tracker_requests(

Check warning on line 188 in zung_torrent/src/sources/mod.rs

View check run for this annotation

Codecov / codecov/patch

zung_torrent/src/sources/mod.rs#L188

Added line #L188 was not covered by tests
&self,
info_hash: InfoHashEncoded,
peer_id: PeerID,
) -> Option<FuturesUnordered<JoinHandle<Result<TrackerRequest>>>> {
match self {
DownloadSources::Trackers { tracker_list }
| DownloadSources::Hybrid { tracker_list, .. } => {
Some(tracker_list.generate_requests(info_hash, peer_id))
) -> Option<Vec<TrackerRequest>> {
if let Some(list) = self.tracker_list() {
let mut result = Vec::with_capacity(list.len());
let mut request_futures = list.generate_requests(info_hash, peer_id).await;
while let Some(request) = request_futures.next().await {
match request {
Ok(Ok(tracker_request)) => result.push(tracker_request),
Err(e) => eprintln!("{e}"),
Ok(Err(e)) => eprintln!("{e}"),

Check warning on line 200 in zung_torrent/src/sources/mod.rs

View check run for this annotation

Codecov / codecov/patch

zung_torrent/src/sources/mod.rs#L192-L200

Added lines #L192 - L200 were not covered by tests
}
}
DownloadSources::HttpSeeders { .. } => None,
Some(result)

Check warning on line 203 in zung_torrent/src/sources/mod.rs

View check run for this annotation

Codecov / codecov/patch

zung_torrent/src/sources/mod.rs#L203

Added line #L203 was not covered by tests
} else {
None

Check warning on line 205 in zung_torrent/src/sources/mod.rs

View check run for this annotation

Codecov / codecov/patch

zung_torrent/src/sources/mod.rs#L205

Added line #L205 was not covered by tests
}
}
}
32 changes: 19 additions & 13 deletions zung_torrent/src/sources/trackers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@
mod request;
pub use request::*;

use std::ops::Deref;
use std::sync::Arc;
use std::{net::Ipv4Addr, ops::Deref};

use crate::meta_info::InfoHashEncoded;
use crate::PeerID;
use anyhow::{bail, Result};
use futures::stream::FuturesUnordered;
use tokio::task::JoinHandle;
use tokio::{net::UdpSocket, task::JoinHandle};

// TODO: Look into SmallStr
#[derive(Debug)]
Expand Down Expand Up @@ -58,6 +58,7 @@ impl Tracker {

pub async fn generate_request(
&self,
socket: Arc<UdpSocket>,
info_hash: InfoHashEncoded,
peer_id: PeerID,
) -> Result<TrackerRequest> {
Expand All @@ -72,10 +73,7 @@ impl Tracker {
Some(s) => s.0,
None => udp_url,

Check warning on line 74 in zung_torrent/src/sources/trackers/mod.rs

View check run for this annotation

Codecov / codecov/patch

zung_torrent/src/sources/trackers/mod.rs#L74

Added line #L74 was not covered by tests
};
let connection = UdpConnectRequest::new()
.await?
.connect_with(udp_url)
.await?;
let connection = UdpConnectRequest::new(socket).connect_with(udp_url).await?;

let connection_id = connection.connection_id();
Ok(TrackerRequest::Udp {
Expand Down Expand Up @@ -111,16 +109,21 @@ impl TrackerList {
/// Asyncly generates the [`TrackerRequest`]
///
// TODO: Revisit this if there is a faster more efficient way.
pub fn generate_requests(
pub async fn generate_requests(
&self,
info_hash: InfoHashEncoded,
peer_id: PeerID,
) -> FuturesUnordered<JoinHandle<Result<TrackerRequest>>> {
let socket = Arc::new(UdpSocket::bind((Ipv4Addr::UNSPECIFIED, 0)).await.unwrap());

self.as_array()
.iter()
.cloned() // The clone here is just Arc::clone
.map(|tracker| {
tokio::spawn(async move { tracker.generate_request(info_hash, peer_id).await })
let socket = Arc::clone(&socket);
tokio::spawn(
async move { tracker.generate_request(socket, info_hash, peer_id).await },
)
})
.collect()
}
Expand Down Expand Up @@ -155,9 +158,10 @@ mod tracker_tests {
let sample_url = "http://example.com/announce";
let info_hash = InfoHash::new(b"test info_hash").as_encoded();
let peer_id = PeerID::default();
let socket = Arc::new(UdpSocket::bind((Ipv4Addr::UNSPECIFIED, 0)).await.unwrap());
let tracker_request = Tracker::new(sample_url);
let tracker_request = tracker_request
.generate_request(info_hash, peer_id)
.generate_request(socket, info_hash, peer_id)
.await
.unwrap();

Expand Down Expand Up @@ -185,9 +189,10 @@ mod tracker_tests {
let url = "http://example.com/announce";
let info_hash = InfoHash::new(b"test info_hash").as_encoded();
let peer_id = PeerID::default();
let socket = Arc::new(UdpSocket::bind((Ipv4Addr::UNSPECIFIED, 0)).await.unwrap());
let tracker_request = Tracker::new(url);
let tracker_request = tracker_request
.generate_request(info_hash, peer_id)
.generate_request(socket, info_hash, peer_id)
.await
.unwrap();

Expand All @@ -214,11 +219,11 @@ mod tracker_tests {
async fn test_bool_as_int_serialization() {
let url = "http://example.com/announce";
let info_hash = InfoHash::new(b"test info_hash").as_encoded();

let socket = Arc::new(UdpSocket::bind((Ipv4Addr::UNSPECIFIED, 0)).await.unwrap());
let peer_id = PeerID::default();
let tracker_request = Tracker::new(url);
let mut tracker_request = tracker_request
.generate_request(info_hash, peer_id)
.generate_request(socket, info_hash, peer_id)
.await
.unwrap();

Expand Down Expand Up @@ -258,10 +263,11 @@ mod tracker_tests {
async fn test_optional_parameters() {
let url = "http://example.com/announce";
let info_hash = InfoHash::new(b"test info_hash").as_encoded();
let socket = Arc::new(UdpSocket::bind((Ipv4Addr::UNSPECIFIED, 0)).await.unwrap());
let peer_id = PeerID::default();
let tracker_request = Tracker::new(url);
let mut tracker_request = tracker_request
.generate_request(info_hash, peer_id)
.generate_request(socket, info_hash, peer_id)
.await
.unwrap();

Expand Down
Loading

0 comments on commit 6b0867b

Please sign in to comment.