btpeer 0.5.0

Simple CLI tool and library to get peers from TCP/HTTP and UDP BitTorrent trackers
Documentation
mod config;
mod http;
mod peer;
mod udp;

use peer::Peer;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    use clap::Parser;
    use colored::Colorize;
    use config::Config;

    fn stats(interval: u32, leechers: u32, seeders: u32, peers: Vec<Peer>) {
        println!("{}", format!("Update interval: {interval}s").yellow());
        println!("{}: {seeders}, {}: {leechers}", "S".green(), "L".red());
        if peers.is_empty() {
            println!("{}", "No peers.".red());
        } else {
            for peer in peers {
                println!("{peer}")
            }
        }
    }

    let config = Config::parse();

    if config.http_tracker.as_ref().is_none_or(|h| h.is_empty())
        && config.udp_tracker.as_ref().is_none_or(|u| u.is_empty())
    {
        println!("{}", "Provide at least one HTTP or UDP tracker(s)".red());
        std::process::exit(1);
    }

    if let Some(http_tracker) = config.http_tracker {
        for url in http_tracker {
            let query = http::Query::new(url.as_str(), &config.info_hash, config.port)?;
            println!(
                "{}",
                format!("Sending HTTP announce to `{query}`...").blue()
            );
            let mut peers = peer::new_buffer(Some(config.peers_buffer_capacity));
            match http::request(&query, config.timeout, Some(&mut peers)) {
                Ok(response) => stats(
                    response.interval,
                    response.leechers,
                    response.seeders,
                    peers,
                ),
                Err(e) => println!("{}", e.to_string().red()),
            }
        }
    }

    if let Some(udp_tracker) = config.udp_tracker {
        for address in udp_tracker {
            println!(
                "{}",
                format!("Sending UDP announce to `{address}`...").blue()
            );
            let mut peers = peer::new_buffer(Some(config.peers_buffer_capacity));
            match udp::request(
                &config.info_hash,
                &address,
                config.port,
                config.timeout,
                Some(&mut peers),
            ) {
                Ok(response) => stats(
                    response.interval,
                    response.leechers,
                    response.seeders,
                    peers,
                ),
                Err(e) => println!("{}", e.to_string().red()),
            }
        }
    }

    Ok(())
}