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 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 } 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 debug!("fn_callback_get_env_num_var, var_name={:?}", var_name);
209
210 }
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}