use std::str::FromStr;
use url::Url;
pub struct Query(Url);
impl Query {
pub fn new(
announce_url: &str,
info_hash: &[u8; 20],
port: u16,
) -> Result<Self, Box<dyn std::error::Error>> {
fn url_encode_bytes(bytes: &[u8]) -> String {
bytes.iter().map(|b| format!("%{:02x}", b)).collect()
}
let mut url = Url::from_str(announce_url)?;
let mut rng = rand::rng();
let mut peer_id = [0u8; 20];
rand::RngExt::fill(&mut rng, &mut peer_id);
url.set_query(Some(&format!(
"info_hash={}&peer_id={}&port={port}&uploaded=0&downloaded=0&left=1000&compact=1",
url_encode_bytes(info_hash),
url_encode_bytes(&peer_id)
)));
Ok(Self(url))
}
pub fn url(&self) -> &Url {
&self.0
}
}
impl std::fmt::Display for Query {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}