Skip to main content

rpc/natives/account/
mod.rs

1//! Account-domain natives. Wraps `server::command::{CreateAccount, ListAccounts,
2//! ListAccountsForManage, GetAccountForManage, SetAccountTag, GetAccount,
3//! GetAccountCommodities, GetBalance, GetBalances}` as nomiscript-callable host fns.
4
5use 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}