This commit is contained in:
Michael Zhang 2021-07-29 22:47:53 -05:00
parent 04bd3e62b6
commit 5a9f847097
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
9 changed files with 190 additions and 60 deletions

92
Cargo.lock generated
View file

@ -43,6 +43,19 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
dependencies = [
"libc",
"num-integer",
"num-traits",
"time",
"winapi",
]
[[package]]
name = "clap"
version = "3.0.0-beta.2"
@ -301,6 +314,25 @@ dependencies = [
"winapi",
]
[[package]]
name = "num-integer"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.13.0"
@ -324,15 +356,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afb2e1c3ee07430c2cf76151675e583e0f19985fa6efae47d6848a3e2c824f85"
[[package]]
name = "panorama-core"
name = "panorama-daemon"
version = "0.1.0"
dependencies = [
"anyhow",
"clap",
"futures",
"inotify",
"log",
"serde",
"stderrlog",
"tokio",
"toml",
"xdg",
]
[[package]]
@ -482,6 +518,19 @@ version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
[[package]]
name = "stderrlog"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45a53e2eff3e94a019afa6265e8ee04cb05b9d33fe9f5078b14e4e391d155a38"
dependencies = [
"atty",
"chrono",
"log",
"termcolor",
"thread_local",
]
[[package]]
name = "strsim"
version = "0.10.0"
@ -517,6 +566,26 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "thread_local"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
dependencies = [
"lazy_static",
]
[[package]]
name = "time"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
dependencies = [
"libc",
"wasi",
"winapi",
]
[[package]]
name = "tokio"
version = "1.9.0"
@ -548,6 +617,15 @@ dependencies = [
"syn",
]
[[package]]
name = "toml"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
dependencies = [
"serde",
]
[[package]]
name = "unicode-segmentation"
version = "1.8.0"
@ -578,6 +656,12 @@ version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "winapi"
version = "0.3.9"
@ -608,3 +692,9 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "xdg"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57"

View file

@ -1,4 +1,4 @@
[workspace]
members = [
"core",
"daemon",
]

View file

View file

@ -1,37 +0,0 @@
#[macro_use]
extern crate serde;
extern crate futures;
mod config;
mod imap;
use std::path::PathBuf;
use clap::Clap;
use anyhow::Result;
use crate::config::Config;
/// Panorama core
#[derive(Debug, Clap)]
struct Options {
/// Config file path (defaults to XDG)
#[clap(long = "config", short = 'c')]
config_file: Option<PathBuf>,
}
async fn run_with_config(config: Config) -> Result<()> {
Ok(())
}
#[tokio::main]
async fn main() -> Result<()> {
let opts = Options::parse();
println!("{:?}", opts);
let (tx, mut rx) = watch::channel(());
loop {
}
}

View file

@ -1,5 +1,5 @@
[package]
name = "panorama-core"
name = "panorama-daemon"
version = "0.1.0"
edition = "2018"
@ -10,3 +10,7 @@ tokio = { version = "1.9.0", features = ["full"] }
clap = "3.0.0-beta.2"
futures = "0.3.16"
inotify = { version = "0.9.3", features = ["stream"] }
xdg = "2.2.0"
log = "0.4.14"
toml = "0.5.8"
stderrlog = "0.5.1"

View file

