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
async
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.check_accounts();
state.redraw(); state.redraw();
}, },
ThreadEvent::ThreadJoin(id) => { ThreadEvent::NewThread(id, name) => {
state.join(id); state.new_thread(id, name);
}, },
} }
}, },

View File

@ -38,7 +38,7 @@ use melib::StackVec;
use text_processing::GlobMatch; use text_processing::GlobMatch;
use crate::types::UIEvent::{self, EnvelopeRemove, EnvelopeRename, EnvelopeUpdate, Notification}; use crate::types::UIEvent::{self, EnvelopeRemove, EnvelopeRename, EnvelopeUpdate, Notification};
use crate::{workers::WorkController, StatusEvent, ThreadEvent}; use crate::{StatusEvent, ThreadEvent};
use crossbeam::Sender; use crossbeam::Sender;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::fs; use std::fs;
@ -162,6 +162,7 @@ pub struct Account {
pub(crate) runtime_settings: AccountConf, pub(crate) runtime_settings: AccountConf,
pub(crate) backend: Arc<RwLock<Box<dyn MailBackend>>>, pub(crate) backend: Arc<RwLock<Box<dyn MailBackend>>>,
sender: Sender<ThreadEvent>,
event_queue: VecDeque<(FolderHash, RefreshEvent)>, event_queue: VecDeque<(FolderHash, RefreshEvent)>,
notify_fn: Arc<NotifyFn>, notify_fn: Arc<NotifyFn>,
} }
@ -245,6 +246,7 @@ impl Account {
mut settings: AccountConf, mut settings: AccountConf,
map: &Backends, map: &Backends,
work_context: WorkContext, work_context: WorkContext,
sender: Sender<ThreadEvent>,
notify_fn: NotifyFn, notify_fn: NotifyFn,
) -> Result<Self> { ) -> Result<Self> {
let s = settings.clone(); let s = settings.clone();
@ -300,6 +302,7 @@ impl Account {
settings, settings,
backend: Arc::new(RwLock::new(backend)), backend: Arc::new(RwLock::new(backend)),
notify_fn, notify_fn,
sender,
event_queue: VecDeque::with_capacity(8), event_queue: VecDeque::with_capacity(8),
}) })
@ -514,16 +517,7 @@ impl Account {
} }
Some(w) Some(w)
} }
pub fn reload( pub fn reload(&mut self, event: RefreshEvent, folder_hash: FolderHash) -> Option<UIEvent> {
&mut self,
event: RefreshEvent,
folder_hash: FolderHash,
context: (
&mut WorkController,
&Sender<ThreadEvent>,
&mut VecDeque<UIEvent>,
),
) -> Option<UIEvent> {
if !self.folders[&folder_hash].is_available() { if !self.folders[&folder_hash].is_available() {
self.event_queue.push_back((folder_hash, event)); self.event_queue.push_back((folder_hash, event));
return None; return None;
@ -683,6 +677,7 @@ impl Account {
} }
RefreshEventKind::Failure(e) => { RefreshEventKind::Failure(e) => {
debug!("RefreshEvent Failure: {}", e.to_string()); debug!("RefreshEvent Failure: {}", e.to_string());
/*
context context
.1 .1
.send(ThreadEvent::UIEvent(UIEvent::Notification( .send(ThreadEvent::UIEvent(UIEvent::Notification(
@ -691,43 +686,39 @@ impl Account {
Some(crate::types::NotificationType::ERROR), Some(crate::types::NotificationType::ERROR),
))) )))
.expect("Could not send event on main channel"); .expect("Could not send event on main channel");
self.watch(context); */
self.watch();
} }
} }
} }
None None
} }
pub fn watch( pub fn watch(&self) {
&self, let sender_ = self.sender.clone();
context: (
&mut WorkController,
&Sender<ThreadEvent>,
&mut VecDeque<UIEvent>,
),
) {
let (work_controller, sender, replies) = context;
let sender = sender.clone();
let r = RefreshEventConsumer::new(Box::new(move |r| { let r = RefreshEventConsumer::new(Box::new(move |r| {
sender.send(ThreadEvent::from(r)).unwrap(); sender_.send(ThreadEvent::from(r)).unwrap();
})); }));
match self match self
.backend .backend
.read() .read()
.unwrap() .unwrap()
.watch(r, work_controller.get_context()) .watch(r, self.work_context.clone())
{ {
Ok(id) => { Ok(id) => {
work_controller self.sender
.static_threads .send(ThreadEvent::NewThread(
.lock() id,
.unwrap() format!("watching {}", self.name()).into(),
.insert(id, format!("watching {}", self.name()).into()); ))
.unwrap();
} }
Err(e) => { Err(e) => {
replies.push_back(UIEvent::StatusEvent(StatusEvent::DisplayMessage( self.sender
e.to_string(), .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 { pub fn is_online(&mut self, account_pos: usize) -> bool {
let Context { let Context {
ref mut work_controller,
ref sender,
ref mut replies,
ref mut accounts, ref mut accounts,
ref mut mailbox_hashes, ref mut mailbox_hashes,
.. ..
@ -158,7 +155,7 @@ impl Context {
* inform the main binary that refresh events arrived * inform the main binary that refresh events arrived
* - replies to report any failures to the user * - replies to report any failures to the user
*/ */
accounts[account_pos].watch((work_controller, sender, replies)); accounts[account_pos].watch();
} }
true true
} else { } else {
@ -184,7 +181,6 @@ pub struct State {
components: Vec<Box<dyn Component>>, components: Vec<Box<dyn Component>>,
pub context: Context, pub context: Context,
timer: thread::JoinHandle<()>, timer: thread::JoinHandle<()>,
threads: FnvHashMap<thread::ThreadId, (Sender<bool>, thread::JoinHandle<()>)>,
} }
impl Drop for State { impl Drop for State {
@ -232,6 +228,7 @@ impl State {
a_s.clone(), a_s.clone(),
&backends, &backends,
work_controller.get_context(), work_controller.get_context(),
sender.clone(),
NotifyFn::new(Box::new(move |f: FolderHash| { NotifyFn::new(Box::new(move |f: FolderHash| {
sender sender
.send(ThreadEvent::UIEvent(UIEvent::StartupCheck(f))) .send(ThreadEvent::UIEvent(UIEvent::StartupCheck(f)))
@ -286,7 +283,6 @@ impl State {
tx: input_thread.0, tx: input_thread.0,
}, },
}, },
threads: FnvHashMap::with_capacity_and_hasher(1, Default::default()),
}; };
if s.context.settings.terminal.ascii_drawing { if s.context.settings.terminal.ascii_drawing {
s.grid.set_ascii_drawing(true); s.grid.set_ascii_drawing(true);
@ -319,41 +315,29 @@ impl State {
return; return;
} }
let Context { let Context {
ref mut work_controller, ref mut accounts, ..
ref sender,
ref mut replies,
ref mut accounts,
..
} = &mut self.context; } = &mut self.context;
if let Some(notification) = if let Some(notification) = accounts[idxa].reload(event, hash) {
accounts[idxa].reload(event, hash, (work_controller, sender, replies))
{
if let UIEvent::Notification(_, _, _) = notification { if let UIEvent::Notification(_, _, _) = notification {
self.rcv_event(UIEvent::MailboxUpdate((idxa, hash))); self.rcv_event(UIEvent::MailboxUpdate((idxa, hash)));
} }
self.rcv_event(notification); self.rcv_event(notification);
} }
} else { } else {
if let melib::backends::RefreshEventKind::Failure(e) = event.kind() { if let melib::backends::RefreshEventKind::Failure(err) = event.kind() {
self.context debug!(err);
.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 an owned thread returns a `ThreadEvent::ThreadJoin` event to `State` then it must remove pub fn new_thread(&mut self, id: thread::ThreadId, name: String) {
/// the thread from its list and `join` it. self.context
pub fn join(&mut self, id: thread::ThreadId) { .work_controller
let (tx, handle) = self.threads.remove(&id).unwrap(); .static_threads
tx.send(true).unwrap(); .lock()
handle.join().unwrap(); .unwrap()
.insert(id, name.into());
} }
/// Switch back to the terminal's main screen (The command line the user sees before opening /// 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. /// to the main process.
#[derive(Debug)] #[derive(Debug)]
pub enum ThreadEvent { pub enum ThreadEvent {
ThreadJoin(thread::ThreadId), NewThread(thread::ThreadId, String),
/// User input. /// User input.
Input(Key), Input(Key),
/// User input and input as raw bytes. /// User input and input as raw bytes.