Poll all parse workers on startup
parent
f2a646158d
commit
3f35b69ff1
|
@ -67,7 +67,6 @@ impl<T> Async<T> {
|
||||||
Some(AsyncStatus::Finished) => {
|
Some(AsyncStatus::Finished) => {
|
||||||
},
|
},
|
||||||
Some(a) => {
|
Some(a) => {
|
||||||
eprintln!("async got {:?}", a);
|
|
||||||
return Ok(a);
|
return Ok(a);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -79,7 +78,6 @@ impl<T> Async<T> {
|
||||||
}
|
}
|
||||||
let v = self.worker.take().unwrap().join().unwrap();
|
let v = self.worker.take().unwrap().join().unwrap();
|
||||||
self.value = Some(v);
|
self.value = Some(v);
|
||||||
eprintln!("worker joined");
|
|
||||||
return Ok(AsyncStatus::Finished);
|
return Ok(AsyncStatus::Finished);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ pub struct Account {
|
||||||
name: String,
|
name: String,
|
||||||
folders: Vec<Option<Result<Mailbox>>>,
|
folders: Vec<Option<Result<Mailbox>>>,
|
||||||
|
|
||||||
workers: Vec<Worker>,
|
pub workers: Vec<Worker>,
|
||||||
|
|
||||||
sent_folder: Option<usize>,
|
sent_folder: Option<usize>,
|
||||||
|
|
||||||
|
|
|
@ -137,7 +137,6 @@ impl BackendOp for MaildirOp {
|
||||||
if !(flags & Flag::TRASHED).is_empty() {
|
if !(flags & Flag::TRASHED).is_empty() {
|
||||||
new_name.push('T');
|
new_name.push('T');
|
||||||
}
|
}
|
||||||
eprintln!("new name is {}", new_name);
|
|
||||||
|
|
||||||
fs::rename(&self.path, &new_name)?;
|
fs::rename(&self.path, &new_name)?;
|
||||||
envelope.set_operation_token(
|
envelope.set_operation_token(
|
||||||
|
@ -191,9 +190,9 @@ impl MailBackend for MaildirType {
|
||||||
hasher.write(path.as_bytes());
|
hasher.write(path.as_bytes());
|
||||||
sender.send(RefreshEvent {
|
sender.send(RefreshEvent {
|
||||||
folder: format!(
|
folder: format!(
|
||||||
"{}", path
|
"{}", path
|
||||||
),
|
),
|
||||||
hash: hasher.finish(),
|
hash: hasher.finish(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -202,7 +201,7 @@ impl MailBackend for MaildirType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,9 +219,9 @@ impl MaildirType {
|
||||||
p.push(d);
|
p.push(d);
|
||||||
if !p.is_dir() {
|
if !p.is_dir() {
|
||||||
return Err(MeliError::new(format!(
|
return Err(MeliError::new(format!(
|
||||||
"{} is not a valid maildir folder",
|
"{} is not a valid maildir folder",
|
||||||
path
|
path
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
p.pop();
|
p.pop();
|
||||||
}
|
}
|
||||||
|
@ -235,67 +234,67 @@ impl MaildirType {
|
||||||
// TODO: Avoid clone
|
// TODO: Avoid clone
|
||||||
let folder = folder.clone();
|
let folder = folder.clone();
|
||||||
|
|
||||||
thread::Builder::new()
|
thread::Builder::new()
|
||||||
.name(format!("parsing {:?}", folder))
|
.name(format!("parsing {:?}", folder))
|
||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
MaildirType::is_valid(&folder)?;
|
MaildirType::is_valid(&folder)?;
|
||||||
let path = folder.path();
|
let path = folder.path();
|
||||||
let mut path = PathBuf::from(path);
|
let mut path = PathBuf::from(path);
|
||||||
path.push("cur");
|
path.push("cur");
|
||||||
let iter = path.read_dir()?;
|
let iter = path.read_dir()?;
|
||||||
let count = path.read_dir()?.count();
|
let count = path.read_dir()?.count();
|
||||||
let mut files: Vec<String> = Vec::with_capacity(count);
|
let mut files: Vec<String> = Vec::with_capacity(count);
|
||||||
let mut r = Vec::with_capacity(count);
|
let mut r = Vec::with_capacity(count);
|
||||||
for e in iter {
|
for e in iter {
|
||||||
let e = e.and_then(|x| {
|
let e = e.and_then(|x| {
|
||||||
let path = x.path();
|
let path = x.path();
|
||||||
Ok(path.to_str().unwrap().to_string())
|
Ok(path.to_str().unwrap().to_string())
|
||||||
})?;
|
})?;
|
||||||
files.push(e);
|
files.push(e);
|
||||||
}
|
}
|
||||||
let mut threads = Vec::with_capacity(cores);
|
let mut threads = Vec::with_capacity(cores);
|
||||||
if !files.is_empty() {
|
if !files.is_empty() {
|
||||||
crossbeam::scope(|scope| {
|
crossbeam::scope(|scope| {
|
||||||
let chunk_size = if count / cores > 0 {
|
let chunk_size = if count / cores > 0 {
|
||||||
count / cores
|
count / cores
|
||||||
} else {
|
} else {
|
||||||
count
|
count
|
||||||
};
|
};
|
||||||
for chunk in files.chunks(chunk_size) {
|
for chunk in files.chunks(chunk_size) {
|
||||||
let mut tx = tx.clone();
|
let mut tx = tx.clone();
|
||||||
let s = scope.spawn(move || {
|
let s = scope.spawn(move || {
|
||||||
let len = chunk.len();
|
let len = chunk.len();
|
||||||
let size = if len <= 100 { 100 } else { (len / 100) * 100};
|
let size = if len <= 100 { 100 } else { (len / 100) * 100};
|
||||||
let mut local_r: Vec<Envelope> = Vec::with_capacity(chunk.len());
|
let mut local_r: Vec<Envelope> = Vec::with_capacity(chunk.len());
|
||||||
for c in chunk.chunks(size) {
|
for c in chunk.chunks(size) {
|
||||||
let len = c.len();
|
let len = c.len();
|
||||||
for e in c {
|
for e in c {
|
||||||
let e_copy = e.to_string();
|
let e_copy = e.to_string();
|
||||||
if let Some(mut e) =
|
if let Some(mut e) =
|
||||||
Envelope::from_token(Box::new(BackendOpGenerator::new(Box::new(
|
Envelope::from_token(Box::new(BackendOpGenerator::new(Box::new(
|
||||||
move || Box::new(MaildirOp::new(e_copy.clone())),
|
move || Box::new(MaildirOp::new(e_copy.clone())),
|
||||||
)))) {
|
)))) {
|
||||||
if e.populate_headers().is_err() {
|
if e.populate_headers().is_err() {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
local_r.push(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
local_r.push(e);
|
tx.send(AsyncStatus::ProgressReport(len));
|
||||||
}
|
}
|
||||||
|
local_r
|
||||||
|
});
|
||||||
|
threads.push(s);
|
||||||
}
|
}
|
||||||
tx.send(AsyncStatus::ProgressReport(len));
|
});
|
||||||
}
|
}
|
||||||
local_r
|
for t in threads {
|
||||||
});
|
let mut result = t.join();
|
||||||
threads.push(s);
|
r.append(&mut result);
|
||||||
}
|
}
|
||||||
});
|
tx.send(AsyncStatus::Finished);
|
||||||
}
|
Ok(r)
|
||||||
for t in threads {
|
}).unwrap()
|
||||||
let mut result = t.join();
|
|
||||||
r.append(&mut result);
|
|
||||||
}
|
|
||||||
tx.send(AsyncStatus::Finished);
|
|
||||||
Ok(r)
|
|
||||||
}).unwrap()
|
|
||||||
};
|
};
|
||||||
w.build(handle)
|
w.build(handle)
|
||||||
}
|
}
|
||||||
|
|
24
src/bin.rs
24
src/bin.rs
|
@ -59,7 +59,7 @@ fn make_input_thread(
|
||||||
sx.send(ThreadEvent::Input(k));
|
sx.send(ThreadEvent::Input(k));
|
||||||
},
|
},
|
||||||
|| {
|
|| {
|
||||||
sx.send(ThreadEvent::UIEventType(UIEventType::ChangeMode(
|
sx.send(ThreadEvent::UIEvent(UIEventType::ChangeMode(
|
||||||
UIMode::Fork,
|
UIMode::Fork,
|
||||||
)));
|
)));
|
||||||
},
|
},
|
||||||
|
@ -189,11 +189,29 @@ fn main() {
|
||||||
state.redraw();
|
state.redraw();
|
||||||
/* Don't handle this yet. */
|
/* Don't handle this yet. */
|
||||||
},
|
},
|
||||||
ThreadEvent::UIEventType(UIEventType::ChangeMode(f)) => {
|
ThreadEvent::UIEvent(UIEventType::ChangeMode(f)) => {
|
||||||
state.mode = f;
|
state.mode = f;
|
||||||
break 'inner; // `goto` 'reap loop, and wait on child.
|
break 'inner; // `goto` 'reap loop, and wait on child.
|
||||||
}
|
}
|
||||||
ThreadEvent::UIEventType(e) => {
|
ThreadEvent::UIEvent(UIEventType::StartupCheck) => {
|
||||||
|
let mut flag = false;
|
||||||
|
for account in &mut state.context.accounts {
|
||||||
|
let len = account.len();
|
||||||
|
for i in 0..len {
|
||||||
|
match account.status(i) {
|
||||||
|
Ok(()) => { },
|
||||||
|
Err(_) => {
|
||||||
|
flag |= true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !flag {
|
||||||
|
state.finish_startup();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
ThreadEvent::UIEvent(e) => {
|
||||||
state.rcv_event(UIEvent { id: 0, event_type: e});
|
state.rcv_event(UIEvent { id: 0, event_type: e});
|
||||||
state.render();
|
state.render();
|
||||||
},
|
},
|
||||||
|
|
|
@ -64,14 +64,13 @@ impl MailListing {
|
||||||
// Get mailbox as a reference.
|
// Get mailbox as a reference.
|
||||||
//
|
//
|
||||||
loop {
|
loop {
|
||||||
eprintln!("loop round");
|
match context.accounts[self.cursor_pos.0].status(self.cursor_pos.1) {
|
||||||
match context.accounts[self.cursor_pos.0].status(self.cursor_pos.1) {
|
Ok(()) => { break; },
|
||||||
Ok(()) => { break; },
|
Err(_) => {
|
||||||
Err(a) => {
|
// TODO: Show progress visually
|
||||||
eprintln!("status returned {:?}", a);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
let mailbox = &mut context.accounts[self.cursor_pos.0][self.cursor_pos.1]
|
let mailbox = &mut context.accounts[self.cursor_pos.0][self.cursor_pos.1]
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -455,8 +454,7 @@ impl Component for MailListing {
|
||||||
&mut mailbox.collection[idx]
|
&mut mailbox.collection[idx]
|
||||||
};
|
};
|
||||||
if !envelope.is_seen() {
|
if !envelope.is_seen() {
|
||||||
eprintln!("setting seen");
|
envelope.set_seen().unwrap();
|
||||||
envelope.set_seen();
|
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
@ -464,7 +462,6 @@ impl Component for MailListing {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if must_highlight {
|
if must_highlight {
|
||||||
eprintln!("must highlight");
|
|
||||||
self.highlight_line_self(idx, context);
|
self.highlight_line_self(idx, context);
|
||||||
}
|
}
|
||||||
let mid = get_y(upper_left) + total_rows - bottom_entity_rows;
|
let mid = get_y(upper_left) + total_rows - bottom_entity_rows;
|
||||||
|
@ -659,13 +656,12 @@ impl Component for MailListing {
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
Action::ViewMailbox(idx) => {
|
Action::ViewMailbox(idx) => {
|
||||||
eprintln!("listing got viewmailbox({})", idx);
|
|
||||||
self.new_cursor_pos.1 = *idx;
|
self.new_cursor_pos.1 = *idx;
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
self.refresh_mailbox(context);
|
self.refresh_mailbox(context);
|
||||||
return;
|
return;
|
||||||
}
|
},
|
||||||
_ => {},
|
//_ => {},
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,8 @@ use melib::*;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
use std::thread;
|
||||||
|
use std::time;
|
||||||
extern crate termion;
|
extern crate termion;
|
||||||
use termion::event::Key as TermionKey;
|
use termion::event::Key as TermionKey;
|
||||||
use termion::input::TermRead;
|
use termion::input::TermRead;
|
||||||
|
@ -77,7 +79,7 @@ pub enum ThreadEvent {
|
||||||
RefreshMailbox {
|
RefreshMailbox {
|
||||||
hash: u64,
|
hash: u64,
|
||||||
},
|
},
|
||||||
UIEventType(UIEventType),
|
UIEvent(UIEventType),
|
||||||
//Decode { _ }, // For gpg2 signature check
|
//Decode { _ }, // For gpg2 signature check
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,6 +112,8 @@ pub enum UIEventType {
|
||||||
Action(Action),
|
Action(Action),
|
||||||
StatusNotification(String),
|
StatusNotification(String),
|
||||||
MailboxUpdate((usize, usize)),
|
MailboxUpdate((usize, usize)),
|
||||||
|
|
||||||
|
StartupCheck,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An event passed from `State` to its Entities.
|
/// An event passed from `State` to its Entities.
|
||||||
|
@ -186,6 +190,8 @@ pub struct State<W: Write> {
|
||||||
sender: Sender<ThreadEvent>,
|
sender: Sender<ThreadEvent>,
|
||||||
entities: Vec<Entity>,
|
entities: Vec<Entity>,
|
||||||
pub context: Context,
|
pub context: Context,
|
||||||
|
|
||||||
|
startup_thread: Option<(chan::Sender<bool>, thread::JoinHandle<()>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: Write> Drop for State<W> {
|
impl<W: Write> Drop for State<W> {
|
||||||
|
@ -222,6 +228,25 @@ impl State<std::io::Stdout> {
|
||||||
.map(|(n, a_s)| Account::new(n.to_string(), a_s.clone(), &backends))
|
.map(|(n, a_s)| Account::new(n.to_string(), a_s.clone(), &backends))
|
||||||
.collect();
|
.collect();
|
||||||
accounts.sort_by(|a, b| a.name().cmp(&b.name()));
|
accounts.sort_by(|a, b| a.name().cmp(&b.name()));
|
||||||
|
let (startup_tx, startup_rx) = chan::async();
|
||||||
|
let startup_thread = {
|
||||||
|
let sender = sender.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() -> _ => {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sender.send(ThreadEvent::UIEvent(UIEventType::StartupCheck));
|
||||||
|
thread::sleep(dur);
|
||||||
|
}
|
||||||
|
}).unwrap()
|
||||||
|
};
|
||||||
let mut s = State {
|
let mut s = State {
|
||||||
cols: cols,
|
cols: cols,
|
||||||
rows: rows,
|
rows: rows,
|
||||||
|
@ -242,6 +267,7 @@ impl State<std::io::Stdout> {
|
||||||
|
|
||||||
input_thread: input_thread,
|
input_thread: input_thread,
|
||||||
},
|
},
|
||||||
|
startup_thread: Some((startup_tx, startup_thread)),
|
||||||
};
|
};
|
||||||
write!(
|
write!(
|
||||||
s.stdout(),
|
s.stdout(),
|
||||||
|
@ -259,6 +285,17 @@ impl State<std::io::Stdout> {
|
||||||
}
|
}
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
pub fn finish_startup(&mut self) {
|
||||||
|
// TODO: Encode startup process with the type system if possible
|
||||||
|
if self.startup_thread.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let (tx, handle) = self.startup_thread.take().unwrap();
|
||||||
|
tx.send(true);
|
||||||
|
handle.join().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn to_main_screen(&mut self) {
|
pub fn to_main_screen(&mut self) {
|
||||||
write!(
|
write!(
|
||||||
self.stdout(),
|
self.stdout(),
|
||||||
|
|
Loading…
Reference in New Issue