@ -1,33 +1,37 @@
mod watcher;
use std::path::{PathBuf, Path};
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
use anyhow::Result;
pub use self::watcher::spawn_config_watcher_system;
/// Configuration
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
pub struct Config {
/// Version of the config to use
/// (potentially for migration later?)
pub version: String,
/// Directory to store panorama-related data in
pub data_dir: PathBuf,
/// Mail accounts
#[serde(rename = "mail")]
pub mail_accounts: HashMap<String, MailAccountConfig>,
}
impl Config {
pub async fn from_file(path: impl AsRef<Path>) -> Result<Self> {
let mut file = File::open(path.as_ref())?;
let mut contents = Vec::new();
file.read_to_end(&mut contents)?;
let config = toml::from_slice(&contents)?;
Ok(config)
}
pub async fn from_file(path: impl AsRef<Path>) -> Result<Self> {
let mut file = File::open(path.as_ref())?;
let mut contents = Vec::new();
file.read_to_end(&mut contents)?;
let config = toml::from_slice(&contents)?;
Ok(config)
}
}
/// Configuration for a single mail account
@ -42,10 +46,13 @@ pub struct MailAccountConfig {
pub struct ImapConfig {
/// Host of the IMAP server (needs to be hostname for TLS)
pub server: String,
/// Port of the IMAP server
pub port: u16,
/// TLS
pub tls: TlsMethod,
/// Auth
#[serde(flatten)]
pub auth: ImapAuth,
@ -57,7 +64,6 @@ pub struct ImapConfig {
pub enum ImapAuth {
/// Use plain username/password authentication
#[serde(rename = "plain")]
#[allow(missing_docs)]
Plain { username: String, password: String },
}
@ -67,10 +73,12 @@ pub enum TlsMethod {
/// Perform TLS handshake immediately upon connection
#[serde(rename = "on")]
On,
/// Perform TLS handshake after issuing the STARTTLS command
#[serde(rename = "starttls")]
Starttls,
/// Don't perform TLS handshake at all (unsecured)
#[serde(rename = "off")]
Off,
}
}

View file

@ -1,9 +1,11 @@
use std::fs;
use std::path::{Path, PathBuf};
use anyhow::{Result, Context};
use anyhow::{Context, Result};
use futures::{future::TryFutureExt, stream::StreamExt};
use inotify::Inotify;
use tokio::{task::JoinHandle, sync::watch};
use inotify::{Inotify, WatchMask};
use tokio::{sync::watch, task::JoinHandle};
use xdg::BaseDirectories;
use super::Config;
@ -18,19 +20,15 @@ pub fn spawn_config_watcher_system() -> Result<(JoinHandle<()>, ConfigWatcher)>
if !config_home.exists() {
fs::create_dir_all(&config_home)?;
}
inotify
.add_watch(&config_home, WatchMask::CLOSE_WRITE)
.context("adding watch for config home")?;
// let config_file_path = config_home.join("panorama.toml");
// if config_file_path.exists() {
// inotify
// .add_watch(config_file_path, WatchMask::ALL_EVENTS)
// .context("adding watch for config file")?;
// }
debug!("watching {:?}", config_home);
let (config_tx, config_update) = watch::channel(Config::default());
let handle = tokio::spawn(
start_inotify_stream(inotify, config_home, config_tx).unwrap_or_else(report_err),
start_inotify_stream(inotify, config_home, config_tx).unwrap_or_else(|_err| todo!()),
);
Ok((handle, config_update))
}

1
daemon/src/imap.rs Normal file
View file

@ -0,0 +1 @@
pub struct ImapClient {}

66
daemon/src/main.rs Normal file
View file

@ -0,0 +1,66 @@
#[macro_use]
extern crate serde;
#[macro_use]
extern crate log;
#[macro_use]
extern crate futures;
mod config;
mod imap;
use anyhow::Result;
use clap::Clap;
use futures::future::FutureExt;
use tokio::sync::oneshot;
use crate::config::Config;
type ExitListener = oneshot::Receiver<()>;
/// The panorama daemon runs in the background and communicates with other panorama components over Unix sockets.
#[derive(Debug, Clap)]
struct Options {
// /// Config file path (defaults to XDG)
// #[clap(long = "config", short = 'c')]
// config_file: Option<PathBuf>,
/// Verbose mode (-v, -vv, -vvv, etc)
#[clap(short = 'v', long = "verbose", parse(from_occurrences))]
verbose: usize,
}
#[tokio::main]
async fn main() -> Result<()> {
let opt = Options::parse();
println!("{:?}", opt);
stderrlog::new()
.module(module_path!())
.verbosity(opt.verbose)
.init()
.unwrap();
let (_, mut config_watcher) = config::spawn_config_watcher_system()?;
loop {
let (exit_tx, exit_rx) = oneshot::channel();
let new_config = config_watcher.borrow().clone();
tokio::spawn(run_with_config(new_config, exit_rx));
// wait till the config has changed, then tell the current thread to stop
config_watcher.changed().await?;
let _ = exit_tx.send(());
}
}
async fn run_with_config(config: Config, exit: ExitListener) -> Result<()> {
println!("run with config: {:?}", config);
let mut exit = exit.fuse();
loop {
select! {
_ = exit => break,
}
}
Ok(())
}