beginner - Rust Torrent Parser - Code Review Stack Exchange
Thu Jul 07 2022 10:05:59 GMT+0000 (UTC)
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