Skip to main content

scripting/
commodity.rs

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        // Lock the tags HashMap
60        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        // Fetch the value corresponding to the key
67        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}