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 trait MailBackend: ::std::fmt::Debug + Send + Sync {
fn is_async(&self) -> bool;
fn is_remote(&self) -> bool;
fn supports_search(&self) -> bool;
fn capabilities(&self) -> MailBackendCapabilities;
fn is_online(&self) -> Result<()> {
Err(MeliError::new("Unimplemented."))
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -375,7 +375,7 @@ impl State {
s.switch_to_alternate_screen();
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();
}
if s.context.is_online(i).is_ok() && s.context.accounts[i].is_empty() {