daemon
This commit is contained in:
parent
04bd3e62b6
commit
5a9f847097
9 changed files with 190 additions and 60 deletions
92
Cargo.lock
generated
92
Cargo.lock
generated
|
@ -43,6 +43,19 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
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]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "3.0.0-beta.2"
|
version = "3.0.0-beta.2"
|
||||||
|
@ -301,6 +314,25 @@ dependencies = [
|
||||||
"winapi",
|
"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]]
|
[[package]]
|
||||||
name = "num_cpus"
|
name = "num_cpus"
|
||||||
version = "1.13.0"
|
version = "1.13.0"
|
||||||
|
@ -324,15 +356,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "afb2e1c3ee07430c2cf76151675e583e0f19985fa6efae47d6848a3e2c824f85"
|
checksum = "afb2e1c3ee07430c2cf76151675e583e0f19985fa6efae47d6848a3e2c824f85"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "panorama-core"
|
name = "panorama-daemon"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
"futures",
|
"futures",
|
||||||
"inotify",
|
"inotify",
|
||||||
|
"log",
|
||||||
"serde",
|
"serde",
|
||||||
|
"stderrlog",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"toml",
|
||||||
|
"xdg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -482,6 +518,19 @@ version = "1.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
|
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]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
|
@ -517,6 +566,26 @@ dependencies = [
|
||||||
"unicode-width",
|
"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]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.9.0"
|
version = "1.9.0"
|
||||||
|
@ -548,6 +617,15 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.5.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-segmentation"
|
name = "unicode-segmentation"
|
||||||
version = "1.8.0"
|
version = "1.8.0"
|
||||||
|
@ -578,6 +656,12 @@ version = "0.9.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
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]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
|
@ -608,3 +692,9 @@ name = "winapi-x86_64-pc-windows-gnu"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xdg"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"core",
|
"daemon",
|
||||||
]
|
]
|
||||||
|
|
|
@ -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 {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
[package]
|
[package]
|
||||||
name = "panorama-core"
|
name = "panorama-daemon"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
|
@ -10,3 +10,7 @@ tokio = { version = "1.9.0", features = ["full"] }
|
||||||
clap = "3.0.0-beta.2"
|
clap = "3.0.0-beta.2"
|
||||||
futures = "0.3.16"
|
futures = "0.3.16"
|
||||||
inotify = { version = "0.9.3", features = ["stream"] }
|
inotify = { version = "0.9.3", features = ["stream"] }
|
||||||
|
xdg = "2.2.0"
|
||||||
|
log = "0.4.14"
|
||||||
|
toml = "0.5.8"
|
||||||
|
stderrlog = "0.5.1"
|
|
@ -1,33 +1,37 @@
|
||||||
mod watcher;
|
mod watcher;
|
||||||
|
|
||||||
use std::path::{PathBuf, Path};
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
|
pub use self::watcher::spawn_config_watcher_system;
|
||||||
|
|
||||||
/// Configuration
|
/// Configuration
|
||||||
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
|
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
/// Version of the config to use
|
/// Version of the config to use
|
||||||
/// (potentially for migration later?)
|
/// (potentially for migration later?)
|
||||||
pub version: String,
|
pub version: String,
|
||||||
|
|
||||||
/// Directory to store panorama-related data in
|
/// Directory to store panorama-related data in
|
||||||
pub data_dir: PathBuf,
|
pub data_dir: PathBuf,
|
||||||
|
|
||||||
/// Mail accounts
|
/// Mail accounts
|
||||||
#[serde(rename = "mail")]
|
#[serde(rename = "mail")]
|
||||||
pub mail_accounts: HashMap<String, MailAccountConfig>,
|
pub mail_accounts: HashMap<String, MailAccountConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub async fn from_file(path: impl AsRef<Path>) -> Result<Self> {
|
pub async fn from_file(path: impl AsRef<Path>) -> Result<Self> {
|
||||||
let mut file = File::open(path.as_ref())?;
|
let mut file = File::open(path.as_ref())?;
|
||||||
let mut contents = Vec::new();
|
let mut contents = Vec::new();
|
||||||
file.read_to_end(&mut contents)?;
|
file.read_to_end(&mut contents)?;
|
||||||
let config = toml::from_slice(&contents)?;
|
let config = toml::from_slice(&contents)?;
|
||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configuration for a single mail account
|
/// Configuration for a single mail account
|
||||||
|
@ -42,10 +46,13 @@ pub struct MailAccountConfig {
|
||||||
pub struct ImapConfig {
|
pub struct ImapConfig {
|
||||||
/// Host of the IMAP server (needs to be hostname for TLS)
|
/// Host of the IMAP server (needs to be hostname for TLS)
|
||||||
pub server: String,
|
pub server: String,
|
||||||
|
|
||||||
/// Port of the IMAP server
|
/// Port of the IMAP server
|
||||||
pub port: u16,
|
pub port: u16,
|
||||||
|
|
||||||
/// TLS
|
/// TLS
|
||||||
pub tls: TlsMethod,
|
pub tls: TlsMethod,
|
||||||
|
|
||||||
/// Auth
|
/// Auth
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub auth: ImapAuth,
|
pub auth: ImapAuth,
|
||||||
|
@ -57,7 +64,6 @@ pub struct ImapConfig {
|
||||||
pub enum ImapAuth {
|
pub enum ImapAuth {
|
||||||
/// Use plain username/password authentication
|
/// Use plain username/password authentication
|
||||||
#[serde(rename = "plain")]
|
#[serde(rename = "plain")]
|
||||||
#[allow(missing_docs)]
|
|
||||||
Plain { username: String, password: String },
|
Plain { username: String, password: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,10 +73,12 @@ pub enum TlsMethod {
|
||||||
/// Perform TLS handshake immediately upon connection
|
/// Perform TLS handshake immediately upon connection
|
||||||
#[serde(rename = "on")]
|
#[serde(rename = "on")]
|
||||||
On,
|
On,
|
||||||
|
|
||||||
/// Perform TLS handshake after issuing the STARTTLS command
|
/// Perform TLS handshake after issuing the STARTTLS command
|
||||||
#[serde(rename = "starttls")]
|
#[serde(rename = "starttls")]
|
||||||
Starttls,
|
Starttls,
|
||||||
|
|
||||||
/// Don't perform TLS handshake at all (unsecured)
|
/// Don't perform TLS handshake at all (unsecured)
|
||||||
#[serde(rename = "off")]
|
#[serde(rename = "off")]
|
||||||
Off,
|
Off,
|
||||||
}
|
}
|
|
@ -1,9 +1,11 @@
|
||||||
|
use std::fs;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use anyhow::{Result, Context};
|
use anyhow::{Context, Result};
|
||||||
use futures::{future::TryFutureExt, stream::StreamExt};
|
use futures::{future::TryFutureExt, stream::StreamExt};
|
||||||
use inotify::Inotify;
|
use inotify::{Inotify, WatchMask};
|
||||||
use tokio::{task::JoinHandle, sync::watch};
|
use tokio::{sync::watch, task::JoinHandle};
|
||||||
|
use xdg::BaseDirectories;
|
||||||
|
|
||||||
use super::Config;
|
use super::Config;
|
||||||
|
|
||||||
|
@ -18,19 +20,15 @@ pub fn spawn_config_watcher_system() -> Result<(JoinHandle<()>, ConfigWatcher)>
|
||||||
if !config_home.exists() {
|
if !config_home.exists() {
|
||||||
fs::create_dir_all(&config_home)?;
|
fs::create_dir_all(&config_home)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
inotify
|
inotify
|
||||||
.add_watch(&config_home, WatchMask::CLOSE_WRITE)
|
.add_watch(&config_home, WatchMask::CLOSE_WRITE)
|
||||||
.context("adding watch for config home")?;
|
.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);
|
debug!("watching {:?}", config_home);
|
||||||
let (config_tx, config_update) = watch::channel(Config::default());
|
let (config_tx, config_update) = watch::channel(Config::default());
|
||||||
let handle = tokio::spawn(
|
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))
|
Ok((handle, config_update))
|
||||||
}
|
}
|
1
daemon/src/imap.rs
Normal file
1
daemon/src/imap.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub struct ImapClient {}
|
66
daemon/src/main.rs
Normal file
66
daemon/src/main.rs
Normal 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(())
|
||||||
|
}
|
Loading…
Reference in a new issue