🐝 My patches for macos etc...
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.

451 lines
13 KiB

  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::{JobExecutor, JobId};
  38. use super::terminal::*;
  39. use crate::components::{Component, ComponentId, ScrollUpdate};
  40. use std::sync::Arc;
  41. use melib::backends::{AccountHash, BackendEvent, MailboxHash};
  42. use melib::{EnvelopeHash, RefreshEvent, ThreadHash};
  43. use nix::unistd::Pid;
  44. use std::fmt;
  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. SetMouse(bool),
  56. ScrollUpdate(ScrollUpdate),
  57. }
  58. /// `ThreadEvent` encapsulates all of the possible values we need to transfer between our threads
  59. /// to the main process.
  60. #[derive(Debug)]
  61. pub enum ThreadEvent {
  62. /// User input.
  63. Input((Key, Vec<u8>)),
  64. /// User input and input as raw bytes.
  65. /// A watched Mailbox has been refreshed.
  66. RefreshMailbox(Box<RefreshEvent>),
  67. UIEvent(UIEvent),
  68. /// A thread has updated some of its information
  69. Pulse,
  70. //Decode { _ }, // For gpg2 signature check
  71. JobFinished(JobId),
  72. }
  73. impl From<RefreshEvent> for ThreadEvent {
  74. fn from(event: RefreshEvent) -> Self {
  75. ThreadEvent::RefreshMailbox(Box::new(event))
  76. }
  77. }
  78. #[derive(Debug)]
  79. pub enum ForkType {
  80. /// Already finished fork, we only want to restore input/output
  81. Finished,
  82. /// Embed pty
  83. Embed(Pid),
  84. Generic(std::process::Child),
  85. NewDraft(File, std::process::Child),
  86. }
  87. #[derive(Debug, PartialEq, Copy, Clone)]
  88. pub enum NotificationType {
  89. Info,
  90. Error(melib::error::ErrorKind),
  91. NewMail,
  92. SentMail,
  93. Saved,
  94. }
  95. impl core::fmt::Display for NotificationType {
  96. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  97. match *self {
  98. NotificationType::Info => write!(f, "info"),
  99. NotificationType::Error(melib::error::ErrorKind::None) => write!(f, "error"),
  100. NotificationType::Error(kind) => write!(f, "error: {}", kind),
  101. NotificationType::NewMail => write!(f, "new mail"),
  102. NotificationType::SentMail => write!(f, "sent mail"),
  103. NotificationType::Saved => write!(f, "saved"),
  104. }
  105. }
  106. }
  107. #[derive(Debug)]
  108. pub enum UIEvent {
  109. Input(Key),
  110. CmdInput(Key),
  111. InsertInput(Key),
  112. EmbedInput((Key, Vec<u8>)),
  113. //Quit?
  114. Resize,
  115. /// Force redraw.
  116. Fork(ForkType),
  117. ChangeMailbox(usize),
  118. ChangeMode(UIMode),
  119. Command(String),
  120. Notification(Option<String>, String, Option<NotificationType>),
  121. Action(Action),
  122. StatusEvent(StatusEvent),
  123. MailboxUpdate((AccountHash, MailboxHash)), // (account_idx, mailbox_idx)
  124. MailboxDelete((AccountHash, MailboxHash)),
  125. MailboxCreate((AccountHash, MailboxHash)),
  126. AccountStatusChange(AccountHash),
  127. ComponentKill(Uuid),
  128. BackendEvent(AccountHash, BackendEvent),
  129. StartupCheck(MailboxHash),
  130. RefreshEvent(Box<RefreshEvent>),
  131. EnvelopeUpdate(EnvelopeHash),
  132. EnvelopeRename(EnvelopeHash, EnvelopeHash), // old_hash, new_hash
  133. EnvelopeRemove(EnvelopeHash, ThreadHash),
  134. Contacts(ContactEvent),
  135. Compose(ComposeEvent),
  136. FinishedUIDialog(ComponentId, UIMessage),
  137. Callback(CallbackFn),
  138. GlobalUIDialog(Box<dyn Component>),
  139. Timer(Uuid),
  140. ConfigReload {
  141. old_settings: crate::conf::Settings,
  142. },
  143. VisibilityChange(bool),
  144. }
  145. pub struct CallbackFn(pub Box<dyn FnOnce(&mut crate::Context) -> () + Send + 'static>);
  146. impl core::fmt::Debug for CallbackFn {
  147. fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
  148. write!(fmt, "CallbackFn")
  149. }
  150. }
  151. impl From<RefreshEvent> for UIEvent {
  152. fn from(event: RefreshEvent) -> Self {
  153. UIEvent::RefreshEvent(Box::new(event))
  154. }
  155. }
  156. #[derive(Debug, PartialEq, Copy, Clone)]
  157. pub enum UIMode {
  158. Normal,
  159. Insert,
  160. /// Forward input to an embed pseudoterminal.
  161. Embed,
  162. Command,
  163. Fork,
  164. }
  165. impl fmt::Display for UIMode {
  166. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  167. write!(
  168. f,
  169. "{}",
  170. match *self {
  171. UIMode::Normal => "NORMAL",
  172. UIMode::Insert => "INSERT",
  173. UIMode::Command => "COMMAND",
  174. UIMode::Fork => "FORK",
  175. UIMode::Embed => "EMBED",
  176. }
  177. )
  178. }
  179. }
  180. /// An event notification that is passed to Entities for handling.
  181. pub struct Notification {
  182. _title: String,
  183. _content: String,
  184. _timestamp: std::time::Instant,
  185. }
  186. pub mod segment_tree {
  187. /*! Simple segment tree implementation for maximum in range queries. This is useful if given an
  188. * array of numbers you want to get the maximum value inside an interval quickly.
  189. */
  190. use smallvec::SmallVec;
  191. use std::convert::TryFrom;
  192. use std::iter::FromIterator;
  193. #[derive(Default, Debug, Clone)]
  194. pub struct SegmentTree {
  195. pub array: SmallVec<[u8; 1024]>,
  196. tree: SmallVec<[u8; 1024]>,
  197. }
  198. impl From<SmallVec<[u8; 1024]>> for SegmentTree {
  199. fn from(val: SmallVec<[u8; 1024]>) -> SegmentTree {
  200. SegmentTree::new(val)
  201. }
  202. }
  203. impl SegmentTree {
  204. pub fn new(val: SmallVec<[u8; 1024]>) -> SegmentTree {
  205. if val.is_empty() {
  206. return SegmentTree {
  207. array: val.clone(),
  208. tree: val,
  209. };
  210. }
  211. let height = (f64::from(u32::try_from(val.len()).unwrap_or(0)))
  212. .log2()
  213. .ceil() as u32;
  214. let max_size = 2 * (2_usize.pow(height));
  215. let mut segment_tree: SmallVec<[u8; 1024]> =
  216. SmallVec::from_iter(core::iter::repeat(0).take(max_size));
  217. for i in 0..val.len() {
  218. segment_tree[val.len() + i] = val[i];
  219. }
  220. for i in (1..val.len()).rev() {
  221. segment_tree[i] = std::cmp::max(segment_tree[2 * i], segment_tree[2 * i + 1]);
  222. }
  223. SegmentTree {
  224. array: val,
  225. tree: segment_tree,
  226. }
  227. }
  228. /// (left, right) is inclusive
  229. pub fn get_max(&self, mut left: usize, mut right: usize) -> u8 {
  230. if self.array.is_empty() {
  231. return 0;
  232. }
  233. let len = self.array.len();
  234. debug_assert!(left <= right);
  235. if right >= len {
  236. right = len.saturating_sub(1);
  237. }
  238. left += len;
  239. right += len + 1;
  240. let mut max = 0;
  241. while left < right {
  242. if (left & 1) > 0 {
  243. max = std::cmp::max(max, self.tree[left]);
  244. left += 1;
  245. }
  246. if (right & 1) > 0 {
  247. right -= 1;
  248. max = std::cmp::max(max, self.tree[right]);
  249. }
  250. left /= 2;
  251. right /= 2;
  252. }
  253. max
  254. }
  255. pub fn update(&mut self, pos: usize, value: u8) {
  256. let mut ctr = pos + self.array.len();
  257. // Update leaf node value
  258. self.tree[ctr] = value;
  259. while ctr > 1 {
  260. // move up one level
  261. ctr >>= 1;
  262. self.tree[ctr] = std::cmp::max(self.tree[2 * ctr], self.tree[2 * ctr + 1]);
  263. }
  264. }
  265. }
  266. #[test]
  267. fn test_segment_tree() {
  268. let array: SmallVec<[u8; 1024]> = [9, 1, 17, 2, 3, 23, 4, 5, 6, 37]
  269. .iter()
  270. .cloned()
  271. .collect::<SmallVec<[u8; 1024]>>();
  272. let mut segment_tree = SegmentTree::from(array.clone());
  273. assert_eq!(segment_tree.get_max(0, 5), 23);
  274. assert_eq!(segment_tree.get_max(6, 9), 37);
  275. segment_tree.update(2_usize, 24_u8);
  276. assert_eq!(segment_tree.get_max(0, 5), 24);
  277. }
  278. }
  279. #[derive(Debug)]
  280. pub struct RateLimit {
  281. last_tick: std::time::Instant,
  282. pub timer: crate::jobs::Timer,
  283. rate: std::time::Duration,
  284. reqs: u64,
  285. millis: std::time::Duration,
  286. pub active: bool,
  287. }
  288. impl RateLimit {
  289. pub fn new(reqs: u64, millis: u64, job_executor: Arc<JobExecutor>) -> Self {
  290. RateLimit {
  291. last_tick: std::time::Instant::now(),
  292. timer: job_executor.create_timer(
  293. std::time::Duration::from_secs(0),
  294. std::time::Duration::from_millis(millis),
  295. ),
  296. rate: std::time::Duration::from_millis(millis / reqs),
  297. reqs,
  298. millis: std::time::Duration::from_millis(millis),
  299. active: false,
  300. }
  301. }
  302. pub fn reset(&mut self) {
  303. self.last_tick = std::time::Instant::now();
  304. self.active = false;
  305. }
  306. pub fn tick(&mut self) -> bool {
  307. let now = std::time::Instant::now();
  308. if self.last_tick + self.rate > now {
  309. self.active = false;
  310. } else {
  311. self.timer.rearm();
  312. self.last_tick = now;
  313. self.active = true;
  314. }
  315. self.active
  316. }
  317. #[inline(always)]
  318. pub fn id(&self) -> Uuid {
  319. self.timer.id()
  320. }
  321. }
  322. #[test]
  323. fn test_rate_limit() {
  324. /*
  325. let (sender, receiver) =
  326. crossbeam::channel::bounded(4096 * ::std::mem::size_of::<ThreadEvent>());
  327. use std::sync::Arc;
  328. let job_executor = Arc::new(JobExecutor::new(sender));
  329. /* Accept at most one request per 3 milliseconds */
  330. let mut rt = RateLimit::new(1, 3, job_executor.clone());
  331. std::thread::sleep(std::time::Duration::from_millis(2000));
  332. /* assert that only one request per 3 milliseconds is accepted */
  333. for _ in 0..5 {
  334. assert!(rt.tick());
  335. std::thread::sleep(std::time::Duration::from_millis(1));
  336. assert!(!rt.tick());
  337. std::thread::sleep(std::time::Duration::from_millis(1));
  338. assert!(!rt.tick());
  339. std::thread::sleep(std::time::Duration::from_millis(1));
  340. /* How many times was the signal handler called? We've slept for at least 3
  341. * milliseconds, so it should have been called once */
  342. let mut ctr = 0;
  343. while receiver.try_recv().is_ok() {
  344. ctr += 1;
  345. println!("got {}", ctr);
  346. }
  347. println!("ctr = {} {}", ctr, ctr == 1);
  348. assert_eq!(ctr, 1);
  349. }
  350. /* next, test at most 100 requests per second */
  351. let mut rt = RateLimit::new(100, 1000, job_executor.clone());
  352. for _ in 0..5 {
  353. let mut ctr = 0;
  354. for _ in 0..500 {
  355. if rt.tick() {
  356. ctr += 1;
  357. }
  358. std::thread::sleep(std::time::Duration::from_millis(2));
  359. }
  360. /* around 100 requests should succeed. might be 99 if in first loop, since
  361. * RateLimit::new() has a delay */
  362. assert!(ctr > 97 && ctr < 103);
  363. /* alarm should expire in 1 second */
  364. std::thread::sleep(std::time::Duration::from_millis(1000));
  365. /* How many times was the signal handler called? */
  366. ctr = 0;
  367. while receiver.try_recv().is_ok() {
  368. ctr += 1;
  369. }
  370. assert_eq!(ctr, 1);
  371. }
  372. /* next, test at most 500 requests per second */
  373. let mut rt = RateLimit::new(500, 1000, job_executor.clone());
  374. for _ in 0..5 {
  375. let mut ctr = 0;
  376. for _ in 0..500 {
  377. if rt.tick() {
  378. ctr += 1;
  379. }
  380. std::thread::sleep(std::time::Duration::from_millis(2));
  381. }
  382. /* all requests should succeed. */
  383. assert!(ctr < 503 && ctr > 497);
  384. /* alarm should expire in 1 second */
  385. std::thread::sleep(std::time::Duration::from_millis(1000));
  386. /* How many times was the signal handler called? */
  387. ctr = 0;
  388. while receiver.try_recv().is_ok() {
  389. ctr += 1;
  390. }
  391. assert_eq!(ctr, 1);
  392. }
  393. */
  394. }
  395. #[derive(Debug)]
  396. pub enum ContactEvent {
  397. CreateContacts(Vec<melib::Card>),
  398. }
  399. #[derive(Debug)]
  400. pub enum ComposeEvent {
  401. SetReceipients(Vec<melib::Address>),
  402. }
  403. pub type UIMessage = Box<dyn 'static + std::any::Any + Send + Sync>;