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