Display upload speed in Web UI
This commit is contained in:
parent
4784f3f14b
commit
80df2c1001
8 changed files with 89 additions and 55 deletions
|
|
@ -188,7 +188,8 @@ pub struct TorrentStateLive {
|
|||
cancel_tx: tokio::sync::watch::Sender<()>,
|
||||
cancel_rx: tokio::sync::watch::Receiver<()>,
|
||||
|
||||
speed_estimator: SpeedEstimator,
|
||||
down_speed_estimator: SpeedEstimator,
|
||||
up_speed_estimator: SpeedEstimator,
|
||||
}
|
||||
|
||||
impl TorrentStateLive {
|
||||
|
|
@ -198,7 +199,8 @@ impl TorrentStateLive {
|
|||
) -> Arc<Self> {
|
||||
let (peer_queue_tx, peer_queue_rx) = unbounded_channel();
|
||||
|
||||
let speed_estimator = SpeedEstimator::new(5);
|
||||
let down_speed_estimator = SpeedEstimator::new(5);
|
||||
let up_speed_estimator = SpeedEstimator::new(5);
|
||||
|
||||
let have_bytes = paused.have_bytes;
|
||||
let needed_bytes = paused.info.lengths.total_length() - have_bytes;
|
||||
|
|
@ -225,7 +227,8 @@ impl TorrentStateLive {
|
|||
peer_semaphore: Semaphore::new(128),
|
||||
peer_queue_tx,
|
||||
finished_notify: Notify::new(),
|
||||
speed_estimator,
|
||||
down_speed_estimator,
|
||||
up_speed_estimator,
|
||||
cancel_rx,
|
||||
cancel_tx,
|
||||
});
|
||||
|
|
@ -249,6 +252,7 @@ impl TorrentStateLive {
|
|||
Some(state) => state,
|
||||
None => return Ok(()),
|
||||
};
|
||||
let now = Instant::now();
|
||||
let stats = state.stats_snapshot();
|
||||
let fetched = stats.fetched_bytes;
|
||||
let needed = state.initially_needed();
|
||||
|
|
@ -257,8 +261,11 @@ impl TorrentStateLive {
|
|||
.wrapping_sub(fetched)
|
||||
.min(needed - stats.downloaded_and_checked_bytes);
|
||||
state
|
||||
.speed_estimator
|
||||
.add_snapshot(fetched, remaining, Instant::now());
|
||||
.down_speed_estimator
|
||||
.add_snapshot(fetched, Some(remaining), now);
|
||||
state
|
||||
.up_speed_estimator
|
||||
.add_snapshot(stats.uploaded_bytes, None, now);
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
}
|
||||
}
|
||||
|
|
@ -291,8 +298,12 @@ impl TorrentStateLive {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn speed_estimator(&self) -> &SpeedEstimator {
|
||||
&self.speed_estimator
|
||||
pub fn down_speed_estimator(&self) -> &SpeedEstimator {
|
||||
&self.down_speed_estimator
|
||||
}
|
||||
|
||||
pub fn up_speed_estimator(&self) -> &SpeedEstimator {
|
||||
&self.up_speed_estimator
|
||||
}
|
||||
|
||||
async fn tracker_one_request(&self, tracker_url: Url) -> anyhow::Result<u64> {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ pub struct LiveStats {
|
|||
pub snapshot: StatsSnapshot,
|
||||
pub average_piece_download_time: Option<Duration>,
|
||||
pub download_speed: Speed,
|
||||
pub upload_speed: Speed,
|
||||
pub time_remaining: Option<DurationWithHumanReadable>,
|
||||
}
|
||||
|
||||
|
|
@ -17,8 +18,9 @@ impl std::fmt::Display for LiveStats {
|
|||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "down speed: {}", self.download_speed)?;
|
||||
if let Some(time_remaining) = &self.time_remaining {
|
||||
write!(f, " eta: {time_remaining}")?;
|
||||
write!(f, ", eta: {time_remaining}")?;
|
||||
}
|
||||
write!(f, ", up speed: {}", self.upload_speed)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -26,13 +28,17 @@ impl std::fmt::Display for LiveStats {
|
|||
impl From<&TorrentStateLive> for LiveStats {
|
||||
fn from(live: &TorrentStateLive) -> Self {
|
||||
let snapshot = live.stats_snapshot();
|
||||
let estimator = live.speed_estimator();
|
||||
let down_estimator = live.down_speed_estimator();
|
||||
let up_estimator = live.up_speed_estimator();
|
||||
|
||||
Self {
|
||||
average_piece_download_time: snapshot.average_piece_download_time(),
|
||||
snapshot,
|
||||
download_speed: estimator.download_mbps().into(),
|
||||
time_remaining: estimator.time_remaining().map(DurationWithHumanReadable),
|
||||
download_speed: down_estimator.mbps().into(),
|
||||
upload_speed: up_estimator.mbps().into(),
|
||||
time_remaining: down_estimator
|
||||
.time_remaining()
|
||||
.map(DurationWithHumanReadable),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
18
crates/librqbit/webui/dist/assets/index.js
vendored
18
crates/librqbit/webui/dist/assets/index.js
vendored
File diff suppressed because one or more lines are too long
2
crates/librqbit/webui/dist/manifest.json
vendored
2
crates/librqbit/webui/dist/manifest.json
vendored
|
|
@ -4,7 +4,7 @@
|
|||
"src": "assets/logo.svg"
|
||||
},
|
||||
"index.html": {
|
||||
"file": "assets/index-6d4556f3.js",
|
||||
"file": "assets/index-713a95fc.js",
|
||||
"isEntry": true,
|
||||
"src": "index.html"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,11 @@ export interface ListTorrentsResponse {
|
|||
torrents: Array<TorrentId>;
|
||||
}
|
||||
|
||||
export interface Speed {
|
||||
mbps: number;
|
||||
human_readable: string;
|
||||
}
|
||||
|
||||
// Interface for the Torrent Stats API response
|
||||
export interface LiveTorrentStats {
|
||||
snapshot: {
|
||||
|
|
@ -52,10 +57,8 @@ export interface LiveTorrentStats {
|
|||
secs: number;
|
||||
nanos: number;
|
||||
};
|
||||
download_speed: {
|
||||
mbps: number;
|
||||
human_readable: string;
|
||||
};
|
||||
download_speed: Speed;
|
||||
upload_speed: Speed;
|
||||
all_time_download_speed: {
|
||||
mbps: number;
|
||||
human_readable: string;
|
||||
|
|
|
|||
|
|
@ -185,6 +185,27 @@ const TorrentActions: React.FC<{
|
|||
</Row>
|
||||
}
|
||||
|
||||
const Speed: React.FC<{ statsResponse: TorrentStats }> = ({ statsResponse }) => {
|
||||
switch (statsResponse.state) {
|
||||
case STATE_PAUSED: return 'Paused';
|
||||
case STATE_INITIALIZING: return 'Checking files';
|
||||
case STATE_ERROR: return 'Error';
|
||||
}
|
||||
// Unknown state
|
||||
if (statsResponse.state != 'live' || statsResponse.live === null) {
|
||||
return statsResponse.state;
|
||||
}
|
||||
|
||||
return <>
|
||||
{!statsResponse.finished && <p>↓ {statsResponse.live.download_speed.human_readable}</p>}
|
||||
<p>↑ {statsResponse.live.upload_speed.human_readable}</p>
|
||||
</>
|
||||
|
||||
if (statsResponse.finished) {
|
||||
return <span>Completed</span>;
|
||||
}
|
||||
}
|
||||
|
||||
const TorrentRow: React.FC<{
|
||||
id: number,
|
||||
detailsResponse: TorrentDetails | null,
|
||||
|
|
@ -208,19 +229,6 @@ const TorrentRow: React.FC<{
|
|||
return `${peer_stats.live} / ${peer_stats.seen}`;
|
||||
}
|
||||
|
||||
const formatDownloadSpeed = () => {
|
||||
if (finished) {
|
||||
return 'Completed';
|
||||
}
|
||||
switch (state) {
|
||||
case STATE_PAUSED: return 'Paused';
|
||||
case STATE_INITIALIZING: return 'Checking files';
|
||||
case STATE_ERROR: return 'Error';
|
||||
}
|
||||
|
||||
return statsResponse?.live?.download_speed.human_readable ?? "N/A";
|
||||
}
|
||||
|
||||
let classNames = [];
|
||||
|
||||
if (error) {
|
||||
|
|
@ -253,7 +261,9 @@ const TorrentRow: React.FC<{
|
|||
animated={isAnimated}
|
||||
variant={progressBarVariant} />
|
||||
</Column>
|
||||
<Column size={2} label="Down Speed">{formatDownloadSpeed()}</Column>
|
||||
<Column size={2} label="Speed">
|
||||
<Speed statsResponse={statsResponse} />
|
||||
</Column>
|
||||
<Column label="ETA">{getCompletionETA(statsResponse)}</Column>
|
||||
<Column size={2} label="Peers">{formatPeersString()}</Column >
|
||||
<Column label="Actions">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue