diff --git a/crates/librqbit/src/api.rs b/crates/librqbit/src/api.rs index 6003966..b164ee0 100644 --- a/crates/librqbit/src/api.rs +++ b/crates/librqbit/src/api.rs @@ -14,6 +14,7 @@ use crate::{ session::{ AddTorrent, AddTorrentOptions, AddTorrentResponse, ListOnlyResponse, Session, TorrentId, }, + session_stats::snapshot::SessionStatsSnapshot, torrent_state::{ peer::stats::snapshot::{PeerStatsFilter, PeerStatsSnapshot}, FileStream, ManagedTorrentHandle, @@ -171,6 +172,10 @@ impl Api { make_torrent_details(&info_hash, &handle.info().info, only_files.as_deref()) } + pub fn api_session_stats(&self) -> SessionStatsSnapshot { + self.session().stats_snapshot() + } + pub fn torrent_file_mime_type( &self, idx: TorrentIdOrHash, diff --git a/crates/librqbit/src/http_api.rs b/crates/librqbit/src/http_api.rs index eddd339..f72b95b 100644 --- a/crates/librqbit/src/http_api.rs +++ b/crates/librqbit/src/http_api.rs @@ -63,6 +63,7 @@ impl HttpApi { "GET /dht/table": "DHT routing table", "GET /torrents": "List torrents", "GET /torrents/playlist": "Generate M3U8 playlist for all files in all torrents", + "GET /stats": "Global session stats", "POST /torrents/resolve_magnet": "Resolve a magnet to torrent file bytes", "GET /torrents/{id_or_infohash}": "Torrent details", "GET /torrents/{id_or_infohash}/haves": "The bitfield of have pieces", @@ -92,6 +93,10 @@ impl HttpApi { state.api_dht_table().map(axum::Json) } + async fn session_stats(State(state): State) -> impl IntoResponse { + axum::Json(state.api_session_stats()) + } + async fn torrents_list(State(state): State) -> impl IntoResponse { axum::Json(state.api_torrent_list()) } @@ -450,6 +455,7 @@ impl HttpApi { .route("/rust_log", post(set_rust_log)) .route("/dht/stats", get(dht_stats)) .route("/dht/table", get(dht_table)) + .route("/stats", get(session_stats)) .route("/torrents", get(torrents_list)) .route("/torrents/:id", get(torrent_details)) .route("/torrents/:id/haves", get(torrent_haves)) diff --git a/crates/librqbit/src/session_stats/atomic.rs b/crates/librqbit/src/session_stats/atomic.rs index fb2ae1c..416521c 100644 --- a/crates/librqbit/src/session_stats/atomic.rs +++ b/crates/librqbit/src/session_stats/atomic.rs @@ -6,5 +6,5 @@ use crate::torrent_state::live::peers::stats::atomic::AggregatePeerStatsAtomic; pub struct AtomicSessionStats { pub fetched_bytes: AtomicU64, pub uploaded_bytes: AtomicU64, - pub peers: AggregatePeerStatsAtomic, + pub(crate) peers: AggregatePeerStatsAtomic, } diff --git a/crates/librqbit/src/session_stats/mod.rs b/crates/librqbit/src/session_stats/mod.rs index 87afcf6..ef3d814 100644 --- a/crates/librqbit/src/session_stats/mod.rs +++ b/crates/librqbit/src/session_stats/mod.rs @@ -5,11 +5,13 @@ use std::{ use atomic::AtomicSessionStats; use librqbit_core::speed_estimator::SpeedEstimator; +use snapshot::SessionStatsSnapshot; use tracing::error_span; use crate::Session; pub mod atomic; +pub mod snapshot; pub struct SessionStats { pub atomic: Arc, @@ -27,6 +29,12 @@ impl SessionStats { } } +impl Default for SessionStats { + fn default() -> Self { + Self::new() + } +} + impl Session { pub(crate) fn start_speed_estimator_updater(self: &Arc) { self.spawn(error_span!(parent: self.rs(), "speed_estimator"), { @@ -47,4 +55,8 @@ impl Session { } }) } + + pub fn stats_snapshot(&self) -> SessionStatsSnapshot { + SessionStatsSnapshot::from(&self.stats) + } } diff --git a/crates/librqbit/src/session_stats/snapshot.rs b/crates/librqbit/src/session_stats/snapshot.rs new file mode 100644 index 0000000..b2feb2d --- /dev/null +++ b/crates/librqbit/src/session_stats/snapshot.rs @@ -0,0 +1,22 @@ +use serde::Serialize; + +use crate::torrent_state::{peers::stats::snapshot::AggregatePeerStats, stats::Speed}; + +use super::SessionStats; + +#[derive(Debug, Serialize)] +pub struct SessionStatsSnapshot { + download_speed: Speed, + upload_speed: Speed, + peers: AggregatePeerStats, +} + +impl From<&SessionStats> for SessionStatsSnapshot { + fn from(s: &SessionStats) -> Self { + Self { + download_speed: s.down_speed_estimator.mbps().into(), + upload_speed: s.up_speed_estimator.mbps().into(), + peers: AggregatePeerStats::from(&s.atomic.peers), + } + } +}