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