reactive_graph_sys_binary/behaviour/component/
load_binary_data.rs

1use std::fs::File;
2use std::io::Read;
3use std::path::Path;
4
5use base64::Engine;
6use base64::engine::general_purpose::STANDARD;
7use mime_guess::from_path;
8use reactive_graph_behaviour_model_api::behaviour_validator;
9use reactive_graph_behaviour_model_api::prelude::*;
10use reactive_graph_behaviour_model_impl::entity_behaviour;
11use reactive_graph_graph::prelude::*;
12use reactive_graph_reactive_model_impl::ReactiveEntity;
13use reactive_graph_runtime_model::ActionProperties::TRIGGER;
14use serde_json::Value;
15use serde_json::json;
16use uuid::Uuid;
17
18use reactive_graph_sys_binary_model::BinaryDataProperties::DATA_URL;
19use reactive_graph_sys_file_model::FileProperties::FILENAME;
20
21entity_behaviour!(
22    LoadBinaryData,
23    LoadBinaryDataFactory,
24    LoadBinaryDataFsm,
25    LoadBinaryDataBehaviourTransitions,
26    LoadBinaryDataValidator
27);
28
29behaviour_validator!(LoadBinaryDataValidator, Uuid, ReactiveEntity, TRIGGER.as_ref(), FILENAME.as_ref(), DATA_URL.as_ref());
30
31impl BehaviourInit<Uuid, ReactiveEntity> for LoadBinaryDataBehaviourTransitions {
32    fn init(&self) -> Result<(), BehaviourInitializationFailed> {
33        if self.reactive_instance.as_bool(TRIGGER).unwrap_or(false) {
34            if let Some(value) = self.reactive_instance.as_string(FILENAME).and_then(load_binary_data) {
35                self.reactive_instance.set(DATA_URL, value);
36            }
37        }
38        Ok(())
39    }
40}
41
42impl BehaviourConnect<Uuid, ReactiveEntity> for LoadBinaryDataBehaviourTransitions {
43    fn connect(&self) -> Result<(), BehaviourConnectFailed> {
44        let reactive_instance = self.reactive_instance.clone();
45        self.property_observers.observe_with_handle(TRIGGER.as_ref(), move |trigger: &Value| {
46            if !trigger.as_bool().unwrap_or(false) {
47                // Invalid type
48                return;
49            }
50            if let Some(value) = reactive_instance.as_string(FILENAME).and_then(load_binary_data) {
51                reactive_instance.set(DATA_URL, value);
52            }
53        });
54        let reactive_instance = self.reactive_instance.clone();
55        self.property_observers.observe_with_handle(FILENAME.as_ref(), move |filename: &Value| {
56            if let Some(value) = filename.as_str().map(String::from).and_then(load_binary_data) {
57                reactive_instance.set(DATA_URL, value);
58            }
59        });
60        Ok(())
61    }
62}
63
64impl BehaviourShutdown<Uuid, ReactiveEntity> for LoadBinaryDataBehaviourTransitions {}
65impl BehaviourTransitions<Uuid, ReactiveEntity> for LoadBinaryDataBehaviourTransitions {}
66
67fn load_binary_data(filename: String) -> Option<Value> {
68    let filename = shellexpand::tilde(&filename);
69    let path = Path::new(filename.as_ref());
70    File::open(path).ok().and_then(|mut file| {
71        let mut buffer = Vec::new();
72        let _ = file.read_to_end(&mut buffer);
73        infer::get(&buffer)
74            .map(|kind| kind.mime_type().to_string())
75            .or_else(|| from_path(path).first().map(|x| x.to_string()))
76            .map(|mime_type| json!(format!("data:{};base64,{}", mime_type, STANDARD.encode(&buffer))))
77    })
78}