Preview:
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());
    }
}
downloadDownload PNG downloadDownload JPEG downloadDownload SVG

Tip: You can change the style, width & colours of the snippet with the inspect tool before clicking Download!

Click to optimize width for Twitter