btpeer 0.11.0

Simple CLI tool and library to get peers from TCP/HTTP and UDP BitTorrent trackers
Documentation
use crate::InfoHash;
use bendy::decoding::{Error, FromBencode, Object};
use std::collections::HashMap;

#[derive(Debug, Default)]
pub struct Total {
    pub complete: u32,
    pub incomplete: u32,
    pub downloaded: u32,
}

#[derive(Default)]
pub struct Scrape {
    pub total: Total,
    pub stats: HashMap<InfoHash, Total>,
}

impl FromBencode for Scrape {
    fn decode_bencode_object(object: Object) -> Result<Self, Error> {
        let mut root_dict = object.try_into_dictionary()?;
        let mut response = Self::default();

        while let Some(root_pair) = root_dict.next_pair()? {
            match root_pair {
                (b"files", files_value) => {
                    let mut files_dict = files_value.try_into_dictionary()?;

                    while let Some((id, torrent_data_value)) = files_dict.next_pair()? {
                        let info_hash = InfoHash::V1(id.to_vec());
                        let mut total = Total::default();

                        let mut torrent_dict = torrent_data_value.try_into_dictionary()?;

                        while let Some(stat_pair) = torrent_dict.next_pair()? {
                            match stat_pair {
                                (b"complete", value) => {
                                    let count: u32 = value
                                        .try_into_integer()
                                        .map_err(Error::malformed_content)?
                                        .parse()
                                        .map_err(Error::malformed_content)?;
                                    total.complete = count;
                                    response.total.complete += count;
                                }
                                (b"incomplete", value) => {
                                    let count: u32 = value
                                        .try_into_integer()
                                        .map_err(Error::malformed_content)?
                                        .parse()
                                        .map_err(Error::malformed_content)?;
                                    total.incomplete = count;
                                    response.total.incomplete += count;
                                }
                                (b"downloaded", value) => {
                                    let count: u32 = value
                                        .try_into_integer()
                                        .map_err(Error::malformed_content)?
                                        .parse()
                                        .map_err(Error::malformed_content)?;
                                    total.downloaded = count;
                                    response.total.downloaded += count;
                                }
                                _ => continue,
                            }
                        }
                        response.stats.insert(info_hash, total);
                    }
                }
                _ => continue,
            }
        }

        Ok(response)
    }
}