parent
b2c7430907
commit
710920c67b
|
@ -29,6 +29,12 @@ use mailbox::backends::{Backends, RefreshEventConsumer};
|
|||
use mailbox::*;
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::result;
|
||||
use std::mem;
|
||||
|
||||
pub struct NewMailEvent {
|
||||
pub folder: u64,
|
||||
pub index: Vec<usize>,
|
||||
}
|
||||
|
||||
pub type Worker = Option<Async<Result<Vec<Envelope>>>>;
|
||||
|
||||
|
@ -93,13 +99,32 @@ impl Account {
|
|||
pub fn workers(&mut self) -> &mut Vec<Worker> {
|
||||
&mut self.workers
|
||||
}
|
||||
fn load_mailbox(&mut self, index: usize, envelopes: Result<Vec<Envelope>>) -> () {
|
||||
fn load_mailbox(&mut self, index: usize, envelopes: Result<Vec<Envelope>>) -> Option<NewMailEvent> {
|
||||
let mut ret: Option<NewMailEvent> = None;
|
||||
|
||||
// TODO: Cleanup this function
|
||||
let folders = self.backend.folders();
|
||||
let folder = &folders[index];
|
||||
if self.sent_folder.is_some() {
|
||||
let id = self.sent_folder.unwrap();
|
||||
if id == index {
|
||||
self.folders[index] = Some(Mailbox::new(folder, &None, envelopes));
|
||||
/* ======================== */
|
||||
let old_m = mem::replace(&mut self.folders[index], Some(Mailbox::new(folder, &None, envelopes)));
|
||||
if let Some(old_m) = old_m {
|
||||
if self.folders[index].is_some() && old_m.is_ok() {
|
||||
let diff = self.folders[index].as_ref().map(|v| v.as_ref().unwrap().collection.len()).unwrap_or(0).saturating_sub(old_m.as_ref().map(|v| v.collection.len()).unwrap_or(0));
|
||||
if diff > 0 {
|
||||
let mut index = old_m.as_ref().unwrap().collection.iter().zip(&self.folders[index].as_ref().unwrap().as_ref().unwrap().collection).count();
|
||||
ret = Some(NewMailEvent {
|
||||
folder: folder.hash(),
|
||||
index: (index.saturating_sub(1)..(self.folders[index].as_ref().unwrap().as_ref().unwrap().collection.len().saturating_sub(1))).collect(),
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
/* ======================== */
|
||||
} else {
|
||||
let (sent, cur) = {
|
||||
let ptr = self.folders.as_mut_ptr();
|
||||
|
@ -115,17 +140,51 @@ impl Account {
|
|||
if sent[0].is_none() {
|
||||
sent[0] = Some(Mailbox::new(sent_path, &None, envelopes.clone()));
|
||||
}
|
||||
cur[0] = Some(Mailbox::new(folder, &sent[0], envelopes));
|
||||
/* ======================== */
|
||||
let old_m = mem::replace(&mut cur[0], Some(Mailbox::new(folder, &sent[0], envelopes)));
|
||||
if let Some(old_m) = old_m {
|
||||
if cur[0].is_some() && old_m.is_ok() {
|
||||
let diff = cur[0].as_ref().map(|v| v.as_ref().unwrap().collection.len()).unwrap_or(0).saturating_sub(old_m.as_ref().map(|v| v.collection.len()).unwrap_or(0));
|
||||
if diff > 0 {
|
||||
let mut index = old_m.as_ref().unwrap().collection.iter().zip(&cur[0].as_ref().unwrap().as_ref().unwrap().collection).count();
|
||||
ret = Some(NewMailEvent {
|
||||
folder: folder.hash(),
|
||||
index: (index.saturating_sub(1)..(cur[0].as_ref().unwrap().as_ref().unwrap().collection.len()).saturating_sub(1)).collect(),
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
/* ======================== */
|
||||
}
|
||||
} else {
|
||||
self.folders[index] = Some(Mailbox::new(folder, &None, envelopes));
|
||||
/* ======================== */
|
||||
let old_m = mem::replace(&mut self.folders[index], Some(Mailbox::new(folder, &None, envelopes)));
|
||||
if let Some(old_m) = old_m {
|
||||
if self.folders[index].is_some() && old_m.is_ok() {
|
||||
let diff = self.folders[index].as_ref().map(|v| v.as_ref().unwrap().collection.len()).unwrap_or(0).saturating_sub(old_m.as_ref().map(|v| v.collection.len()).unwrap_or(0));
|
||||
if diff > 0 {
|
||||
let mut index = old_m.as_ref().unwrap().collection.iter().zip(&self.folders[index].as_ref().unwrap().as_ref().unwrap().collection).count();
|
||||
ret = Some(NewMailEvent {
|
||||
folder: folder.hash(),
|
||||
index: (index.saturating_sub(1)..(self.folders[index].as_ref().unwrap().as_ref().unwrap().collection.len().saturating_sub(1))).collect(),
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
/* ======================== */
|
||||
};
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
pub fn status(&mut self, index: usize) -> result::Result<bool, usize> {
|
||||
pub fn status(&mut self, index: usize) -> result::Result<Option<NewMailEvent>, usize> {
|
||||
match self.workers[index].as_mut() {
|
||||
None => {
|
||||
return Ok(false);
|
||||
return Ok(None);
|
||||
}
|
||||
Some(ref mut w) => match w.poll() {
|
||||
Ok(AsyncStatus::NoUpdate) => {
|
||||
|
@ -142,9 +201,8 @@ impl Account {
|
|||
},
|
||||
};
|
||||
let m = self.workers[index].take().unwrap().extract();
|
||||
self.load_mailbox(index, m);
|
||||
self.workers[index] = None;
|
||||
Ok(true)
|
||||
Ok(self.load_mailbox(index, m))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ use std::fs;
|
|||
use std::io;
|
||||
use std::io::Read;
|
||||
use std::sync::{Mutex, Arc};
|
||||
use std::hash::Hasher;
|
||||
use std::hash::{Hasher, Hash};
|
||||
use std::path::{Path, PathBuf};
|
||||
extern crate fnv;
|
||||
use self::fnv::FnvHashMap;
|
||||
|
@ -213,21 +213,20 @@ impl MailBackend for MaildirType {
|
|||
Ok(event) => match event {
|
||||
DebouncedEvent::Create(mut pathbuf)
|
||||
| DebouncedEvent::Remove(mut pathbuf) => {
|
||||
let path = if pathbuf.is_dir() {
|
||||
if pathbuf.is_dir() {
|
||||
if pathbuf.ends_with("cur") | pathbuf.ends_with("new") {
|
||||
pathbuf.pop();
|
||||
}
|
||||
pathbuf.to_str().unwrap()
|
||||
} else {
|
||||
pathbuf.pop();
|
||||
pathbuf.parent().unwrap().to_str().unwrap()
|
||||
pathbuf.pop();
|
||||
};
|
||||
eprintln!(" got event in {}", path);
|
||||
eprintln!(" got event in {}", pathbuf.display());
|
||||
|
||||
let mut hasher = DefaultHasher::new();
|
||||
hasher.write(path.as_bytes());
|
||||
pathbuf.hash(&mut hasher);
|
||||
sender.send(RefreshEvent {
|
||||
folder: format!("{}", path),
|
||||
folder: format!("{}", pathbuf.display()),
|
||||
hash: hasher.finish(),
|
||||
});
|
||||
}
|
||||
|
@ -306,16 +305,15 @@ impl MaildirType {
|
|||
let tx = w.tx();
|
||||
// TODO: Avoid clone
|
||||
let folder: &MaildirFolder = &self.folders[self.owned_folder_idx(folder)];
|
||||
let path = folder.path().to_string();
|
||||
let mut path: PathBuf = folder.path().into();
|
||||
let name = format!("parsing {:?}", folder.name());
|
||||
let map = self.hash_index.clone();
|
||||
let map2 = self.hash_index.clone();
|
||||
|
||||
thread::Builder::new()
|
||||
.name(name)
|
||||
.name(name.clone())
|
||||
.spawn(move || {
|
||||
let cache_dir = cache_dir.clone();
|
||||
let mut path = PathBuf::from(path);
|
||||
path.push("cur");
|
||||
let iter = path.read_dir()?;
|
||||
let count = path.read_dir()?.count();
|
||||
|
@ -341,7 +339,7 @@ impl MaildirType {
|
|||
let cache_dir = cache_dir.clone();
|
||||
let mut tx = tx.clone();
|
||||
let map = map.clone();
|
||||
let s = scope.spawn(move || {
|
||||
let s = scope.builder().name(name.clone()).spawn(move || {
|
||||
let len = chunk.len();
|
||||
let size = if len <= 100 { 100 } else { (len / 100) * 100 };
|
||||
let mut local_r: Vec<Envelope> = Vec::with_capacity(chunk.len());
|
||||
|
@ -419,7 +417,7 @@ impl MaildirType {
|
|||
}
|
||||
local_r
|
||||
});
|
||||
threads.push(s);
|
||||
threads.push(s.unwrap());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -447,26 +445,27 @@ impl MaildirType {
|
|||
pub struct MaildirFolder {
|
||||
hash: u64,
|
||||
name: String,
|
||||
path: String,
|
||||
path: PathBuf,
|
||||
children: Vec<usize>,
|
||||
}
|
||||
|
||||
impl MaildirFolder {
|
||||
pub fn new(path: String, file_name: String, children: Vec<usize>) -> Result<Self> {
|
||||
let pathbuf = PathBuf::from(path);
|
||||
let mut h = DefaultHasher::new();
|
||||
h.write(&path.as_bytes());
|
||||
pathbuf.hash(&mut h);
|
||||
|
||||
let ret = MaildirFolder {
|
||||
hash: h.finish(),
|
||||
name: file_name,
|
||||
path: path,
|
||||
path: pathbuf,
|
||||
children: children,
|
||||
};
|
||||
ret.is_valid()?;
|
||||
Ok(ret)
|
||||
}
|
||||
pub fn path(&self) -> &str {
|
||||
&self.path
|
||||
pub fn path(&self) -> &Path {
|
||||
self.path.as_path()
|
||||
}
|
||||
fn is_valid(&self) -> Result<()> {
|
||||
let path = self.path();
|
||||
|
@ -476,7 +475,7 @@ impl MaildirFolder {
|
|||
if !p.is_dir() {
|
||||
return Err(MeliError::new(format!(
|
||||
"{} is not a valid maildir folder",
|
||||
path
|
||||
path.display()
|
||||
)));
|
||||
}
|
||||
p.pop();
|
||||
|
|
11
src/bin.rs
11
src/bin.rs
|
@ -66,7 +66,7 @@ fn main() {
|
|||
let menu = Entity {
|
||||
component: Box::new(AccountMenu::new(&state.context.accounts)),
|
||||
};
|
||||
let listing = CompactListing::new();
|
||||
let listing = MailListing::new();
|
||||
let b = Entity {
|
||||
component: Box::new(listing),
|
||||
};
|
||||
|
@ -150,7 +150,6 @@ fn main() {
|
|||
},
|
||||
ThreadEvent::RefreshMailbox { hash : h } => {
|
||||
state.hash_to_folder(h);
|
||||
state.rcv_event(UIEvent { id: 0, event_type: UIEventType::Notification(String::from("Update in mailbox"))});
|
||||
state.redraw();
|
||||
},
|
||||
ThreadEvent::UIEvent(UIEventType::ChangeMode(f)) => {
|
||||
|
@ -160,10 +159,10 @@ fn main() {
|
|||
ThreadEvent::UIEvent(UIEventType::StartupCheck) => {
|
||||
let mut flag = false;
|
||||
let mut render_flag = false;
|
||||
for account in &mut state.context.accounts {
|
||||
let len = account.len();
|
||||
for i in 0..len {
|
||||
match account.status(i) {
|
||||
for idx_a in 0..state.context.accounts.len() {
|
||||
let len = state.context.accounts[idx_a].len();
|
||||
for idx_m in 0..len {
|
||||
match state.context.account_status(idx_a, idx_m) {
|
||||
Ok(true) => {
|
||||
render_flag = true;
|
||||
},
|
||||
|
|
|
@ -33,6 +33,7 @@ use chan::{Receiver, Sender};
|
|||
use fnv::FnvHashMap;
|
||||
use std::io::Write;
|
||||
use std::thread;
|
||||
use std::result;
|
||||
use std::time;
|
||||
use termion::raw::IntoRawMode;
|
||||
use termion::screen::AlternateScreen;
|
||||
|
@ -97,6 +98,24 @@ impl Context {
|
|||
pub fn restore_input(&self) {
|
||||
self.input.restore(self.sender.clone());
|
||||
}
|
||||
pub fn account_status(&mut self, idx_a: usize, idx_m: usize) -> result::Result<bool, usize> {
|
||||
let s = self.accounts[idx_a].status(idx_m)?;
|
||||
if let Some(event) = s {
|
||||
eprintln!("setting up notification");
|
||||
let (idx_a, idx_m) = self.mailbox_hashes[&event.folder];
|
||||
let subjects = {
|
||||
let mut ret = Vec::with_capacity(event.index.len());
|
||||
eprintln!("index is {:?}", &event.index);
|
||||
for &i in &event.index {
|
||||
ret.push(self.accounts[idx_a][idx_m].as_ref().unwrap().collection[i].subject());
|
||||
}
|
||||
ret
|
||||
};
|
||||
self.replies.push_back(UIEvent { id: 0, event_type: UIEventType::Notification(format!("Update in {}/{}, indexes {:?}", self.accounts[idx_a].name(), self.accounts[idx_a][idx_m].as_ref().unwrap().folder.name(), subjects)) });
|
||||
return Ok(true);
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
/// A State object to manage and own components and entities of the UI. `State` is responsible for
|
||||
|
@ -224,8 +243,10 @@ impl State<std::io::Stdout> {
|
|||
cursor::Goto(1, 1)
|
||||
).unwrap();
|
||||
s.flush();
|
||||
eprintln!("DEBUG: inserting mailbox hashes:");
|
||||
for (x, account) in s.context.accounts.iter_mut().enumerate() {
|
||||
for (y, folder) in account.backend.folders().iter().enumerate() {
|
||||
eprintln!("{:?}", folder);
|
||||
s.context.mailbox_hashes.insert(folder.hash(), (x, y));
|
||||
}
|
||||
let sender = s.context.sender.clone();
|
||||
|
@ -242,35 +263,38 @@ impl State<std::io::Stdout> {
|
|||
* and startup a thread to remind us to poll it every now and then till it's finished.
|
||||
*/
|
||||
pub fn hash_to_folder(&mut self, hash: u64) {
|
||||
let (idxa, idxm) = self.context.mailbox_hashes[&hash];
|
||||
self.context.accounts[idxa].reload(idxm);
|
||||
let (startup_tx, startup_rx) = chan::async();
|
||||
let startup_thread = {
|
||||
let sender = self.context.sender.clone();
|
||||
let startup_rx = startup_rx.clone();
|
||||
if let Some(&(idxa, idxm)) = self.context.mailbox_hashes.get(&hash) {
|
||||
self.context.accounts[idxa].reload(idxm);
|
||||
let (startup_tx, startup_rx) = chan::async();
|
||||
let startup_thread = {
|
||||
let sender = self.context.sender.clone();
|
||||
let startup_rx = startup_rx.clone();
|
||||
|
||||
thread::Builder::new()
|
||||
.name("startup-thread".to_string())
|
||||
.spawn(move || {
|
||||
let dur = time::Duration::from_millis(100);
|
||||
loop {
|
||||
chan_select! {
|
||||
default => {},
|
||||
startup_rx.recv() -> _ => {
|
||||
sender.send(ThreadEvent::UIEvent(UIEventType::MailboxUpdate((idxa,idxm))));
|
||||
sender.send(ThreadEvent::ThreadJoin(thread::current().id()));
|
||||
return;
|
||||
thread::Builder::new()
|
||||
.name("startup-thread".to_string())
|
||||
.spawn(move || {
|
||||
let dur = time::Duration::from_millis(100);
|
||||
loop {
|
||||
chan_select! {
|
||||
default => {},
|
||||
startup_rx.recv() -> _ => {
|
||||
sender.send(ThreadEvent::UIEvent(UIEventType::MailboxUpdate((idxa,idxm))));
|
||||
sender.send(ThreadEvent::ThreadJoin(thread::current().id()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
sender.send(ThreadEvent::UIEvent(UIEventType::StartupCheck));
|
||||
thread::sleep(dur);
|
||||
}
|
||||
sender.send(ThreadEvent::UIEvent(UIEventType::StartupCheck));
|
||||
thread::sleep(dur);
|
||||
}
|
||||
})
|
||||
.unwrap()
|
||||
};
|
||||
self.startup_thread = Some(startup_tx.clone());
|
||||
self.threads
|
||||
.insert(startup_thread.thread().id(), (startup_tx, startup_thread));
|
||||
})
|
||||
.expect("Failed to spawn startup-thread in hash_to_folder()")
|
||||
};
|
||||
self.startup_thread = Some(startup_tx.clone());
|
||||
self.threads
|
||||
.insert(startup_thread.thread().id(), (startup_tx, startup_thread));
|
||||
} else {
|
||||
eprintln!("BUG: mailbox with hash {} not found in mailbox_hashes.", hash);
|
||||
}
|
||||
}
|
||||
|
||||
/// If an owned thread returns a `ThreadEvent::ThreadJoin` event to `State` then it must remove
|
||||
|
|
Loading…
Reference in New Issue