1
use std::collections::HashMap;
2
use std::sync::{Arc, Mutex};
3

            
4
use finance::commodity::{Commodity, CommodityBuilder};
5
use rust_i18n::t;
6
use wasmtime::{Engine, Linker, Module, Store};
7

            
8
use crate::error::HookError;
9
use crate::wrappers::{
10
    DataStore, wrap_wasm_str_list_get, wrap_wasm_str_map, wrap_wasm_str_transform,
11
};
12

            
13
38
async fn update(
14
38
    commodity: Commodity,
15
38
    tags: Arc<Mutex<HashMap<String, String>>>,
16
38
    script: &[u8],
17
38
) -> Result<Commodity, HookError> {
18
38
    let engine = Engine::default();
19
38
    let mut linker = Linker::new(&engine);
20
38
    let mut builder = CommodityBuilder::new();
21
38
    builder.id(commodity.id);
22

            
23
38
    let store_data = Arc::new(DataStore {
24
38
        data: Mutex::new((builder, tags.clone())),
25
38
        memory: Mutex::new(None),
26
38
    });
27

            
28
38
    let mut store = Store::new(&engine, store_data.clone());
29

            
30
38
    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
38
    let get_tag_list = wrap_wasm_str_list_get(&mut store, |data| {
36
38
        let tags = data
37
38
            .1
38
38
            .lock()
39
38
            .map_err(|_| anyhow::anyhow!("Failed to lock tags"))?;
40
38
        tracing::info!("{:?}", tags.keys().cloned());
41
38
        Ok(tags.keys().cloned().collect())
42
38
    });
43

            
44
38
    linker.define(&store, "env", "get_tag_list", get_tag_list)?;
45

            
46
57
    let update_tag = wrap_wasm_str_map(&mut store, |data, key, value| {
47
57
        let mut tags = data
48
57
            .1
49
57
            .lock()
50
57
            .map_err(|_| anyhow::anyhow!("Failed to lock tags"))?;
51
57
        tracing::info!("Inserting {key:?} {value:?}");
52
57
        tags.insert(key, value);
53
57
        Ok(())
54
57
    });
55

            
56
38
    linker.define(&store, "env", "update_tag", update_tag)?;
57

            
58
38
    let get_tag = wrap_wasm_str_transform(&mut store, |data, key| {
59
        // Lock the tags HashMap
60
19
        let tags = data
61
19
            .1
62
19
            .lock()
63
19
            .map_err(|_| anyhow::anyhow!("Failed to lock tags HashMap"))?;
64

            
65
19
        tracing::info!("Found value: {:?}", tags.get(&key).cloned());
66
        // Fetch the value corresponding to the key
67
19
        tags.get(&key)
68
19
            .cloned()
69
19
            .ok_or_else(|| anyhow::anyhow!("Key not found in tags: {key}"))
70
19
    });
71

            
72
38
    linker.define(&store, "env", "get_tag", get_tag)?;
73

            
74
38
    let instance = linker.instantiate(&mut store, &module)?;
75
38
    if let Some(memory) = instance.get_memory(&mut store, "memory") {
76
38
        store_data.memory.lock()?.replace(memory);
77
    } else {
78
        tracing::error!("{}", t!("WASM memory access problem"));
79
        return Err(HookError::WASMMem);
80
    }
81

            
82
38
    let process = instance.get_typed_func::<(), ()>(&mut store, "process")?;
83
38
    process.call(&mut store, ())?;
84

            
85
38
    tracing::info!("{:?}", store_data.clone().data.lock()?.1);
86

            
87
38
    let result = store_data.clone().data.lock()?.0.build()?;
88
38
    Ok(result)
89
38
}
90

            
91
38
pub async fn apply_commodity_hook(
92
38
    commodity: Commodity,
93
38
    tags: Arc<Mutex<HashMap<String, String>>>,
94
38
    hook: &[u8],
95
38
) -> Result<Commodity, HookError> {
96
38
    let updated = update(commodity, tags, hook).await?;
97
38
    Ok(updated)
98
38
}