ui: add ratelimiting in UI notifications and drawing
parent
1eb49efb22
commit
f58ed387dd
|
@ -254,7 +254,7 @@ fn run_app() -> Result<()> {
|
|||
let status_bar = Box::new(StatusBar::new(window));
|
||||
state.register_component(status_bar);
|
||||
|
||||
let xdg_notifications = Box::new(ui::components::notifications::XDGNotifications {});
|
||||
let xdg_notifications = Box::new(ui::components::notifications::XDGNotifications::new());
|
||||
state.register_component(xdg_notifications);
|
||||
state.register_component(Box::new(
|
||||
ui::components::notifications::NotificationFilter {},
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
/*!
|
||||
Notification handling components.
|
||||
*/
|
||||
use crate::types::RateLimit;
|
||||
use notify_rust;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
|
@ -29,7 +30,9 @@ use super::*;
|
|||
|
||||
/// Passes notifications to the OS using the XDG specifications.
|
||||
#[derive(Debug)]
|
||||
pub struct XDGNotifications {}
|
||||
pub struct XDGNotifications {
|
||||
rate_limit: RateLimit,
|
||||
}
|
||||
|
||||
impl fmt::Display for XDGNotifications {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
|
@ -38,10 +41,22 @@ impl fmt::Display for XDGNotifications {
|
|||
}
|
||||
}
|
||||
|
||||
impl XDGNotifications {
|
||||
pub fn new() -> Self {
|
||||
XDGNotifications {
|
||||
rate_limit: RateLimit::new(3, 1000),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for XDGNotifications {
|
||||
fn draw(&mut self, _grid: &mut CellBuffer, _area: Area, _context: &mut Context) {}
|
||||
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
|
||||
if let UIEvent::Notification(ref title, ref body, ref kind) = event {
|
||||
if !self.rate_limit.tick() {
|
||||
return true;
|
||||
}
|
||||
|
||||
let settings = &context.runtime_settings.notifications;
|
||||
let mut notification = notify_rust::Notification::new();
|
||||
notification
|
||||
|
|
|
@ -176,6 +176,7 @@ pub struct State {
|
|||
rows: usize,
|
||||
|
||||
grid: CellBuffer,
|
||||
draw_rate_limit: RateLimit,
|
||||
stdout: Option<StateStdout>,
|
||||
child: Option<ForkType>,
|
||||
pub mode: UIMode,
|
||||
|
@ -272,6 +273,7 @@ impl State {
|
|||
mode: UIMode::Normal,
|
||||
components: Vec::with_capacity(1),
|
||||
timer,
|
||||
draw_rate_limit: RateLimit::new(1, 3),
|
||||
|
||||
context: Context {
|
||||
accounts,
|
||||
|
@ -293,6 +295,9 @@ impl State {
|
|||
},
|
||||
},
|
||||
};
|
||||
s.draw_rate_limit
|
||||
.timer
|
||||
.set_value(std::time::Duration::from_millis(3));
|
||||
if s.context.settings.terminal.ascii_drawing {
|
||||
s.grid.set_ascii_drawing(true);
|
||||
}
|
||||
|
@ -429,6 +434,10 @@ impl State {
|
|||
|
||||
/// Force a redraw for all dirty components.
|
||||
pub fn redraw(&mut self) {
|
||||
if !self.draw_rate_limit.tick() {
|
||||
return;
|
||||
}
|
||||
|
||||
for i in 0..self.components.len() {
|
||||
self.draw_component(i);
|
||||
}
|
||||
|
@ -677,6 +686,11 @@ impl State {
|
|||
self.context.input_to_raw();
|
||||
}
|
||||
}
|
||||
UIEvent::Timer(id) if id == self.draw_rate_limit.id() => {
|
||||
self.draw_rate_limit.reset();
|
||||
self.redraw();
|
||||
return;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
/* inform each component */
|
||||
|
|
|
@ -242,3 +242,56 @@ pub mod segment_tree {
|
|||
assert_eq!(segment_tree.get_max(6, 9), 37);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RateLimit {
|
||||
last_tick: std::time::Instant,
|
||||
pub timer: crate::timer::PosixTimer,
|
||||
rate: std::time::Duration,
|
||||
reqs: u64,
|
||||
millis: std::time::Duration,
|
||||
pub active: bool,
|
||||
}
|
||||
|
||||
impl RateLimit {
|
||||
pub fn new(reqs: u64, millis: u64) -> Self {
|
||||
RateLimit {
|
||||
last_tick: std::time::Instant::now(),
|
||||
timer: crate::timer::PosixTimer::new_with_signal(
|
||||
std::time::Duration::from_secs(0),
|
||||
std::time::Duration::from_secs(1),
|
||||
nix::sys::signal::Signal::SIGALRM,
|
||||
)
|
||||
.unwrap(),
|
||||
|
||||
rate: std::time::Duration::from_millis(millis / reqs),
|
||||
reqs,
|
||||
millis: std::time::Duration::from_millis(millis),
|
||||
active: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.last_tick = std::time::Instant::now();
|
||||
self.active = false;
|
||||
}
|
||||
|
||||
pub fn tick(&mut self) -> bool {
|
||||
let now = std::time::Instant::now();
|
||||
self.last_tick += self.rate;
|
||||
if self.last_tick < now {
|
||||
self.last_tick = now + self.rate;
|
||||
} else if self.last_tick > now + self.millis {
|
||||
self.timer.rearm();
|
||||
self.active = true;
|
||||
return false;
|
||||
}
|
||||
self.active = false;
|
||||
true
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn id(&self) -> u8 {
|
||||
self.timer.si_value
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue