dhaar-torrent 0.4.0

A BitTorrent client library: peer wire protocol, piece management and a resumable on-disk store
Documentation
use std::{collections::HashSet, net::SocketAddr};

use tokio::task::JoinHandle;
use tracing::{debug, error};

use crate::error::Result;

pub mod channel;
pub mod tracker;

pub struct PeerExplorer {
    pub peer_sources: Vec<Box<dyn PeerSource + Send>>,
}

impl PeerExplorer {
    pub fn new(peer_sources: Vec<Box<dyn PeerSource + Send>>) -> PeerExplorer {
        PeerExplorer { peer_sources }
    }

    pub async fn start(mut self, peer_explorer_channel_sender: channel::PeerExplorerChannelSender) {
        let (peer_source_channel_sender, mut peer_source_channel_receiver) =
            channel::new_peer_source_channel();

        for peer_source in self.peer_sources.iter_mut() {
            if let Err(e) = peer_source.start(peer_source_channel_sender.clone()).await {
                error!("Failed to start peer source: {}", e);
            }
        }

        let mut dedup = HashSet::new();
        while let Some(message) = peer_source_channel_receiver.recv().await {
            match message {
                channel::PeerSourceChannelMessage::PeerFound(peer) => {
                    if dedup.insert(peer) {
                        debug!("New unique peer discovered, {} total so far", dedup.len());
                        peer_explorer_channel_sender
                            .send(channel::PeerExplorerChannelMessage::PeerFound(peer))
                            .await
                            .expect("Failed to send peer from Peer Explorer");
                    }
                }
            }
        }
    }
}

#[async_trait::async_trait]
pub trait PeerSource {
    async fn start(
        &self,
        peer_source_channel_sender: channel::PeerSourceChannelSender,
    ) -> Result<JoinHandle<()>>;
}

#[derive(Debug, Clone, Copy, Eq)]
pub struct Peer {
    pub peer_id: Option<[u8; 20]>,
    pub address: SocketAddr,
}

impl PartialEq for Peer {
    fn eq(&self, other: &Self) -> bool {
        self.address == other.address
    }
}

impl std::hash::Hash for Peer {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.address.hash(state);
    }
}