1use scripting::runtime::{alloc_commodity_ref, alloc_ratio_ref, alloc_string_ref, read_string_arg};
6use server::command::account::{ListAccounts, ListAccountsForManage};
7use wasmtime::{ArrayRef, Caller, Linker, Rooted, StructRef};
8
9use crate::session::SessionData;
10
11mod balance;
12mod create;
13mod list;
14#[cfg(test)]
15mod tests;
16
17pub const REGISTERED_COMMANDS: &[&str] = &[
18 "create-account",
19 "list-accounts",
20 "list-accounts-for-manage",
21 "get-account-for-manage",
22 "set-account-tag",
23 "get-account",
24 "get-account-commodities",
25 "get-balance",
26 "get-balances",
27];
28
29pub fn register(linker: &mut Linker<SessionData>) -> wasmtime::Result<()> {
30 register_readonly(linker)?;
31 register_mutators(linker)?;
32 Ok(())
33}
34
35pub fn register_readonly(linker: &mut Linker<SessionData>) -> wasmtime::Result<()> {
36 linker.func_wrap_async(
37 "nomi",
38 "account_list_accounts",
39 |mut caller: Caller<'_, SessionData>,
40 ()|
41 -> Box<
42 dyn std::future::Future<Output = wasmtime::Result<Option<Rooted<StructRef>>>> + Send,
43 > {
44 Box::new(async move {
45 let user_id = caller.data().ctx().user_id;
46 let result = ListAccounts::new().user_id(user_id).run().await;
47 let entries = list::list_account_entries("list-accounts", result)?;
48 list::alloc_account_chain(&mut caller, entries).await
49 })
50 },
51 )?;
52 linker.func_wrap_async(
53 "nomi",
54 "account_get_account",
55 |mut caller: Caller<'_, SessionData>,
56 (key_arg,): (Option<Rooted<ArrayRef>>,)|
57 -> Box<
58 dyn std::future::Future<Output = wasmtime::Result<Option<Rooted<StructRef>>>> + Send,
59 > {
60 Box::new(async move {
61 let user_id = caller.data().ctx().user_id;
62 let key = read_string_arg(&mut caller, key_arg)?;
63 list::run_get_account(&mut caller, user_id, key).await
64 })
65 },
66 )?;
67 linker.func_wrap_async(
68 "nomi",
69 "account_get_balance",
70 |mut caller: Caller<'_, SessionData>,
71 (id_arg,): (Option<Rooted<ArrayRef>>,)|
72 -> Box<
73 dyn std::future::Future<Output = wasmtime::Result<Option<Rooted<StructRef>>>> + Send,
74 > {
75 Box::new(async move {
76 let user_id = caller.data().ctx().user_id;
77 let id = read_string_arg(&mut caller, id_arg)?;
78 let (numer, denom) = balance::run_get_balance_single(user_id, id).await?;
79 Ok(Some(alloc_ratio_ref(&mut caller, numer, denom)?))
80 })
81 },
82 )?;
83 linker.func_wrap_async(
84 "nomi",
85 "account_get_balances",
86 |mut caller: Caller<'_, SessionData>,
87 (id_arg,): (Option<Rooted<ArrayRef>>,)|
88 -> Box<
89 dyn std::future::Future<Output = wasmtime::Result<Option<Rooted<StructRef>>>> + Send,
90 > {
91 Box::new(async move {
92 let user_id = caller.data().ctx().user_id;
93 let id = read_string_arg(&mut caller, id_arg)?;
94 let lines = balance::run_get_balances(user_id, id).await?;
95 balance::alloc_string_pair_chain(&mut caller, lines).await
96 })
97 },
98 )?;
99 linker.func_wrap_async(
100 "nomi",
101 "account_get_account_commodities",
102 |mut caller: Caller<'_, SessionData>,
103 (id_arg,): (Option<Rooted<ArrayRef>>,)|
104 -> Box<
105 dyn std::future::Future<Output = wasmtime::Result<Option<Rooted<StructRef>>>> + Send,
106 > {
107 Box::new(async move {
108 let user_id = caller.data().ctx().user_id;
109 let id = read_string_arg(&mut caller, id_arg)?;
110 list::run_get_account_commodities(&mut caller, user_id, id).await
111 })
112 },
113 )?;
114 linker.func_wrap_async(
115 "nomi",
116 "account_list_accounts_for_manage",
117 |mut caller: Caller<'_, SessionData>,
118 ()|
119 -> Box<
120 dyn std::future::Future<Output = wasmtime::Result<Option<Rooted<StructRef>>>> + Send,
121 > {
122 Box::new(async move {
123 let user_id = caller.data().ctx().user_id;
124 let result = ListAccountsForManage::new().user_id(user_id).run().await;
125 let entries = list::list_account_entries("list-accounts-for-manage", result)?;
126 list::alloc_account_chain(&mut caller, entries).await
127 })
128 },
129 )?;
130 linker.func_wrap_async(
131 "nomi",
132 "account_get_account_for_manage",
133 |mut caller: Caller<'_, SessionData>,
134 (id_arg,): (Option<Rooted<ArrayRef>>,)|
135 -> Box<
136 dyn std::future::Future<Output = wasmtime::Result<Option<Rooted<StructRef>>>> + Send,
137 > {
138 Box::new(async move {
139 let user_id = caller.data().ctx().user_id;
140 let id = read_string_arg(&mut caller, id_arg)?;
141 list::run_get_account_for_manage(&mut caller, user_id, id).await
142 })
143 },
144 )?;
145 linker.func_wrap_async(
146 "nomi",
147 "account_account_count",
148 |caller: Caller<'_, SessionData>,
149 ()|
150 -> Box<dyn std::future::Future<Output = i32> + Send> {
151 Box::new(async move {
152 let user_id = caller.data().ctx().user_id;
153 balance::count_accounts(user_id).await
154 })
155 },
156 )?;
157 linker.func_wrap_async(
158 "nomi",
159 "account_account_balance",
160 |mut caller: Caller<'_, SessionData>,
161 (id_arg,): (Option<Rooted<ArrayRef>>,)|
162 -> Box<
163 dyn std::future::Future<Output = wasmtime::Result<Option<Rooted<StructRef>>>> + Send,
164 > {
165 Box::new(async move {
166 let user_id = caller.data().ctx().user_id;
167 let id = read_string_arg(&mut caller, id_arg)?;
168 let (numer, denom, commodity_id) = balance::resolve_balance(user_id, id).await?;
169 let ref_ = alloc_commodity_ref(&mut caller, numer, denom, commodity_id).await?;
170 Ok(Some(ref_))
171 })
172 },
173 )?;
174 Ok(())
175}
176
177pub fn register_mutators(linker: &mut Linker<SessionData>) -> wasmtime::Result<()> {
178 linker.func_wrap_async(
179 "nomi",
180 "account_set_account_tag",
181 |mut caller: Caller<'_, SessionData>,
182 (id_arg, name_arg, value_arg): super::StringArgTriple|
183 -> Box<dyn std::future::Future<Output = wasmtime::Result<i32>> + Send> {
184 Box::new(async move {
185 let user_id = caller.data().ctx().user_id;
186 let id = read_string_arg(&mut caller, id_arg)?;
187 let name = read_string_arg(&mut caller, name_arg)?;
188 let value = read_string_arg(&mut caller, value_arg)?;
189 create::run_set_account_tag(user_id, id, name, value).await
190 })
191 },
192 )?;
193 linker.func_wrap_async(
194 "nomi",
195 "account_create_account",
196 |mut caller: Caller<'_, SessionData>,
197 (name_arg, parent_arg): (Option<Rooted<ArrayRef>>, Option<Rooted<ArrayRef>>)|
198 -> Box<
199 dyn std::future::Future<Output = wasmtime::Result<Option<Rooted<ArrayRef>>>> + Send,
200 > {
201 Box::new(async move {
202 let user_id = caller.data().ctx().user_id;
203 let name = read_string_arg(&mut caller, name_arg)?;
204 let parent = read_string_arg(&mut caller, parent_arg)?;
205 let id = create::run_create_account(user_id, name, parent).await?;
206 Ok(Some(alloc_string_ref(&mut caller, id.as_bytes())?))
207 })
208 },
209 )?;
210 Ok(())
211}
212
213pub(super) fn quote_string(s: &str) -> String {
214 let mut q = String::with_capacity(s.len() + 2);
215 q.push('"');
216 for ch in s.chars() {
217 match ch {
218 '"' => q.push_str("\\\""),
219 '\\' => q.push_str("\\\\"),
220 other => q.push(other),
221 }
222 }
223 q.push('"');
224 q
225}