ui: refactor watch thread spawning procedure

- Remove unnecessary parameters from watch(), reload()
- Add NewThread event that adds new threads in
work_controller.static_threads hashmap
- removed obsolete field State.threads
- silence watch thread error notifications
memfd
Manos Pitsidianakis 2019-12-12 01:01:11 +02:00
parent 7732b851e6
commit 59f7f03d64
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
4 changed files with 39 additions and 64 deletions

View File

@ -373,8 +373,8 @@ fn run_app() -> Result<()> {
state.check_accounts();
state.redraw();
},
ThreadEvent::ThreadJoin(id) => {
state.join(id);
ThreadEvent::NewThread(id, name) => {
state.new_thread(id, name);
},
}
},

View File

@ -38,7 +38,7 @@ use melib::StackVec;
use text_processing::GlobMatch;
use crate::types::UIEvent::{self, EnvelopeRemove, EnvelopeRename, EnvelopeUpdate, Notification};
use crate::{workers::WorkController, StatusEvent, ThreadEvent};
use crate::{StatusEvent, ThreadEvent};
use crossbeam::Sender;
use std::collections::VecDeque;
use std::fs;
@ -162,6 +162,7 @@ pub struct Account {
pub(crate) runtime_settings: AccountConf,
pub(crate) backend: Arc<RwLock<Box<dyn MailBackend>>>,
sender: Sender<ThreadEvent>,
event_queue: VecDeque<(FolderHash, RefreshEvent)>,
notify_fn: Arc<NotifyFn>,
}
@ -245,6 +246,7 @@ impl Account {
mut settings: AccountConf,
map: &Backends,
work_context: WorkContext,
sender: Sender<ThreadEvent>,
notify_fn: NotifyFn,
) -> Result<Self> {
let s = settings.clone();
@ -300,6 +302,7 @@ impl Account {
settings,
backend: Arc::new(RwLock::new(backend)),
notify_fn,
sender,
event_queue: VecDeque::with_capacity(8),
})
@ -514,16 +517,7 @@ impl Account {
}
Some(w)
}
pub fn reload(
&mut self,
event: RefreshEvent,
folder_hash: FolderHash,
context: (
&mut WorkController,
&Sender<ThreadEvent>,
&mut VecDeque<UIEvent>,
),
) -> Option<UIEvent> {
pub fn reload(&mut self, event: RefreshEvent, folder_hash: FolderHash) -> Option<UIEvent> {
if !self.folders[&folder_hash].is_available() {
self.event_queue.push_back((folder_hash, event));
return None;
@ -683,6 +677,7 @@ impl Account {
}
RefreshEventKind::Failure(e) => {
debug!("RefreshEvent Failure: {}", e.to_string());
/*
context
.1
.send(ThreadEvent::UIEvent(UIEvent::Notification(
@ -691,43 +686,39 @@ impl Account {
Some(crate::types::NotificationType::ERROR),
)))
.expect("Could not send event on main channel");
self.watch(context);
*/
self.watch();
}
}
}
None
}
pub fn watch(
&self,
context: (
&mut WorkController,
&Sender<ThreadEvent>,
&mut VecDeque<UIEvent>,
),
) {
let (work_controller, sender, replies) = context;
let sender = sender.clone();
pub fn watch(&self) {
let sender_ = self.sender.clone();
let r = RefreshEventConsumer::new(Box::new(move |r| {
sender.send(ThreadEvent::from(r)).unwrap();
sender_.send(ThreadEvent::from(r)).unwrap();
}));
match self
.backend
.read()
.unwrap()
.watch(r, work_controller.get_context())
.watch(r, self.work_context.clone())
{
Ok(id) => {
work_controller
.static_threads
.lock()
.unwrap()
.insert(id, format!("watching {}", self.name()).into());
self.sender
.send(ThreadEvent::NewThread(
id,
format!("watching {}", self.name()).into(),
))
.unwrap();
}
Err(e) => {
replies.push_back(UIEvent::StatusEvent(StatusEvent::DisplayMessage(
e.to_string(),
)));
self.sender
.send(ThreadEvent::UIEvent(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(e.to_string()),
)))
.unwrap();
}
}
}

View File

@ -137,9 +137,6 @@ impl Context {
pub fn is_online(&mut self, account_pos: usize) -> bool {
let Context {
ref mut work_controller,
ref sender,
ref mut replies,
ref mut accounts,
ref mut mailbox_hashes,
..
@ -158,7 +155,7 @@ impl Context {
* inform the main binary that refresh events arrived
* - replies to report any failures to the user
*/
accounts[account_pos].watch((work_controller, sender, replies));
accounts[account_pos].watch();
}
true
} else {
@ -184,7 +181,6 @@ pub struct State {
components: Vec<Box<dyn Component>>,
pub context: Context,
timer: thread::JoinHandle<()>,
threads: FnvHashMap<thread::ThreadId, (Sender<bool>, thread::JoinHandle<()>)>,
}
impl Drop for State {
@ -232,6 +228,7 @@ impl State {
a_s.clone(),
&backends,
work_controller.get_context(),
sender.clone(),
NotifyFn::new(Box::new(move |f: FolderHash| {
sender
.send(ThreadEvent::UIEvent(UIEvent::StartupCheck(f)))
@ -286,7 +283,6 @@ impl State {
tx: input_thread.0,
},
},
threads: FnvHashMap::with_capacity_and_hasher(1, Default::default()),
};
if s.context.settings.terminal.ascii_drawing {
s.grid.set_ascii_drawing(true);
@ -319,41 +315,29 @@ impl State {
return;
}
let Context {
ref mut work_controller,
ref sender,
ref mut replies,
ref mut accounts,
..
ref mut accounts, ..
} = &mut self.context;
if let Some(notification) =
accounts[idxa].reload(event, hash, (work_controller, sender, replies))
{
if let Some(notification) = accounts[idxa].reload(event, hash) {
if let UIEvent::Notification(_, _, _) = notification {
self.rcv_event(UIEvent::MailboxUpdate((idxa, hash)));
}
self.rcv_event(notification);
}
} else {
if let melib::backends::RefreshEventKind::Failure(e) = event.kind() {
self.context
.sender
.send(ThreadEvent::UIEvent(UIEvent::Notification(
Some("watcher thread exited with error".to_string()),
e.to_string(),
Some(crate::types::NotificationType::ERROR),
)))
.expect("Could not send event on main channel");
if let melib::backends::RefreshEventKind::Failure(err) = event.kind() {
debug!(err);
}
}
}
/// If an owned thread returns a `ThreadEvent::ThreadJoin` event to `State` then it must remove
/// the thread from its list and `join` it.
pub fn join(&mut self, id: thread::ThreadId) {
let (tx, handle) = self.threads.remove(&id).unwrap();
tx.send(true).unwrap();
handle.join().unwrap();
pub fn new_thread(&mut self, id: thread::ThreadId, name: String) {
self.context
.work_controller
.static_threads
.lock()
.unwrap()
.insert(id, name.into());
}
/// Switch back to the terminal's main screen (The command line the user sees before opening

View File

@ -46,7 +46,7 @@ pub enum StatusEvent {
/// to the main process.
#[derive(Debug)]
pub enum ThreadEvent {
ThreadJoin(thread::ThreadId),
NewThread(thread::ThreadId, String),
/// User input.
Input(Key),
/// User input and input as raw bytes.