From f5d3a896414415ea9958aa539aad5d0b04ebc2d6 Mon Sep 17 00:00:00 2001 From: Michael Zhang Date: Fri, 19 Feb 2021 19:44:04 -0600 Subject: [PATCH] what the heck --- Cargo.lock | 23 +++++++++++ Cargo.toml | 1 + README.md | 2 + src/config.rs | 6 +++ src/lib.rs | 4 +- src/mail/imap2.rs | 101 ++++++++++++++++++++++++++++++++++++---------- src/mail/mod.rs | 3 +- src/main.rs | 2 +- src/ui/mod.rs | 2 +- 9 files changed, 119 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 92a865a..fc0cbec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -247,6 +247,28 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +[[package]] +name = "format-bytes" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc35f5e45d6b31053cea13078ffc6fa52fa8617aa54b7ac2011720d9c009e04f" +dependencies = [ + "format-bytes-macros", + "proc-macro-hack", +] + +[[package]] +name = "format-bytes-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05089e341a0460449e2210c3bf7b61597860b07f0deae58da38dbed0a4c6b6d" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "funty" version = "1.1.0" @@ -645,6 +667,7 @@ dependencies = [ "cfg-if", "chrono", "crossterm", + "format-bytes", "futures", "inotify", "lettre", diff --git a/Cargo.toml b/Cargo.toml index adecd74..ee9112c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ async-trait = "0.1.42" cfg-if = "1.0.0" chrono = "0.4.19" crossterm = "0.19.0" +format-bytes = "0.2.0" futures = "0.3.12" inotify = { version = "0.9.2", features = ["stream"] } lettre = "0.9.5" diff --git a/README.md b/README.md index 7607732..1ff60f6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ panorama ======== +[![](https://tokei.rs/b1/github/iptq/panorama?category=lines)](https://github.com/XAMPPRocky/tokei). + Panorama is a terminal Personal Information Manager (PIM). Goals: diff --git a/src/config.rs b/src/config.rs index 5089b9c..d60492f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -90,6 +90,12 @@ async fn start_inotify_stream( let config_home = config_home.as_ref().to_path_buf(); let config_path = config_home.join("panorama.toml"); + // first shot + { + let config = read_config(&config_path).await?; + config_tx.send(config)?; + } + while let Some(v) = event_stream.next().await { let event = v.context("event")?; diff --git a/src/lib.rs b/src/lib.rs index aa8862b..33492e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,13 +3,15 @@ #![deny(missing_docs)] // TODO: get rid of this before any kind of public release -#![allow(unused_imports)] +#![allow(unused_imports, unused_variables)] #[macro_use] extern crate anyhow; #[macro_use] extern crate crossterm; #[macro_use] +extern crate format_bytes; +#[macro_use] extern crate serde; #[macro_use] extern crate tracing; diff --git a/src/mail/imap2.rs b/src/mail/imap2.rs index 02b718a..4b7a15b 100644 --- a/src/mail/imap2.rs +++ b/src/mail/imap2.rs @@ -5,8 +5,9 @@ use std::sync::Arc; use anyhow::Result; use futures::{ - future::{Future, TryFuture}, - stream::Stream, + future::{self, BoxFuture, Future, FutureExt, TryFuture}, + sink::{Sink, SinkExt}, + stream::{Stream, StreamExt}, }; use panorama_imap::builders::command::Command; use parking_lot::Mutex; @@ -16,7 +17,7 @@ use tokio::{ sync::{oneshot, Notify}, }; use tokio_rustls::{rustls::ClientConfig, webpki::DNSNameRef, TlsConnector}; -use tokio_util::codec::{Framed, Decoder, LinesCodec}; +use tokio_util::codec::{Decoder, Framed, FramedRead, FramedWrite, LinesCodec, LinesCodecError}; use crate::config::{ImapConfig, TlsMethod}; @@ -26,6 +27,7 @@ pub async fn open_imap_connection(config: ImapConfig) -> Result<()> { let stream = TcpStream::connect((server, port)).await?; + debug!("hellosu"); match config.tls { TlsMethod::Off => begin_authentication(config, stream).await, TlsMethod::On => { @@ -33,13 +35,23 @@ pub async fn open_imap_connection(config: ImapConfig) -> Result<()> { begin_authentication(config, stream).await } TlsMethod::Starttls => { - let cmd_mgr = CommandManager::new(stream); + let (stream, cmd_mgr) = CommandManager::new(stream); + let flights = cmd_mgr.flights(); + + // listen(stream, flights).await?; + // async move { + // let mut cmd_mgr = cmd_mgr; + // cmd_mgr.capabilities().await; + // } + // .await; + todo!() } } } /// Performs TLS negotiation, using the webpki_roots and verifying the server name +#[instrument(skip(server_name, stream))] async fn perform_tls_negotiation( server_name: impl AsRef, stream: impl AsyncRead + AsyncWrite + Unpin, @@ -61,10 +73,10 @@ async fn fetch_capabilities(stream: impl AsyncRead + AsyncWrite) -> Result ImapStream for T {} +pub async fn listen( + mut stream: impl Stream> + Unpin, + in_flight: InFlight, +) -> Result<()> { + debug!("listening for messages from server"); + loop { + let line = match stream.next().await { + Some(v) => v?, + None => break, + }; + debug!("line: {:?}", line); + + let mut parts = line.split(' '); + let tag = parts.next().unwrap().parse()?; // TODO: handle empty + + { + let mut in_flight = in_flight.lock(); + if let Some(sender) = in_flight.remove(&tag) { + sender.send(()).unwrap(); + } + } + } + + Ok(()) +} + +// trait ImapStream: AsyncRead + AsyncWrite + Send + Unpin {} +// impl ImapStream for T {} + +trait ImapSink: Sink + Unpin {} +impl + Unpin> ImapSink for T {} + +type InFlightMap = HashMap>; +type InFlight = Arc>; struct CommandManager<'a> { id: usize, in_flight: Arc>>>, - stream: Framed, LinesCodec>, + sink: Box, } impl<'a> CommandManager<'a> { - pub fn new(stream: impl ImapStream + 'a) -> Self { + pub fn new( + stream: impl AsyncRead + AsyncWrite + 'a, + ) -> (impl Stream>, Self) { let codec = LinesCodec::new(); - let framed = codec.framed(Box::new(stream) as Box<_>); + let framed = codec.framed(stream); + let (framed_sink, framed_stream) = framed.split(); - CommandManager { + let cmd_mgr = CommandManager { id: 0, in_flight: Arc::new(Mutex::new(HashMap::new())), - stream: framed, - } + sink: Box::new(framed_sink), + }; + (framed_stream, cmd_mgr) } - pub fn decompose(self) -> impl ImapStream + 'a { - let parts = self.stream.into_parts(); - parts.io + pub fn flights(&self) -> Arc>>> { + self.in_flight.clone() } - pub async fn listen(&self) { - loop { - } + pub fn decompose(self) -> impl ImapSink + Unpin + 'a { + self.sink } - pub fn run(&mut self, command: Command) -> impl TryFuture { + pub async fn capabilities(&mut self) -> Result> { + self.exec(Command { + args: b"CAPABILITY".to_vec(), + next_state: None, + }) + .await?; + Ok(vec![]) + } + + pub async fn exec(&mut self, command: Command) -> Result<()> { let id = self.id; self.id += 1; + let cmd_str = String::from_utf8(command.args)?; + self.sink.send(cmd_str).await?; + let (tx, rx) = oneshot::channel(); { let mut in_flight = self.in_flight.lock(); in_flight.insert(id, tx); } - async { rx.await } + rx.await?; + Ok(()) } } diff --git a/src/mail/mod.rs b/src/mail/mod.rs index 495ec4c..1eca111 100644 --- a/src/mail/mod.rs +++ b/src/mail/mod.rs @@ -11,7 +11,7 @@ use tokio_stream::wrappers::WatchStream; use crate::config::{Config, ConfigWatcher}; -use self::imap::open_imap_connection; +use self::imap2::open_imap_connection; /// Command sent to the mail thread by something else (i.e. UI) pub enum MailCommand { @@ -47,6 +47,7 @@ pub async fn run_mail( let handle = tokio::spawn(async { for acct in config.mail_accounts.into_iter() { + debug!("opening imap connection for {:?}", acct); open_imap_connection(acct.imap).await.unwrap(); } }); diff --git a/src/main.rs b/src/main.rs index 3e84a0b..a3b660f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,7 +21,7 @@ struct Opt { #[tokio::main(flavor = "multi_thread")] async fn main() -> Result<()> { // parse command line arguments into options struct - let opt = Opt::from_args(); + let _opt = Opt::from_args(); // print logs to file as directed by command line options use tracing_subscriber::filter::LevelFilter; diff --git a/src/ui/mod.rs b/src/ui/mod.rs index ac290a2..296fc51 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -27,7 +27,7 @@ const FRAME: Duration = Duration::from_millis(20); pub struct Rect(u16, u16, u16, u16); /// UI entrypoint. -#[instrument] +#[instrument(skip(w, exit))] pub async fn run_ui(mut w: impl Write + Debug, exit: ExitSender) -> Result<()> { execute!(w, cursor::Hide, terminal::EnterAlternateScreen)?; terminal::enable_raw_mode()?;