ui: add ratelimiting in UI notifications and drawing

master
Manos Pitsidianakis 2020-01-15 12:36:31 +02:00
parent 1eb49efb22
commit f58ed387dd
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
4 changed files with 84 additions and 2 deletions

View File

@ -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 {},

View File

@ -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

View File

@ -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 */

View File

@ -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
}
}