reactive_graph_net_http/behaviour/component/
json_rpc.rs

1use reactive_graph_behaviour_model_api::behaviour_validator;
2use reactive_graph_behaviour_model_api::prelude::*;
3use reactive_graph_behaviour_model_impl::entity_behaviour;
4use reactive_graph_graph::prelude::*;
5use reactive_graph_reactive_model_impl::ReactiveEntity;
6use serde_json::Value;
7use serde_json::json;
8use uuid::Uuid;
9
10use log::error;
11
12use reactive_graph_net_http_model::JsonRpcProperties::ERROR;
13use reactive_graph_net_http_model::JsonRpcProperties::JSON_RPC_VERSION;
14use reactive_graph_net_http_model::JsonRpcProperties::METHOD;
15use reactive_graph_net_http_model::JsonRpcProperties::PARAMS;
16use reactive_graph_net_http_model::UrlProperties::URL;
17use reactive_graph_runtime_model::ActionProperties::TRIGGER;
18use reactive_graph_std_result_model::ResultObjectProperties::RESULT;
19
20entity_behaviour!(JsonRpc, JsonRpcFactory, JsonRpcFsm, JsonRpcBehaviourTransitions, JsonRpcValidator);
21
22behaviour_validator!(
23    JsonRpcValidator,
24    Uuid,
25    ReactiveEntity,
26    METHOD.as_ref(),
27    JSON_RPC_VERSION.as_ref(),
28    PARAMS.as_ref(),
29    ERROR.as_ref(),
30    RESULT.as_ref(),
31    URL.as_ref()
32);
33
34impl BehaviourInit<Uuid, ReactiveEntity> for JsonRpcBehaviourTransitions {}
35
36impl BehaviourConnect<Uuid, ReactiveEntity> for JsonRpcBehaviourTransitions {
37    fn connect(&self) -> Result<(), BehaviourConnectFailed> {
38        let reactive_instance = self.reactive_instance.clone();
39        self.property_observers.observe_with_handle(TRIGGER.as_ref(), move |trigger: &Value| {
40            if !trigger.as_bool().unwrap_or(false) {
41                return;
42            }
43            let Some(method) = reactive_instance.as_string(METHOD) else {
44                return;
45            };
46            let Some(url) = reactive_instance.as_string(URL) else {
47                return;
48            };
49            let Some(params) = reactive_instance.get(PARAMS) else {
50                return;
51            };
52            if !params.is_object() && !params.is_array() {
53                // params must be either object or array
54                return;
55            }
56            let json_rpc_version = reactive_instance
57                .as_string(JSON_RPC_VERSION)
58                .unwrap_or_else(|| JSON_RPC_VERSION.default_value().to_string());
59
60            // TODO: increase ID (new property)
61            let payload = json!({
62                "jsonrpc": json_rpc_version,
63                "method": method,
64                "params": params,
65                "id": 1_u32
66            });
67
68            let request = ureq::post(url.as_str()).set("content-type", "application/json");
69
70            let result = request.send_json(payload);
71            match result {
72                Ok(response) => match response.into_json() {
73                    Ok(response_payload) => {
74                        let json_rpc_response: Value = response_payload;
75                        match json_rpc_response.get(RESULT.as_ref()) {
76                            Some(result) => {
77                                reactive_instance.set(RESULT, result.clone());
78                                reactive_instance.set(ERROR, json!({}));
79                            }
80                            None => {
81                                if let Some(error) = json_rpc_response.get(ERROR.as_ref()) {
82                                    reactive_instance.set(ERROR, error.clone());
83                                    reactive_instance.set(RESULT, json!({}));
84                                }
85                            }
86                        }
87                    }
88                    Err(e) => error!("Failed to parse response as JSON: {}", e.to_string()),
89                },
90                Err(e) => {
91                    error!("Failed to send request: {}", e.to_string());
92                }
93            }
94        });
95        Ok(())
96    }
97}
98
99impl BehaviourShutdown<Uuid, ReactiveEntity> for JsonRpcBehaviourTransitions {}
100impl BehaviourTransitions<Uuid, ReactiveEntity> for JsonRpcBehaviourTransitions {}