userd 0.2.0

A user daemon, managing services and regular running of jobs, in user space.
use futures::{FutureExt, future::BoxFuture};
use std::path::PathBuf;

use crate::prelude::*;

pub(crate) struct File {
    filename: PathBuf,
    negate: bool,
    check: config::ContentCheck,
    update_check: config::UpdateCheck,
    last_content: ccutils::sync::ArcRwLock<String>,
}

impl File {
    pub(crate) fn new(
        filename: PathBuf,
        negate: bool,
        check: config::ContentCheck,
        update_check: config::UpdateCheck,
    ) -> Self {
        Self {
            filename,
            negate,
            check,
            update_check,
            last_content: Default::default(),
        }
    }
}

impl super::Condition for File {
    fn check(&self) -> BoxFuture<'static, Result<bool>> {
        let content = std::fs::read_to_string(&self.filename);
        let negate = self.negate;
        let check = self.check.clone();
        let last_content = self.last_content.clone();
        async move {
            let content = content?;
            let r = match check {
                config::ContentCheck::Contains { value } => content.contains(&value),
            };
            *last_content.write().unwrap() = content;
            Ok(r != negate)
        }
        .boxed()
    }
    fn wait_for_change(&self) -> BoxFuture<'static, Result<()>> {
        let filename = self.filename.clone();
        let last_content = self.last_content.clone();
        let update_check = self.update_check.clone();
        async move {
            loop {
                match update_check {
                    config::UpdateCheck::Watch => {
                        utils::async_watch(filename.clone()).await?;
                    }
                    config::UpdateCheck::Every { duration } => {
                        tokio::time::sleep(duration).await;
                    }
                }

                let content = std::fs::read_to_string(&filename)?;
                if content != *last_content.read().unwrap() {
                    log::info!(
                        "File {:?} content has changed from '{}' to '{}'.",
                        filename,
                        content,
                        last_content.read().unwrap()
                    );
                    break;
                }
            }
            Ok(())
        }
        .boxed()
    }
}