Skip to main content

state_engine/
store.rs

1use crate::ports::required::{InMemoryClient, KVSClient, HttpClient};
2use crate::core::fixed_bits;
3use serde_json::Value;
4use std::collections::HashMap;
5
6pub struct Store<'a> {
7    in_memory: Option<&'a dyn InMemoryClient>,
8    kvs: Option<&'a dyn KVSClient>,
9    http: Option<&'a dyn HttpClient>,
10}
11
12impl<'a> Store<'a> {
13    pub fn new() -> Self {
14        Self {
15            in_memory: None,
16            kvs: None,
17            http: None,
18        }
19    }
20
21    pub fn with_in_memory(mut self, client: &'a dyn InMemoryClient) -> Self {
22        self.in_memory = Some(client);
23        self
24    }
25
26    pub fn with_kvs(mut self, client: &'a dyn KVSClient) -> Self {
27        self.kvs = Some(client);
28        self
29    }
30
31    pub fn with_http(mut self, client: &'a dyn HttpClient) -> Self {
32        self.http = Some(client);
33        self
34    }
35
36    pub fn get(&self, store_config: &HashMap<String, Value>) -> Option<Value> {
37        let client = store_config.get("client")?.as_u64()?;
38
39        match client {
40            fixed_bits::CLIENT_IN_MEMORY => {
41                let in_memory = self.in_memory.as_ref()?;
42                let key = store_config.get("key")?.as_str()?;
43                in_memory.get(key)
44            }
45            fixed_bits::CLIENT_KVS => {
46                let kvs = self.kvs.as_ref()?;
47                let key = store_config.get("key")?.as_str()?;
48                let value_str = kvs.get(key)?;
49                serde_json::from_str(&value_str).ok()
50            }
51            fixed_bits::CLIENT_HTTP => {
52                let http = self.http.as_ref()?;
53                let url = store_config.get("url")?.as_str()?;
54                let headers = store_config
55                    .get("headers")
56                    .and_then(|v| v.as_object())
57                    .map(|obj| obj.iter()
58                        .filter_map(|(k, v)| v.as_str().map(|s| (k.clone(), s.to_string())))
59                        .collect::<HashMap<String, String>>());
60                http.get(url, headers.as_ref())
61            }
62            _ => None,
63        }
64    }
65
66    pub fn set(
67        &self,
68        store_config: &HashMap<String, Value>,
69        value: Value,
70        ttl: Option<u64>,
71    ) -> Result<bool, String> {
72        let client = store_config
73            .get("client")
74            .and_then(|v| v.as_u64())
75            .ok_or_else(|| "Store::set: 'client' not found in store config".to_string())?;
76
77        match client {
78            fixed_bits::CLIENT_IN_MEMORY => {
79                let in_memory = self.in_memory.as_ref()
80                    .ok_or_else(|| "Store::set: InMemoryClient not configured".to_string())?;
81                let key = store_config.get("key").and_then(|v| v.as_str())
82                    .ok_or_else(|| "Store::set: 'key' not found in store config".to_string())?;
83                Ok(in_memory.set(key, value))
84            }
85            fixed_bits::CLIENT_KVS => {
86                let kvs = self.kvs.as_ref()
87                    .ok_or_else(|| "Store::set: KVSClient not configured".to_string())?;
88                let key = store_config.get("key").and_then(|v| v.as_str())
89                    .ok_or_else(|| "Store::set: 'key' not found in store config".to_string())?;
90                let serialized = serde_json::to_string(&value)
91                    .map_err(|e| format!("Store::set: JSON serialize error: {}", e))?;
92                let final_ttl = ttl.or_else(|| store_config.get("ttl").and_then(|v| v.as_u64()));
93                Ok(kvs.set(key, serialized, final_ttl))
94            }
95            fixed_bits::CLIENT_HTTP => {
96                let http = self.http.as_ref()
97                    .ok_or_else(|| "Store::set: HttpClient not configured".to_string())?;
98                let url = store_config.get("url").and_then(|v| v.as_str())
99                    .ok_or_else(|| "Store::set: 'url' not found in store config".to_string())?;
100                let headers = store_config
101                    .get("headers")
102                    .and_then(|v| v.as_object())
103                    .map(|obj| obj.iter()
104                        .filter_map(|(k, v)| v.as_str().map(|s| (k.clone(), s.to_string())))
105                        .collect::<HashMap<String, String>>());
106                Ok(http.set(url, value, headers.as_ref()))
107            }
108            _ => Err(format!("Store::set: unsupported client '{}'", client)),
109        }
110    }
111
112    pub fn delete(&self, store_config: &HashMap<String, Value>) -> Result<bool, String> {
113        let client = store_config
114            .get("client")
115            .and_then(|v| v.as_u64())
116            .ok_or_else(|| "Store::delete: 'client' not found in store config".to_string())?;
117
118        match client {
119            fixed_bits::CLIENT_IN_MEMORY => {
120                let in_memory = self.in_memory.as_ref()
121                    .ok_or_else(|| "Store::delete: InMemoryClient not configured".to_string())?;
122                let key = store_config.get("key").and_then(|v| v.as_str())
123                    .ok_or_else(|| "Store::delete: 'key' not found in store config".to_string())?;
124                Ok(in_memory.delete(key))
125            }
126            fixed_bits::CLIENT_KVS => {
127                let kvs = self.kvs.as_ref()
128                    .ok_or_else(|| "Store::delete: KVSClient not configured".to_string())?;
129                let key = store_config.get("key").and_then(|v| v.as_str())
130                    .ok_or_else(|| "Store::delete: 'key' not found in store config".to_string())?;
131                Ok(kvs.delete(key))
132            }
133            fixed_bits::CLIENT_HTTP => {
134                let http = self.http.as_ref()
135                    .ok_or_else(|| "Store::delete: HttpClient not configured".to_string())?;
136                let url = store_config.get("url").and_then(|v| v.as_str())
137                    .ok_or_else(|| "Store::delete: 'url' not found in store config".to_string())?;
138                let headers = store_config
139                    .get("headers")
140                    .and_then(|v| v.as_object())
141                    .map(|obj| obj.iter()
142                        .filter_map(|(k, v)| v.as_str().map(|s| (k.clone(), s.to_string())))
143                        .collect::<HashMap<String, String>>());
144                Ok(http.delete(url, headers.as_ref()))
145            }
146            _ => Err(format!("Store::delete: unsupported client '{}'", client)),
147        }
148    }
149}
150
151impl<'a> Default for Store<'a> {
152    fn default() -> Self {
153        Self::new()
154    }
155}