1use std::collections::HashMap;
2use std::sync::{Arc, Mutex};
3
4use finance::commodity::{Commodity, CommodityBuilder};
5use rust_i18n::t;
6use wasmtime::{Engine, Linker, Module, Store};
7
8use crate::error::HookError;
9use crate::wrappers::{
10 DataStore, wrap_wasm_str_list_get, wrap_wasm_str_map, wrap_wasm_str_transform,
11};
12
13async fn update(
14 commodity: Commodity,
15 tags: Arc<Mutex<HashMap<String, String>>>,
16 script: &[u8],
17) -> Result<Commodity, HookError> {
18 let engine = Engine::default();
19 let mut linker = Linker::new(&engine);
20 let mut builder = CommodityBuilder::new();
21 builder.id(commodity.id);
22
23 let store_data = Arc::new(DataStore {
24 data: Mutex::new((builder, tags.clone())),
25 memory: Mutex::new(None),
26 });
27
28 let mut store = Store::new(&engine, store_data.clone());
29
30 let module = Module::new(store.engine(), script).map_err(|e| {
31 tracing::error!("{}: {}", t!("Module creation error"), e);
32 HookError::WASM(e)
33 })?;
34
35 let get_tag_list = wrap_wasm_str_list_get(&mut store, |data| {
36 let tags = data
37 .1
38 .lock()
39 .map_err(|_| anyhow::anyhow!("Failed to lock tags"))?;
40 tracing::info!("{:?}", tags.keys().cloned());
41 Ok(tags.keys().cloned().collect())
42 });
43
44 linker.define(&store, "env", "get_tag_list", get_tag_list)?;
45
46 let update_tag = wrap_wasm_str_map(&mut store, |data, key, value| {
47 let mut tags = data
48 .1
49 .lock()
50 .map_err(|_| anyhow::anyhow!("Failed to lock tags"))?;
51 tracing::info!("Inserting {key:?} {value:?}");
52 tags.insert(key, value);
53 Ok(())
54 });
55
56 linker.define(&store, "env", "update_tag", update_tag)?;
57
58 let get_tag = wrap_wasm_str_transform(&mut store, |data, key| {
59 let tags = data
61 .1
62 .lock()
63 .map_err(|_| anyhow::anyhow!("Failed to lock tags HashMap"))?;
64
65 tracing::info!("Found value: {:?}", tags.get(&key).cloned());
66 tags.get(&key)
68 .cloned()
69 .ok_or_else(|| anyhow::anyhow!("Key not found in tags: {key}"))
70 });
71
72 linker.define(&store, "env", "get_tag", get_tag)?;
73
74 let instance = linker.instantiate(&mut store, &module)?;
75 if let Some(memory) = instance.get_memory(&mut store, "memory") {
76 store_data.memory.lock()?.replace(memory);
77 } else {
78 tracing::error!("{}", t!("WASM memory access problem"));
79 return Err(HookError::WASMMem);
80 }
81
82 let process = instance.get_typed_func::<(), ()>(&mut store, "process")?;
83 process.call(&mut store, ())?;
84
85 tracing::info!("{:?}", store_data.clone().data.lock()?.1);
86
87 let result = store_data.clone().data.lock()?.0.build()?;
88 Ok(result)
89}
90
91pub async fn apply_commodity_hook(
92 commodity: Commodity,
93 tags: Arc<Mutex<HashMap<String, String>>>,
94 hook: &[u8],
95) -> Result<Commodity, HookError> {
96 let updated = update(commodity, tags, hook).await?;
97 Ok(updated)
98}