melib/MailBackend: add MailBackendCapabilities struct
parent
4aaa784d8f
commit
3f8aa560f0
|
@ -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."))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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<()> {
|
||||||
|
|
|
@ -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<()> {
|
||||||
|
|
|
@ -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<()> {
|
||||||
|
|
|
@ -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<()> {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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<()> {
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
Loading…
Reference in New Issue