1*7b32f508SLoGin use std::error; 2*7b32f508SLoGin 3*7b32f508SLoGin use rand::{distributions::Uniform, prelude::Distribution, rngs::ThreadRng}; 4*7b32f508SLoGin use ratatui::widgets::ListState; 5*7b32f508SLoGin 6*7b32f508SLoGin /// Application result type. 7*7b32f508SLoGin pub type AppResult<T> = std::result::Result<T, Box<dyn error::Error>>; 8*7b32f508SLoGin 9*7b32f508SLoGin /// Application. 10*7b32f508SLoGin #[derive(Debug)] 11*7b32f508SLoGin pub struct App<'a> { 12*7b32f508SLoGin /// APP的标题 13*7b32f508SLoGin pub title: &'a str, 14*7b32f508SLoGin /// Is the application running? 15*7b32f508SLoGin pub running: bool, 16*7b32f508SLoGin 17*7b32f508SLoGin pub enhanced_graphics: bool, 18*7b32f508SLoGin 19*7b32f508SLoGin /// counter 20*7b32f508SLoGin pub counter: u8, 21*7b32f508SLoGin 22*7b32f508SLoGin pub tabs: TabsState<'a>, 23*7b32f508SLoGin 24*7b32f508SLoGin pub memory_log_sparkline: Signal<RandomSignal>, 25*7b32f508SLoGin 26*7b32f508SLoGin logs: Vec<String>, 27*7b32f508SLoGin pub stateful_logs: StatefulList<(&'a str, &'a str)>, 28*7b32f508SLoGin 29*7b32f508SLoGin backend_log_receiver: Option<std::sync::mpsc::Receiver<String>>, 30*7b32f508SLoGin } 31*7b32f508SLoGin 32*7b32f508SLoGin impl<'a> App<'a> { 33*7b32f508SLoGin /// Constructs a new instance of [`App`]. new(title: &'a str) -> Self34*7b32f508SLoGin pub fn new(title: &'a str) -> Self { 35*7b32f508SLoGin let mut rand_signal = RandomSignal::new(0, 100); 36*7b32f508SLoGin let sparkline_points = rand_signal.by_ref().take(300).collect(); 37*7b32f508SLoGin let sparkline = Signal { 38*7b32f508SLoGin source: rand_signal, 39*7b32f508SLoGin points: sparkline_points, 40*7b32f508SLoGin tick_rate: 1, 41*7b32f508SLoGin }; 42*7b32f508SLoGin 43*7b32f508SLoGin Self { 44*7b32f508SLoGin title, 45*7b32f508SLoGin running: true, 46*7b32f508SLoGin enhanced_graphics: true, 47*7b32f508SLoGin counter: 0, 48*7b32f508SLoGin tabs: TabsState::new(vec!["Tab0", "Tab1", "Tab2"]), 49*7b32f508SLoGin memory_log_sparkline: sparkline, 50*7b32f508SLoGin logs: Vec::new(), 51*7b32f508SLoGin stateful_logs: StatefulList::with_items(vec![]), 52*7b32f508SLoGin backend_log_receiver: None, 53*7b32f508SLoGin } 54*7b32f508SLoGin } 55*7b32f508SLoGin set_backend_log_receiver(&mut self, receiver: std::sync::mpsc::Receiver<String>)56*7b32f508SLoGin pub fn set_backend_log_receiver(&mut self, receiver: std::sync::mpsc::Receiver<String>) { 57*7b32f508SLoGin self.backend_log_receiver = Some(receiver); 58*7b32f508SLoGin } 59*7b32f508SLoGin 60*7b32f508SLoGin /// Handles the tick event of the terminal. tick(&mut self)61*7b32f508SLoGin pub fn tick(&mut self) { 62*7b32f508SLoGin self.memory_log_sparkline.on_tick(); 63*7b32f508SLoGin self.handle_logs_on_tick(); 64*7b32f508SLoGin } 65*7b32f508SLoGin 66*7b32f508SLoGin /// 当到达tick时,处理日志 handle_logs_on_tick(&mut self)67*7b32f508SLoGin fn handle_logs_on_tick(&mut self) { 68*7b32f508SLoGin let logs_to_push = self 69*7b32f508SLoGin .backend_log_receiver 70*7b32f508SLoGin .as_ref() 71*7b32f508SLoGin .map(|rv| rv.try_iter().collect::<Vec<String>>()); 72*7b32f508SLoGin 73*7b32f508SLoGin if let Some(logs) = logs_to_push { 74*7b32f508SLoGin for log in logs { 75*7b32f508SLoGin self.push_log(log); 76*7b32f508SLoGin } 77*7b32f508SLoGin } 78*7b32f508SLoGin } 79*7b32f508SLoGin 80*7b32f508SLoGin /// Set running to false to quit the application. quit(&mut self)81*7b32f508SLoGin pub fn quit(&mut self) { 82*7b32f508SLoGin self.running = false; 83*7b32f508SLoGin } 84*7b32f508SLoGin increment_counter(&mut self)85*7b32f508SLoGin pub fn increment_counter(&mut self) { 86*7b32f508SLoGin if let Some(res) = self.counter.checked_add(1) { 87*7b32f508SLoGin self.counter = res; 88*7b32f508SLoGin } 89*7b32f508SLoGin } 90*7b32f508SLoGin decrement_counter(&mut self)91*7b32f508SLoGin pub fn decrement_counter(&mut self) { 92*7b32f508SLoGin if let Some(res) = self.counter.checked_sub(1) { 93*7b32f508SLoGin self.counter = res; 94*7b32f508SLoGin } 95*7b32f508SLoGin } 96*7b32f508SLoGin push_log(&mut self, log: String)97*7b32f508SLoGin pub fn push_log(&mut self, log: String) { 98*7b32f508SLoGin self.logs.push(log); 99*7b32f508SLoGin } 100*7b32f508SLoGin logs(&self) -> &Vec<String>101*7b32f508SLoGin pub fn logs(&self) -> &Vec<String> { 102*7b32f508SLoGin &self.logs 103*7b32f508SLoGin } 104*7b32f508SLoGin } 105*7b32f508SLoGin 106*7b32f508SLoGin #[derive(Debug)] 107*7b32f508SLoGin pub struct TabsState<'a> { 108*7b32f508SLoGin pub titles: Vec<&'a str>, 109*7b32f508SLoGin pub index: usize, 110*7b32f508SLoGin } 111*7b32f508SLoGin 112*7b32f508SLoGin impl<'a> TabsState<'a> { new(titles: Vec<&'a str>) -> TabsState113*7b32f508SLoGin pub fn new(titles: Vec<&'a str>) -> TabsState { 114*7b32f508SLoGin TabsState { titles, index: 0 } 115*7b32f508SLoGin } next(&mut self)116*7b32f508SLoGin pub fn next(&mut self) { 117*7b32f508SLoGin self.index = (self.index + 1) % self.titles.len(); 118*7b32f508SLoGin } 119*7b32f508SLoGin previous(&mut self)120*7b32f508SLoGin pub fn previous(&mut self) { 121*7b32f508SLoGin if self.index > 0 { 122*7b32f508SLoGin self.index -= 1; 123*7b32f508SLoGin } else { 124*7b32f508SLoGin self.index = self.titles.len() - 1; 125*7b32f508SLoGin } 126*7b32f508SLoGin } 127*7b32f508SLoGin } 128*7b32f508SLoGin 129*7b32f508SLoGin #[derive(Clone, Debug)] 130*7b32f508SLoGin pub struct Signal<S: Iterator> { 131*7b32f508SLoGin source: S, 132*7b32f508SLoGin pub points: Vec<S::Item>, 133*7b32f508SLoGin tick_rate: usize, 134*7b32f508SLoGin } 135*7b32f508SLoGin 136*7b32f508SLoGin impl<S> Signal<S> 137*7b32f508SLoGin where 138*7b32f508SLoGin S: Iterator, 139*7b32f508SLoGin { on_tick(&mut self)140*7b32f508SLoGin fn on_tick(&mut self) { 141*7b32f508SLoGin for _ in 0..self.tick_rate { 142*7b32f508SLoGin self.points.remove(0); 143*7b32f508SLoGin } 144*7b32f508SLoGin self.points 145*7b32f508SLoGin .extend(self.source.by_ref().take(self.tick_rate)); 146*7b32f508SLoGin } 147*7b32f508SLoGin } 148*7b32f508SLoGin 149*7b32f508SLoGin #[derive(Clone, Debug)] 150*7b32f508SLoGin pub struct RandomSignal { 151*7b32f508SLoGin distribution: Uniform<u64>, 152*7b32f508SLoGin rng: ThreadRng, 153*7b32f508SLoGin } 154*7b32f508SLoGin 155*7b32f508SLoGin impl RandomSignal { new(lower: u64, upper: u64) -> RandomSignal156*7b32f508SLoGin pub fn new(lower: u64, upper: u64) -> RandomSignal { 157*7b32f508SLoGin RandomSignal { 158*7b32f508SLoGin distribution: Uniform::new(lower, upper), 159*7b32f508SLoGin rng: rand::thread_rng(), 160*7b32f508SLoGin } 161*7b32f508SLoGin } 162*7b32f508SLoGin } 163*7b32f508SLoGin 164*7b32f508SLoGin impl Iterator for RandomSignal { 165*7b32f508SLoGin type Item = u64; next(&mut self) -> Option<u64>166*7b32f508SLoGin fn next(&mut self) -> Option<u64> { 167*7b32f508SLoGin Some(self.distribution.sample(&mut self.rng)) 168*7b32f508SLoGin } 169*7b32f508SLoGin } 170*7b32f508SLoGin 171*7b32f508SLoGin #[derive(Debug)] 172*7b32f508SLoGin pub struct StatefulList<T> { 173*7b32f508SLoGin pub state: ListState, 174*7b32f508SLoGin pub items: Vec<T>, 175*7b32f508SLoGin } 176*7b32f508SLoGin 177*7b32f508SLoGin impl<T> StatefulList<T> { with_items(items: Vec<T>) -> StatefulList<T>178*7b32f508SLoGin pub fn with_items(items: Vec<T>) -> StatefulList<T> { 179*7b32f508SLoGin StatefulList { 180*7b32f508SLoGin state: ListState::default(), 181*7b32f508SLoGin items, 182*7b32f508SLoGin } 183*7b32f508SLoGin } 184*7b32f508SLoGin next(&mut self)185*7b32f508SLoGin pub fn next(&mut self) { 186*7b32f508SLoGin let i = match self.state.selected() { 187*7b32f508SLoGin Some(i) => { 188*7b32f508SLoGin if i >= self.items.len() - 1 { 189*7b32f508SLoGin 0 190*7b32f508SLoGin } else { 191*7b32f508SLoGin i + 1 192*7b32f508SLoGin } 193*7b32f508SLoGin } 194*7b32f508SLoGin None => 0, 195*7b32f508SLoGin }; 196*7b32f508SLoGin self.state.select(Some(i)); 197*7b32f508SLoGin } 198*7b32f508SLoGin previous(&mut self)199*7b32f508SLoGin pub fn previous(&mut self) { 200*7b32f508SLoGin let i = match self.state.selected() { 201*7b32f508SLoGin Some(i) => { 202*7b32f508SLoGin if i == 0 { 203*7b32f508SLoGin self.items.len() - 1 204*7b32f508SLoGin } else { 205*7b32f508SLoGin i - 1 206*7b32f508SLoGin } 207*7b32f508SLoGin } 208*7b32f508SLoGin None => 0, 209*7b32f508SLoGin }; 210*7b32f508SLoGin self.state.select(Some(i)); 211*7b32f508SLoGin } 212*7b32f508SLoGin } 213