#![feature(iterator_try_collect, never_type)] pub mod client; pub mod server; use anyhow::Result; use clap::{Parser, Subcommand}; use client::Client; use serde::Deserialize; use server::server; use std::{fs::read_to_string, net::SocketAddr, path::PathBuf}; pub type Serial = u64; #[derive(Parser)] struct Args { config: PathBuf, #[clap(subcommand)] action: Action, } #[derive(Subcommand)] enum Action { Daemon, List { peer: Option, }, Restore { peer: String, id: String, destination: PathBuf, }, Backup { path: PathBuf, }, } #[derive(Deserialize)] pub struct Config { storage: StorageConfig, server: ServerConfig, peer: Vec, } #[derive(Deserialize)] pub struct PeerConfig { name: String, address: SocketAddr, shared_secret: String, } #[derive(Deserialize)] pub struct ServerConfig { address: String, } #[derive(Deserialize)] pub struct StorageConfig { root: PathBuf, size: u64, versions: usize, upload_cooldown: u64, download_cooldown: u64, upload_speed: usize, download_speed: usize, } fn main() -> Result<()> { env_logger::init_from_env("LOG"); let args = Args::parse(); let config = read_to_string(&args.config)?; let config = toml::from_str::(&config)?; match args.action { Action::Daemon => server(config.into())?, Action::List { peer } => { let peers = config.peer.iter().filter(|p| { if let Some(pn) = &peer { pn == &p.name } else { true } }); for p in peers { println!("peer {:?}", p.name); let mut client = Client::new(p.address, &p.shared_secret)?; for (mtime, size, serial) in client.list()? { println!("\tserial={serial} mtime={mtime} size={size}") } client.quit()?; } } Action::Restore { id, destination, peer, } => todo!(), Action::Backup { path } => todo!(), } Ok(()) }