1 /*
2 * Copyright (c) 2023 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 #define LOG_TAG "UnifiedDataChannelNapi"
16 #include "unified_data_channel_napi.h"
17
18 #include "napi_data_utils.h"
19 #include "unified_data_napi.h"
20
21 namespace OHOS {
22 namespace UDMF {
23 using namespace OHOS::AppExecFwk;
UnifiedDataChannelInit(napi_env env,napi_value exports)24 napi_value UnifiedDataChannelNapi::UnifiedDataChannelInit(napi_env env, napi_value exports)
25 {
26 LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataChannelNapi");
27 napi_value intention = CreateIntention(env);
28 napi_property_descriptor desc[] = {
29 DECLARE_NAPI_PROPERTY("Intention", intention),
30 DECLARE_NAPI_FUNCTION("insertData", InsertData),
31 DECLARE_NAPI_FUNCTION("updateData", UpdateData),
32 DECLARE_NAPI_FUNCTION("queryData", QueryData),
33 DECLARE_NAPI_FUNCTION("deleteData", DeleteData),
34 DECLARE_NAPI_GETTER("ShareOptions", CreateShareOptions),
35 DECLARE_NAPI_FUNCTION("setAppShareOptions", SetAppShareOptions),
36 DECLARE_NAPI_FUNCTION("removeAppShareOptions", RemoveAppShareOptions),
37 };
38
39 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
40 return exports;
41 }
42
CreateIntention(napi_env env)43 napi_value UnifiedDataChannelNapi::CreateIntention(napi_env env)
44 {
45 napi_value intention = nullptr;
46 napi_create_object(env, &intention);
47 SetNamedProperty(env, intention, JS_UD_INTENTION_NAME_MAP.at(UD_INTENTION_DATA_HUB),
48 UD_INTENTION_MAP.at(UD_INTENTION_DATA_HUB));
49 SetNamedProperty(env, intention, JS_UD_INTENTION_NAME_MAP.at(UD_INTENTION_DRAG),
50 UD_SYSTEM_INTENTION_MAP.at(UD_INTENTION_DRAG));
51 napi_object_freeze(env, intention);
52 return intention;
53 }
54
SetNamedProperty(napi_env env,napi_value & obj,const std::string & name,const std::string & value)55 napi_status UnifiedDataChannelNapi::SetNamedProperty(napi_env env, napi_value &obj, const std::string &name,
56 const std::string &value)
57 {
58 napi_value property = nullptr;
59 napi_status status = NapiDataUtils::SetValue(env, value, property);
60 ASSERT(status == napi_ok, "string to napi_value failed!", status);
61 status = napi_set_named_property(env, obj, name.c_str(), property);
62 ASSERT(status == napi_ok, "napi_set_named_property failed!", status);
63 return status;
64 }
65
InsertData(napi_env env,napi_callback_info info)66 napi_value UnifiedDataChannelNapi::InsertData(napi_env env, napi_callback_info info)
67 {
68 LOG_DEBUG(UDMF_KITS_NAPI, "InsertData is called!");
69 struct InsertContext : public ContextBase {
70 std::string key;
71 Intention intention;
72 std::shared_ptr<UnifiedData> unifiedData;
73 };
74 std::string intention;
75 UnifiedDataNapi *unifiedDataNapi = nullptr;
76 auto ctxt = std::make_shared<InsertContext>();
77 auto input = [env, ctxt, &intention, &unifiedDataNapi](size_t argc, napi_value *argv) {
78 // require 2 arguments <options, unifiedData>
79 ASSERT_BUSINESS_ERR(ctxt, argc >= 2,
80 E_INVALID_PARAMETERS, "Parameter error: Mandatory parameters are left unspecified");
81 ctxt->status = GetNamedProperty(env, argv[0], "intention", intention);
82 ASSERT_BUSINESS_ERR(ctxt, UnifiedDataUtils::GetIntentionByString(intention) != UD_INTENTION_DRAG,
83 E_INVALID_PARAMETERS, "Parameter error: The intention parameter is invalid");
84 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok && UnifiedDataUtils::IsPersist(intention),
85 E_INVALID_PARAMETERS, "Parameter error: parameter options intention type must correspond to Intention");
86 ctxt->status = napi_unwrap(env, argv[1], reinterpret_cast<void **>(&unifiedDataNapi));
87 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, E_INVALID_PARAMETERS,
88 "Parameter error: parameter data type must be UnifiedData");
89 };
90 ctxt->GetCbInfo(env, info, input);
91 ASSERT_NULL(!ctxt->isThrowError, "Insert Exit");
92 ctxt->unifiedData = unifiedDataNapi->value_;
93 ctxt->intention = UnifiedDataUtils::GetIntentionByString(intention);
94 auto execute = [ctxt]() {
95 CustomOption option = { .intention = ctxt->intention };
96 auto status = UdmfClient::GetInstance().SetData(option, *(ctxt->unifiedData), ctxt->key);
97 ASSERT_WITH_ERRCODE(ctxt, status == E_OK, status, "InsertData failed!");
98 };
99
100 auto output = [env, ctxt](napi_value &result) {
101 ctxt->status = NapiDataUtils::SetValue(env, ctxt->key, result);
102 ASSERT_WITH_ERRCODE(ctxt, ctxt->status == napi_ok, E_ERROR, "output failed!");
103 };
104 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
105 }
106
UpdateData(napi_env env,napi_callback_info info)107 napi_value UnifiedDataChannelNapi::UpdateData(napi_env env, napi_callback_info info)
108 {
109 LOG_DEBUG(UDMF_KITS_NAPI, "UpdateData is called!");
110 struct UpdateContext : public ContextBase {
111 std::string key;
112 std::shared_ptr<UnifiedData> unifiedData;
113 };
114 std::string key;
115 UnifiedDataNapi *unifiedDataNapi = nullptr;
116 auto ctxt = std::make_shared<UpdateContext>();
117 auto input = [env, ctxt, &unifiedDataNapi](size_t argc, napi_value *argv) {
118 // require 2 arguments <options, unifiedData>
119 ASSERT_BUSINESS_ERR(ctxt, argc >= 2,
120 E_INVALID_PARAMETERS, "Parameter error: Mandatory parameters are left unspecified");
121 ctxt->status = GetNamedProperty(env, argv[0], "key", ctxt->key);
122 UnifiedKey key(ctxt->key);
123 ASSERT_BUSINESS_ERR(ctxt,
124 ctxt->status == napi_ok && key.IsValid() && UnifiedDataUtils::IsPersist(key.intention),
125 E_INVALID_PARAMETERS, "Parameter error: parameter options intention type must correspond to Intention");
126 ctxt->status = napi_unwrap(env, argv[1], reinterpret_cast<void **>(&unifiedDataNapi));
127 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, E_INVALID_PARAMETERS,
128 "Parameter error: parameter data type must be UnifiedData");
129 };
130 ctxt->GetCbInfo(env, info, input);
131 ASSERT_NULL(!ctxt->isThrowError, "Update Exit");
132 ctxt->unifiedData = unifiedDataNapi->value_;
133 auto execute = [ctxt]() {
134 QueryOption option = { .key = ctxt->key };
135 auto status = UdmfClient::GetInstance().UpdateData(option, *(ctxt->unifiedData));
136 ASSERT_WITH_ERRCODE(ctxt, status == E_OK, status, "UpdateData failed!");
137 };
138 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
139 }
140
QueryData(napi_env env,napi_callback_info info)141 napi_value UnifiedDataChannelNapi::QueryData(napi_env env, napi_callback_info info)
142 {
143 LOG_DEBUG(UDMF_KITS_NAPI, "QueryData is called!");
144 struct QueryContext : public ContextBase {
145 std::string key;
146 Intention intention;
147 std::vector<UnifiedData> unifiedDataSet;
148 };
149 std::string intention;
150 auto ctxt = std::make_shared<QueryContext>();
151 auto input = [env, ctxt, &intention](size_t argc, napi_value *argv) {
152 // require 1 arguments <options>
153 ASSERT_BUSINESS_ERR(ctxt, argc >= 1,
154 E_INVALID_PARAMETERS, "Parameter error: Mandatory parameters are left unspecified");
155 napi_status keyStatus;
156 napi_status intentionStatus;
157 auto options = argv[0];
158 keyStatus = GetNamedProperty(env, options, "key", ctxt->key);
159 intentionStatus = GetNamedProperty(env, options, "intention", intention);
160 ASSERT_BUSINESS_ERR(ctxt, UnifiedDataUtils::GetIntentionByString(intention) != UD_INTENTION_DRAG,
161 E_INVALID_PARAMETERS, "Parameter error: The intention parameter is invalid");
162 ASSERT_BUSINESS_ERR(ctxt, (keyStatus == napi_ok || intentionStatus == napi_ok) &&
163 UnifiedDataUtils::IsValidOptions(ctxt->key, intention),
164 E_INVALID_PARAMETERS, "Parameter error: parameter options intention type must correspond to Intention");
165 };
166 ctxt->GetCbInfo(env, info, input);
167 ASSERT_NULL(!ctxt->isThrowError, "Query Exit");
168 ctxt->intention = UnifiedDataUtils::GetIntentionByString(intention);
169 auto execute = [env, ctxt]() {
170 QueryOption option = {
171 .key = ctxt->key,
172 .intention = ctxt->intention,
173 };
174 auto status = UdmfClient::GetInstance().GetBatchData(option, ctxt->unifiedDataSet);
175 LOG_DEBUG(UDMF_SERVICE, "GetBatchData : status = %{public}d!", status);
176 ASSERT_WITH_ERRCODE(ctxt, status == E_OK, status, "QueryData failed!");
177 };
178 auto output = [env, ctxt](napi_value &result) {
179 ASSERT_WITH_ERRCODE(ctxt, !ctxt->unifiedDataSet.empty(), E_ERROR, "unifiedDataSet is empty!");
180 ctxt->status = ConvertUnifiedDataSetToNapi(env, ctxt->unifiedDataSet, result);
181 ASSERT_WITH_ERRCODE(ctxt, ctxt->status == napi_ok, E_ERROR, "ConvertUnifiedDataSetToNapi failed!");
182 };
183 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
184 }
185
DeleteData(napi_env env,napi_callback_info info)186 napi_value UnifiedDataChannelNapi::DeleteData(napi_env env, napi_callback_info info)
187 {
188 LOG_DEBUG(UDMF_KITS_NAPI, "DeleteData is called!");
189 struct DeleteContext : public ContextBase {
190 std::string key;
191 Intention intention;
192 std::vector<UnifiedData> unifiedDataSet;
193 };
194 std::string intention;
195 auto ctxt = std::make_shared<DeleteContext>();
196 auto input = [env, ctxt, &intention](size_t argc, napi_value *argv) {
197 // require 1 arguments <options>
198 ASSERT_BUSINESS_ERR(ctxt, argc >= 1,
199 E_INVALID_PARAMETERS, "Parameter error: Mandatory parameters are left unspecified");
200 napi_status keyStatus;
201 napi_status intentionStatus;
202 napi_value options = argv[0];
203 keyStatus = GetNamedProperty(env, options, "key", ctxt->key);
204 intentionStatus = GetNamedProperty(env, options, "intention", intention);
205 ASSERT_BUSINESS_ERR(ctxt, intention.empty() ||
206 UnifiedDataUtils::GetIntentionByString(intention) == UD_INTENTION_DATA_HUB,
207 E_INVALID_PARAMETERS, "Parameter error: The intention parameter is invalid");
208 ASSERT_BUSINESS_ERR(ctxt,
209 (keyStatus == napi_ok || intentionStatus == napi_ok) &&
210 UnifiedDataUtils::IsValidOptions(ctxt->key, intention),
211 E_INVALID_PARAMETERS, "Parameter error: parameter options intention type must correspond to Intention");
212 };
213 ctxt->GetCbInfo(env, info, input);
214 ASSERT_NULL(!ctxt->isThrowError, "Delete Exit");
215 ctxt->intention = UnifiedDataUtils::GetIntentionByString(intention);
216 auto execute = [env, ctxt]() {
217 QueryOption option = {
218 .key = ctxt->key,
219 .intention = ctxt->intention,
220 };
221 auto status = UdmfClient::GetInstance().DeleteData(option, ctxt->unifiedDataSet);
222 ASSERT_WITH_ERRCODE(ctxt, status == E_OK, status, "DeleteData failed!");
223 };
224
225 auto output = [env, ctxt](napi_value &result) {
226 ASSERT_WITH_ERRCODE(ctxt, !ctxt->unifiedDataSet.empty(), E_ERROR, "unifiedDataSet is empty!");
227 ctxt->status = ConvertUnifiedDataSetToNapi(env, ctxt->unifiedDataSet, result);
228 ASSERT_WITH_ERRCODE(ctxt, ctxt->status == napi_ok, E_ERROR, "ConvertUnifiedDataSetToNapi failed!");
229 };
230 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
231 }
232
GetNamedProperty(napi_env env,napi_value & obj,const std::string & key,std::string & value)233 napi_status UnifiedDataChannelNapi::GetNamedProperty(napi_env env, napi_value &obj, const std::string &key,
234 std::string &value)
235 {
236 bool hasKey = false;
237 napi_status status = napi_has_named_property(env, obj, key.c_str(), &hasKey);
238 if (status != napi_ok) {
239 LOG_ERROR(UDMF_KITS_NAPI, "napi_has_named_property failed, name = %{public}s", key.c_str());
240 return napi_generic_failure;
241 }
242 if (!hasKey) {
243 LOG_ERROR(UDMF_KITS_NAPI, "The property name is non-existent, name: %{public}s", key.c_str());
244 return napi_generic_failure;
245 }
246 napi_value napiValue = nullptr;
247 status = napi_get_named_property(env, obj, key.c_str(), &napiValue);
248 if (status != napi_ok || napiValue == nullptr) {
249 LOG_ERROR(UDMF_KITS_NAPI, "napi_get_named_property failed, name = %{public}s", key.c_str());
250 return napi_generic_failure;
251 }
252 if (NapiDataUtils::IsNull(env, napiValue)) {
253 LOG_ERROR(UDMF_KITS_NAPI, "The property value is null, name = %{public}s", key.c_str());
254 return napi_generic_failure;
255 }
256 status = NapiDataUtils::GetValue(env, napiValue, value);
257 if (status != napi_ok) {
258 LOG_ERROR(UDMF_KITS_NAPI, "NapiDataUtils::GetValue failed, name = %{public}s", key.c_str());
259 return status;
260 }
261 LOG_DEBUG(UDMF_KITS_NAPI, "Param parse successful, Options.%{public}s = %{public}s", key.c_str(), value.c_str());
262 return status;
263 }
264
CreateShareOptions(napi_env env,napi_callback_info info)265 napi_value UnifiedDataChannelNapi::CreateShareOptions(napi_env env, napi_callback_info info)
266 {
267 napi_value jsShareOptions = nullptr;
268 napi_create_object(env, &jsShareOptions);
269
270 napi_value jsInApp;
271 NapiDataUtils::SetValue(env, static_cast<int32_t>(ShareOptions::IN_APP), jsInApp);
272 NAPI_CALL(env, napi_set_named_property(env, jsShareOptions, "IN_APP", jsInApp));
273
274 napi_value jsCrossDevice;
275 NapiDataUtils::SetValue(env, static_cast<int32_t>(ShareOptions::CROSS_APP), jsCrossDevice);
276 NAPI_CALL(env, napi_set_named_property(env, jsShareOptions, "CROSS_APP", jsCrossDevice));
277 return jsShareOptions;
278 }
279
SetAppShareOptions(napi_env env,napi_callback_info info)280 napi_value UnifiedDataChannelNapi::SetAppShareOptions(napi_env env, napi_callback_info info)
281 {
282 LOG_DEBUG(UDMF_KITS_NAPI, "SetAppShareOption is called!");
283 std::string intention;
284 int32_t shareOptionValue = ShareOptions::CROSS_APP;
285 auto ctxt = std::make_shared<ContextBase>();
286 auto input = [env, ctxt, &intention, &shareOptionValue](size_t argc, napi_value* argv) {
287 LOG_DEBUG(UDMF_KITS_NAPI, "set appShareOption, argc = %{public}zu !", argc);
288 // required 2 arguments : intention, shareOption
289 ASSERT_BUSINESS_ERR(ctxt, argc > 1,
290 Status::E_INVALID_PARAMETERS, "Parameter error: Mandatory parameters are left unspecified");
291 ctxt->status = NapiDataUtils::GetValue(env, argv[0], intention);
292 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, E_INVALID_PARAMETERS,
293 "Parameter error:The parameter intention must be within the scope of the Intention enumeration.");
294 ctxt->status = NapiDataUtils::GetValue(env, argv[1], shareOptionValue);
295 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, E_INVALID_PARAMETERS,
296 "Parameter error:The parameter shareOption must be within the scope of the ShareOptions enumeration.");
297 };
298 ctxt->GetCbInfoSync(env, info, input);
299 ASSERT_NULL(!ctxt->isThrowError, "SetAppShareOption Exit");
300 auto status = E_OK;
301 ASSERT_ERR(ctxt->env, intention == "Drag",
302 E_INVALID_PARAMETERS, "Parameter error: The intention parameter is invalid!");
303 ASSERT_ERR(ctxt->env, (shareOptionValue >= IN_APP && shareOptionValue < SHARE_OPTIONS_BUTT),
304 E_INVALID_PARAMETERS, "Parameter error: The shareOptions parameter is invalid!");
305 std::transform(intention.begin(), intention.end(), intention.begin(), ::tolower); // js : Drag --> drag
306 status = UdmfClient::GetInstance().SetAppShareOption(intention, static_cast<ShareOptions>(shareOptionValue));
307 ASSERT_BUSINESS_ERR_VOID(ctxt, !(status == E_SETTINGS_EXISTED), E_SETTINGS_EXISTED, "Settings already exist!");
308 ASSERT_BUSINESS_ERR_VOID(ctxt, status != E_NO_PERMISSION, E_NO_PERMISSION, "Permission denied!");
309 ASSERT_ERR(ctxt->env, status == E_OK, status, "invalid arguments!");
310 return nullptr;
311 }
312
RemoveAppShareOptions(napi_env env,napi_callback_info info)313 napi_value UnifiedDataChannelNapi::RemoveAppShareOptions(napi_env env, napi_callback_info info)
314 {
315 LOG_DEBUG(UDMF_KITS_NAPI, "RemoveAppShareOption is called!");
316 std::string intention;
317 auto ctxt = std::make_shared<ContextBase>();
318 auto input = [env, ctxt, &intention](size_t argc, napi_value* argv) {
319 LOG_DEBUG(UDMF_KITS_NAPI, "RemoveAppShareOption, argc = %{public}zu !", argc);
320 // required 2 arguments : typeId
321 ASSERT_BUSINESS_ERR(ctxt, argc > 0,
322 Status::E_INVALID_PARAMETERS, "Parameter error: Mandatory parameters are left unspecified");
323 ctxt->status = NapiDataUtils::GetValue(env, argv[0], intention);
324 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, E_INVALID_PARAMETERS,
325 "Parameter error:The parameter intention must be within the scope of the Intention enumeration.");
326 };
327 ctxt->GetCbInfoSync(env, info, input);
328 ASSERT_NULL(!ctxt->isThrowError, "RemoveAppShareOption Exit");
329 ASSERT_ERR(ctxt->env, intention == "Drag",
330 E_INVALID_PARAMETERS, "Parameter error: The intention parameter is invalid!");
331 std::transform(intention.begin(), intention.end(), intention.begin(), ::tolower); // js : Drag --> drag
332 auto status = E_OK;
333 status = UdmfClient::GetInstance().RemoveAppShareOption(intention);
334 ASSERT_BUSINESS_ERR_VOID(ctxt, status != E_NO_PERMISSION, E_NO_PERMISSION, "Permission denied!");
335 ASSERT_ERR(ctxt->env, status == E_OK, status, "invalid arguments!");
336 return nullptr;
337 }
338
ConvertUnifiedDataSetToNapi(napi_env env,const std::vector<UnifiedData> & dataSet,napi_value & output)339 napi_status UnifiedDataChannelNapi::ConvertUnifiedDataSetToNapi(
340 napi_env env, const std::vector<UnifiedData> &dataSet, napi_value &output)
341 {
342 auto status = napi_create_array_with_length(env, dataSet.size(), &output);
343 if (status != napi_ok) {
344 LOG_ERROR(UDMF_KITS_NAPI, "napi_create_array_with_length failed!");
345 return napi_generic_failure;
346 }
347 int index = 0;
348 for (const UnifiedData &data : dataSet) {
349 std::shared_ptr<UnifiedData> unifiedData = std::make_shared<UnifiedData>();
350 unifiedData->SetRecords(data.GetRecords());
351 napi_value dataNapi = nullptr;
352 UnifiedDataNapi::NewInstance(env, unifiedData, dataNapi);
353 status = napi_set_element(env, output, index++, dataNapi);
354 if (status != napi_ok) {
355 LOG_ERROR(UDMF_KITS_NAPI, "napi_set_element failed!");
356 return napi_generic_failure;
357 }
358 }
359 return napi_ok;
360 }
361 } // namespace UDMF
362 } // namespace OHOS