reactive_graph_sys_config/behaviour/component/
config_file.rs

1use std::path::Path;
2
3use log::error;
4use reactive_graph_behaviour_model_api::behaviour_validator;
5use reactive_graph_behaviour_model_api::prelude::*;
6use reactive_graph_behaviour_model_impl::entity_behaviour;
7use reactive_graph_graph::prelude::*;
8use reactive_graph_reactive_model_impl::ReactiveEntity;
9use reactive_graph_runtime_model::ActionProperties::TRIGGER;
10use serde_json::Value;
11use uuid::Uuid;
12
13use reactive_graph_std_result_model::ResultObjectProperties::RESULT;
14use reactive_graph_sys_file_model::FileProperties::FILENAME;
15
16entity_behaviour!(ConfigFile, ConfigFileFactory, ConfigFileFsm, ConfigFileBehaviourTransitions, ConfigFileValidator);
17
18behaviour_validator!(ConfigFileValidator, Uuid, ReactiveEntity, TRIGGER.as_ref(), RESULT.as_ref(), FILENAME.as_ref());
19
20impl BehaviourInit<Uuid, ReactiveEntity> for ConfigFileBehaviourTransitions {
21    fn init(&self) -> Result<(), BehaviourInitializationFailed> {
22        if let Some(data) = self.reactive_instance.as_string(FILENAME).and_then(read_toml) {
23            self.reactive_instance.set(RESULT, data);
24        }
25        Ok(())
26    }
27}
28
29impl BehaviourConnect<Uuid, ReactiveEntity> for ConfigFileBehaviourTransitions {
30    fn connect(&self) -> Result<(), BehaviourConnectFailed> {
31        let reactive_instance = self.reactive_instance.clone();
32        self.property_observers.observe_with_handle(TRIGGER.as_ref(), move |trigger: &Value| {
33            if !trigger.as_bool().unwrap_or(false) {
34                return;
35            }
36            if let Some(data) = reactive_instance.as_string(FILENAME).and_then(read_toml) {
37                reactive_instance.set(RESULT, data);
38            }
39        });
40        Ok(())
41    }
42}
43
44impl BehaviourShutdown<Uuid, ReactiveEntity> for ConfigFileBehaviourTransitions {}
45impl BehaviourTransitions<Uuid, ReactiveEntity> for ConfigFileBehaviourTransitions {}
46
47fn read_toml(filename: String) -> Option<Value> {
48    let filename = shellexpand::tilde(&filename);
49    let path = Path::new(filename.as_ref());
50    let toml_config = std::fs::read_to_string(path);
51    match toml_config {
52        Ok(toml_config) => {
53            let data = toml::from_str::<Value>(toml_config.as_str());
54            match data {
55                Ok(data) => Some(data),
56                Err(e) => {
57                    error!("Failed to parse config file {}: {}", filename, e);
58                    None
59                }
60            }
61        }
62        Err(e) => {
63            error!("config file {} does not exist: {}", filename, e);
64            None
65        }
66    }
67}