1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License a
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "aip_napi_utils.h"
17
18 #include <dlfcn.h>
19 #include <memory>
20 #include <climits>
21
22 #include "js_ability.h"
23 #include "aip_log.h"
24
25 #undef LOG_TAG
26 #define LOG_TAG "AipNapiUtils"
27
28 namespace OHOS {
29 namespace DataIntelligence {
30 namespace {
31 using namespace OHOS::AppDataMgrJsKit;
32 static constexpr uint32_t MAX_VALUE_LENGTH = 1024 * 1024 * 8; // the max length of all kand of out string value
33 static constexpr uint8_t CONFIG_LENGTH_1 = 2;
34 static constexpr uint8_t CONFIG_LENGTH_2 = 3;
35 static constexpr uint32_t MAX_STR_PARAM_LEN = 512;
36 constexpr const char *PATH_SPLIT = "/";
37 struct OperatorInfo {
38 const char *operatorStr;
39 int32_t operatorEnum;
40 };
41 } // namespace
42
LoadAlgoLibrary(const std::string & libraryName,AipCoreManagerHandle & aipMgrHandler)43 bool AipNapiUtils::LoadAlgoLibrary(const std::string &libraryName, AipCoreManagerHandle &aipMgrHandler)
44 {
45 AIP_HILOGD("Enter");
46 if (aipMgrHandler.handle != nullptr) {
47 AIP_HILOGE("handle has exists");
48 return false;
49 }
50
51 if (libraryName.empty()) {
52 AIP_HILOGE("algoPath is empty");
53 return false;
54 }
55 char libRealPath[PATH_MAX] = {};
56 if (realpath(libraryName.c_str(), libRealPath) == nullptr) {
57 AIP_HILOGE("get absolute algoPath error, %{public}d", errno);
58 return false;
59 }
60
61 aipMgrHandler.handle = dlopen(libRealPath, RTLD_LAZY);
62 if (aipMgrHandler.handle == nullptr) {
63 AIP_HILOGE("cannot load lib error: %{public}s", dlerror());
64 return false;
65 }
66
67 aipMgrHandler.create = reinterpret_cast<IAipCoreManager *(*)()>(dlsym(aipMgrHandler.handle, "Create"));
68 aipMgrHandler.destroy = reinterpret_cast<void (*)(const IAipCoreManager *)>(dlsym(aipMgrHandler.handle, "Destroy"));
69 if (aipMgrHandler.create == nullptr || aipMgrHandler.destroy == nullptr) {
70 dlclose(aipMgrHandler.handle);
71 aipMgrHandler.Clear();
72 AIP_HILOGE("Failed to create and destroy algo");
73 return false;
74 }
75
76 aipMgrHandler.pAipManager = aipMgrHandler.create();
77 AIP_HILOGD("Exit");
78 return true;
79 }
80
81
UnLoadAlgoLibrary(AipCoreManagerHandle & aipMgrHandler)82 bool AipNapiUtils::UnLoadAlgoLibrary(AipCoreManagerHandle &aipMgrHandler)
83 {
84 AIP_HILOGD("Enter");
85 if (aipMgrHandler.handle == nullptr) {
86 AIP_HILOGE("handle is nullptr");
87 return false;
88 }
89
90 if (aipMgrHandler.pAipManager != nullptr && aipMgrHandler.destroy != nullptr) {
91 aipMgrHandler.destroy(aipMgrHandler.pAipManager);
92 aipMgrHandler.pAipManager = nullptr;
93 }
94
95 dlclose(aipMgrHandler.handle);
96 aipMgrHandler.Clear();
97 AIP_HILOGD("Exit");
98 return true;
99 }
100
GetAlgoObj(AipCoreManagerHandle & aipMgrHandler)101 IAipCoreManager *AipNapiUtils::GetAlgoObj(AipCoreManagerHandle &aipMgrHandler)
102 {
103 AIP_HILOGD("Enter");
104 if (aipMgrHandler.handle == nullptr) {
105 AIP_HILOGE("handle is nullptr");
106 return nullptr;
107 }
108
109 if (aipMgrHandler.pAipManager != nullptr) {
110 AIP_HILOGD("pAipManager already exists");
111 return aipMgrHandler.pAipManager;
112 }
113
114 if (aipMgrHandler.create == nullptr) {
115 AIP_HILOGE("create is nullptr");
116 return nullptr;
117 }
118
119 aipMgrHandler.pAipManager = aipMgrHandler.create();
120 AIP_HILOGD("Exit");
121 return aipMgrHandler.pAipManager;
122 }
123
ValidateArgsType(napi_env env,napi_value * args,size_t argc,const std::vector<std::string> & expectedTypes)124 bool AipNapiUtils::ValidateArgsType(napi_env env, napi_value *args, size_t argc,
125 const std::vector<std::string> &expectedTypes)
126 {
127 AIP_HILOGD("Enter");
128 napi_status status = napi_ok;
129 napi_valuetype valueType = napi_undefined;
130
131 if (argc != expectedTypes.size()) {
132 AIP_HILOGE("Wrong number of arguments");
133 return false;
134 }
135
136 for (size_t i = 0; i < argc; ++i) {
137 status = napi_typeof(env, args[i], &valueType);
138 if (status != napi_ok) {
139 AIP_HILOGE("Error while checking arguments types");
140 return false;
141 }
142 std::string expectedType = expectedTypes[i];
143 if ((expectedType == "string" && valueType != napi_string) ||
144 (expectedType == "object" && valueType != napi_object) ||
145 (expectedType == "number" && valueType != napi_number) ||
146 (expectedType == "function" && valueType != napi_function)) {
147 AIP_HILOGE("Wrong argument type");
148 return false;
149 }
150 }
151 return true;
152 }
153
TransJsToStr(napi_env env,napi_value value,std::string & str)154 bool AipNapiUtils::TransJsToStr(napi_env env, napi_value value, std::string &str)
155 {
156 size_t strlen = 0;
157 napi_status status = napi_get_value_string_utf8(env, value, nullptr, 0, &strlen);
158 if (status != napi_ok) {
159 AIP_HILOGE("Error string length invalid");
160 return false;
161 }
162 if (strlen < 0 || strlen > MAX_STR_PARAM_LEN) {
163 AIP_HILOGE("The string length invalid");
164 return false;
165 }
166 std::vector<char> buf(strlen + 1);
167 status = napi_get_value_string_utf8(env, value, buf.data(), strlen + 1, &strlen);
168 if (status != napi_ok) {
169 AIP_HILOGE("napi_get_value_string_utf8 failed");
170 return false;
171 }
172 str = buf.data();
173 return true;
174 }
175
TransJsToStrUnlimited(napi_env env,napi_value value,std::string & str)176 bool AipNapiUtils::TransJsToStrUnlimited(napi_env env, napi_value value, std::string &str)
177 {
178 size_t strlen = 0;
179 napi_status status = napi_get_value_string_utf8(env, value, nullptr, 0, &strlen);
180 if (status != napi_ok) {
181 AIP_HILOGE("Error string length invalid");
182 return false;
183 }
184 if (strlen < 0) {
185 AIP_HILOGE("The string length invalid");
186 return false;
187 }
188 std::vector<char> buf(strlen + 1);
189 status = napi_get_value_string_utf8(env, value, buf.data(), strlen + 1, &strlen);
190 if (status != napi_ok) {
191 AIP_HILOGE("napi_get_value_string_utf8 failed");
192 return false;
193 }
194 str = buf.data();
195 return true;
196 }
197
TransJsToInt32(napi_env env,napi_value value,int32_t & res)198 bool AipNapiUtils::TransJsToInt32(napi_env env, napi_value value, int32_t &res)
199 {
200 napi_status status = napi_get_value_int32(env, value, &res);
201 if (status != napi_ok) {
202 AIP_HILOGE("napi_get_value_int32 failed");
203 return false;
204 }
205 return true;
206 }
207
TransJsToDouble(napi_env env,napi_value value,double & res)208 bool AipNapiUtils::TransJsToDouble(napi_env env, napi_value value, double &res)
209 {
210 napi_status status = napi_get_value_double(env, value, &res);
211 if (status != napi_ok) {
212 AIP_HILOGE("napi_get_value_double failed");
213 return false;
214 }
215 return true;
216 }
217
TransJsToBool(napi_env env,napi_value value,bool & res)218 bool AipNapiUtils::TransJsToBool(napi_env env, napi_value value, bool &res)
219 {
220 napi_status status = napi_get_value_bool(env, value, &res);
221 if (status != napi_ok) {
222 return false;
223 }
224 return true;
225 }
226
CreateStringData(napi_env env,napi_value aipServiceValue,napi_value result,const std::string name,std::string & content)227 void AipNapiUtils::CreateStringData(napi_env env, napi_value aipServiceValue, napi_value result, const std::string name,
228 std::string &content)
229 {
230 napi_status ret = napi_create_string_utf8(env, content.c_str(), NAPI_AUTO_LENGTH, &aipServiceValue);
231 if (ret != napi_ok) {
232 AIP_HILOGE("napi_create_string_utf8 failed");
233 return;
234 }
235
236 ret = napi_set_named_property(env, result, name.c_str(), aipServiceValue);
237 if (ret != napi_ok) {
238 AIP_HILOGE("napi_set_named_property failed");
239 }
240 }
241
CreateInt32Data(napi_env env,napi_value aipServiceValue,napi_value result,const std::string name,int32_t value)242 void AipNapiUtils::CreateInt32Data(napi_env env, napi_value aipServiceValue, napi_value result, const std::string name,
243 int32_t value)
244 {
245 napi_status ret = napi_create_int32(env, value, &aipServiceValue);
246 if (ret != napi_ok) {
247 AIP_HILOGE("napi_create_int32 failed");
248 return;
249 }
250
251 ret = napi_set_named_property(env, result, name.c_str(), aipServiceValue);
252 if (ret != napi_ok) {
253 AIP_HILOGE("napi_set_named_property failed");
254 }
255 }
256
CreateDoubleData(napi_env env,double value,napi_value * result)257 void AipNapiUtils::CreateDoubleData(napi_env env, double value, napi_value *result)
258 {
259 napi_status ret = napi_create_double(env, value, result);
260 if (ret != napi_ok) {
261 AIP_HILOGE("napi_create_int32 failed");
262 return;
263 }
264 }
265
SetInt32Property(napi_env env,napi_value targetObj,int32_t value,const char * propName)266 void AipNapiUtils::SetInt32Property(napi_env env, napi_value targetObj, int32_t value, const char *propName)
267 {
268 napi_value prop = nullptr;
269 napi_status ret = napi_create_int32(env, value, &prop);
270 if (ret != napi_ok) {
271 AIP_HILOGE("napi_create_int32 failed");
272 return;
273 }
274 SetPropertyName(env, targetObj, propName, prop);
275 }
276
SetStringProperty(napi_env env,napi_value targetObj,std::string value,const char * propName)277 void AipNapiUtils::SetStringProperty(napi_env env, napi_value targetObj, std::string value, const char *propName)
278 {
279 napi_value prop = nullptr;
280 napi_status ret = napi_create_string_utf8(env, value.c_str(), value.size(), &prop);
281 if (ret != napi_ok) {
282 AIP_HILOGE("napi_create_int32 failed");
283 return;
284 }
285 SetPropertyName(env, targetObj, propName, prop);
286 }
287
SetPropertyName(napi_env env,napi_value targetObj,const char * propName,napi_value propValue)288 void AipNapiUtils::SetPropertyName(napi_env env, napi_value targetObj, const char *propName, napi_value propValue)
289 {
290 napi_status status = napi_set_named_property(env, targetObj, propName, propValue);
291 if (status != napi_ok) {
292 AIP_HILOGE("napi_set_named_property failed");
293 return;
294 }
295 }
296
CheckModelConfig(napi_env env,napi_value value)297 bool AipNapiUtils::CheckModelConfig(napi_env env, napi_value value)
298 {
299 napi_valuetype valuetype;
300 napi_status status = napi_typeof(env, value, &valuetype);
301 if (status != napi_ok || valuetype != napi_object) {
302 AIP_HILOGE("ModelConfig is not object");
303 return false;
304 }
305
306 napi_value KeysArray;
307 status = napi_get_property_names(env, value, &KeysArray);
308 if (status != napi_ok) {
309 AIP_HILOGE("Failed to get property names");
310 return false;
311 }
312
313 uint32_t length;
314 status = napi_get_array_length(env, KeysArray, &length);
315 if (status != napi_ok) {
316 AIP_HILOGE("Failed to get array length");
317 return false;
318 }
319
320 if (length != CONFIG_LENGTH_1 && length != CONFIG_LENGTH_2) {
321 AIP_HILOGE("The modelConfig length is failed");
322 return false;
323 }
324 return true;
325 }
326
Convert2Value(napi_env env,napi_value in,bool & out)327 napi_status AipNapiUtils::Convert2Value(napi_env env, napi_value in, bool &out)
328 {
329 return napi_get_value_bool(env, in, &out);
330 }
331
Convert2Value(napi_env env,napi_value in,int32_t & out)332 napi_status AipNapiUtils::Convert2Value(napi_env env, napi_value in, int32_t &out)
333 {
334 return napi_get_value_int32(env, in, &out);
335 }
336
Convert2Value(napi_env env,napi_value in,uint32_t & out)337 napi_status AipNapiUtils::Convert2Value(napi_env env, napi_value in, uint32_t &out)
338 {
339 return napi_get_value_uint32(env, in, &out);
340 }
341
Convert2Value(napi_env env,napi_value in,std::vector<uint8_t> & out)342 napi_status AipNapiUtils::Convert2Value(napi_env env, napi_value in, std::vector<uint8_t> &out)
343 {
344 bool isTypedArray = false;
345 napi_is_typedarray(env, in, &isTypedArray);
346 if (!isTypedArray) {
347 return napi_invalid_arg;
348 }
349
350 napi_typedarray_type type;
351 napi_value input_buffer = nullptr;
352 size_t byte_offset = 0;
353 size_t length = 0;
354 void *tmp = nullptr;
355 auto status = napi_get_typedarray_info(env, in, &type, &length, &tmp, &input_buffer, &byte_offset);
356 if (status != napi_ok || type != napi_uint8_array) {
357 return napi_invalid_arg;
358 }
359
360 out = (tmp != nullptr ? std::vector<uint8_t>(static_cast<uint8_t *>(tmp), static_cast<uint8_t *>(tmp) + length)
361 : std::vector<uint8_t>());
362 return status;
363 }
364
Convert2Value(napi_env env,napi_value in,int64_t & out)365 napi_status AipNapiUtils::Convert2Value(napi_env env, napi_value in, int64_t &out)
366 {
367 return napi_get_value_int64(env, in, &out);
368 }
369
Convert2Value(napi_env env,napi_value in,std::string & out)370 napi_status AipNapiUtils::Convert2Value(napi_env env, napi_value in, std::string &out)
371 {
372 napi_valuetype type = napi_undefined;
373 napi_status status = napi_typeof(env, in, &type);
374 LOG_ERROR_RETURN((status == napi_ok) && (type == napi_string), "The parameter type is not a string.",
375 napi_invalid_arg);
376 size_t buffSize = 0;
377 napi_get_value_string_utf8(env, in, nullptr, 0, &buffSize);
378 // cut down with 0 if more than MAX_VALUE_LENGTH
379 if (buffSize >= MAX_VALUE_LENGTH - 1) {
380 buffSize = MAX_VALUE_LENGTH - 1;
381 }
382 std::unique_ptr<char[]> buffer = std::make_unique<char[]>(buffSize + 1);
383 LOG_ERROR_RETURN(buffer, "Buffer data is nullptr.", napi_invalid_arg);
384 status = napi_get_value_string_utf8(env, in, buffer.get(), buffSize + 1, &buffSize);
385 LOG_ERROR_RETURN(status == napi_ok, "napi_get_value_string_utf8 failed", napi_invalid_arg);
386 out = std::string(buffer.get());
387 return status;
388 }
389
Convert2Value(napi_env env,napi_value in,std::vector<float> & out)390 napi_status AipNapiUtils::Convert2Value(napi_env env, napi_value in, std::vector<float> &out)
391 {
392 bool isTypedArray = false;
393 napi_is_typedarray(env, in, &isTypedArray);
394 if (!isTypedArray) {
395 return napi_invalid_arg;
396 }
397
398 napi_typedarray_type type;
399 napi_value input_buffer = nullptr;
400 size_t byte_offset = 0;
401 size_t length = 0;
402 void *tmp = nullptr;
403 auto status = napi_get_typedarray_info(env, in, &type, &length, &tmp, &input_buffer, &byte_offset);
404 if (status != napi_ok || type != napi_float32_array) {
405 return napi_invalid_arg;
406 }
407
408 out = (tmp != nullptr
409 ? std::vector<float>(static_cast<float *>(tmp), static_cast<float *>(tmp) + length / sizeof(float))
410 : std::vector<float>());
411 return status;
412 }
413
Convert2Value(napi_env env,napi_value in,float & out)414 napi_status AipNapiUtils::Convert2Value(napi_env env, napi_value in, float &out)
415 {
416 double tmp;
417 napi_status status = napi_get_value_double(env, in, &tmp);
418 out = tmp;
419 return status;
420 }
421
Convert2Value(napi_env env,napi_value in,double & out)422 napi_status AipNapiUtils::Convert2Value(napi_env env, napi_value in, double &out)
423 {
424 return napi_get_value_double(env, in, &out);
425 }
426
IsNull(napi_env env,napi_value value)427 bool AipNapiUtils::IsNull(napi_env env, napi_value value)
428 {
429 napi_valuetype type = napi_undefined;
430 napi_status status = napi_typeof(env, value, &type);
431 return status == napi_ok && (type == napi_undefined || type == napi_null);
432 }
433
GetInnerValue(napi_env env,napi_value in,const std::string & prop,bool optional)434 std::pair<napi_status, napi_value> AipNapiUtils::GetInnerValue(
435 napi_env env, napi_value in, const std::string &prop, bool optional)
436 {
437 bool hasProp = false;
438 napi_status status = napi_has_named_property(env, in, prop.c_str(), &hasProp);
439 if (status != napi_ok) {
440 return std::make_pair(napi_generic_failure, nullptr);
441 }
442 if (!hasProp) {
443 status = optional ? napi_ok : napi_generic_failure;
444 return std::make_pair(status, nullptr);
445 }
446 napi_value inner = nullptr;
447 status = napi_get_named_property(env, in, prop.c_str(), &inner);
448 if (status != napi_ok || inner == nullptr) {
449 return std::make_pair(napi_generic_failure, nullptr);
450 }
451 if (optional && AipNapiUtils::IsNull(env, inner)) {
452 return std::make_pair(napi_ok, nullptr);
453 }
454 return std::make_pair(napi_ok, inner);
455 }
456
GetCustomDatabasePath(const std::string & rootDir,const std::string & name,const std::string & customDir)457 std::string GetCustomDatabasePath(
458 const std::string &rootDir, const std::string &name, const std::string &customDir)
459 {
460 std::string databasePath;
461 databasePath.append(rootDir).append(PATH_SPLIT).append(customDir).append(PATH_SPLIT).append(name);
462 return databasePath;
463 }
464
GetDefaultDatabasePath(const std::string & baseDir,const std::string & name,const std::string & customDir)465 std::string GetDefaultDatabasePath(
466 const std::string &baseDir, const std::string &name, const std::string &customDir)
467 {
468 std::string databaseDir;
469 databaseDir.append(baseDir).append("/rdb/").append(customDir).append(PATH_SPLIT).append(name);
470 return databaseDir;
471 }
472
Convert2Value(napi_env env,const napi_value & in,napi_value & out)473 napi_status AipNapiUtils::Convert2Value(napi_env env, const napi_value &in, napi_value &out)
474 {
475 out = in;
476 return napi_ok;
477 }
478
Convert2JSValue(napi_env env,const std::vector<uint8_t> & in,napi_value & out)479 napi_status AipNapiUtils::Convert2JSValue(napi_env env, const std::vector<uint8_t> &in, napi_value &out)
480 {
481 void *native = nullptr;
482 napi_value buffer = nullptr;
483 napi_status status = napi_create_arraybuffer(env, in.size(), &native, &buffer);
484 if (status != napi_ok) {
485 return status;
486 }
487 for (size_t i = 0; i < in.size(); i++) {
488 *(static_cast<uint8_t *>(native) + i) = in[i];
489 }
490 status = napi_create_typedarray(env, napi_uint8_array, in.size(), buffer, 0, &out);
491 if (status != napi_ok) {
492 return status;
493 }
494 return napi_ok;
495 }
496
Convert2JSValue(napi_env env,const std::vector<float> & in,napi_value & out)497 napi_status AipNapiUtils::Convert2JSValue(napi_env env, const std::vector<float> &in, napi_value &out)
498 {
499 float *native = nullptr;
500 napi_value buffer = nullptr;
501 napi_status status = napi_create_arraybuffer(env, in.size() * sizeof(float), (void **)&native, &buffer);
502 if (status != napi_ok) {
503 return status;
504 }
505 if (native == nullptr) {
506 return status;
507 }
508 for (size_t i = 0; i < in.size(); i++) {
509 *(native + i) = in[i];
510 }
511 status = napi_create_typedarray(env, napi_float32_array, in.size(), buffer, 0, &out);
512 if (status != napi_ok) {
513 return status;
514 }
515 return napi_ok;
516 }
517
Convert2JSValue(napi_env env,const std::string & in,napi_value & out)518 napi_status AipNapiUtils::Convert2JSValue(napi_env env, const std::string &in, napi_value &out)
519 {
520 return napi_create_string_utf8(env, in.c_str(), in.size(), &out);
521 }
522
Convert2JSValue(napi_env env,const double & in,napi_value & out)523 napi_status AipNapiUtils::Convert2JSValue(napi_env env, const double &in, napi_value &out)
524 {
525 return napi_create_double(env, in, &out);
526 }
527
Convert2JSValue(napi_env env,const bool & in,napi_value & out)528 napi_status AipNapiUtils::Convert2JSValue(napi_env env, const bool &in, napi_value &out)
529 {
530 return napi_get_boolean(env, in, &out);
531 }
532
Convert2JSValue(napi_env env,const int32_t & in,napi_value & out)533 napi_status AipNapiUtils::Convert2JSValue(napi_env env, const int32_t &in, napi_value &out)
534 {
535 return napi_create_int32(env, in, &out);
536 }
537
Convert2JSValue(napi_env env,const int64_t & in,napi_value & out)538 napi_status AipNapiUtils::Convert2JSValue(napi_env env, const int64_t &in, napi_value &out)
539 {
540 return napi_create_int64(env, in, &out);
541 }
542
Convert2JSValue(napi_env env,const uint64_t & in,napi_value & out)543 napi_status AipNapiUtils::Convert2JSValue(napi_env env, const uint64_t &in, napi_value &out)
544 {
545 return napi_create_bigint_uint64(env, in, &out);
546 }
547
Convert2JSValue(napi_env env,const std::map<std::string,double> & in,napi_value & out)548 napi_status AipNapiUtils::Convert2JSValue(napi_env env, const std::map<std::string, double> &in, napi_value &out)
549 {
550 napi_create_object(env, &out);
551 for (auto const &[key, value] : in) {
552 napi_value jsValue = nullptr;
553 Convert2JSValue(env, value, jsValue);
554 napi_set_named_property(env, out, key.c_str(), jsValue);
555 }
556 return napi_ok;
557 }
558 } // namespace DataIntelligence
559 } // namespace OHOS
560