use crate::daemon::{Answer, AnswerErr, Command as OtherCommand}; use crate::run_path; use anyhow::{Context, Result}; use clap::{Parser, Subcommand}; use std::net::Shutdown; use std::os::unix::net::UnixStream; use std::time::Duration; #[derive(Parser)] #[command(name = "timers")] /// A simple timer daemon/cli. pub struct Cli { #[command(subcommand)] pub command: Command, #[arg(short, long)] #[clap(default_value_t = format!("{}/timers.socket", run_path()))] pub socket: String, } #[derive(Debug, Subcommand)] pub enum Command { /// Run as daemon #[clap(visible_alias = "d")] Daemon { /// do not send notifications #[arg(short, long)] no_notify: bool, }, /// Add a timer #[clap(visible_alias = "a")] Add { /// name of the timer name: String, /// duration of the timer duration: humantime::Duration, }, /// List timers #[clap(visible_alias = "l")] List, /// Remove a timer #[clap(visible_alias = "r")] Remove { /// name of the timer to remove name: String, }, /// Pomodoro specific command #[command(subcommand)] #[clap(visible_alias = "p")] Pomodoro(PomodoroCommand), } #[derive(Debug, Subcommand)] pub enum PomodoroCommand { /// Start pomodoro #[clap(visible_alias = "s")] Start { /// duration to work for #[arg(long)] #[clap(default_value_t = Duration::from_secs(25 * 60).into())] work: humantime::Duration, /// duration for short pauses #[arg(long)] #[clap(default_value_t = Duration::from_secs(5 * 60).into())] pause: humantime::Duration, /// duration for long pauses #[arg(long)] #[clap(default_value_t = Duration::from_secs(10 * 60).into())] long_pause: humantime::Duration, /// number of short pauses till long pause #[arg(long)] #[clap(default_value_t = 3)] pauses_till_long: u64, }, /// Stop the pomodoro #[clap(visible_alias = "p")] Remove, /// List the pomodoro settings and remaining duration #[clap(visible_alias = "l")] List, } fn get_stream(socket_path: &String) -> Result { UnixStream::connect(socket_path) .context(format!("Could not connect to socket {}!", socket_path)) } pub fn send_command(socket_path: &String, command: OtherCommand) -> Result { let stream = get_stream(socket_path)?; serde_cbor::to_writer(&stream, &command).context("Could not write command!")?; stream .shutdown(Shutdown::Write) .context("Could not shutdown write!")?; let answer: Result = serde_cbor::from_reader(&stream).context("Could not read answer!")?; Ok(answer?) }