cyndikator 0.2.0

A cli rss reader
use std::process::Command;
use std::time::Duration;

use crate::db::Database;
use cyndikator_dispatch::{Action, Event};

use log::{debug, error};
use notify_rust::Notification;
use wait_timeout::ChildExt;

pub struct Invoker<'a> {
    db: &'a mut Database,
}

impl<'a> Invoker<'a> {
    pub fn new(db: &'a mut Database) -> Invoker {
        Invoker { db }
    }

    pub fn invoke(&mut self, action: &Action, event: &Event) {
        match action {
            Action::Notify => {
                debug!(
                    "dispatching event {} {} {} {}",
                    event.feed_title.as_deref().unwrap_or("''"),
                    event.title.as_deref().unwrap_or("''"),
                    event.feed_url,
                    event.url.as_deref().unwrap_or("''"),
                );

                let res = Notification::new()
                    .summary(event.title.as_deref().unwrap_or_else(|| "(untitled event)"))
                    .body(event.url.as_deref().unwrap_or_else(|| ""))
                    .show();

                if let Err(err) = res {
                    error!("error notifing {}", err)
                }
            }

            Action::Record => {
                debug!(
                    "recording event {} {} {} {}",
                    event.feed_title.as_deref().unwrap_or("''"),
                    event.title.as_deref().unwrap_or("''"),
                    event.feed_url,
                    event.url.as_deref().unwrap_or("''"),
                );

                let res = self.db.record(
                    &event.feed_url,
                    event.title.as_deref(),
                    event.url.as_deref(),
                    event.description.as_deref(),
                    &event.categories,
                );

                if let Err(err) = res {
                    error!("error recording {}", err)
                }
            }

            Action::Exec(cmd) => {
                debug!(
                    "execing event {} {} {} {} `{}`",
                    event.feed_title.as_deref().unwrap_or("''"),
                    event.title.as_deref().unwrap_or("''"),
                    event.feed_url,
                    event.url.as_deref().unwrap_or("''"),
                    cmd,
                );

                let res = shell_exec(cmd);

                if let Err(err) = res {
                    error!("error execing {}", err)
                }
            }
        };
    }
}

fn shell_exec(cmd: &str) -> Result<(), std::io::Error> {
    let mut child = if cfg!(target_os = "windows") {
        Command::new("cmd").args(&["/C", cmd]).spawn()?
    } else {
        Command::new("sh").args(&["-c", cmd]).spawn()?
    };

    child.wait_timeout(Duration::from_secs(30))?;

    Ok(())
}