torrust-tracker
torrust-tracker copied to clipboard
UDP Tracker client: Print unexpected responses in JSON
Parent issue: https://github.com/torrust/torrust-tracker/issues/669
When you run the UDP tracker client:
cargo run --bin udp_tracker_client announce 127.0.0.1:6969 9c38422213e30bff212b30c360d26f9a02136422
Not all responses are printed in JSON. Some of them are printed in Rust Debug format.
fn print_response(response: Response) -> anyhow::Result<()> {
match response {
AnnounceIpv4(response) => {
let pretty_json = serde_json::to_string_pretty(&AnnounceResponseDto::from(response))
.context("announce IPv4 response JSON serialization")?;
println!("{pretty_json}");
}
AnnounceIpv6(response) => {
let pretty_json = serde_json::to_string_pretty(&AnnounceResponseDto::from(response))
.context("announce IPv6 response JSON serialization")?;
println!("{pretty_json}");
}
Scrape(response) => {
let pretty_json =
serde_json::to_string_pretty(&ScrapeResponseDto::from(response)).context("scrape response JSON serialization")?;
println!("{pretty_json}");
}
_ => println!("{response:#?}"), // todo: serialize to JSON all aquatic responses.
};
Ok(())
}
We have to implement JSON serialization for all aquatic UDP responses:
//! Aquatic responses are not serializable. These are the serializable wrappers.
use std::net::{Ipv4Addr, Ipv6Addr};
use aquatic_udp_protocol::{AnnounceResponse, ScrapeResponse};
use serde::Serialize;
#[derive(Serialize)]
pub struct AnnounceResponseDto {
transaction_id: i32,
announce_interval: i32,
leechers: i32,
seeders: i32,
peers: Vec<String>,
}
impl From<AnnounceResponse<Ipv4Addr>> for AnnounceResponseDto {
fn from(announce: AnnounceResponse<Ipv4Addr>) -> Self {
Self {
transaction_id: announce.transaction_id.0,
announce_interval: announce.announce_interval.0,
leechers: announce.leechers.0,
seeders: announce.seeders.0,
peers: announce
.peers
.iter()
.map(|peer| format!("{}:{}", peer.ip_address, peer.port.0))
.collect::<Vec<_>>(),
}
}
}
impl From<AnnounceResponse<Ipv6Addr>> for AnnounceResponseDto {
fn from(announce: AnnounceResponse<Ipv6Addr>) -> Self {
Self {
transaction_id: announce.transaction_id.0,
announce_interval: announce.announce_interval.0,
leechers: announce.leechers.0,
seeders: announce.seeders.0,
peers: announce
.peers
.iter()
.map(|peer| format!("{}:{}", peer.ip_address, peer.port.0))
.collect::<Vec<_>>(),
}
}
}
#[derive(Serialize)]
pub struct ScrapeResponseDto {
transaction_id: i32,
torrent_stats: Vec<TorrentStats>,
}
impl From<ScrapeResponse> for ScrapeResponseDto {
fn from(scrape: ScrapeResponse) -> Self {
Self {
transaction_id: scrape.transaction_id.0,
torrent_stats: scrape
.torrent_stats
.iter()
.map(|torrent_scrape_statistics| TorrentStats {
seeders: torrent_scrape_statistics.seeders.0,
completed: torrent_scrape_statistics.completed.0,
leechers: torrent_scrape_statistics.leechers.0,
})
.collect::<Vec<_>>(),
}
}
}
#[derive(Serialize)]
struct Peer {
seeders: i32,
completed: i32,
leechers: i32,
}
#[derive(Serialize)]
struct TorrentStats {
seeders: i32,
completed: i32,
leechers: i32,
}