Add AccountHash to RefreshEvent

Different accounts might have same inboxes with same MailboxHashes. Use
the hash of the account's name to differentiate.
memfd
Manos Pitsidianakis 2020-05-10 22:05:04 +03:00
parent eb701695f7
commit 8648b229ad
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
8 changed files with 211 additions and 84 deletions

View File

@ -204,7 +204,7 @@ impl Backends {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum RefreshEventKind { pub enum RefreshEventKind {
Update(EnvelopeHash, Box<Envelope>), Update(EnvelopeHash, Box<Envelope>),
/// Rename(old_hash, new_hash) /// Rename(old_hash, new_hash)
@ -216,16 +216,22 @@ pub enum RefreshEventKind {
Failure(MeliError), Failure(MeliError),
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct RefreshEvent { pub struct RefreshEvent {
hash: MailboxHash, mailbox_hash: MailboxHash,
account_hash: AccountHash,
kind: RefreshEventKind, kind: RefreshEventKind,
} }
impl RefreshEvent { impl RefreshEvent {
pub fn hash(&self) -> MailboxHash { pub fn mailbox_hash(&self) -> MailboxHash {
self.hash self.mailbox_hash
} }
pub fn account_hash(&self) -> AccountHash {
self.account_hash
}
pub fn kind(self) -> RefreshEventKind { pub fn kind(self) -> RefreshEventKind {
/* consumes self! */ /* consumes self! */
self.kind self.kind
@ -245,6 +251,12 @@ impl RefreshEventConsumer {
} }
} }
impl fmt::Debug for RefreshEventConsumer {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "RefreshEventConsumer")
}
}
pub struct NotifyFn(Box<dyn Fn(MailboxHash) -> () + Send + Sync>); pub struct NotifyFn(Box<dyn Fn(MailboxHash) -> () + Send + Sync>);
impl fmt::Debug for NotifyFn { impl fmt::Debug for NotifyFn {
@ -555,6 +567,7 @@ pub fn mailbox_default() -> Mailbox {
}) })
} }
pub type AccountHash = u64;
pub type MailboxHash = u64; pub type MailboxHash = u64;
pub type Mailbox = Box<dyn BackendMailbox + Send + Sync>; pub type Mailbox = Box<dyn BackendMailbox + Send + Sync>;

View File

