• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 at
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 #define LOG_TAG "Node"
17 
18 #include "napi_node.h"
19 
20 #include "napi_error_utils.h"
21 #include "napi_parser.h"
22 
23 namespace OHOS::CollaborationEdit {
24 static __thread napi_ref g_node_cons_ref = nullptr;
25 
Node(std::string name)26 Node::Node(std::string name) : AbstractType(), name_(name)
27 {}
28 
~Node()29 Node::~Node()
30 {}
31 
Init(napi_env env,napi_value exports)32 void Node::Init(napi_env env, napi_value exports)
33 {
34     napi_value cons = Node::Constructor(env);
35     NAPI_CALL_RETURN_VOID(env, napi_create_reference(env, cons, 1, &g_node_cons_ref));
36     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, exports, "Node", cons));
37     LOG_DEBUG("Node::Init end.");
38 }
39 
Constructor(napi_env env)40 napi_value Node::Constructor(napi_env env)
41 {
42     napi_property_descriptor descriptors[] = {
43         DECLARE_NAPI_FUNCTION("getId", GetUniqueId),
44         DECLARE_NAPI_FUNCTION("getName", GetName),
45         DECLARE_NAPI_FUNCTION("insertNodes", InsertNodes),
46         DECLARE_NAPI_FUNCTION("delete", Delete),
47         DECLARE_NAPI_FUNCTION("getChildren", GetChildren),
48         DECLARE_NAPI_FUNCTION("getJsonResult", GetJsonResult),
49         DECLARE_NAPI_FUNCTION("insertTexts", InsertTexts),
50         DECLARE_NAPI_FUNCTION("setAttributes", SetAttributes),
51         DECLARE_NAPI_FUNCTION("removeAttributes", RemoveAttributes),
52         DECLARE_NAPI_FUNCTION("getAttributes", GetAttributes),
53         DECLARE_NAPI_FUNCTION("setAsset", SetAsset),
54     };
55     napi_value cons = nullptr;
56     NAPI_CALL(env, napi_define_class(env, "Node", NAPI_AUTO_LENGTH, New, nullptr,
57         sizeof(descriptors) / sizeof(napi_property_descriptor), descriptors, &cons));
58     return cons;
59 }
60 
New(napi_env env,napi_callback_info info)61 napi_value Node::New(napi_env env, napi_callback_info info)
62 {
63     napi_value newTarget = nullptr;
64     NAPI_CALL(env, napi_get_new_target(env, info, &newTarget));
65 
66     size_t argc = 1;
67     napi_value argv[1] = {nullptr};
68     napi_value self = nullptr;
69     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr));
70 
71     // create instance by 'new Node(name)'
72     if (newTarget != nullptr) {
73         napi_valuetype valueType = napi_undefined;
74         NAPI_CALL(env, napi_typeof(env, argv[0], &valueType));
75         if (valueType != napi_string) {
76             ThrowNapiError(env, Status::INVALID_ARGUMENT, "Param error. The name must be a string");
77             return nullptr;
78         }
79         std::string name = "";
80         NapiUtils::GetValue(env, argv[0], name);
81         Node *node = new (std::nothrow) Node(name);
82         ASSERT_THROW_BASE(env, node != nullptr, Status::INTERNAL_ERROR, "new: new node go wrong", self);
83         auto finalize = [](napi_env env, void *data, void *hint) {
84             Node *node = reinterpret_cast<Node *>(data);
85             delete node;
86         };
87         napi_status status = napi_wrap(env, self, node, finalize, nullptr, nullptr);
88         if (status != napi_ok) {
89             LOG_ERROR("napi_wrap failed. code:%{public}d", status);
90             delete node;
91             return nullptr;
92         }
93         return self;
94     }
95 
96     // create instance by 'Node(name)'
97     napi_value cons = nullptr;
98     NAPI_CALL(env, napi_get_reference_value(env, g_node_cons_ref, &cons));
99     napi_value output = nullptr;
100     NAPI_CALL(env, napi_new_instance(env, cons, argc, argv, &output));
101     return output;
102 }
103 
InnerGetName()104 std::string Node::InnerGetName()
105 {
106     return this->name_;
107 }
108 
GetName(napi_env env,napi_callback_info info)109 napi_value Node::GetName(napi_env env, napi_callback_info info)
110 {
111     napi_value self = nullptr;
112     NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr));
113     Node *thisNode = nullptr;
114     NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast<void **>(&thisNode)));
115     ASSERT_THROW(env, thisNode != nullptr, Status::INTERNAL_ERROR, "unwrap self is null");
116     napi_value result;
117     NapiUtils::SetValue(env, thisNode->name_, result);
118     return result;
119 }
120 
GetUniqueId(napi_env env,napi_callback_info info)121 napi_value Node::GetUniqueId(napi_env env, napi_callback_info info)
122 {
123     napi_value self = nullptr;
124     NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr));
125     Node *thisNode = nullptr;
126     NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast<void **>(&thisNode)));
127     ASSERT(thisNode != nullptr, "unwrap self go wrong.", nullptr);
128     ASSERT_THROW(env, thisNode->GetID().has_value(), Status::UNSUPPORTED_OPERATION, "empty id");
129     ID id = thisNode->GetID().value();
130     napi_value result;
131     NAPI_CALL(env, napi_create_object(env, &result));
132     napi_value jsDeviceId;
133     NapiUtils::SetValue(env, id.deviceId, jsDeviceId);
134     NAPI_CALL(env, napi_set_named_property(env, result, "id", jsDeviceId));
135     napi_value jsClock;
136     NapiUtils::SetValue(env, static_cast<int64_t>(id.clock), jsClock);
137     NAPI_CALL(env, napi_set_named_property(env, result, "clock", jsClock));
138     return result;
139 }
140 
InsertNodes(napi_env env,napi_callback_info info)141 napi_value Node::InsertNodes(napi_env env, napi_callback_info info)
142 {
143     size_t argc = 2;
144     napi_value argv[2] = {nullptr};
145     napi_value self = nullptr;
146     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr));
147     Node *thisNode = nullptr;
148     NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast<void **>(&thisNode)));
149     ASSERT(thisNode != nullptr, "unwrap self go wrong.", nullptr);
150     ASSERT_THROW(env, thisNode->GetID().has_value(), Status::UNSUPPORTED_OPERATION, "empty id");
151     int64_t index = 0;
152     napi_status status = NapiUtils::GetValue(env, argv[0], index);
153     ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: Read index go wrong.");
154     ASSERT_THROW(env, index >= 0, Status::INVALID_ARGUMENT, "Param Error: Invalid index.");
155     bool isArray = false;
156     NAPI_CALL(env, napi_is_array(env, argv[1], &isArray));
157     ASSERT_THROW(env, isArray, Status::INVALID_ARGUMENT, "Param Error: The nodes must be an array.");
158     uint32_t length = 0;
159     NAPI_CALL(env, napi_get_array_length(env, argv[1], &length));
160     LOG_INFO("length = %{public}u", length);
161     for (uint32_t i = 0; i < length; i++) {
162         napi_value jsNode = nullptr;
163         NAPI_CALL(env, napi_get_element(env, argv[1], i, &jsNode));
164         Node *tempNode = nullptr;
165         NAPI_CALL(env, napi_unwrap(env, jsNode, reinterpret_cast<void **>(&tempNode)));
166         auto [retCode, id] = thisNode->GetAdapter()->InsertNode(index + i, tempNode->InnerGetName());
167         if (retCode != SUCCESS || !id.has_value()) {
168             ThrowNapiError(env, retCode, "InsertNodes go wrong.");
169             return nullptr;
170         }
171         tempNode->SetID(id);
172         tempNode->SetTableName(thisNode->GetTableName());
173         tempNode->SetDBStore(thisNode->GetDBStore());
174     }
175     return nullptr;
176 }
177 
Delete(napi_env env,napi_callback_info info)178 napi_value Node::Delete(napi_env env, napi_callback_info info)
179 {
180     size_t argc = 2;
181     napi_value argv[2] = {nullptr};
182     napi_value self = nullptr;
183     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr));
184     Node *thisNode = nullptr;
185     NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast<void **>(&thisNode)));
186     ASSERT(thisNode != nullptr, "unwrap self go wrong.", nullptr);
187     ASSERT_THROW(env, thisNode->GetID().has_value(), Status::UNSUPPORTED_OPERATION, "empty id");
188     int64_t index = 0;
189     napi_status status = NapiUtils::GetValue(env, argv[0], index);
190     ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: Read index go wrong.");
191     ASSERT_THROW(env, index >= 0, Status::INVALID_ARGUMENT, "Param Error: Invalid index.");
192     int64_t length = 0;
193     status = NapiUtils::GetValue(env, argv[1], length);
194     ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: Read length go wrong.");
195     ASSERT_THROW(env, length > 0, Status::INVALID_ARGUMENT, "Param Error: Invalid length.");
196 
197     int32_t retCode = thisNode->GetAdapter()->DeleteChildren(index, length);
198     if (retCode != SUCCESS) {
199         ThrowNapiError(env, retCode, "Delete Nodes go wrong.");
200     }
201     return nullptr;
202 }
203 
GetChildren(napi_env env,napi_callback_info info)204 napi_value Node::GetChildren(napi_env env, napi_callback_info info)
205 {
206     size_t argc = 2;
207     napi_value argv[2] = {nullptr};
208     napi_value self = nullptr;
209     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr));
210     Node *thisNode = nullptr;
211     NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast<void **>(&thisNode)));
212     ASSERT(thisNode != nullptr, "unwrap self go wrong.", nullptr);
213     ASSERT_THROW(env, thisNode->GetID().has_value(), Status::UNSUPPORTED_OPERATION, "empty id");
214     int64_t start = 0;
215     napi_status status = NapiUtils::GetValue(env, argv[0], start);
216     ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: Read start index go wrong.");
217     ASSERT_THROW(env, start >= 0, Status::INVALID_ARGUMENT, "Param Error: Invalid start.");
218     int64_t end = 0;
219     status = NapiUtils::GetValue(env, argv[1], end);
220     ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: Read end index go wrong.");
221     ASSERT_THROW(env, end >= 0, Status::INVALID_ARGUMENT, "Param Error: Invalid end.");
222     ASSERT_THROW(env, end > start, Status::INVALID_ARGUMENT, "Param Error: end should be greater than start.");
223 
224     auto [retCode, result] = thisNode->GetAdapter()->GetChildren(start, end - start);
225     if (retCode != SUCCESS) {
226         ThrowNapiError(env, retCode, "Get Children go wrong.");
227         return nullptr;
228     }
229     // transfer string to node array
230     napi_value output = nullptr;
231     int ret = Parser::ParseJsonStrToJsChildren(env, result, thisNode, output);
232     if (ret != OK) {
233         ThrowNapiError(env, Status::INTERNAL_ERROR, "convert result go wrong.");
234         return nullptr;
235     }
236     return output;
237 }
238 
GetJsonResult(napi_env env,napi_callback_info info)239 napi_value Node::GetJsonResult(napi_env env, napi_callback_info info)
240 {
241     napi_value self = nullptr;
242     NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr));
243     Node *thisNode = nullptr;
244     NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast<void **>(&thisNode)));
245     ASSERT(thisNode != nullptr, "unwrap self go wrong.", nullptr);
246     ASSERT_THROW(env, thisNode->GetID().has_value(), Status::UNSUPPORTED_OPERATION, "empty id");
247     auto [retCode, result] = thisNode->GetAdapter()->GetJsonString();
248     if (retCode != SUCCESS) {
249         ThrowNapiError(env, retCode, "toString go wrong.");
250         return nullptr;
251     }
252     napi_value output = nullptr;
253     napi_status status = NapiUtils::SetValue(env, result, output);
254     if (status != napi_ok || output == nullptr) {
255         ThrowNapiError(env, Status::INTERNAL_ERROR, "convert result go wrong.");
256         return nullptr;
257     }
258     return output;
259 }
260 
InsertTexts(napi_env env,napi_callback_info info)261 napi_value Node::InsertTexts(napi_env env, napi_callback_info info)
262 {
263     size_t argc = 2;
264     napi_value argv[2] = {nullptr};
265     napi_value self = nullptr;
266     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr));
267     Node *thisNode = nullptr;
268     NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast<void **>(&thisNode)));
269     ASSERT(thisNode != nullptr, "unwrap self go wrong.", nullptr);
270     ASSERT_THROW(env, thisNode->GetID().has_value(), Status::UNSUPPORTED_OPERATION, "empty id");
271     int64_t index = 0;
272     napi_status status = NapiUtils::GetValue(env, argv[0], index);
273     ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: Read index go wrong.");
274     ASSERT_THROW(env, index >= 0, Status::INVALID_ARGUMENT, "Param Error: Invalid index.");
275     bool isArray = false;
276     NAPI_CALL(env, napi_is_array(env, argv[1], &isArray));
277     ASSERT_THROW(env, isArray, Status::INVALID_ARGUMENT, "Param Error: The nodes must be an array.");
278     uint32_t length = 0;
279     NAPI_CALL(env, napi_get_array_length(env, argv[1], &length));
280     for (uint32_t i = 0; i < length; i++) {
281         napi_value jsText = nullptr;
282         NAPI_CALL(env, napi_get_element(env, argv[1], i, &jsText));
283         Text *tempText = nullptr;
284         NAPI_CALL(env, napi_unwrap(env, jsText, reinterpret_cast<void **>(&tempText)));
285         auto [retCode, id] = thisNode->GetAdapter()->InsertText(index + i);
286         if (retCode != SUCCESS || !id.has_value()) {
287             ThrowNapiError(env, retCode, "InsertText go wrong.");
288             return nullptr;
289         }
290         tempText->SetID(id);
291         tempText->SetTableName(thisNode->GetTableName());
292         tempText->SetDBStore(thisNode->GetDBStore());
293     }
294     return nullptr;
295 }
296 
SetAttributes(napi_env env,napi_callback_info info)297 napi_value Node::SetAttributes(napi_env env, napi_callback_info info)
298 {
299     size_t argc = 1;
300     napi_value argv[1] = {nullptr};
301     napi_value self = nullptr;
302     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr));
303     Node *thisNode = nullptr;
304     NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast<void **>(&thisNode)));
305     ASSERT(thisNode != nullptr, "unwrap self go wrong.", nullptr);
306     ASSERT_THROW(env, thisNode->GetID().has_value(), Status::UNSUPPORTED_OPERATION, "empty id");
307 
308     // convert input argument
309     napi_value keys = nullptr;
310     napi_get_all_property_names(env, argv[0], napi_key_own_only,
311         static_cast<napi_key_filter>(napi_key_enumerable | napi_key_skip_symbols), napi_key_numbers_to_strings, &keys);
312     uint32_t arrLen = 0;
313     napi_status status = napi_get_array_length(env, keys, &arrLen);
314     ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: Parse argument go wrong.");
315     for (size_t i = 0; i < arrLen; i++) {
316         napi_value key = nullptr;
317         status = napi_get_element(env, keys, i, &key);
318         ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: get element go wrong.");
319         std::string keyStr;
320         NapiUtils::GetValue(env, key, keyStr);
321         napi_value value = nullptr;
322         napi_get_property(env, argv[0], key, &value);
323         std::string valueStr;
324         int retCode = Parser::ParseVariantJsValueToStr(env, value, valueStr);
325         ASSERT(retCode == OK, "parse value go wrong.", nullptr);
326         retCode = thisNode->GetAdapter()->SetAttribute(keyStr, valueStr, 0);
327         ASSERT_THROW(env, retCode == SUCCESS, retCode, "Set attribute go wrong.");
328     }
329     return nullptr;
330 }
331 
RemoveAttributes(napi_env env,napi_callback_info info)332 napi_value Node::RemoveAttributes(napi_env env, napi_callback_info info)
333 {
334     size_t argc = 1;
335     napi_value argv[1] = {nullptr};
336     napi_value self = nullptr;
337     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr));
338     Node *thisNode = nullptr;
339     NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast<void **>(&thisNode)));
340     ASSERT(thisNode != nullptr, "unwrap self go wrong.", nullptr);
341     bool isArray;
342     NAPI_CALL(env, napi_is_array(env, argv[0], &isArray));
343     if (!isArray) {
344         ThrowNapiError(env, Status::INVALID_ARGUMENT, "Param Error: The argument must be an array.");
345         return nullptr;
346     }
347     uint32_t length = 0;
348     NAPI_CALL(env, napi_get_array_length(env, argv[0], &length));
349     for (uint32_t i = 0; i < length; i++) {
350         napi_value jsAttributeName = nullptr;
351         NAPI_CALL(env, napi_get_element(env, argv[0], i, &jsAttributeName));
352         std::string attributeName;
353         NapiUtils::GetValue(env, jsAttributeName, attributeName);
354         int32_t retCode = thisNode->GetAdapter()->RemoveAttrribute(attributeName);
355         if (retCode != SUCCESS) {
356             ThrowNapiError(env, retCode, "RemoveAttrribute go wrong.");
357             return nullptr;
358         }
359     }
360     return nullptr;
361 }
362 
GetAttributes(napi_env env,napi_callback_info info)363 napi_value Node::GetAttributes(napi_env env, napi_callback_info info)
364 {
365     napi_value self = nullptr;
366     NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr));
367     Node *thisNode = nullptr;
368     NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast<void **>(&thisNode)));
369     ASSERT(thisNode != nullptr, "unwrap self go wrong.", nullptr);
370     ASSERT_THROW(env, thisNode->GetID().has_value(), Status::UNSUPPORTED_OPERATION, "empty id");
371 
372     auto [retCode, result] = thisNode->GetAdapter()->GetAttributes();
373     if (retCode != SUCCESS) {
374         ThrowNapiError(env, retCode, "GetAttributes go wrong.");
375         return nullptr;
376     }
377     // convert result string to record
378     napi_value output = nullptr;
379     int ret = Parser::ParseFromAttrsJsonStr(env, result, output);
380     if (ret != OK) {
381         ThrowNapiError(env, Status::INTERNAL_ERROR, "parse result go wrong.");
382         return nullptr;
383     }
384     return output;
385 }
386 
SetAsset(napi_env env,napi_callback_info info)387 napi_value Node::SetAsset(napi_env env, napi_callback_info info)
388 {
389     size_t argc = 2;
390     napi_value argv[2] = {nullptr};
391     napi_value self = nullptr;
392     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr));
393     Node *thisNode = nullptr;
394     NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast<void **>(&thisNode)));
395     ASSERT(thisNode != nullptr, "unwrap self go wrong.", nullptr);
396     ASSERT_THROW(env, thisNode->GetID().has_value(), Status::UNSUPPORTED_OPERATION, "empty id");
397 
398     // convert input argument
399     std::string assetKey;
400     napi_status status = NapiUtils::GetValue(env, argv[0], assetKey);
401     ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: get asset key go wrong.");
402 
403     std::string assetValue;
404     status = NapiUtils::GetValue(env, argv[1], assetValue);
405     ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: get asset value go wrong.");
406 
407     int32_t retCode = thisNode->GetAdapter()->SetAttribute(assetKey, assetValue, 1);
408     if (retCode != SUCCESS) {
409         ThrowNapiError(env, retCode, "Set asset go wrong.");
410     }
411     return nullptr;
412 }
413 } // namespace OHOS::CollaborationEdit
414