use std::convert::TryInto;
use std::time::SystemTime;
struct Entry {
bytes: u64,
timestamp: u64,
}
impl Entry {
fn new(bytes: u64) -> Entry {
Entry {
bytes,
timestamp: millis_since_epoch(),
}
}
fn new_quiet(bytes: u64) -> Entry {
Entry {
bytes,
timestamp: 0,
}
}
fn is_quiet(&self) -> bool {
self.timestamp == 0
}
}
pub struct RateCounter {
last_min_entries: Vec<Entry>,
}
impl RateCounter {
pub fn new() -> RateCounter {
RateCounter {
last_min_entries: vec![],
}
}
pub fn inc(&mut self, bytes: u64) {
self.last_min_entries.push(Entry::new(bytes));
self.truncate();
}
pub fn inc_quiet(&mut self, bytes: u64) {
self.last_min_entries.push(Entry::new_quiet(bytes));
self.truncate();
}
fn truncate(&mut self) {
let now_millis = millis_since_epoch();
while !self.last_min_entries.is_empty()
&& self.last_min_entries[0].timestamp + 60000 < now_millis
{
self.last_min_entries.remove(0);
}
}
pub fn bytes_per_min(&self) -> u64 {
self.last_min_entries.iter().map(|x| x.bytes).sum()
}
pub fn count_per_min(&self) -> u64 {
self.last_min_entries
.iter()
.filter(|x| !x.is_quiet())
.count() as u64
}
pub fn elapsed_since_last_msg(&self) -> Option<u64> {
self.last_min_entries
.last()
.map(|x| millis_since_epoch().saturating_sub(x.timestamp))
}
}
fn millis_since_epoch() -> u64 {
SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.map(|since_epoch| since_epoch.as_millis().try_into().unwrap_or(0))
.unwrap_or(0)
}