v_common_v8/
callback.rs

1use crate::common::*;
2use crate::session_cache::*;
3use std::cell::RefCell;
4use std::sync::Mutex;
5use v8::{Context, GetPropertyNamesArgs, HandleScope, Local};
6use v_common::az_impl::az_lmdb::LmdbAzContext;
7use v_common::module::module_impl::Module;
8use v_common::module::remote_indv_r_storage::get_individual;
9use v_common::onto::individual::Individual;
10use v_common::onto::parser::parse_raw;
11use v_common::search::common::FTQuery;
12use v_common::search::ft_client::*;
13use v_common::v_api::api_client::IndvOp;
14use v_common::v_authorization::common::{Access, AuthorizationContext, ACCESS_8_LIST, ACCESS_PREDICATE_LIST};
15
16lazy_static! {
17    static ref AZ: Mutex<RefCell<LmdbAzContext>> = Mutex::new(RefCell::new(LmdbAzContext::new(1000)));
18    static ref FT_CLIENT: Mutex<RefCell<FTClient>> = Mutex::new(RefCell::new(FTClient::new(Module::get_property("ft_query_service_url").unwrap_or_default())));
19    pub static ref G_VARS: Mutex<RefCell<CallbackSharedData>> = Mutex::new(RefCell::new(CallbackSharedData::default()));
20    pub static ref G_TRANSACTION: Mutex<RefCell<Transaction>> = Mutex::new(RefCell::new(Transaction::default()));
21}
22
23pub fn fn_callback_get_rights(scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue) {
24    //let ticket = get_string_arg(scope, &args, 0, "callback_get_rights: ticket not found or invalid").unwrap_or_default();
25    let id = get_string_arg(scope, &args, 1, None).unwrap_or_default();
26    let user_id = if let Some(u) = get_string_arg(scope, &args, 2, None) {
27        u
28    } else {
29        let key = v8::String::new(scope, "user_uri").unwrap();
30        let user_uri = scope.get_current_context().global(scope).get(scope, key.into()).unwrap().to_string(scope).unwrap();
31        user_uri.to_rust_string_lossy(scope)
32    };
33
34    debug!("user_id={}, doc_id={}", user_id, id);
35
36    let mut sh_az = AZ.lock().unwrap();
37    let az = sh_az.get_mut();
38
39    let rights = az.authorize(&id, &user_id, Access::CanRead as u8 | Access::CanCreate as u8 | Access::CanDelete as u8 | Access::CanUpdate as u8, false).unwrap_or(0);
40
41    let mut pstm = Individual::default();
42    pstm.set_id("_");
43    pstm.add_uri("rdf:type", "v-s:PermissionStatement");
44    for ch_access in ACCESS_8_LIST {
45        if rights & ch_access > 0 {
46            pstm.add_bool(ACCESS_PREDICATE_LIST[ch_access as usize], rights & ch_access > 0);
47        }
48    }
49    let j_indv = individual2v8obj(scope, pstm.parse_all());
50    rv.set(j_indv.into());
51
52    drop(sh_az);
53}
54
55pub fn fn_callback_get_individual(scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue) {
56    let id = get_string_arg(scope, &args, 1, Some("callback_get_individual: id not found or invalid")).unwrap_or_default();
57
58    if id == "undefined" {
59        // Do nothing
60    } else if id.starts_with('$') {
61        let mut sh_g_vars = G_VARS.lock().unwrap();
62        let g_vars = sh_g_vars.get_mut();
63
64        if let Some(indv) = g_vars.g_key2indv.get_mut(&id) {
65            let j_indv = individual2v8obj(scope, indv.parse_all());
66            rv.set(j_indv.into());
67        }
68        drop(sh_g_vars);
69    } else {
70        let mut sh_tnx = G_TRANSACTION.lock().unwrap();
71        let tnx = sh_tnx.get_mut();
72
73        if let Some(indv) = tnx.get_indv(&id) {
74            let j_indv = individual2v8obj(scope, indv);
75            rv.set(j_indv.into());
76        } else {
77            match get_individual(&id) {
78                Ok(Some(mut indv)) => {
79                    if parse_raw(&mut indv).is_ok() {
80                        let j_indv = individual2v8obj(scope, indv.parse_all());
81                        rv.set(j_indv.into());
82                    } else {
83                        let error_msg = format!("Failed to parse binobj for id: {}", id);
84                        error!("callback_get_individual: {}", error_msg);
85                        let error_string = v8::String::new(scope, &error_msg).unwrap();
86                        let error = v8::Exception::error(scope, error_string);
87                        scope.throw_exception(error);
88                    }
89                },
90                Ok(None) => {
91                    let warn_msg = format!("Individual not found for id: {}", id);
92                    warn!("callback_get_individual: {}", warn_msg);
93                    rv.set(v8::undefined(scope).into());
94                },
95                Err(e) => {
96                    let error_msg = format!("Error getting individual for id: {}, error: {:?}", id, e);
97                    error!("callback_get_individual: {}", error_msg);
98                    let error_string = v8::String::new(scope, &error_msg).unwrap();
99                    let error = v8::Exception::error(scope, error_string);
100                    scope.throw_exception(error);
101                },
102            }
103        }
104
105        drop(sh_tnx);
106    }
107}
108
109pub fn fn_callback_get_individuals(scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue) {
110    let j_res = v8::Array::new(scope, 0);
111
112    let arg1 = args.get(1);
113    if arg1.is_array() {
114        if let Some(r) = arg1.to_object(scope) {
115            if let Some(arr_keys) = r.get_property_names(scope, GetPropertyNamesArgs::default()) {
116                let mut sh_tnx = G_TRANSACTION.lock().unwrap();
117                let tnx = sh_tnx.get_mut();
118
119                for idx in 0..arr_keys.length() {
120                    let j_idx = v8::Integer::new(scope, idx as i32);
121                    let j_id = r.get(scope, j_idx.into()).unwrap().to_object(scope).unwrap();
122                    let id = j_id.to_string(scope).unwrap().to_rust_string_lossy(scope);
123
124                    if let Some(indv) = tnx.get_indv(&id) {
125                        let j_indv = individual2v8obj(scope, indv);
126                        j_res.set(scope, j_idx.into(), j_indv.into());
127                    } else {
128                        match get_individual(&id) {
129                            Ok(Some(mut indv)) => {
130                                if parse_raw(&mut indv).is_ok() {
131                                    let j_indv = individual2v8obj(scope, indv.parse_all());
132                                    j_res.set(scope, j_idx.into(), j_indv.into());
133                                } else {
134                                    let error_msg = format!("Failed to parse binobj for id: {}", id);
135                                    error!("callback_get_individuals: {}", error_msg);
136                                    let error_string = v8::String::new(scope, &error_msg).unwrap();
137                                    let error = v8::Exception::error(scope, error_string);
138                                    scope.throw_exception(error);
139                                    return;
140                                }
141                            },
142                            Ok(None) => {
143                                warn!("callback_get_individuals: individual not found, id={}", id);
144                                let null_value = v8::null(scope);
145                                j_res.set(scope, j_idx.into(), null_value.into());
146                            },
147                            Err(e) => {
148                                let error_msg = format!("Error getting individual, id={}, error={:?}", id, e);
149                                error!("callback_get_individuals: {}", error_msg);
150                                let error_string = v8::String::new(scope, &error_msg).unwrap();
151                                let error = v8::Exception::error(scope, error_string);
152                                scope.throw_exception(error);
153                                return;
154                            },
155                        }
156                    }
157                }
158                drop(sh_tnx);
159            }
160        }
161    } else {
162        let error_msg = "Argument is not an array";
163        error!("callback_get_individuals: {}", error_msg);
164        let error_string = v8::String::new(scope, error_msg).unwrap();
165        let error = v8::Exception::type_error(scope, error_string);
166        scope.throw_exception(error);
167        return;
168    }
169    rv.set(j_res.into());
170}
171
172pub fn fn_callback_print(scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, mut _rv: v8::ReturnValue) {
173    let mut str_out = String::new();
174
175    for idx in 0..args.length() {
176        let arg = args.get(idx);
177        str_out.push_str(&arg.to_string(scope).unwrap().to_rust_string_lossy(scope));
178        str_out.push(' ');
179    }
180    info!("{}", str_out);
181}
182
183pub fn fn_callback_log_trace(scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, mut _rv: v8::ReturnValue) {
184    let arg1 = args.get(0);
185    info!("{}", arg1.to_string(scope).unwrap().to_rust_string_lossy(scope));
186}
187
188pub fn fn_callback_get_env_str_var(scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue) {
189    if let Some(var_name) = get_string_arg(scope, &args, 0, Some("fn_callback_get_env_str_var: arg not found or invalid")) {
190        let mut sh_g_vars = G_VARS.lock().unwrap();
191        let g_vars = sh_g_vars.get_mut();
192
193        debug!("fn_callback_get_env_str_var, var_name={:?}", var_name);
194
195        if let Some(v) = g_vars.g_key2attr.get(&var_name) {
196            let j_res = str_2_v8(scope, v);
197            rv.set(j_res.into());
198        }
199
200        drop(sh_g_vars);
201    }
202}
203pub fn fn_callback_get_env_num_var(scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, mut _rv: v8::ReturnValue) {
204    if let Some(var_name) = get_string_arg(scope, &args, 0, Some("fn_callback_get_env_str_var: arg not found or invalid")) {
205        //let mut sh_g_vars = G_VARS.lock().unwrap();
206        //let _g_vars = sh_g_vars.get_mut();
207
208        debug!("fn_callback_get_env_num_var, var_name={:?}", var_name);
209
210        //if var_name == "$queue_elements_count" || var_name == "$queue_elements_processed" {
211        //    return;
212        //}
213    }
214}
215
216pub fn fn_callback_query(scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue) {
217    let ticket = get_string_arg(scope, &args, 0, Some("callback_query: arg0 [ticket] not found or invalid"));
218    if ticket.is_none() {
219        return;
220    }
221    let mut ticket = ticket.unwrap();
222
223    let query = get_string_arg(scope, &args, 1, Some("callback_query: arg1 [query] not found or invalid"));
224    if query.is_none() {
225        return;
226    }
227
228    let sort;
229    let databases;
230    let top;
231    let limit;
232    let from;
233
234    if ticket.is_empty() {
235        let mut sh_tnx = G_TRANSACTION.lock().unwrap();
236        let tnx = sh_tnx.get_mut();
237        ticket = tnx.sys_ticket.to_owned();
238        drop(sh_tnx);
239    }
240
241    let mut query = FTQuery::new_with_ticket(&ticket, &query.unwrap());
242    if args.length() > 2 {
243        sort = get_string_arg(scope, &args, 2, Some("callback_query: arg2 [sort] not found or invalid"));
244        query.sort = sort.unwrap_or_default();
245        if args.length() > 3 {
246            databases = get_string_arg(scope, &args, 3, Some("callback_query: arg3 [databases] not found or invalid"));
247            query.databases = databases.unwrap_or_default();
248            if args.length() > 4 {
249                top = get_string_i32(scope, &args, 4, Some("callback_query: arg4 [top] not found or invalid"));
250                query.top = top.unwrap_or(100000);
251                if args.length() > 5 {
252                    limit = get_string_i32(scope, &args, 5, Some("callback_query: arg5 [limit] not found or invalid"));
253                    query.limit = limit.unwrap_or(100000);
254                    if args.length() > 6 {
255                        from = get_string_i32(scope, &args, 6, Some("callback_query: arg6 [from] not found or invalid"));
256                        query.from = from.unwrap_or_default();
257                    }
258                }
259            }
260        }
261    }
262
263    let _context = scope.get_current_context();
264
265    let mut sh_ft_client = FT_CLIENT.lock().unwrap();
266    let ft_client = sh_ft_client.get_mut();
267
268    let res = ft_client.query(query);
269
270    drop(sh_ft_client);
271
272    let j_res = query_result2v8obj(scope, &res);
273    rv.set(j_res.into());
274}
275
276fn fn_callback_update(opt: IndvOp, scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue) {
277    let wticket = get_string_arg(scope, &args, 0, Some("fn_callback_update: arg0 [ticket] not found or invalid"));
278    if wticket.is_none() {
279        return;
280    }
281    let mut ticket = wticket.unwrap_or_default();
282
283    let arg1 = args.get(1);
284    let mut indv;
285
286    if opt == IndvOp::Remove {
287        indv = Individual::default();
288
289        if arg1.is_string() {
290            if let Some(id) = arg1.to_string(scope) {
291                indv.set_id(&id.to_rust_string_lossy(scope));
292            }
293        } else {
294            error!("callback {:?}, argument is not string", opt);
295        }
296    } else if arg1.is_object() {
297        let js_obj = arg1.to_object(scope).unwrap();
298        indv = v8obj2individual(scope, js_obj);
299    } else {
300        indv = Individual::default();
301        error!("callback {:?}, argument is not object", opt);
302    }
303
304    if !indv.get_id().is_empty() {
305        let mut sh_tnx = G_TRANSACTION.lock().unwrap();
306        let tnx = sh_tnx.get_mut();
307
308        if ticket.is_empty() {
309            ticket = tnx.sys_ticket.to_owned();
310        }
311
312        debug!("ADD TO TRANSACTION {:?} {}", &opt, indv.get_id());
313        let res = tnx.add_to_transaction(opt, indv, ticket, "".to_string());
314        debug!("res={:?}", res);
315
316        rv.set(v8::Integer::new(scope, res as i32).into());
317    } else {
318        error!("callback {:?}, invalid argument", opt);
319    }
320}
321
322pub fn fn_callback_put_individual(scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, rv: v8::ReturnValue) {
323    fn_callback_update(IndvOp::Put, scope, args, rv);
324}
325
326pub fn fn_callback_remove_individual(scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, rv: v8::ReturnValue) {
327    fn_callback_update(IndvOp::Remove, scope, args, rv);
328}
329pub fn fn_callback_add_to_individual(scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, rv: v8::ReturnValue) {
330    fn_callback_update(IndvOp::AddTo, scope, args, rv);
331}
332pub fn fn_callback_set_in_individual(scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, rv: v8::ReturnValue) {
333    fn_callback_update(IndvOp::SetIn, scope, args, rv);
334}
335pub fn fn_callback_remove_from_individual(scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, rv: v8::ReturnValue) {
336    fn_callback_update(IndvOp::RemoveFrom, scope, args, rv);
337}
338
339pub fn init_context_with_callback<'a>(scope: &mut HandleScope<'a, ()>) -> Local<'a, Context> {
340    let object_templ = v8::ObjectTemplate::new(scope);
341    object_templ.set(str_2_v8(scope, "print").into(), v8::FunctionTemplate::new(scope, fn_callback_print).into());
342    object_templ.set(str_2_v8(scope, "get_individual").into(), v8::FunctionTemplate::new(scope, fn_callback_get_individual).into());
343    object_templ.set(str_2_v8(scope, "get_individuals").into(), v8::FunctionTemplate::new(scope, fn_callback_get_individuals).into());
344    object_templ.set(str_2_v8(scope, "put_individual").into(), v8::FunctionTemplate::new(scope, fn_callback_put_individual).into());
345    object_templ.set(str_2_v8(scope, "get_env_str_var").into(), v8::FunctionTemplate::new(scope, fn_callback_get_env_str_var).into());
346    object_templ.set(str_2_v8(scope, "get_env_num_var").into(), v8::FunctionTemplate::new(scope, fn_callback_get_env_num_var).into());
347    object_templ.set(str_2_v8(scope, "query").into(), v8::FunctionTemplate::new(scope, fn_callback_query).into());
348    object_templ.set(str_2_v8(scope, "remove_individual").into(), v8::FunctionTemplate::new(scope, fn_callback_remove_individual).into());
349    object_templ.set(str_2_v8(scope, "add_to_individual").into(), v8::FunctionTemplate::new(scope, fn_callback_add_to_individual).into());
350    object_templ.set(str_2_v8(scope, "set_in_individual").into(), v8::FunctionTemplate::new(scope, fn_callback_set_in_individual).into());
351    object_templ.set(str_2_v8(scope, "remove_from_individual").into(), v8::FunctionTemplate::new(scope, fn_callback_remove_from_individual).into());
352    object_templ.set(str_2_v8(scope, "log_trace").into(), v8::FunctionTemplate::new(scope, fn_callback_log_trace).into());
353    object_templ.set(str_2_v8(scope, "get_rights").into(), v8::FunctionTemplate::new(scope, fn_callback_get_rights).into());
354
355    v8::Context::new_from_template(scope, object_templ)
356}
357
358fn get_string_arg(scope: &mut v8::HandleScope, args: &v8::FunctionCallbackArguments, idx: i32, warn_msg: Option<&str>) -> Option<String> {
359    let arg = args.get(idx);
360
361    if !arg.is_null_or_undefined() {
362        if let Some(arg) = arg.to_string(scope) {
363            return Some(arg.to_rust_string_lossy(scope));
364        }
365    }
366
367    if let Some(msg) = warn_msg {
368        warn!("{}", msg);
369    }
370    None
371}
372
373fn get_string_i32(scope: &mut v8::HandleScope, args: &v8::FunctionCallbackArguments, idx: i32, warn_msg: Option<&str>) -> Option<i32> {
374    let arg = args.get(idx).int32_value(scope);
375    if arg.is_none() {
376        if let Some(msg) = warn_msg {
377            warn!("{}", msg);
378        }
379        return None;
380    }
381    arg
382}