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