xref: /DragonOS/tools/debugging/logmonitor/src/app.rs (revision 7b32f5080f42bcbf7d2421013f3ea53c776a063c)
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