diff --git a/crates/librqbit/src/http_api.rs b/crates/librqbit/src/http_api.rs index dca4264..0b96dc3 100644 --- a/crates/librqbit/src/http_api.rs +++ b/crates/librqbit/src/http_api.rs @@ -17,9 +17,10 @@ use tracing::{info, warn}; use axum::Router; use crate::http_api_error::{ApiError, ApiErrorExt}; +use crate::peer_state::PeerStatsFilter; use crate::session::{AddTorrentOptions, AddTorrentResponse, ListOnlyResponse, Session}; use crate::torrent_manager::TorrentManagerHandle; -use crate::torrent_state::{PeerStatsFilter, StatsSnapshot}; +use crate::torrent_state::StatsSnapshot; // Public API #[derive(Clone)] @@ -274,7 +275,7 @@ impl ApiInternal { &self, idx: usize, filter: PeerStatsFilter, - ) -> Result { + ) -> Result { let handle = self.mgr_handle(idx)?; Ok(handle.torrent_state().per_peer_stats_snapshot(filter)) } diff --git a/crates/librqbit/src/peer_state.rs b/crates/librqbit/src/peer_state.rs index 1a055e1..bb6df51 100644 --- a/crates/librqbit/src/peer_state.rs +++ b/crates/librqbit/src/peer_state.rs @@ -267,3 +267,82 @@ impl LivePeerState { .map_or(false, |s| s.all()) } } + +mod peer_stats_snapshot { + use std::{collections::HashMap, sync::atomic::Ordering}; + + use serde::{Deserialize, Serialize}; + + use crate::peer_state::PeerState; + + #[derive(Serialize, Deserialize)] + pub struct PeerCounters { + pub fetched_bytes: u64, + pub total_time_connecting_ms: u64, + pub connection_attempts: u32, + pub connections: u32, + pub errors: u32, + pub fetched_chunks: u32, + pub downloaded_and_checked_pieces: u32, + } + + #[derive(Serialize, Deserialize)] + pub struct PeerStats { + pub counters: PeerCounters, + pub state: &'static str, + } + + impl From<&crate::peer_state::PeerCounters> for PeerCounters { + fn from(counters: &crate::peer_state::PeerCounters) -> Self { + Self { + fetched_bytes: counters.fetched_bytes.load(Ordering::Relaxed), + total_time_connecting_ms: counters.total_time_connecting_ms.load(Ordering::Relaxed), + connection_attempts: counters.connection_attempts.load(Ordering::Relaxed), + connections: counters.connections.load(Ordering::Relaxed), + errors: counters.errors.load(Ordering::Relaxed), + fetched_chunks: counters.fetched_chunks.load(Ordering::Relaxed), + downloaded_and_checked_pieces: counters + .downloaded_and_checked_pieces + .load(Ordering::Relaxed), + } + } + } + + impl From<&crate::peer_state::Peer> for PeerStats { + fn from(peer: &crate::peer_state::Peer) -> Self { + Self { + counters: peer.stats.counters.as_ref().into(), + state: peer.state.get().name(), + } + } + } + + #[derive(Serialize)] + pub struct PeerStatsSnapshot { + pub peers: HashMap, + } + + #[derive(Clone, Copy, Default, Deserialize)] + pub enum PeerStatsFilterState { + All, + #[default] + Live, + } + + impl PeerStatsFilterState { + pub fn matches(&self, s: &PeerState) -> bool { + match (self, s) { + (Self::All, _) => true, + (Self::Live, PeerState::Live(_)) => true, + _ => false, + } + } + } + + #[derive(Default, Deserialize)] + pub struct PeerStatsFilter { + pub state: PeerStatsFilterState, + } +} + +pub use peer_stats_snapshot::{PeerStatsFilter, PeerStatsSnapshot}; diff --git a/crates/librqbit/src/torrent_state.rs b/crates/librqbit/src/torrent_state.rs index 272a8d5..9472477 100644 --- a/crates/librqbit/src/torrent_state.rs +++ b/crates/librqbit/src/torrent_state.rs @@ -85,7 +85,7 @@ use crate::{ }, peer_state::{ atomic_inc, AggregatePeerStatsAtomic, InflightRequest, LivePeerState, Peer, PeerCounters, - PeerRx, PeerState, PeerTx, SendMany, + PeerRx, PeerState, PeerStatsFilter, PeerStatsSnapshot, PeerTx, SendMany, }, spawn_utils::{spawn, BlockingSpawner}, type_aliases::{PeerHandle, BF}, @@ -399,88 +399,6 @@ mod timed_existence { } } -mod peer_stats_snapshot { - use std::{collections::HashMap, sync::atomic::Ordering}; - - use serde::{Deserialize, Serialize}; - - use crate::peer_state::PeerState; - - use super::AggregatePeerStats; - - #[derive(Serialize, Deserialize)] - pub struct PeerCounters { - pub fetched_bytes: u64, - pub total_time_connecting_ms: u64, - pub connection_attempts: u32, - pub connections: u32, - pub errors: u32, - pub fetched_chunks: u32, - pub downloaded_and_checked_pieces: u32, - } - - #[derive(Serialize, Deserialize)] - pub struct PeerStats { - pub counters: PeerCounters, - pub state: &'static str, - } - - impl From<&crate::peer_state::PeerCounters> for PeerCounters { - fn from(counters: &crate::peer_state::PeerCounters) -> Self { - Self { - fetched_bytes: counters.fetched_bytes.load(Ordering::Relaxed), - total_time_connecting_ms: counters.total_time_connecting_ms.load(Ordering::Relaxed), - connection_attempts: counters.connection_attempts.load(Ordering::Relaxed), - connections: counters.connections.load(Ordering::Relaxed), - errors: counters.errors.load(Ordering::Relaxed), - fetched_chunks: counters.fetched_chunks.load(Ordering::Relaxed), - downloaded_and_checked_pieces: counters - .downloaded_and_checked_pieces - .load(Ordering::Relaxed), - } - } - } - - impl From<&crate::peer_state::Peer> for PeerStats { - fn from(peer: &crate::peer_state::Peer) -> Self { - Self { - counters: peer.stats.counters.as_ref().into(), - state: peer.state.get().name(), - } - } - } - - #[derive(Serialize)] - pub struct PeerStatsSnapshot { - pub peers: HashMap, - pub aggregate: AggregatePeerStats, - } - - #[derive(Clone, Copy, Default, Deserialize)] - pub enum PeerStatsFilterState { - All, - #[default] - Live, - } - - impl PeerStatsFilterState { - pub fn matches(&self, s: &PeerState) -> bool { - match (self, s) { - (Self::All, _) => true, - (Self::Live, PeerState::Live(_)) => true, - _ => false, - } - } - } - - #[derive(Default, Deserialize)] - pub struct PeerStatsFilter { - pub state: PeerStatsFilterState, - } -} - -pub use peer_stats_snapshot::{PeerStatsFilter, PeerStatsSnapshot}; - pub use timed_existence::{timeit, TimedExistence}; impl TorrentState { @@ -783,11 +701,8 @@ impl TorrentState { } } - pub fn per_peer_stats_snapshot( - &self, - filter: PeerStatsFilter, - ) -> peer_stats_snapshot::PeerStatsSnapshot { - peer_stats_snapshot::PeerStatsSnapshot { + pub fn per_peer_stats_snapshot(&self, filter: PeerStatsFilter) -> PeerStatsSnapshot { + PeerStatsSnapshot { peers: self .peers .states @@ -795,7 +710,6 @@ impl TorrentState { .filter(|e| filter.state.matches(e.value().state.get())) .map(|e| (e.key().to_string(), e.value().into())) .collect(), - aggregate: self.peers.stats(), } }