You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

463 lines
14 KiB

3 years ago
  1. /*
  2. * meli
  3. *
  4. * Copyright 2017-2018 Manos Pitsidianakis
  5. *
  6. * This file is part of meli.
  7. *
  8. * meli is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * meli is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with meli. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. /*! UI types used throughout meli.
  22. *
  23. * The `segment_tree` module performs maximum range queries. This is used in getting the maximum
  24. * element of a column within a specific range in e-mail lists. That way a very large value that
  25. * is not the in the currently displayed page does not cause the column to be rendered bigger
  26. * than it has to.
  27. *
  28. * `UIMode` describes the application's... mode. Same as in the modal editor `vi`.
  29. *
  30. * `UIEvent` is the type passed around `Component`s when something happens.
  31. */
  32. extern crate serde;
  33. #[macro_use]
  34. mod helpers;
  35. pub use self::helpers::*;
  36. use super::command::Action;
  37. use super::jobs::JobId;
  38. use super::terminal::*;
  39. use crate::components::{Component, ComponentId};
  40. use melib::backends::{AccountHash, MailboxHash};
  41. use melib::{EnvelopeHash, RefreshEvent, ThreadHash};
  42. use nix::unistd::Pid;
  43. use std::fmt;
  44. use std::thread;
  45. use uuid::Uuid;
  46. #[derive(Debug)]
  47. pub enum StatusEvent {
  48. DisplayMessage(String),
  49. BufClear,
  50. BufSet(String),
  51. UpdateStatus(String),
  52. NewJob(JobId),
  53. JobFinished(JobId),
  54. JobCanceled(JobId),
  55. }
  56. /// `ThreadEvent` encapsulates all of the possible values we need to transfer between our threads
  57. /// to the main process.
  58. #[derive(Debug)]
  59. pub enum ThreadEvent {
  60. NewThread(thread::ThreadId, String),
  61. /// User input.
  62. Input((Key, Vec<u8>)),
  63. /// User input and input as raw bytes.
  64. /// A watched Mailbox has been refreshed.
  65. RefreshMailbox(Box<RefreshEvent>),
  66. UIEvent(UIEvent),
  67. /// A thread has updated some of its information
  68. Pulse,
  69. //Decode { _ }, // For gpg2 signature check
  70. JobFinished(JobId),
  71. }
  72. impl From<RefreshEvent> for ThreadEvent {
  73. fn from(event: RefreshEvent) -> Self {
  74. ThreadEvent::RefreshMailbox(Box::new(event))
  75. }
  76. }
  77. #[derive(Debug)]
  78. pub enum ForkType {
  79. /// Already finished fork, we only want to restore input/output
  80. Finished,
  81. /// Embed pty
  82. Embed(Pid),
  83. Generic(std::process::Child),
  84. NewDraft(File, std::process::Child),
  85. }
  86. #[derive(Debug)]
  87. pub enum NotificationType {
  88. INFO,
  89. ERROR,
  90. NewMail,
  91. }
  92. #[derive(Debug)]
  93. pub enum UIEvent {
  94. Input(Key),
  95. CmdInput(Key),
  96. InsertInput(Key),
  97. EmbedInput((Key, Vec<u8>)),
  98. //Quit?
  99. Resize,
  100. /// Force redraw.
  101. Fork(ForkType),
  102. ChangeMailbox(usize),
  103. ChangeMode(UIMode),
  104. Command(String),
  105. Notification(Option<String>, String, Option<NotificationType>),
  106. Action(Action),
  107. StatusEvent(StatusEvent),
  108. MailboxUpdate((usize, MailboxHash)), // (account_idx, mailbox_idx)
  109. MailboxDelete((usize, MailboxHash)),
  110. MailboxCreate((usize, MailboxHash)),
  111. AccountStatusChange(usize),
  112. ComponentKill(Uuid),
  113. WorkerProgress(AccountHash, MailboxHash),
  114. StartupCheck(MailboxHash),
  115. RefreshEvent(Box<RefreshEvent>),
  116. EnvelopeUpdate(EnvelopeHash),
  117. EnvelopeRename(EnvelopeHash, EnvelopeHash), // old_hash, new_hash
  118. EnvelopeRemove(EnvelopeHash, ThreadHash),
  119. Contacts(ContactEvent),
  120. Compose(ComposeEvent),
  121. FinishedUIDialog(ComponentId, UIMessage),
  122. GlobalUIDialog(Box<dyn Component>),
  123. Timer(u8),
  124. }
  125. impl From<RefreshEvent> for UIEvent {
  126. fn from(event: RefreshEvent) -> Self {
  127. UIEvent::RefreshEvent(Box::new(event))
  128. }
  129. }
  130. #[derive(Debug, PartialEq, Copy, Clone)]
  131. pub enum UIMode {
  132. Normal,
  133. Insert,
  134. /// Forward input to an embed pseudoterminal.
  135. Embed,
  136. Command,
  137. Fork,
  138. }
  139. impl fmt::Display for UIMode {
  140. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  141. write!(
  142. f,
  143. "{}",
  144. match *self {
  145. UIMode::Normal => "NORMAL",
  146. UIMode::Insert => "INSERT",
  147. UIMode::Command => "COMMAND",
  148. UIMode::Fork => "FORK",
  149. UIMode::Embed => "EMBED",
  150. }
  151. )
  152. }
  153. }
  154. /// An event notification that is passed to Entities for handling.
  155. pub struct Notification {
  156. _title: String,
  157. _content: String,
  158. _timestamp: std::time::Instant,
  159. }
  160. pub mod segment_tree {
  161. /*! Simple segment tree implementation for maximum in range queries. This is useful if given an
  162. * array of numbers you want to get the maximum value inside an interval quickly.
  163. */
  164. use smallvec::SmallVec;
  165. use std::convert::TryFrom;
  166. use std::iter::FromIterator;
  167. #[derive(Default, Debug, Clone)]
  168. pub struct SegmentTree {
  169. pub array: SmallVec<[u8; 1024]>,
  170. tree: SmallVec<[u8; 1024]>,
  171. }
  172. impl From<SmallVec<[u8; 1024]>> for SegmentTree {
  173. fn from(val: SmallVec<[u8; 1024]>) -> SegmentTree {
  174. SegmentTree::new(val)
  175. }
  176. }
  177. impl SegmentTree {
  178. pub fn new(val: SmallVec<[u8; 1024]>) -> SegmentTree {
  179. if val.is_empty() {
  180. return SegmentTree {
  181. array: val.clone(),
  182. tree: val,
  183. };
  184. }
  185. let height = (f64::from(u32::try_from(val.len()).unwrap_or(0)))
  186. .log2()
  187. .ceil() as u32;
  188. let max_size = 2 * (2_usize.pow(height));
  189. let mut segment_tree: SmallVec<[u8; 1024]> =
  190. SmallVec::from_iter(core::iter::repeat(0).take(max_size));
  191. for i in 0..val.len() {
  192. segment_tree[val.len() + i] = val[i];
  193. }
  194. for i in (1..val.len()).rev() {
  195. segment_tree[i] = std::cmp::max(segment_tree[2 * i], segment_tree[2 * i + 1]);
  196. }
  197. SegmentTree {
  198. array: val,
  199. tree: segment_tree,
  200. }
  201. }
  202. /// (left, right) is inclusive
  203. pub fn get_max(&self, mut left: usize, mut right: usize) -> u8 {
  204. let len = self.array.len();
  205. debug_assert!(left <= right);
  206. if right >= len {
  207. right = len.saturating_sub(1);
  208. }
  209. left += len;
  210. right += len + 1;
  211. let mut max = 0;
  212. while left < right {
  213. if (left & 1) > 0 {
  214. max = std::cmp::max(max, self.tree[left]);
  215. left += 1;
  216. }
  217. if (right & 1) > 0 {
  218. right -= 1;
  219. max = std::cmp::max(max, self.tree[right]);
  220. }
  221. left /= 2;
  222. right /= 2;
  223. }
  224. max
  225. }
  226. pub fn update(&mut self, pos: usize, value: u8) {
  227. let mut ctr = pos + self.array.len();
  228. // Update leaf node value
  229. self.tree[ctr] = value;
  230. while ctr > 1 {
  231. // move up one level
  232. ctr >>= 1;
  233. self.tree[ctr] = std::cmp::max(self.tree[2 * ctr], self.tree[2 * ctr + 1]);
  234. }
  235. }
  236. }
  237. #[test]
  238. fn test_segment_tree() {
  239. let array: SmallVec<[u8; 1024]> = [9, 1, 17, 2, 3, 23, 4, 5, 6, 37]
  240. .iter()
  241. .cloned()
  242. .collect::<SmallVec<[u8; 1024]>>();
  243. let mut segment_tree = SegmentTree::from(array.clone());
  244. assert_eq!(segment_tree.get_max(0, 5), 23);
  245. assert_eq!(segment_tree.get_max(6, 9), 37);
  246. segment_tree.update(2_usize, 24_u8);
  247. assert_eq!(segment_tree.get_max(0, 5), 24);
  248. }
  249. }
  250. #[derive(Debug)]
  251. pub struct RateLimit {
  252. last_tick: std::time::Instant,
  253. pub timer: crate::timer::PosixTimer,
  254. rate: std::time::Duration,
  255. reqs: u64,
  256. millis: std::time::Duration,
  257. pub active: bool,
  258. }
  259. //FIXME: tests.
  260. impl RateLimit {
  261. pub fn new(reqs: u64, millis: u64) -> Self {
  262. RateLimit {
  263. last_tick: std::time::Instant::now(),
  264. timer: crate::timer::PosixTimer::new_with_signal(
  265. std::time::Duration::from_secs(0),
  266. std::time::Duration::from_millis(millis),
  267. nix::sys::signal::Signal::SIGALRM,
  268. )
  269. .unwrap(),
  270. rate: std::time::Duration::from_millis(millis / reqs),
  271. reqs,
  272. millis: std::time::Duration::from_millis(millis),
  273. active: false,
  274. }
  275. }
  276. pub fn reset(&mut self) {
  277. self.last_tick = std::time::Instant::now();
  278. self.active = false;
  279. }
  280. pub fn tick(&mut self) -> bool {
  281. let now = std::time::Instant::now();
  282. if self.last_tick + self.rate > now {
  283. self.active = false;
  284. } else {
  285. self.timer.rearm();
  286. self.last_tick = now;
  287. self.active = true;
  288. }
  289. self.active
  290. }
  291. #[inline(always)]
  292. pub fn id(&self) -> u8 {
  293. self.timer.si_value
  294. }
  295. }
  296. #[test]
  297. fn test_rate_limit() {
  298. use std::sync::{Arc, Condvar, Mutex};
  299. /* RateLimit sends a SIGALRM with its timer value in siginfo_t. */
  300. let pair = Arc::new((Mutex::new(None), Condvar::new()));
  301. let pair2 = pair.clone();
  302. /* self-pipe trick:
  303. * since we can only use signal-safe functions in the signal handler, make a pipe and
  304. * write one byte to it from the handler. Counting the number of bytes in the pipe can tell
  305. * us how many times the handler was called */
  306. let (alarm_pipe_r, alarm_pipe_w) = nix::unistd::pipe().unwrap();
  307. nix::fcntl::fcntl(
  308. alarm_pipe_r,
  309. nix::fcntl::FcntlArg::F_SETFL(nix::fcntl::OFlag::O_NONBLOCK),
  310. )
  311. .expect("Could not set pipe to NONBLOCK?");
  312. let alarm_handler = move |info: &nix::libc::siginfo_t| {
  313. let value = unsafe { info.si_value().sival_ptr as u8 };
  314. let (lock, cvar) = &*pair2;
  315. let mut started = lock.lock().unwrap();
  316. /* set mutex to timer value */
  317. *started = Some(value);
  318. /* notify condvar in order to wake up the test thread */
  319. cvar.notify_all();
  320. nix::unistd::write(alarm_pipe_w, &[value]).expect("Could not write inside alarm handler?");
  321. };
  322. unsafe {
  323. signal_hook_registry::register_sigaction(signal_hook::SIGALRM, alarm_handler).unwrap();
  324. }
  325. /* Accept at most one request per 3 milliseconds */
  326. let mut rt = RateLimit::new(1, 3);
  327. std::thread::sleep(std::time::Duration::from_millis(2000));
  328. let (lock, cvar) = &*pair;
  329. let started = lock.lock().unwrap();
  330. let result = cvar
  331. .wait_timeout(started, std::time::Duration::from_millis(100))
  332. .unwrap();
  333. /* assert that the handler was called with rt's timer id */
  334. assert_eq!(*result.0, Some(rt.id()));
  335. drop(result);
  336. drop(pair);
  337. let mut buf = [0; 1];
  338. nix::unistd::read(alarm_pipe_r, buf.as_mut()).expect("Could not read from self-pipe?");
  339. /* assert that only one request per 3 milliseconds is accepted */
  340. for _ in 0..5 {
  341. assert!(rt.tick());
  342. std::thread::sleep(std::time::Duration::from_millis(1));
  343. assert!(!rt.tick());
  344. std::thread::sleep(std::time::Duration::from_millis(1));
  345. assert!(!rt.tick());
  346. std::thread::sleep(std::time::Duration::from_millis(1));
  347. /* How many times was the signal handler called? We've slept for at least 3
  348. * milliseconds, so it should have been called once */
  349. let mut ctr = 0;
  350. while nix::unistd::read(alarm_pipe_r, buf.as_mut())
  351. .map(|s| s > 0)
  352. .unwrap_or(false)
  353. {
  354. ctr += 1;
  355. }
  356. assert_eq!(ctr, 1);
  357. }
  358. /* next, test at most 100 requests per second */
  359. let mut rt = RateLimit::new(100, 1000);
  360. for _ in 0..5 {
  361. let mut ctr = 0;
  362. for _ in 0..500 {
  363. if rt.tick() {
  364. ctr += 1;
  365. }
  366. std::thread::sleep(std::time::Duration::from_millis(2));
  367. }
  368. /* around 100 requests should succeed. might be 99 if in first loop, since
  369. * RateLimit::new() has a delay */
  370. assert!(ctr > 97 && ctr < 103);
  371. /* alarm should expire in 1 second */
  372. std::thread::sleep(std::time::Duration::from_millis(1000));
  373. /* How many times was the signal handler called? */
  374. ctr = 0;
  375. while nix::unistd::read(alarm_pipe_r, buf.as_mut())
  376. .map(|s| s > 0)
  377. .unwrap_or(false)
  378. {
  379. ctr += 1;
  380. }
  381. assert_eq!(ctr, 1);
  382. }
  383. /* next, test at most 500 requests per second */
  384. let mut rt = RateLimit::new(500, 1000);
  385. for _ in 0..5 {
  386. let mut ctr = 0;
  387. for _ in 0..500 {
  388. if rt.tick() {
  389. ctr += 1;
  390. }
  391. std::thread::sleep(std::time::Duration::from_millis(2));
  392. }
  393. /* all requests should succeed. */
  394. assert!(ctr < 503 && ctr > 497);
  395. /* alarm should expire in 1 second */
  396. std::thread::sleep(std::time::Duration::from_millis(1000));
  397. /* How many times was the signal handler called? */
  398. ctr = 0;
  399. while nix::unistd::read(alarm_pipe_r, buf.as_mut())
  400. .map(|s| s > 0)
  401. .unwrap_or(false)
  402. {
  403. ctr += 1;
  404. }
  405. assert_eq!(ctr, 1);
  406. }
  407. }
  408. #[derive(Debug)]
  409. pub enum ContactEvent {
  410. CreateContacts(Vec<melib::Card>),
  411. }
  412. #[derive(Debug)]
  413. pub enum ComposeEvent {
  414. SetReceipients(Vec<melib::Address>),
  415. }
  416. pub type UIMessage = Box<dyn 'static + std::any::Any + Send + Sync>;