use std::collections::BTreeMap;
use bencode::{Bencode, Encoder};
use bencode::util::ByteString;
#[derive(Default, Debug)]
pub struct Torrent {
announce: String,
announce_list: Vec<String>,
name: String,
comment: String,
multi_file: bool,
piece_length: i32,
length: i64,
creation_date: String,
total_size: i32,
}
impl Torrent {
pub fn new() -> Self {
return Torrent {
..Default::default()
};
}
pub fn populate_from_bencode(&mut self, b: Bencode) -> Bencode {
if let Bencode::Dict(dict) = b {
dict.into_iter().for_each(|(s, b)| {
if s.as_slice() == b"announce" {
self.announce = extract_string(b).unwrap_or_else(|| panic!("unable to extract announce"));
} else if s.as_slice() == b"name" {
self.name = extract_string(b).unwrap_or_else(|| panic!("unable to extract name"));
} else if s.as_slice() == b"pieces" {} else if s.as_slice() == b"comment" {
self.comment = extract_string(b).unwrap_or_else(|| panic!("unable to extract comment"));
} else if s.as_slice() == b"creation-date" {
self.creation_date = extract_string(b).unwrap_or_else(|| panic!("unable to extract creation-date"));
} else if s.as_slice() == b"info" {
self.populate_from_bencode(b);
} else if s.as_slice() == b"length" {
if let Bencode::Number(length) = self.populate_from_bencode(b) {
self.length = length;
}
} else if s.as_slice() == b"announce-list" {
if let Bencode::List(x) = self.populate_from_bencode(b) {
self.announce_list = x.into_iter()
.map(|x| extract_list(x).unwrap_or_else(|| panic!("list")))
.flatten()
.map(|x| extract_string(x).unwrap_or_else(|| panic!("unable to extract string")))
.collect();
}
}
});
return Bencode::Empty;
} else {
return b;
}
}
}
fn extract_list(b: Bencode) -> Option<Vec<Bencode>> {
if let Bencode::List(s) = b {
return Some(s);
}
return None;
}
fn extract_pieces(b: Bencode) -> Option<Vec<u8>> {
if let Bencode::ByteString(x) = b {
return Some(x);
}
return None;
}
fn extract_string(b: Bencode) -> Option<String> {
if let Bencode::ByteString(s) = b {
return Some(String::from_utf8_lossy(&s).to_string());
}
return None;
}
//decoder.rs
use std::fs::File;
use std::io::Read;
use bencode::Bencode;
use crate::torrent;
use crate::torrent::Torrent;
pub fn decode_file_into_torrent(path: &'static str) -> Result<Torrent, Box<dyn std::error::Error>> {
let mut file = File::open(path)?;
let v = file.bytes().map(|x| x.unwrap()).collect::<Vec<u8>>();
let bencode = bencode::from_vec(v).unwrap();
let mut t = Torrent::new();
t.populate_from_bencode(bencode);
Ok(t)
}
#[cfg(test)]
mod tests {
use crate::decoder;
use super::*;
#[test]
fn test_parser() {
let t = decoder::decode_file_into_torrent("src/test.torrent");
assert!(t.is_ok());
}
}
Comments