maybe i shouldn't be using a widget impl?

This commit is contained in:
Michael Zhang 2021-03-01 03:50:20 -06:00
parent 84cd7ae0f4
commit f0e5042a76
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
4 changed files with 98 additions and 31 deletions

View file

@ -12,7 +12,10 @@ use panorama_imap::{
}, },
command::Command as ImapCommand, command::Command as ImapCommand,
}; };
use tokio::{sync::mpsc::UnboundedReceiver, task::JoinHandle}; use tokio::{
sync::mpsc::{UnboundedReceiver, UnboundedSender},
task::JoinHandle,
};
use tokio_stream::wrappers::WatchStream; use tokio_stream::wrappers::WatchStream;
use crate::config::{Config, ConfigWatcher, ImapAuth, MailAccountConfig, TlsMethod}; use crate::config::{Config, ConfigWatcher, ImapAuth, MailAccountConfig, TlsMethod};
@ -26,10 +29,14 @@ pub enum MailCommand {
Raw(ImapCommand), Raw(ImapCommand),
} }
/// Possible events returned from the server that should be sent to the UI
pub enum MailEvent {}
/// Main entrypoint for the mail listener. /// Main entrypoint for the mail listener.
pub async fn run_mail( pub async fn run_mail(
mut config_watcher: ConfigWatcher, mut config_watcher: ConfigWatcher,
_cmd_in: UnboundedReceiver<MailCommand>, ui2mail_rx: UnboundedReceiver<MailCommand>,
mail2ui_tx: UnboundedSender<MailEvent>,
) -> Result<()> { ) -> Result<()> {
let mut curr_conn: Vec<JoinHandle<_>> = Vec::new(); let mut curr_conn: Vec<JoinHandle<_>> = Vec::new();
@ -53,6 +60,8 @@ pub async fn run_mail(
for acct in config.mail_accounts.into_iter() { for acct in config.mail_accounts.into_iter() {
let handle = tokio::spawn(async move { let handle = tokio::spawn(async move {
// debug!("opening imap connection for {:?}", acct); // debug!("opening imap connection for {:?}", acct);
// this loop is to make sure accounts are restarted on error
loop { loop {
match imap_main(acct.clone()).await { match imap_main(acct.clone()).await {
Ok(_) => {} Ok(_) => {}
@ -62,6 +71,13 @@ pub async fn run_mail(
} }
warn!("connection dropped, retrying"); warn!("connection dropped, retrying");
// wait a bit so we're not hitting the server really fast if the fail happens
// early on
//
// TODO: some kind of smart exponential backoff that considers some time
// threshold to be a failing case?
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
} }
}); });
curr_conn.push(handle); curr_conn.push(handle);
@ -96,9 +112,12 @@ async fn imap_main(acct: MailAccountConfig) -> Result<()> {
debug!("preparing to auth"); debug!("preparing to auth");
// check if the authentication method is supported // check if the authentication method is supported
let mut authed = match acct.imap.auth { let mut authed = match &acct.imap.auth {
ImapAuth::Plain { username, password } => { ImapAuth::Plain { username, password } => {
let auth = auth::Plain { username, password }; let auth = auth::Plain {
username: username.clone(),
password: password.clone(),
};
auth.perform_auth(unauth).await? auth.perform_auth(unauth).await?
} }
}; };
@ -118,7 +137,22 @@ async fn imap_main(acct: MailAccountConfig) -> Result<()> {
loop { loop {
idle_stream.next().await; idle_stream.next().await;
debug!("got an event"); debug!("got an event");
if false {
break;
} }
} }
if false {
break;
}
}
// wait a bit so we're not hitting the server really fast if the fail happens
// early on
//
// TODO: some kind of smart exponential backoff that considers some time
// threshold to be a failing case?
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
} }
} }

View file

@ -49,12 +49,15 @@ async fn run(opt: Opt) -> Result<()> {
// used to notify the runtime that the process should exit // used to notify the runtime that the process should exit
let (exit_tx, mut exit_rx) = mpsc::channel::<()>(1); let (exit_tx, mut exit_rx) = mpsc::channel::<()>(1);
// used to send commands to the mail service // send messages from the UI thread to the mail thread
let (_mail_tx, mail_rx) = mpsc::unbounded_channel(); let (ui2mail_tx, ui2mail_rx) = mpsc::unbounded_channel();
// send messages from the mail thread to the UI thread
let (mail2ui_tx, mail2ui_rx) = mpsc::unbounded_channel();
tokio::spawn(async move { tokio::spawn(async move {
let config_update = config_update.clone(); let config_update = config_update.clone();
mail::run_mail(config_update, mail_rx) mail::run_mail(config_update, ui2mail_rx, mail2ui_tx)
.unwrap_or_else(report_err) .unwrap_or_else(report_err)
.await; .await;
}); });

19
src/ui/mail_tab.rs Normal file
View file

@ -0,0 +1,19 @@
use tui::{widgets::{Widget, StatefulWidget}, buffer::Buffer, layout::Rect};
pub struct MailTabState {
}
impl MailTabState {
pub fn new() -> Self {
MailTabState{}
}
}
pub struct MailTab;
impl StatefulWidget for MailTab {
type State = MailTabState;
fn render(self, rect: Rect, buffer: &mut Buffer, state: &mut Self::State) {
}
}

View file

@ -1,5 +1,7 @@
//! UI library //! UI library
mod mail_tab;
use std::io::Stdout; use std::io::Stdout;
use std::mem; use std::mem;
use std::time::Duration; use std::time::Duration;
@ -17,9 +19,14 @@ use tui::{
style::{Color, Modifier, Style}, style::{Color, Modifier, Style},
text::Spans, text::Spans,
widgets::*, widgets::*,
Frame,
Terminal, Terminal,
}; };
use self::mail_tab::{MailTabState, MailTab};
// pub(crate) type FrameType<'a> = Frame<'a, CrosstermBackend<Stdout>>;
const FRAME_DURATION: Duration = Duration::from_millis(17); const FRAME_DURATION: Duration = Duration::from_millis(17);
/// Main entrypoint for the UI /// Main entrypoint for the UI
@ -28,10 +35,12 @@ pub async fn run_ui(mut stdout: Stdout, exit_tx: mpsc::Sender<()>) -> Result<()>
terminal::enable_raw_mode()?; terminal::enable_raw_mode()?;
let backend = CrosstermBackend::new(&mut stdout); let backend = CrosstermBackend::new(&mut stdout);
let mut terminal = Terminal::new(backend)?; let mut term = Terminal::new(backend)?;
let mut mail_state = MailTabState::new();
loop { loop {
terminal.draw(|f| { term.draw(|f| {
let chunks = Layout::default() let chunks = Layout::default()
.direction(Direction::Vertical) .direction(Direction::Vertical)
.margin(0) .margin(0)
@ -44,35 +53,37 @@ pub async fn run_ui(mut stdout: Stdout, exit_tx: mpsc::Sender<()>) -> Result<()>
]) ])
.split(f.size()); .split(f.size());
let chunks2 = Layout::default() // let chunks2 = Layout::default()
.direction(Direction::Horizontal) // .direction(Direction::Horizontal)
.margin(0) // .margin(0)
.constraints([ // .constraints([
Constraint::Length(20), // Constraint::Length(20),
Constraint::Max(5000), // Constraint::Max(5000),
// // //
]) // ])
.split(chunks[1]); // .split(chunks[1]);
// this is the title bar // this is the title bar
let titles = vec!["hellosu"].into_iter().map(Spans::from).collect(); let titles = vec!["hellosu"].into_iter().map(Spans::from).collect();
let tabs = Tabs::new(titles); let tabs = Tabs::new(titles);
f.render_widget(tabs, chunks[0]); f.render_widget(tabs, chunks[0]);
let mail_tab = MailTab;
f.render_stateful_widget(mail_tab, chunks[1], &mut mail_state);
// TODO: check active tab // TODO: check active tab
let items = [ // let items = [
ListItem::new("Osu"), // ListItem::new("Osu"),
ListItem::new("Game").style(Style::default().add_modifier(Modifier::BOLD)), // ListItem::new("Game").style(Style::default().add_modifier(Modifier::BOLD)),
]; // ];
let dirlist = List::new(items) // let dirlist = List::new(items)
.block(Block::default().title("List").borders(Borders::ALL)) // .block(Block::default().title("List").borders(Borders::ALL))
.style(Style::default().fg(Color::White)) // .style(Style::default().fg(Color::White))
.highlight_style(Style::default().add_modifier(Modifier::ITALIC)) // .highlight_style(Style::default().add_modifier(Modifier::ITALIC))
.highlight_symbol(">>"); // .highlight_symbol(">>");
f.render_widget(dirlist, chunks2[0]); // f.render_widget(dirlist, chunks2[0]);
let block = Block::default().title("Block").borders(Borders::ALL); // let block = Block::default().title("Block").borders(Borders::ALL);
f.render_widget(block, chunks2[1]); // f.render_widget(block, chunks2[1]);
// let block = Block::default().title("Block 2").borders(Borders::ALL); // let block = Block::default().title("Block 2").borders(Borders::ALL);
// f.render_widget(block, chunks[1]); // f.render_widget(block, chunks[1]);
@ -108,7 +119,7 @@ pub async fn run_ui(mut stdout: Stdout, exit_tx: mpsc::Sender<()>) -> Result<()>
// } // }
} }
mem::drop(terminal); mem::drop(term);
execute!( execute!(
stdout, stdout,