melib/MailBackend: add MailBackendCapabilities struct

memfd
Manos Pitsidianakis 2020-07-25 17:53:04 +03:00
parent 4aaa784d8f
commit 3f8aa560f0
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
10 changed files with 82 additions and 107 deletions

View File

@ -282,12 +282,18 @@ impl NotifyFn {
} }
} }
#[derive(Debug, Copy, Clone)]
pub struct MailBackendCapabilities {
pub is_async: bool,
pub is_remote: bool,
pub supports_search: bool,
pub supports_tags: bool,
}
pub type ResultFuture<T> = Result<Pin<Box<dyn Future<Output = Result<T>> + Send + 'static>>>; pub type ResultFuture<T> = Result<Pin<Box<dyn Future<Output = Result<T>> + Send + 'static>>>;
pub trait MailBackend: ::std::fmt::Debug + Send + Sync { pub trait MailBackend: ::std::fmt::Debug + Send + Sync {
fn is_async(&self) -> bool; fn capabilities(&self) -> MailBackendCapabilities;
fn is_remote(&self) -> bool;
fn supports_search(&self) -> bool;
fn is_online(&self) -> Result<()> { fn is_online(&self) -> Result<()> {
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
} }

View File

@ -186,15 +186,14 @@ pub struct ImapType {
} }
impl MailBackend for ImapType { impl MailBackend for ImapType {
fn is_async(&self) -> bool { fn capabilities(&self) -> MailBackendCapabilities {
true const CAPABILITIES: MailBackendCapabilities = MailBackendCapabilities {
} is_async: true,
fn is_remote(&self) -> bool { is_remote: true,
true supports_search: true,
} supports_tags: true,
};
fn supports_search(&self) -> bool { CAPABILITIES
true
} }
fn fetch_async( fn fetch_async(

View File

@ -190,16 +190,14 @@ pub struct JmapType {
} }
impl MailBackend for JmapType { impl MailBackend for JmapType {
fn is_async(&self) -> bool { fn capabilities(&self) -> MailBackendCapabilities {
false const CAPABILITIES: MailBackendCapabilities = MailBackendCapabilities {
} is_async: false,
is_remote: true,
fn is_remote(&self) -> bool { supports_search: true,
true supports_tags: true,
} };
CAPABILITIES
fn supports_search(&self) -> bool {
true
} }
fn is_online(&self) -> Result<()> { fn is_online(&self) -> Result<()> {

View File

@ -175,16 +175,14 @@ pub fn move_to_cur(p: PathBuf) -> Result<PathBuf> {
} }
impl MailBackend for MaildirType { impl MailBackend for MaildirType {
fn is_async(&self) -> bool { fn capabilities(&self) -> MailBackendCapabilities {
false const CAPABILITIES: MailBackendCapabilities = MailBackendCapabilities {
} is_async: false,
is_remote: false,
fn is_remote(&self) -> bool { supports_search: false,
false supports_tags: false,
} };
CAPABILITIES
fn supports_search(&self) -> bool {
false
} }
fn is_online(&self) -> Result<()> { fn is_online(&self) -> Result<()> {

View File

@ -694,16 +694,14 @@ pub struct MboxType {
} }
impl MailBackend for MboxType { impl MailBackend for MboxType {
fn is_async(&self) -> bool { fn capabilities(&self) -> MailBackendCapabilities {
false const CAPABILITIES: MailBackendCapabilities = MailBackendCapabilities {
} is_async: false,
is_remote: false,
fn is_remote(&self) -> bool { supports_search: false,
false supports_tags: false,
} };
CAPABILITIES
fn supports_search(&self) -> bool {
false
} }
fn is_online(&self) -> Result<()> { fn is_online(&self) -> Result<()> {

View File

@ -318,16 +318,14 @@ impl NotmuchDb {
} }
impl MailBackend for NotmuchDb { impl MailBackend for NotmuchDb {
fn is_async(&self) -> bool { fn capabilities(&self) -> MailBackendCapabilities {
false const CAPABILITIES: MailBackendCapabilities = MailBackendCapabilities {
} is_async: false,
is_remote: false,
fn is_remote(&self) -> bool { supports_search: true,
false supports_tags: true,
} };
CAPABILITIES
fn supports_search(&self) -> bool {
true
} }
fn is_online(&self) -> Result<()> { fn is_online(&self) -> Result<()> {

View File

@ -436,7 +436,7 @@ impl Component for AccountStatus {
None, None,
); );
write_string_to_grid( write_string_to_grid(
if backend_lck.tags().is_some() { if a.backend_capabilities.supports_tags {
"yes" "yes"
} else { } else {
"no" "no"
@ -459,31 +459,20 @@ impl Component for AccountStatus {
None, None,
); );
write_string_to_grid( write_string_to_grid(
&if a.settings.account().format() == "imap" &match (
&& *a.settings.conf.search_backend() == SearchBackend::None a.settings.conf.search_backend(),
{ a.backend_capabilities.supports_search,
"server-side search".to_string() ) {
} else if a.settings.account().format() == "notmuch" (SearchBackend::None, true) => "backend-side search".to_string(),
&& *a.settings.conf.search_backend() == SearchBackend::None (SearchBackend::None, false) => "none (search will be slow)".to_string(),
{
"notmuch database".to_string()
} else {
#[cfg(feature = "sqlite3")] #[cfg(feature = "sqlite3")]
{ (SearchBackend::Sqlite3, _) => {
if *a.settings.conf.search_backend() == SearchBackend::Sqlite3 { if let Ok(path) = crate::sqlite3::db_path() {
if let Ok(path) = crate::sqlite3::db_path() { format!("sqlite3 database {}", path.display())
format!("sqlite3 database {}", path.display())
} else {
"sqlite3 database".to_string()
}
} else { } else {
"none (search will be slow)".to_string() "sqlite3 database".to_string()
} }
} }
#[cfg(not(feature = "sqlite3"))]
{
"none (search will be slow)".to_string()
}
}, },
&mut self.content, &mut self.content,
self.theme_default.fg, self.theme_default.fg,

View File

@ -26,11 +26,7 @@
use super::{AccountConf, FileMailboxConf}; use super::{AccountConf, FileMailboxConf};
use crate::jobs::{JobChannel, JobExecutor, JobId, JoinHandle}; use crate::jobs::{JobChannel, JobExecutor, JobId, JoinHandle};
use melib::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext}; use melib::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext};
use melib::backends::{ use melib::backends::*;
AccountHash, BackendOp, Backends, EnvelopeHashBatch, MailBackend, Mailbox, MailboxHash,
NotifyFn, ReadOnlyOp, RefreshEvent, RefreshEventConsumer, RefreshEventKind, ResultFuture,
SpecialUsageMailbox,
};
use melib::email::*; use melib::email::*;
use melib::error::{MeliError, Result}; use melib::error::{MeliError, Result};
use melib::text_processing::GlobMatch; use melib::text_processing::GlobMatch;
@ -160,8 +156,7 @@ pub struct Account {
sender: Sender<ThreadEvent>, sender: Sender<ThreadEvent>,
event_queue: VecDeque<(MailboxHash, RefreshEvent)>, event_queue: VecDeque<(MailboxHash, RefreshEvent)>,
notify_fn: Arc<NotifyFn>, notify_fn: Arc<NotifyFn>,
pub is_async: bool, pub backend_capabilities: MailBackendCapabilities,
pub is_remote: bool,
} }
pub enum JobRequest { pub enum JobRequest {
@ -366,7 +361,7 @@ impl Account {
let mut active_jobs = HashMap::default(); let mut active_jobs = HashMap::default();
let mut active_job_instants = BTreeMap::default(); let mut active_job_instants = BTreeMap::default();
if backend.is_async() { if backend.capabilities().is_async {
if let Ok(mailboxes_job) = backend.mailboxes_async() { if let Ok(mailboxes_job) = backend.mailboxes_async() {
if let Ok(online_job) = backend.is_online_async() { if let Ok(online_job) = backend.is_online_async() {
let (rcvr, handle, job_id) = let (rcvr, handle, job_id) =
@ -380,7 +375,7 @@ impl Account {
index, index,
hash, hash,
name, name,
is_online: if !backend.is_remote() { is_online: if !backend.capabilities().is_remote {
Ok(()) Ok(())
} else { } else {
Err(MeliError::new("Attempting connection.")) Err(MeliError::new("Attempting connection."))
@ -399,12 +394,11 @@ impl Account {
active_jobs, active_jobs,
active_job_instants, active_job_instants,
event_queue: VecDeque::with_capacity(8), event_queue: VecDeque::with_capacity(8),
is_async: backend.is_async(), backend_capabilities: backend.capabilities(),
is_remote: backend.is_remote(),
backend: Arc::new(RwLock::new(backend)), backend: Arc::new(RwLock::new(backend)),
}; };
if !ret.is_remote && !ret.is_async { if !ret.backend_capabilities.is_remote && !ret.backend_capabilities.is_async {
ret.init(None)?; ret.init(None)?;
} }
@ -543,7 +537,7 @@ impl Account {
|| entry.ref_mailbox.special_usage() == SpecialUsageMailbox::Inbox || entry.ref_mailbox.special_usage() == SpecialUsageMailbox::Inbox
{ {
entry.status = MailboxStatus::Parsing(0, 0); entry.status = MailboxStatus::Parsing(0, 0);
if self.is_async { if self.backend_capabilities.is_async {
if let Ok(mailbox_job) = self.backend.write().unwrap().fetch_async(*h) { if let Ok(mailbox_job) = self.backend.write().unwrap().fetch_async(*h) {
let mailbox_job = mailbox_job.into_future(); let mailbox_job = mailbox_job.into_future();
let (rcvr, handle, job_id) = let (rcvr, handle, job_id) =
@ -916,7 +910,7 @@ impl Account {
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();
})); }));
if self.is_async { if self.backend_capabilities.is_async {
if let Ok(refresh_job) = self.backend.write().unwrap().refresh_async(mailbox_hash, r) { if let Ok(refresh_job) = self.backend.write().unwrap().refresh_async(mailbox_hash, r) {
let (rcvr, handle, job_id) = self.job_executor.spawn_specialized(refresh_job); let (rcvr, handle, job_id) = self.job_executor.spawn_specialized(refresh_job);
self.sender self.sender
@ -944,7 +938,7 @@ impl Account {
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();
})); }));
if self.is_async { if self.backend_capabilities.is_async {
if !self.active_jobs.values().any(|j| j.is_watch()) { if !self.active_jobs.values().any(|j| j.is_watch()) {
match self.backend.read().unwrap().watch_async(r) { match self.backend.read().unwrap().watch_async(r) {
Ok(fut) => { Ok(fut) => {
@ -1044,7 +1038,7 @@ impl Account {
Ok(()) Ok(())
} }
MailboxStatus::None => { MailboxStatus::None => {
if self.is_async { if self.backend_capabilities.is_async {
if !self.active_jobs.values().any(|j| j.is_fetch(mailbox_hash)) { if !self.active_jobs.values().any(|j| j.is_fetch(mailbox_hash)) {
let mailbox_job = let mailbox_job =
self.backend.write().unwrap().fetch_async(mailbox_hash); self.backend.write().unwrap().fetch_async(mailbox_hash);
@ -1572,11 +1566,11 @@ impl Account {
/* Call only in Context::is_online, since only Context can launch the watcher threads if an /* Call only in Context::is_online, since only Context can launch the watcher threads if an
* account goes from offline to online. */ * account goes from offline to online. */
pub fn is_online(&mut self) -> Result<()> { pub fn is_online(&mut self) -> Result<()> {
if !self.is_remote && !self.is_async { if !self.backend_capabilities.is_remote && !self.backend_capabilities.is_async {
return Ok(()); return Ok(());
} }
if self.is_async { if self.backend_capabilities.is_async {
if self.is_online.is_ok() { if self.is_online.is_ok() {
return Ok(()); return Ok(());
} }
@ -1617,7 +1611,7 @@ impl Account {
#[cfg(feature = "sqlite3")] #[cfg(feature = "sqlite3")]
crate::conf::SearchBackend::Sqlite3 => crate::sqlite3::search(search_term, _sort), crate::conf::SearchBackend::Sqlite3 => crate::sqlite3::search(search_term, _sort),
crate::conf::SearchBackend::None => { crate::conf::SearchBackend::None => {
if self.backend.read().unwrap().supports_search() { if self.backend_capabilities.supports_search {
self.backend self.backend
.read() .read()
.unwrap() .unwrap()

View File

@ -65,19 +65,14 @@ impl Drop for PluginBackend {
} }
impl MailBackend for PluginBackend { impl MailBackend for PluginBackend {
fn is_async(&self) -> bool { fn capabilities(&self) -> MailBackendCapabilities {
// TODO const CAPABILITIES: MailBackendCapabilities = MailBackendCapabilities {
false is_async: false,
} is_remote: false,
supports_search: false,
fn is_remote(&self) -> bool { supports_tags: false,
// TODO };
false CAPABILITIES
}
fn supports_search(&self) -> bool {
// TODO
false
} }
fn is_online(&self) -> Result<()> { fn is_online(&self) -> Result<()> {

View File

@ -375,7 +375,7 @@ impl State {
s.switch_to_alternate_screen(); s.switch_to_alternate_screen();
for i in 0..s.context.accounts.len() { for i in 0..s.context.accounts.len() {
if !s.context.accounts[i].is_remote { if !s.context.accounts[i].backend_capabilities.is_remote {
s.context.accounts[i].watch(); s.context.accounts[i].watch();
} }
if s.context.is_online(i).is_ok() && s.context.accounts[i].is_empty() { if s.context.is_online(i).is_ok() && s.context.accounts[i].is_empty() {