@ -36,9 +36,9 @@ pub mod managesieve;
use crate::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext}; use crate::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext};
use crate::backends::BackendOp; use crate::backends::BackendOp;
use crate::backends::MailboxHash;
use crate::backends::RefreshEvent; use crate::backends::RefreshEvent;
use crate::backends::RefreshEventKind::{self, *}; use crate::backends::RefreshEventKind::{self, *};
use crate::backends::{AccountHash, MailboxHash};
use crate::backends::{BackendMailbox, MailBackend, Mailbox, RefreshEventConsumer}; use crate::backends::{BackendMailbox, MailBackend, Mailbox, RefreshEventConsumer};
use crate::conf::AccountSettings; use crate::conf::AccountSettings;
use crate::email::*; use crate::email::*;
@ -120,12 +120,26 @@ macro_rules! get_conf_val {
#[derive(Debug)] #[derive(Debug)]
pub struct UIDStore { pub struct UIDStore {
account_hash: AccountHash,
uidvalidity: Arc<Mutex<HashMap<MailboxHash, UID>>>, uidvalidity: Arc<Mutex<HashMap<MailboxHash, UID>>>,
hash_index: Arc<Mutex<HashMap<EnvelopeHash, (UID, MailboxHash)>>>, hash_index: Arc<Mutex<HashMap<EnvelopeHash, (UID, MailboxHash)>>>,
uid_index: Arc<Mutex<HashMap<UID, EnvelopeHash>>>, uid_index: Arc<Mutex<HashMap<UID, EnvelopeHash>>>,
byte_cache: Arc<Mutex<HashMap<UID, EnvelopeCache>>>, byte_cache: Arc<Mutex<HashMap<UID, EnvelopeCache>>>,
} }
impl Default for UIDStore {
fn default() -> Self {
UIDStore {
account_hash: 0,
uidvalidity: Default::default(),
hash_index: Default::default(),
uid_index: Default::default(),
byte_cache: Default::default(),
}
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct ImapType { pub struct ImapType {
account_name: String, account_name: String,
@ -323,6 +337,11 @@ impl MailBackend for ImapType {
let main_conn = self.connection.clone(); let main_conn = self.connection.clone();
let uid_store = self.uid_store.clone(); let uid_store = self.uid_store.clone();
let account_name = self.account_name.clone(); let account_name = self.account_name.clone();
let account_hash = {
let mut hasher = DefaultHasher::new();
hasher.write(self.account_name.as_bytes());
hasher.finish()
};
let w = AsyncBuilder::new(); let w = AsyncBuilder::new();
let closure = move |work_context: WorkContext| { let closure = move |work_context: WorkContext| {
let thread = std::thread::current(); let thread = std::thread::current();
@ -330,7 +349,8 @@ impl MailBackend for ImapType {
Ok(conn) => conn, Ok(conn) => conn,
Err(err) => { Err(err) => {
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: mailbox_hash, account_hash,
mailbox_hash,
kind: RefreshEventKind::Failure(err.clone()), kind: RefreshEventKind::Failure(err.clone()),
}); });
@ -350,6 +370,7 @@ impl MailBackend for ImapType {
.send((thread.id(), "refresh".to_string())) .send((thread.id(), "refresh".to_string()))
.unwrap(); .unwrap();
watch::examine_updates( watch::examine_updates(
account_hash,
&inbox, &inbox,
&sender, &sender,
&mut conn, &mut conn,
@ -374,6 +395,11 @@ impl MailBackend for ImapType {
let main_conn = self.connection.clone(); let main_conn = self.connection.clone();
let is_online = self.online.clone(); let is_online = self.online.clone();
let uid_store = self.uid_store.clone(); let uid_store = self.uid_store.clone();
let account_hash = {
let mut hasher = DefaultHasher::new();
hasher.write(self.account_name.as_bytes());
hasher.finish()
};
let handle = std::thread::Builder::new() let handle = std::thread::Builder::new()
.name(format!("{} imap connection", self.account_name.as_str(),)) .name(format!("{} imap connection", self.account_name.as_str(),))
.spawn(move || { .spawn(move || {
@ -397,6 +423,7 @@ impl MailBackend for ImapType {
sender, sender,
work_context, work_context,
tag_index, tag_index,
account_hash,
}; };
if has_idle { if has_idle {
idle(kit).ok().take(); idle(kit).ok().take();
@ -881,6 +908,15 @@ impl ImapType {
Err(MeliError::new("Account is uninitialised.")), Err(MeliError::new("Account is uninitialised.")),
))); )));
let connection = ImapConnection::new_connection(&server_conf, online.clone()); let connection = ImapConnection::new_connection(&server_conf, online.clone());
let account_hash = {
let mut hasher = DefaultHasher::new();
hasher.write(s.name.as_bytes());
hasher.finish()
};
let uid_store: Arc<UIDStore> = Arc::new(UIDStore {
account_hash,
..UIDStore::default()
});
Ok(Box::new(ImapType { Ok(Box::new(ImapType {
account_name: s.name().to_string(), account_name: s.name().to_string(),
@ -892,12 +928,7 @@ impl ImapType {
tag_index: Arc::new(RwLock::new(Default::default())), tag_index: Arc::new(RwLock::new(Default::default())),
mailboxes: Arc::new(RwLock::new(Default::default())), mailboxes: Arc::new(RwLock::new(Default::default())),
connection: Arc::new(Mutex::new(connection)), connection: Arc::new(Mutex::new(connection)),
uid_store: Arc::new(UIDStore { uid_store,
uidvalidity: Default::default(),
hash_index: Default::default(),
uid_index: Default::default(),
byte_cache: Default::default(),
}),
})) }))
} }

View File

@ -24,6 +24,7 @@ use std::sync::{Arc, Mutex, RwLock};
/// Arguments for IMAP watching functions /// Arguments for IMAP watching functions
pub struct ImapWatchKit { pub struct ImapWatchKit {
pub account_hash: AccountHash,
pub conn: ImapConnection, pub conn: ImapConnection,
pub is_online: Arc<Mutex<(Instant, Result<()>)>>, pub is_online: Arc<Mutex<(Instant, Result<()>)>>,
pub main_conn: Arc<Mutex<ImapConnection>>, pub main_conn: Arc<Mutex<ImapConnection>>,
@ -35,13 +36,14 @@ pub struct ImapWatchKit {
} }
macro_rules! exit_on_error { macro_rules! exit_on_error {
($sender:expr, $mailbox_hash:ident, $work_context:ident, $thread_id:ident, $($result:expr)+) => { ($sender:expr, $account_hash:ident, $mailbox_hash:ident, $work_context:ident, $thread_id:ident, $($result:expr)+) => {
$(if let Err(e) = $result { $(if let Err(e) = $result {
debug!("failure: {}", e.to_string()); debug!("failure: {}", e.to_string());
$work_context.set_status.send(($thread_id, e.to_string())).unwrap(); $work_context.set_status.send(($thread_id, e.to_string())).unwrap();
$work_context.finished.send($thread_id).unwrap(); $work_context.finished.send($thread_id).unwrap();
$sender.send(RefreshEvent { $sender.send(RefreshEvent {
hash: $mailbox_hash, account_hash: $account_hash,
mailbox_hash: $mailbox_hash,
kind: RefreshEventKind::Failure(e.clone()), kind: RefreshEventKind::Failure(e.clone()),
}); });
Err(e) Err(e)
@ -60,6 +62,7 @@ pub fn poll_with_examine(kit: ImapWatchKit) -> Result<()> {
sender, sender,
work_context, work_context,
tag_index, tag_index,
account_hash,
} = kit; } = kit;
loop { loop {
if super::try_lock(&is_online)?.1.is_ok() { if super::try_lock(&is_online)?.1.is_ok() {
@ -86,6 +89,7 @@ pub fn poll_with_examine(kit: ImapWatchKit) -> Result<()> {
)) ))
.unwrap(); .unwrap();
examine_updates( examine_updates(
account_hash,
mailbox, mailbox,
&sender, &sender,
&mut conn, &mut conn,
@ -113,6 +117,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
sender, sender,
work_context, work_context,
tag_index, tag_index,
account_hash,
} = kit; } = kit;
loop { loop {
if super::try_lock(&is_online)?.1.is_ok() { if super::try_lock(&is_online)?.1.is_ok() {
@ -138,7 +143,8 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
.send((thread_id, err.to_string())) .send((thread_id, err.to_string()))
.unwrap(); .unwrap();
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: 0, account_hash,
mailbox_hash: 0,
kind: RefreshEventKind::Failure(err.clone()), kind: RefreshEventKind::Failure(err.clone()),
}); });
return Err(err); return Err(err);
@ -148,6 +154,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
let mut response = String::with_capacity(8 * 1024); let mut response = String::with_capacity(8 * 1024);
exit_on_error!( exit_on_error!(
sender, sender,
account_hash,
mailbox_hash, mailbox_hash,
work_context, work_context,
thread_id, thread_id,
@ -165,7 +172,8 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
if let Some(v) = uidvalidities.get_mut(&mailbox_hash) { if let Some(v) = uidvalidities.get_mut(&mailbox_hash) {
if *v != ok.uidvalidity { if *v != ok.uidvalidity {
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: mailbox_hash, account_hash,
mailbox_hash,
kind: RefreshEventKind::Rescan, kind: RefreshEventKind::Rescan,
}); });
*prev_exists = 0; *prev_exists = 0;
@ -178,11 +186,13 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
} }
} else { } else {
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: mailbox_hash, account_hash,
mailbox_hash,
kind: RefreshEventKind::Rescan, kind: RefreshEventKind::Rescan,
}); });
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: mailbox_hash, account_hash,
mailbox_hash,
kind: RefreshEventKind::Failure(MeliError::new(format!( kind: RefreshEventKind::Failure(MeliError::new(format!(
"Unknown mailbox: {} {}", "Unknown mailbox: {} {}",
mailbox.path(), mailbox.path(),
@ -202,6 +212,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
} }
exit_on_error!( exit_on_error!(
sender, sender,
account_hash,
mailbox_hash, mailbox_hash,
work_context, work_context,
thread_id, thread_id,
@ -224,6 +235,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
let mut main_conn_lck = super::try_lock(&main_conn)?; let mut main_conn_lck = super::try_lock(&main_conn)?;
exit_on_error!( exit_on_error!(
sender, sender,
account_hash,
mailbox_hash, mailbox_hash,
work_context, work_context,
thread_id, thread_id,
@ -250,10 +262,12 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
.unwrap(); .unwrap();
exit_on_error!( exit_on_error!(
sender, sender,
account_hash,
mailbox_hash, mailbox_hash,
work_context, work_context,
thread_id, thread_id,
examine_updates( examine_updates(
account_hash,
mailbox, mailbox,
&sender, &sender,
&mut conn, &mut conn,
@ -282,6 +296,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
/* UID SEARCH RECENT */ /* UID SEARCH RECENT */
exit_on_error!( exit_on_error!(
sender, sender,
account_hash,
mailbox_hash, mailbox_hash,
work_context, work_context,
thread_id, thread_id,
@ -300,6 +315,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
Ok(v) => { Ok(v) => {
exit_on_error!( exit_on_error!(
sender, sender,
account_hash,
mailbox_hash, mailbox_hash,
work_context, work_context,
thread_id, thread_id,
@ -358,7 +374,8 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
*mailbox.exists.lock().unwrap() += 1; *mailbox.exists.lock().unwrap() += 1;
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: mailbox_hash, account_hash,
mailbox_hash,
kind: Create(Box::new(env)), kind: Create(Box::new(env)),
}); });
} }
@ -410,6 +427,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
if n > *prev_exists { if n > *prev_exists {
exit_on_error!( exit_on_error!(
sender, sender,
account_hash,
mailbox_hash, mailbox_hash,
work_context, work_context,
thread_id, thread_id,
@ -475,7 +493,8 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
*mailbox.unseen.lock().unwrap() += 1; *mailbox.unseen.lock().unwrap() += 1;
} }
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: mailbox_hash, account_hash,
mailbox_hash,
kind: Create(Box::new(env)), kind: Create(Box::new(env)),
}); });
} }
@ -503,6 +522,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
debug!("fetch {} {:?}", msg_seq, flags); debug!("fetch {} {:?}", msg_seq, flags);
exit_on_error!( exit_on_error!(
sender, sender,
account_hash,
mailbox_hash, mailbox_hash,
work_context, work_context,
thread_id, thread_id,
@ -524,7 +544,8 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
if let Some(uid) = v.pop() { if let Some(uid) = v.pop() {
if let Some(env_hash) = uid_store.uid_index.lock().unwrap().get(&uid) { if let Some(env_hash) = uid_store.uid_index.lock().unwrap().get(&uid) {
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: mailbox_hash, account_hash,
mailbox_hash,
kind: NewFlags(*env_hash, flags), kind: NewFlags(*env_hash, flags),
}); });
} }
@ -551,7 +572,8 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
.unwrap(); .unwrap();
work_context.finished.send(thread_id).unwrap(); work_context.finished.send(thread_id).unwrap();
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: mailbox_hash, account_hash,
mailbox_hash,
kind: RefreshEventKind::Failure(MeliError::new(format!( kind: RefreshEventKind::Failure(MeliError::new(format!(
"IDLE connection dropped: {}", "IDLE connection dropped: {}",
&err &err
@ -561,6 +583,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
} }
pub fn examine_updates( pub fn examine_updates(
account_hash: AccountHash,
mailbox: &ImapMailbox, mailbox: &ImapMailbox,
sender: &RefreshEventConsumer, sender: &RefreshEventConsumer,
conn: &mut ImapConnection, conn: &mut ImapConnection,
@ -574,6 +597,7 @@ pub fn examine_updates(
let mut response = String::with_capacity(8 * 1024); let mut response = String::with_capacity(8 * 1024);
exit_on_error!( exit_on_error!(
sender, sender,
account_hash,
mailbox_hash, mailbox_hash,
work_context, work_context,
thread_id, thread_id,
@ -589,7 +613,8 @@ pub fn examine_updates(
if let Some(v) = uidvalidities.get_mut(&mailbox_hash) { if let Some(v) = uidvalidities.get_mut(&mailbox_hash) {
if *v != ok.uidvalidity { if *v != ok.uidvalidity {
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: mailbox_hash, account_hash,
mailbox_hash,
kind: RefreshEventKind::Rescan, kind: RefreshEventKind::Rescan,
}); });
/* /*
@ -601,11 +626,13 @@ pub fn examine_updates(
} }
} else { } else {
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: mailbox_hash, account_hash,
mailbox_hash,
kind: RefreshEventKind::Rescan, kind: RefreshEventKind::Rescan,
}); });
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: mailbox_hash, account_hash,
mailbox_hash,
kind: RefreshEventKind::Failure(MeliError::new(format!( kind: RefreshEventKind::Failure(MeliError::new(format!(
"Unknown mailbox: {} {}", "Unknown mailbox: {} {}",
mailbox.path(), mailbox.path(),
@ -621,6 +648,7 @@ pub fn examine_updates(
/* UID SEARCH RECENT */ /* UID SEARCH RECENT */
exit_on_error!( exit_on_error!(
sender, sender,
account_hash,
mailbox_hash, mailbox_hash,
work_context, work_context,
thread_id, thread_id,
@ -637,6 +665,7 @@ pub fn examine_updates(
Ok(v) => { Ok(v) => {
exit_on_error!( exit_on_error!(
sender, sender,
account_hash,
mailbox_hash, mailbox_hash,
work_context, work_context,
thread_id, thread_id,
@ -687,7 +716,8 @@ pub fn examine_updates(
*mailbox.unseen.lock().unwrap() += 1; *mailbox.unseen.lock().unwrap() += 1;
} }
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: mailbox_hash, account_hash,
mailbox_hash,
kind: Create(Box::new(env)), kind: Create(Box::new(env)),
}); });
} }
@ -713,6 +743,7 @@ pub fn examine_updates(
debug!("exists {}", n); debug!("exists {}", n);
exit_on_error!( exit_on_error!(
sender, sender,
account_hash,
mailbox_hash, mailbox_hash,
work_context, work_context,
thread_id, thread_id,
@ -761,7 +792,8 @@ pub fn examine_updates(
*mailbox.unseen.lock().unwrap() += 1; *mailbox.unseen.lock().unwrap() += 1;
} }
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: mailbox_hash, account_hash,
mailbox_hash,
kind: Create(Box::new(env)), kind: Create(Box::new(env)),
}); });
} }

View File

@ -199,6 +199,11 @@ impl MailBackend for MaildirType {
) -> Result<Async<()>> { ) -> Result<Async<()>> {
let w = AsyncBuilder::new(); let w = AsyncBuilder::new();
let cache_dir = xdg::BaseDirectories::with_profile("meli", &self.name).unwrap(); let cache_dir = xdg::BaseDirectories::with_profile("meli", &self.name).unwrap();
let account_hash = {
let mut hasher = DefaultHasher::default();
hasher.write(self.name.as_bytes());
hasher.finish()
};
let handle = { let handle = {
let mailbox: &MaildirMailbox = &self.mailboxes[&mailbox_hash]; let mailbox: &MaildirMailbox = &self.mailboxes[&mailbox_hash];
@ -277,7 +282,8 @@ impl MailBackend for MaildirType {
bincode::serialize_into(writer, &e).unwrap(); bincode::serialize_into(writer, &e).unwrap();
} }
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: mailbox_hash, account_hash,
mailbox_hash,
kind: Create(Box::new(e)), kind: Create(Box::new(e)),
}); });
} else { } else {
@ -290,7 +296,8 @@ impl MailBackend for MaildirType {
} }
} }
for ev in current_hashes.into_iter().map(|h| RefreshEvent { for ev in current_hashes.into_iter().map(|h| RefreshEvent {
hash: mailbox_hash, account_hash,
mailbox_hash,
kind: Remove(h), kind: Remove(h),
}) { }) {
sender.send(ev); sender.send(ev);
@ -299,7 +306,8 @@ impl MailBackend for MaildirType {
}; };
if let Err(err) = thunk(&sender) { if let Err(err) = thunk(&sender) {
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: mailbox_hash, account_hash,
mailbox_hash,
kind: Failure(err), kind: Failure(err),
}); });
} }
@ -314,6 +322,11 @@ impl MailBackend for MaildirType {
) -> Result<std::thread::ThreadId> { ) -> Result<std::thread::ThreadId> {
let (tx, rx) = channel(); let (tx, rx) = channel();
let mut watcher = watcher(tx, Duration::from_secs(2)).unwrap(); let mut watcher = watcher(tx, Duration::from_secs(2)).unwrap();
let account_hash = {
let mut hasher = DefaultHasher::default();
hasher.write(self.name.as_bytes());
hasher.finish()
};
let root_path = self.path.to_path_buf(); let root_path = self.path.to_path_buf();
watcher.watch(&root_path, RecursiveMode::Recursive).unwrap(); watcher.watch(&root_path, RecursiveMode::Recursive).unwrap();
let cache_dir = xdg::BaseDirectories::with_profile("meli", &self.name).unwrap(); let cache_dir = xdg::BaseDirectories::with_profile("meli", &self.name).unwrap();
@ -385,7 +398,8 @@ impl MailBackend for MaildirType {
} }
*mailbox_counts[&mailbox_hash].1.lock().unwrap() += 1; *mailbox_counts[&mailbox_hash].1.lock().unwrap() += 1;
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: mailbox_hash, account_hash,
mailbox_hash,
kind: Create(Box::new(env)), kind: Create(Box::new(env)),
}); });
} }
@ -425,7 +439,8 @@ impl MailBackend for MaildirType {
) { ) {
mailbox_index.lock().unwrap().insert(env.hash(),mailbox_hash); mailbox_index.lock().unwrap().insert(env.hash(),mailbox_hash);
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: mailbox_hash, account_hash,
mailbox_hash,
kind: Create(Box::new(env)), kind: Create(Box::new(env)),
}); });
} }
@ -451,7 +466,8 @@ impl MailBackend for MaildirType {
/* Send Write notice */ /* Send Write notice */
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: mailbox_hash, account_hash,
mailbox_hash,
kind: Update(old_hash, Box::new(env)), kind: Update(old_hash, Box::new(env)),
}); });
} }
@ -500,7 +516,8 @@ impl MailBackend for MaildirType {
}); });
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: mailbox_hash, account_hash,
mailbox_hash,
kind: Remove(hash), kind: Remove(hash),
}); });
} }
@ -530,7 +547,8 @@ impl MailBackend for MaildirType {
e.modified = Some(PathMod::Hash(new_hash)); e.modified = Some(PathMod::Hash(new_hash));
}); });
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: get_path_hash!(dest), account_hash,
mailbox_hash: get_path_hash!(dest),
kind: Rename(old_hash, new_hash), kind: Rename(old_hash, new_hash),
}); });
if !was_seen && is_seen { if !was_seen && is_seen {
@ -588,7 +606,8 @@ impl MailBackend for MaildirType {
} }
*mailbox_counts[&mailbox_hash].1.lock().unwrap() += 1; *mailbox_counts[&mailbox_hash].1.lock().unwrap() += 1;
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: mailbox_hash, account_hash,
mailbox_hash,
kind: Create(Box::new(env)), kind: Create(Box::new(env)),
}); });
continue; continue;
@ -600,7 +619,8 @@ impl MailBackend for MaildirType {
*mailbox_counts[&mailbox_hash].0.lock().unwrap() += 1; *mailbox_counts[&mailbox_hash].0.lock().unwrap() += 1;
} }
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: get_path_hash!(dest), account_hash,
mailbox_hash: get_path_hash!(dest),
kind: Rename(old_hash, new_hash), kind: Rename(old_hash, new_hash),
}); });
debug!("contains_new_key"); debug!("contains_new_key");
@ -608,7 +628,8 @@ impl MailBackend for MaildirType {
/* Maybe a re-read should be triggered here just to be safe. /* Maybe a re-read should be triggered here just to be safe.
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: get_path_hash!(dest), account_hash,
mailbox_hash: get_path_hash!(dest),
kind: Rescan, kind: Rescan,
}); });
*/ */

View File

@ -41,8 +41,9 @@ use memmap::{Mmap, Protection};
use nom::{IResult, Needed}; use nom::{IResult, Needed};
extern crate notify; extern crate notify;
use self::notify::{watcher, DebouncedEvent, RecursiveMode, Watcher}; use self::notify::{watcher, DebouncedEvent, RecursiveMode, Watcher};
use std::collections::HashMap; use std::collections::hash_map::{DefaultHasher, HashMap};
use std::fs::File; use std::fs::File;
use std::hash::Hasher;
use std::io::BufReader; use std::io::BufReader;
use std::io::Read; use std::io::Read;
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
@ -386,6 +387,7 @@ pub fn mbox_parse(
/// Mbox backend /// Mbox backend
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct MboxType { pub struct MboxType {
account_name: String,
path: PathBuf, path: PathBuf,
index: Arc<Mutex<HashMap<EnvelopeHash, (Offset, Length)>>>, index: Arc<Mutex<HashMap<EnvelopeHash, (Offset, Length)>>>,
mailboxes: Arc<Mutex<HashMap<MailboxHash, MboxMailbox>>>, mailboxes: Arc<Mutex<HashMap<MailboxHash, MboxMailbox>>>,
@ -461,13 +463,15 @@ impl MailBackend for MboxType {
.map_err(MeliError::new)?; .map_err(MeliError::new)?;
debug!("watching {:?}", f.path.as_path()); debug!("watching {:?}", f.path.as_path());
} }
let account_hash = {
let mut hasher = DefaultHasher::new();
hasher.write(self.account_name.as_bytes());
hasher.finish()
};
let index = self.index.clone(); let index = self.index.clone();
let mailboxes = self.mailboxes.clone(); let mailboxes = self.mailboxes.clone();
let handle = std::thread::Builder::new() let handle = std::thread::Builder::new()
.name(format!( .name(format!("watching {}", self.account_name,))
"watching {}",
self.path.file_name().unwrap().to_str().unwrap()
))
.spawn(move || { .spawn(move || {
// Move `watcher` in the closure's scope so that it doesn't get dropped. // Move `watcher` in the closure's scope so that it doesn't get dropped.
let _watcher = watcher; let _watcher = watcher;
@ -521,14 +525,16 @@ impl MailBackend for MboxType {
{ {
for env in envelopes { for env in envelopes {
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: mailbox_hash, account_hash,
mailbox_hash,
kind: RefreshEventKind::Create(Box::new(env)), kind: RefreshEventKind::Create(Box::new(env)),
}); });
} }
} }
} else { } else {
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: mailbox_hash, account_hash,
mailbox_hash,
kind: RefreshEventKind::Rescan, kind: RefreshEventKind::Rescan,
}); });
} }
@ -547,7 +553,8 @@ impl MailBackend for MboxType {
{ {
let mailbox_hash = get_path_hash!(&pathbuf); let mailbox_hash = get_path_hash!(&pathbuf);
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: mailbox_hash, account_hash,
mailbox_hash,
kind: RefreshEventKind::Failure(MeliError::new(format!( kind: RefreshEventKind::Failure(MeliError::new(format!(
"mbox mailbox {} was removed.", "mbox mailbox {} was removed.",
pathbuf.display() pathbuf.display()
@ -560,7 +567,8 @@ impl MailBackend for MboxType {
if mailboxes.lock().unwrap().values().any(|f| &f.path == &src) { if mailboxes.lock().unwrap().values().any(|f| &f.path == &src) {
let mailbox_hash = get_path_hash!(&src); let mailbox_hash = get_path_hash!(&src);
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: mailbox_hash, account_hash,
mailbox_hash,
kind: RefreshEventKind::Failure(MeliError::new(format!( kind: RefreshEventKind::Failure(MeliError::new(format!(
"mbox mailbox {} was renamed to {}.", "mbox mailbox {} was renamed to {}.",
src.display(), src.display(),
@ -572,9 +580,10 @@ impl MailBackend for MboxType {
} }
/* Trigger rescan of mailboxes */ /* Trigger rescan of mailboxes */
DebouncedEvent::Rescan => { DebouncedEvent::Rescan => {
for h in mailboxes.lock().unwrap().keys() { for &mailbox_hash in mailboxes.lock().unwrap().keys() {
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: *h, account_hash,
mailbox_hash,
kind: RefreshEventKind::Rescan, kind: RefreshEventKind::Rescan,
}); });
} }
@ -628,6 +637,7 @@ impl MboxType {
))); )));
} }
let ret = MboxType { let ret = MboxType {
account_name: s.name().to_string(),
path, path,
..Default::default() ..Default::default()
}; };

View File

@ -109,6 +109,7 @@ pub struct NotmuchDb {
index: Arc<RwLock<HashMap<EnvelopeHash, CString>>>, index: Arc<RwLock<HashMap<EnvelopeHash, CString>>>,
tag_index: Arc<RwLock<BTreeMap<u64, String>>>, tag_index: Arc<RwLock<BTreeMap<u64, String>>>,
path: PathBuf, path: PathBuf,
account_name: String,
save_messages_to: Option<PathBuf>, save_messages_to: Option<PathBuf>,
} }
@ -238,6 +239,7 @@ impl NotmuchDb {
mailboxes: Arc::new(RwLock::new(mailboxes)), mailboxes: Arc::new(RwLock::new(mailboxes)),
save_messages_to: None, save_messages_to: None,
account_name: s.name().to_string(),
})) }))
} }
@ -435,6 +437,11 @@ impl MailBackend for NotmuchDb {
watcher.watch(&self.path, RecursiveMode::Recursive).unwrap(); watcher.watch(&self.path, RecursiveMode::Recursive).unwrap();
let path = self.path.clone(); let path = self.path.clone();
let lib = self.lib.clone(); let lib = self.lib.clone();
let account_hash = {
let mut hasher = DefaultHasher::new();
hasher.write(self.account_name.as_bytes());
hasher.finish()
};
{ {
let database = NotmuchDb::new_connection(path.as_path(), lib.clone(), false)?; let database = NotmuchDb::new_connection(path.as_path(), lib.clone(), false)?;
let mut revision_uuid_lck = self.revision_uuid.write().unwrap(); let mut revision_uuid_lck = self.revision_uuid.write().unwrap();
@ -450,10 +457,7 @@ impl MailBackend for NotmuchDb {
let revision_uuid = self.revision_uuid.clone(); let revision_uuid = self.revision_uuid.clone();
let handle = std::thread::Builder::new() let handle = std::thread::Builder::new()
.name(format!( .name(format!("watching {}", self.account_name))
"watching {}",
self.path.file_name().unwrap().to_str().unwrap()
))
.spawn(move || { .spawn(move || {
let _watcher = watcher; let _watcher = watcher;
let c = move || -> std::result::Result<(), MeliError> { let c = move || -> std::result::Result<(), MeliError> {
@ -484,7 +488,8 @@ impl MailBackend for NotmuchDb {
if let Err(err) = c() { if let Err(err) = c() {
sender.send(RefreshEvent { sender.send(RefreshEvent {
hash: 0, account_hash,
mailbox_hash: 0,
kind: Failure(err.into()), kind: Failure(err.into()),
}); });
} }

View File

@ -30,7 +30,7 @@ Input is received in the main loop from threads which listen on the stdin for us
use super::*; use super::*;
use crate::plugins::PluginManager; use crate::plugins::PluginManager;
use melib::backends::{MailboxHash, NotifyFn}; use melib::backends::{AccountHash, MailboxHash, NotifyFn};
use crossbeam::channel::{unbounded, Receiver, Sender}; use crossbeam::channel::{unbounded, Receiver, Sender};
use smallvec::SmallVec; use smallvec::SmallVec;
@ -89,7 +89,7 @@ impl InputHandler {
/// A context container for loaded settings, accounts, UI changes, etc. /// A context container for loaded settings, accounts, UI changes, etc.
pub struct Context { pub struct Context {
pub accounts: Vec<Account>, pub accounts: Vec<Account>,
pub mailbox_hashes: HashMap<MailboxHash, usize>, pub account_hashes: HashMap<AccountHash, usize>,
pub settings: Settings, pub settings: Settings,
pub runtime_settings: Settings, pub runtime_settings: Settings,
@ -132,7 +132,6 @@ impl Context {
pub fn is_online(&mut self, account_pos: usize) -> Result<()> { pub fn is_online(&mut self, account_pos: usize) -> Result<()> {
let Context { let Context {
ref mut accounts, ref mut accounts,
ref mut mailbox_hashes,
ref mut replies, ref mut replies,
.. ..
} = self; } = self;
@ -146,7 +145,6 @@ impl Context {
mailbox_node.hash, mailbox_node.hash,
accounts[account_pos][&mailbox_node.hash].name() accounts[account_pos][&mailbox_node.hash].name()
); );
mailbox_hashes.insert(mailbox_node.hash, account_pos);
} }
/* Account::watch() needs /* Account::watch() needs
* - work_controller to pass `work_context` to the watcher threads and then add them * - work_controller to pass `work_context` to the watcher threads and then add them
@ -246,6 +244,7 @@ impl State {
let cols = termsize.0 as usize; let cols = termsize.0 as usize;
let rows = termsize.1 as usize; let rows = termsize.1 as usize;
let mut account_hashes = HashMap::with_capacity_and_hasher(1, Default::default());
let work_controller = WorkController::new(sender.clone()); let work_controller = WorkController::new(sender.clone());
let accounts: Vec<Account> = { let accounts: Vec<Account> = {
let mut file_accs = settings let mut file_accs = settings
@ -259,6 +258,14 @@ impl State {
.enumerate() .enumerate()
.map(|(index, (n, a_s))| { .map(|(index, (n, a_s))| {
let sender = sender.clone(); let sender = sender.clone();
let account_hash = {
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
let mut hasher = DefaultHasher::new();
hasher.write(n.as_bytes());
hasher.finish()
};
account_hashes.insert(account_hash, index);
Account::new( Account::new(
index, index,
n.to_string(), n.to_string(),
@ -268,7 +275,10 @@ impl State {
sender.clone(), sender.clone(),
NotifyFn::new(Box::new(move |f: MailboxHash| { NotifyFn::new(Box::new(move |f: MailboxHash| {
sender sender
.send(ThreadEvent::UIEvent(UIEvent::WorkerProgress(f))) .send(ThreadEvent::UIEvent(UIEvent::WorkerProgress(
account_hash,
f,
)))
.unwrap(); .unwrap();
})), })),
) )
@ -315,8 +325,7 @@ impl State {
context: Context { context: Context {
accounts, accounts,
mailbox_hashes: HashMap::with_capacity_and_hasher(1, Default::default()), account_hashes,
settings: settings.clone(), settings: settings.clone(),
runtime_settings: settings, runtime_settings: settings,
dirty_areas: VecDeque::with_capacity(5), dirty_areas: VecDeque::with_capacity(5),
@ -362,25 +371,31 @@ impl State {
* and startup a thread to remind us to poll it every now and then till it's finished. * and startup a thread to remind us to poll it every now and then till it's finished.
*/ */
pub fn refresh_event(&mut self, event: RefreshEvent) { pub fn refresh_event(&mut self, event: RefreshEvent) {
let hash = event.hash(); let account_hash = event.account_hash();
if let Some(&idxa) = self.context.mailbox_hashes.get(&hash) { let mailbox_hash = event.mailbox_hash();
if self.context.accounts[idxa].load(hash).is_err() { if let Some(&idxa) = self.context.account_hashes.get(&account_hash) {
self.context.replies.push_back(UIEvent::from(event)); if self.context.accounts[idxa]
return; .mailbox_entries
} .contains_key(&mailbox_hash)
let Context { {
ref mut accounts, .. if self.context.accounts[idxa].load(mailbox_hash).is_err() {
} = &mut self.context; self.context.replies.push_back(UIEvent::from(event));
return;
if let Some(notification) = accounts[idxa].reload(event, hash) { }
if let UIEvent::Notification(_, _, _) = notification { let Context {
self.rcv_event(UIEvent::MailboxUpdate((idxa, hash))); ref mut accounts, ..
} = &mut self.context;
if let Some(notification) = accounts[idxa].reload(event, mailbox_hash) {
if let UIEvent::Notification(_, _, _) = notification {
self.rcv_event(UIEvent::MailboxUpdate((idxa, mailbox_hash)));
}
self.rcv_event(notification);
}
} else {
if let melib::backends::RefreshEventKind::Failure(err) = event.kind() {
debug!(err);
} }
self.rcv_event(notification);
}
} else {
if let melib::backends::RefreshEventKind::Failure(err) = event.kind() {
debug!(err);
} }
} }
} }
@ -915,8 +930,8 @@ impl State {
self.child = Some(child); self.child = Some(child);
return; return;
} }
UIEvent::WorkerProgress(mailbox_hash) => { UIEvent::WorkerProgress(account_hash, mailbox_hash) => {
if let Some(&account_idx) = self.context.mailbox_hashes.get(&mailbox_hash) { if let Some(&account_idx) = self.context.account_hashes.get(&account_hash) {
let _ = self.context.accounts[account_idx].load(mailbox_hash); let _ = self.context.accounts[account_idx].load(mailbox_hash);
} }
return; return;

View File

@ -38,7 +38,7 @@ pub use self::helpers::*;
use super::execute::Action; use super::execute::Action;
use super::terminal::*; use super::terminal::*;
use melib::backends::MailboxHash; use melib::backends::{AccountHash, MailboxHash};
use melib::{EnvelopeHash, RefreshEvent}; use melib::{EnvelopeHash, RefreshEvent};
use nix::unistd::Pid; use nix::unistd::Pid;
use std; use std;
@ -115,7 +115,7 @@ pub enum UIEvent {
MailboxCreate((usize, MailboxHash)), MailboxCreate((usize, MailboxHash)),
AccountStatusChange(usize), AccountStatusChange(usize),
ComponentKill(Uuid), ComponentKill(Uuid),
WorkerProgress(MailboxHash), WorkerProgress(AccountHash, MailboxHash),
StartupCheck(MailboxHash), StartupCheck(MailboxHash),
RefreshEvent(Box<RefreshEvent>), RefreshEvent(Box<RefreshEvent>),
EnvelopeUpdate(EnvelopeHash), EnvelopeUpdate(EnvelopeHash),