use core::time::Duration;
use std::time::Instant;
#[derive(Debug, Clone)]
pub struct ProgressDetails {
total_bytes: u64,
processed_bytes: u64,
last_rate_check: Instant,
processed_since_last_check: u64,
bytes_per_sec: u64,
}
impl ProgressDetails {
pub fn new(total_bytes: u64) -> Self {
Self {
total_bytes,
processed_bytes: 0,
last_rate_check: Instant::now(),
processed_since_last_check: 0,
bytes_per_sec: 0,
}
}
pub fn add_chunk(&mut self, data: u64) {
self.processed_bytes += data;
self.processed_since_last_check += data;
if self.processed_bytes > self.total_bytes {
let process = &self;
tracing::warn!(
?process,
"Processed Bytes is larger than Total Bytes, something seems off"
);
}
let current_time = Instant::now();
let since_last_check = current_time - self.last_rate_check;
let since_last_check_f32 = since_last_check.as_secs_f32();
if since_last_check >= Duration::from_millis(500) || (since_last_check_f32 > 0.0 && self.bytes_per_sec == 0) {
let bytes_per_sec = (self.processed_since_last_check as f32 / since_last_check_f32) as u64;
self.processed_since_last_check = 0;
self.last_rate_check = current_time;
if self.bytes_per_sec == 0 {
self.bytes_per_sec = bytes_per_sec;
} else {
self.bytes_per_sec = (self.bytes_per_sec * 3 + bytes_per_sec) / 4;
}
}
}
pub fn total_bytes(&self) -> u64 { self.total_bytes }
pub fn processed_bytes(&self) -> u64 { self.processed_bytes }
pub fn is_finished(&self) -> bool { self.processed_bytes >= self.total_bytes }
pub fn bytes_per_sec(&self) -> u64 { self.bytes_per_sec }
pub fn percent_complete(&self) -> u64 { self.processed_bytes * 100 / self.total_bytes }
pub fn time_remaining(&self) -> Duration {
Duration::from_secs_f32(
(self.total_bytes.saturating_sub(self.processed_bytes)) as f32 / self.bytes_per_sec.max(1) as f32,
)
}
}