assistant_daemon 0.1.0

Daemon program for providing many features.
use anyhow::{bail, Ok, Result};
use async_trait::async_trait;
use std::sync::Arc;
use std::{collections::HashMap, path::PathBuf};
use tokio::sync::RwLock;

use crate::feature::FeatureManager;
use crate::generated::{Config, GetConfigResponse, UpdateConfigRequest, UpdateConfigResponse};
use crate::{
    config::ConfigManager,
    generated::{
        Feature, FeatureUsecase, GetFeatureStatusRequest, GetFeatureStatusResponse,
        GetFeaturesResponse, ToggleFeatureRequest, ToggleFeatureResponse,
    },
};

pub mod wp;
pub use wp::WallpaperUsecaseImpl;
pub mod sshpm;
pub use sshpm::SshpmUsecaseImpl;
#[cfg(target_os = "windows")]
pub mod wslpf;
#[cfg(target_os = "windows")]
pub use wslpf::WslpfUsecaseImpl;

#[derive(Clone)]
pub struct FeatureUsecaseImpl {
    cfg_mngr: Arc<dyn ConfigManager<serde_json::Value>>,
}

impl FeatureUsecaseImpl {
    pub fn new(cfg_mngr: Arc<dyn ConfigManager<serde_json::Value>>) -> Self {
        FeatureUsecaseImpl { cfg_mngr }
    }
}

#[async_trait]
impl FeatureUsecase for FeatureUsecaseImpl {
    async fn toggle_feature(&self, request: ToggleFeatureRequest) -> Result<ToggleFeatureResponse> {
        let config_opt = self.cfg_mngr.get().await?;
        if config_opt.is_none() {
            bail!("configuration is not ready");
        }
        let mut config: serde_json::Value = config_opt.unwrap();

        let new_status = match config.as_object_mut() {
            Some(co) => {
                match co.get_mut("features") {
                    Some(ft) => {
                        match ft.get_mut(&request.feature) {
                            Some(f) => {
                                match f.get_mut("status") {
                                    Some(old_status) => {
                                        if let Some(old_status) = old_status.as_bool() {
                                            let new_status: bool = !old_status;
                                            f.as_object_mut().unwrap().insert(
                                                "status".to_string(),
                                                serde_json::Value::Bool(new_status),
                                            );
                                            new_status
                                        } else {
                                            // if it is not bool, assume it is false, simply overide with true
                                            f.as_object_mut().unwrap().insert(
                                                "status".to_string(),
                                                serde_json::Value::Bool(true),
                                            );
                                            true
                                        }
                                    }
                                    None => {
                                        f.as_object_mut().unwrap().insert(
                                            "status".to_string(),
                                            serde_json::Value::Bool(true),
                                        );
                                        true
                                    }
                                }
                            }
                            None => {
                                let mut map = serde_json::Map::new();
                                map.insert("status".into(), serde_json::Value::Bool(true));
                                ft.as_object_mut().unwrap().insert(
                                    request.feature.clone(),
                                    serde_json::Value::Object(map),
                                );
                                true
                            }
                        }
                    }
                    None => {
                        let mut map = serde_json::Map::new();
                        map.insert("status".into(), serde_json::Value::Bool(true));
                        let mut fmap = serde_json::Map::new();
                        fmap.insert(request.feature.clone(), serde_json::Value::Object(map));
                        co.insert("features".to_string(), serde_json::Value::Object(fmap));
                        true
                    }
                }
            }
            None => {
                let mut map = serde_json::Map::new();
                map.insert("status".into(), serde_json::Value::Bool(true));
                let mut fmap = serde_json::Map::new();
                fmap.insert(request.feature.clone(), serde_json::Value::Object(map));

                let mut co = serde_json::Map::new();
                co.insert("features".to_string(), serde_json::Value::Object(fmap));

                config = serde_json::Value::Object(co);
                true
            }
        };
        self.cfg_mngr.update(config.clone()).await?;
        Ok(ToggleFeatureResponse { status: new_status })
    }

    async fn get_features(&self) -> Result<GetFeaturesResponse> {
        let config_opt = self.cfg_mngr.get().await?;
        if config_opt.is_none() {
            bail!("configuration is not ready");
        }
        let config: serde_json::Value = config_opt.unwrap();
        let features = serde_json::from_value(config.get("features").unwrap().clone())?;
        Ok(GetFeaturesResponse { features })
    }

    async fn get_feature_status(
        &self,
        request: GetFeatureStatusRequest,
    ) -> Result<GetFeatureStatusResponse> {
        let config_opt = self.cfg_mngr.get().await?;
        if config_opt.is_none() {
            bail!("configuration is not ready");
        }
        let config: serde_json::Value = config_opt.unwrap();
        match config.get("features") {
            Some(ft) => match ft.get(&request.feature) {
                Some(f) => match f.get("status") {
                    Some(status) => match status.as_bool() {
                        Some(status) => Ok(GetFeatureStatusResponse { status }),
                        None => Ok(GetFeatureStatusResponse { status: false }),
                    },
                    None => Ok(GetFeatureStatusResponse { status: false }),
                },
                None => Ok(GetFeatureStatusResponse { status: false }),
            },
            None => Ok(GetFeatureStatusResponse { status: false }),
        }
    }

    async fn update_config(&self, request: UpdateConfigRequest) -> Result<UpdateConfigResponse> {
        let config_opt = self.cfg_mngr.get().await?;
        if config_opt.is_none() {
            bail!("configuration is not ready");
        }

        let config = serde_json::to_value(request.config)?;
        self.cfg_mngr.update(config.clone()).await?;

        let config: serde_json::Value = config_opt.unwrap();
        Ok(UpdateConfigResponse {
            config: serde_json::from_value(config)?,
        })
    }

    async fn get_config(&self) -> Result<GetConfigResponse> {
        let config_opt = self.cfg_mngr.get().await?;
        if config_opt.is_none() {
            bail!("configuration is not ready");
        }
        Ok(GetConfigResponse {
            config: serde_json::from_value(config_opt.unwrap())?,
        })
    }
}