rubit 0.1.0

The bencoding decoding package for rubit Bittorrent client
Documentation
use std::{
    collections::HashSet,
    fs::File,
    io::{Read, Seek, SeekFrom},
    sync::{Arc, Mutex},
};

use rand::{distributions::Alphanumeric, thread_rng, Rng};
use sha1::{Digest, Sha1};
use url::Url;

use crate::Tracker;

pub fn get_random_id() -> String {
    let mut peer_id = String::from("RB01-");
    let random_15: String = thread_rng()
        .sample_iter(&Alphanumeric)
        .take(15)
        .map(char::from)
        .collect();
    peer_id.push_str(&random_15);
    peer_id
}

pub fn get_tracker_list(announce: String, announce_list: Vec<Vec<String>>) -> Vec<Tracker> {
    let mut flattened_list: Vec<&String> = announce_list.iter().flatten().collect();
    flattened_list.push(&announce);

    let mut vec = Vec::new();

    for url in flattened_list {
        let parsed = match Url::parse(&url) {
            Ok(u) => u,
            Err(_) => continue,
        };
        let tracker = match Tracker::new(parsed) {
            Ok(t) => t,
            Err(_) => continue,
        };

        vec.push(tracker);
    }
    vec
}

pub fn check_download_percent(
    file: Arc<Mutex<File>>,
    pieces: &Vec<[u8; 20]>,
    total_length: u64,
    piece_len: u64,
) -> HashSet<usize> {
    println!("File already exists, checking downloaded hashes...");

    let mut file = file.lock().unwrap();
    if file.seek(SeekFrom::End(0)).unwrap() == 0 {
        return HashSet::new();
    }

    let mut completed = HashSet::new();
    let mut cursor = 0;

    for i in 0..pieces.len() {
        let mut buf = Vec::new();
        if i == pieces.len() - 1 {
            buf.resize((total_length % piece_len) as usize, 0);
        } else {
            buf.resize(piece_len as usize, 0);
        }
        let mut hasher = Sha1::new();

        file.seek(SeekFrom::Start(cursor)).unwrap();
        file.read(&mut buf).unwrap();

        hasher.update(&buf);
        let hash: [u8; 20] = hasher.finalize().into();

        if hash == pieces[i] {
            completed.insert(i);
        }

        cursor += piece_len;
    }

    completed
}

pub fn retain_not_downloaded_pieces(completed: HashSet<usize>, mut buf: Vec<usize>) -> Vec<usize> {
    buf.retain(|e| !completed.contains(e));
    buf
}