diff --git a/Cargo.toml b/Cargo.toml index 69ea075..e6caad0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,9 @@ edition = "2021" [dependencies] anyhow = "1.0.86" sha1 = "0.10.6" +reqwest = { version = "0.12.5", features = ["blocking"] } +rand = "0.8.5" +urlencoding = "2.1.3" [dev-dependencies] hex-literal = "0.4.1" diff --git a/src/bencode.rs b/src/bencode.rs index 0f5277c..3ec0578 100644 --- a/src/bencode.rs +++ b/src/bencode.rs @@ -5,7 +5,7 @@ use anyhow::{anyhow, ensure, Result}; use sha1::{Digest, Sha1}; -#[derive(Debug, PartialEq, Eq, Hash, Clone)] +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)] pub struct ByteString(Vec); impl Display for ByteString { @@ -91,8 +91,12 @@ impl Bencode { } Bencode::Dict(d) => { let mut result = vec!['d' as u8]; - for (k, v) in d { + let mut sorted_keys = d.keys().collect::>(); + sorted_keys.sort(); + + for k in sorted_keys { result.extend(Self::compose(&Bencode::Bytes(k.clone()))); + let v = &d[k]; result.extend(v.compose()); } result.push('e' as u8); @@ -110,7 +114,8 @@ impl Bencode { pub fn sha1(&self) -> [u8; 20] { let mut hasher = Sha1::new(); - hasher.update(self.compose()); + let composed = self.compose(); + hasher.update(composed); hasher.finalize().into() } diff --git a/src/main.rs b/src/main.rs index 6f65ce7..9c9f44e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,9 @@ use std::{env, fs, path}; use std::collections::HashMap; use anyhow::{anyhow, Result}; +use rand::prelude::*; +use reqwest::blocking::Client; +use reqwest::Url; use crate::bencode::{Bencode, ByteString}; @@ -177,7 +180,45 @@ fn main() -> Result<()> { let torrent = Torrent::from(&torrent_parsed)?; - println!("torrent decoded: {torrent:?}"); + // println!("torrent decoded: {torrent:?}"); + + let torrent_length= torrent.info.length.unwrap_or( + torrent.info.files.unwrap().iter().map(|x| x.length).sum() + ); + + + let mut peer_id= [0u8; 20]; + thread_rng().fill_bytes(&mut peer_id); + + println!("Generated peer id: {}", + peer_id.iter().map(|x| {format!("{x:02x}")}).collect::>().join("")); + println!("Making request to tracker"); + + println!("info hash: {}", torrent.info_hash.iter().map(|x| {format!("{x:02x}")}).collect::>().join("")); + + let mut url = Url::parse(&torrent.announce)?; + url.query_pairs_mut() + .append_pair("port", "6885") + .append_pair("uploaded", "0") + .append_pair("downloaded", "0") + .append_pair("compact", "1") + .append_pair("left", &format!("{torrent_length}")); + + + let mut query = url.query().unwrap().to_string(); + query = format!("{query}&peer_id={}&info_hash={}", + urlencoding::encode_binary(&peer_id[..]), + urlencoding::encode_binary(&torrent.info_hash[..])); + url.set_query(Some(&query)); + + println!("url: {}", url); + + let client = Client::new(); + let resp = client.get(url).send()?; + let status = resp.status(); + + let body = resp.text()?; + println!("Response: {} {}", status, body); Ok(()) }