1 /*
2  * Copyright (C) 2021-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 #include <memory>
16 #include <thread>
17 #include <uv.h>
18 
19 #include "entry_getter.h"
20 #include "napi_common_want.h"
21 #include "pasteboard_common.h"
22 #include "pasteboard_error.h"
23 #include "pasteboard_hilog.h"
24 #include "pasteboard_js_err.h"
25 #include "systempasteboard_napi.h"
26 using namespace OHOS::MiscServices;
27 using namespace OHOS::Media;
28 
29 namespace OHOS {
30 namespace MiscServicesNapi {
31 static thread_local napi_ref g_systemPasteboard = nullptr;
32 static thread_local napi_ref g_systemPasteboard_instance = nullptr;
33 thread_local std::map<napi_ref, std::shared_ptr<PasteboardObserverInstance>> SystemPasteboardNapi::observers_;
34 std::shared_ptr<PasteboardDelayGetterInstance> SystemPasteboardNapi::delayGetter_;
35 std::mutex SystemPasteboardNapi::delayMutex_;
36 constexpr int ARGC_TYPE_SET1 = 1;
37 constexpr size_t MAX_ARGS = 6;
38 constexpr size_t SYNC_TIMEOUT = 3500;
39 constexpr size_t DELAY_TIMEOUT = 2;
40 const std::string STRING_UPDATE = "update";
PasteboardObserverInstance(const napi_env &env, const napi_ref &ref)41 PasteboardObserverInstance::PasteboardObserverInstance(const napi_env &env, const napi_ref &ref) : env_(env), ref_(ref)
42 {
43     stub_ = new (std::nothrow) PasteboardObserverInstance::PasteboardObserverImpl();
44 }
45 
~PasteboardObserverInstance()46 PasteboardObserverInstance::~PasteboardObserverInstance()
47 {
48     napi_delete_reference(env_, ref_);
49 }
50 
GetStub()51 sptr<PasteboardObserverInstance::PasteboardObserverImpl> PasteboardObserverInstance::GetStub()
52 {
53     return stub_;
54 }
55 
UvQueueWorkOnPasteboardChanged(uv_work_t *work, int status)56 void UvQueueWorkOnPasteboardChanged(uv_work_t *work, int status)
57 {
58     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "UvQueueWorkOnPasteboardChanged start");
59     if (UV_ECANCELED == status || work == nullptr || work->data == nullptr) {
60         return;
61     }
62     PasteboardDataWorker *pasteboardDataWorker = (PasteboardDataWorker *)work->data;
63     if (pasteboardDataWorker == nullptr || pasteboardDataWorker->observer == nullptr) {
64         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "pasteboardDataWorker or ref is null");
65         delete work;
66         work = nullptr;
67         return;
68     }
69 
70     auto env = pasteboardDataWorker->observer->GetEnv();
71     auto ref = pasteboardDataWorker->observer->GetRef();
72 
73     napi_handle_scope scope = nullptr;
74     napi_open_handle_scope(env, &scope);
75     if (scope == nullptr) {
76         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "scope null");
77         return;
78     }
79     napi_value undefined = nullptr;
80     napi_get_undefined(env, &undefined);
81 
82     napi_value callback = nullptr;
83     napi_value resultOut = nullptr;
84     napi_get_reference_value(env, ref, &callback);
85     napi_value result = NapiGetNull(env);
86     napi_call_function(env, undefined, callback, 0, &result, &resultOut);
87 
88     napi_close_handle_scope(env, scope);
89     delete pasteboardDataWorker;
90     pasteboardDataWorker = nullptr;
91     delete work;
92 }
93 
OnPasteboardChanged()94 void PasteboardObserverInstance::OnPasteboardChanged()
95 {
96     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "OnPasteboardChanged is called!");
97     uv_loop_s *loop = nullptr;
98     napi_get_uv_event_loop(env_, &loop);
99     if (loop == nullptr) {
100         PASTEBOARD_HILOGW(PASTEBOARD_MODULE_JS_NAPI, "loop instance is nullptr");
101         return;
102     }
103 
104     uv_work_t *work = new (std::nothrow) uv_work_t;
105     if (work == nullptr) {
106         PASTEBOARD_HILOGW(PASTEBOARD_MODULE_JS_NAPI, "work is null");
107         return;
108     }
109     PasteboardDataWorker *pasteboardDataWorker = new (std::nothrow) PasteboardDataWorker();
110     if (pasteboardDataWorker == nullptr) {
111         PASTEBOARD_HILOGW(PASTEBOARD_MODULE_JS_NAPI, "pasteboardDataWorker is null");
112         delete work;
113         work = nullptr;
114         return;
115     }
116     pasteboardDataWorker->observer = shared_from_this();
117 
118     work->data = (void *)pasteboardDataWorker;
119 
120     int ret = uv_queue_work(
121         loop, work, [](uv_work_t *work) {}, UvQueueWorkOnPasteboardChanged);
122     if (ret != 0) {
123         delete pasteboardDataWorker;
124         pasteboardDataWorker = nullptr;
125         delete work;
126         work = nullptr;
127     }
128     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "OnPasteboardChanged end");
129 }
130 
PasteboardDelayGetterInstance(const napi_env &env, const napi_ref &ref)131 PasteboardDelayGetterInstance::PasteboardDelayGetterInstance(const napi_env &env, const napi_ref &ref)
132     : env_(env), ref_(ref)
133 {
134     stub_ = std::make_shared<PasteboardDelayGetterInstance::PasteboardDelayGetterImpl>();
135 }
136 
~PasteboardDelayGetterInstance()137 PasteboardDelayGetterInstance::~PasteboardDelayGetterInstance()
138 {
139     ref_ = nullptr;
140 }
141 
UvQueueWorkGetDelayPasteData(uv_work_t *work, int status)142 void UvQueueWorkGetDelayPasteData(uv_work_t *work, int status)
143 {
144     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "UvQueueWorkGetDelayPasteData start");
145     if (UV_ECANCELED == status || work == nullptr || work->data == nullptr) {
146         return;
147     }
148     PasteboardDelayWorker *pasteboardDelayWorker = (PasteboardDelayWorker *)work->data;
149     if (pasteboardDelayWorker == nullptr || pasteboardDelayWorker->delayGetter == nullptr) {
150         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "pasteboardDataWorker or delayGetter is null");
151         delete work;
152         work = nullptr;
153         return;
154     }
155     auto env = pasteboardDelayWorker->delayGetter->GetEnv();
156     auto ref = pasteboardDelayWorker->delayGetter->GetRef();
157     napi_handle_scope scope = nullptr;
158     napi_open_handle_scope(env, &scope);
159     if (scope == nullptr) {
160         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "scope is null");
161         return;
162     }
163     napi_value undefined = nullptr;
164     napi_get_undefined(env, &undefined);
165     napi_value argv[1] = { CreateNapiString(env, pasteboardDelayWorker->dataType) };
166     napi_value callback = nullptr;
167     napi_value resultOut = nullptr;
168     napi_get_reference_value(env, ref, &callback);
169     {
170         std::unique_lock<std::mutex> lock(pasteboardDelayWorker->mutex);
171         auto ret = napi_call_function(env, undefined, callback, 1, argv, &resultOut);
172         if (ret == napi_ok) {
173             PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "get delay data success");
174             UDMF::UnifiedDataNapi *unifiedDataNapi = nullptr;
175             napi_unwrap(env, resultOut, reinterpret_cast<void **>(&unifiedDataNapi));
176             if (unifiedDataNapi != nullptr) {
177                 pasteboardDelayWorker->unifiedData = unifiedDataNapi->value_;
178             }
179         }
180         napi_close_handle_scope(env, scope);
181         pasteboardDelayWorker->complete = true;
182         if (!pasteboardDelayWorker->clean) {
183             pasteboardDelayWorker->cv.notify_all();
184             return;
185         }
186     }
187     delete pasteboardDelayWorker;
188     pasteboardDelayWorker = nullptr;
189     delete work;
190     work = nullptr;
191 }
192 
GetUnifiedData(const std::string &type, UDMF::UnifiedData &data)193 void PasteboardDelayGetterInstance::GetUnifiedData(const std::string &type, UDMF::UnifiedData &data)
194 {
195     uv_loop_s *loop = nullptr;
196     napi_get_uv_event_loop(env_, &loop);
197     if (loop == nullptr) {
198         PASTEBOARD_HILOGW(PASTEBOARD_MODULE_JS_NAPI, "loop instance is nullptr");
199         return;
200     }
201     uv_work_t *work = new (std::nothrow) uv_work_t;
202     if (work == nullptr) {
203         PASTEBOARD_HILOGW(PASTEBOARD_MODULE_JS_NAPI, "work is null");
204         return;
205     }
206     PasteboardDelayWorker *pasteboardDelayWorker = new (std::nothrow) PasteboardDelayWorker();
207     if (pasteboardDelayWorker == nullptr) {
208         PASTEBOARD_HILOGW(PASTEBOARD_MODULE_JS_NAPI, "pasteboardDataWorker is null");
209         delete work;
210         work = nullptr;
211         return;
212     }
213     pasteboardDelayWorker->delayGetter = shared_from_this();
214     pasteboardDelayWorker->dataType = type;
215     work->data = (void *)pasteboardDelayWorker;
216     bool noNeedClean = false;
217     {
218         std::unique_lock<std::mutex> lock(pasteboardDelayWorker->mutex);
219         int ret = uv_queue_work(loop, work, [](uv_work_t *work) {}, UvQueueWorkGetDelayPasteData);
220         if (ret != 0) {
221             delete pasteboardDelayWorker;
222             pasteboardDelayWorker = nullptr;
223             delete work;
224             work = nullptr;
225             return;
226         }
227         if (pasteboardDelayWorker->cv.wait_for(lock, std::chrono::seconds(DELAY_TIMEOUT),
228             [pasteboardDelayWorker] { return pasteboardDelayWorker->complete; }) &&
229             pasteboardDelayWorker->unifiedData != nullptr) {
230             data = *(pasteboardDelayWorker->unifiedData);
231         }
232         if (!pasteboardDelayWorker->complete && uv_cancel((uv_req_t*)work) != 0) {
233             pasteboardDelayWorker->clean = true;
234             noNeedClean = true;
235         }
236     }
237     if (!noNeedClean) {
238         delete pasteboardDelayWorker;
239         pasteboardDelayWorker = nullptr;
240         delete work;
241         work = nullptr;
242     }
243 }
244 
CheckAgrsOfOnAndOff(napi_env env, bool checkArgsCount, napi_value *argv, size_t argc)245 bool SystemPasteboardNapi::CheckAgrsOfOnAndOff(napi_env env, bool checkArgsCount, napi_value *argv, size_t argc)
246 {
247     if (!CheckExpression(
248         env, checkArgsCount, JSErrorCode::INVALID_PARAMETERS, "Parameter error. The number of arguments is wrong.") ||
249         !CheckArgsType(env, argv[0], napi_string, "Parameter error. The type of mimeType must be string.")) {
250         return false;
251     }
252     std::string mimeType;
253     bool ret = GetValue(env, argv[0], mimeType);
254     if (!ret) {
255         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "GetValue failed");
256         return false;
257     }
258     if (!CheckExpression(env, mimeType == STRING_UPDATE, JSErrorCode::INVALID_PARAMETERS,
259         "Parameter error. The value of type must be update")) {
260         return false;
261     }
262     return true;
263 }
264 
On(napi_env env, napi_callback_info info)265 napi_value SystemPasteboardNapi::On(napi_env env, napi_callback_info info)
266 {
267     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi on() is called!");
268     size_t argc = MAX_ARGS;
269     napi_value argv[MAX_ARGS] = { 0 };
270     napi_value thisVar = 0;
271     void *data = nullptr;
272     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
273     // on(type: 'update', callback: () => void) has 2 args
274     if (!CheckAgrsOfOnAndOff(env, argc >= 2, argv, argc) ||
275         !CheckArgsType(env, argv[1], napi_function, "Parameter error. The type of callback must be function.")) {
276         return nullptr;
277     }
278 
279     napi_value result = nullptr;
280     napi_get_undefined(env, &result);
281     auto observer = GetObserver(env, argv[1]);
282     if (observer != nullptr) {
283         PASTEBOARD_HILOGW(PASTEBOARD_MODULE_JS_NAPI, "observer exist.");
284         return result;
285     }
286     napi_ref ref = nullptr;
287     napi_create_reference(env, argv[1], 1, &ref);
288     observer = std::make_shared<PasteboardObserverInstance>(env, ref);
289     observer->GetStub()->SetObserverWrapper(observer);
290     PasteboardClient::GetInstance()->Subscribe(PasteboardObserverType::OBSERVER_LOCAL, observer->GetStub());
291     observers_[ref] = observer;
292     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi on() is end!");
293     return result;
294 }
295 
Off(napi_env env, napi_callback_info info)296 napi_value SystemPasteboardNapi::Off(napi_env env, napi_callback_info info)
297 {
298     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi off () is called!");
299     size_t argc = MAX_ARGS;
300     napi_value argv[MAX_ARGS] = { 0 };
301     napi_value thisVar = 0;
302     void *data = nullptr;
303     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
304     // off(type: 'update', callback?: () => void) has at least 1 arg
305     if (!CheckAgrsOfOnAndOff(env, argc >= 1, argv, argc)) {
306         return nullptr;
307     }
308 
309     std::shared_ptr<PasteboardObserverInstance> observer = nullptr;
310     // 1: is the observer parameter
311     if (argc > 1) {
312         if (!CheckArgsType(env, argv[1], napi_function, "Parameter error. The type of callback must be function.")) {
313             return nullptr;
314         }
315         observer = GetObserver(env, argv[1]);
316     }
317 
318     DeleteObserver(observer);
319     napi_value result = nullptr;
320     napi_get_undefined(env, &result);
321     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi off () is called!");
322     return result;
323 }
324 
Clear(napi_env env, napi_callback_info info)325 napi_value SystemPasteboardNapi::Clear(napi_env env, napi_callback_info info)
326 {
327     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "Clear is called!");
328     auto context = std::make_shared<AsyncCall::Context>();
329     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
330         // clear has 0 or 1 args
331         if (argc > 0 &&
332             !CheckArgsType(env, argv[0], napi_function, "Parameter error. The type of callback must be function.")) {
333             return napi_invalid_arg;
334         }
335         return napi_ok;
336     };
337     auto exec = [context](AsyncCall::Context *ctx) {
338         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "exec Clear");
339         PasteboardClient::GetInstance()->Clear();
340     };
341     context->SetAction(std::move(input));
342     // 0: the AsyncCall at the first position;
343     AsyncCall asyncCall(env, info, context, 0);
344     return asyncCall.Call(env, exec);
345 }
346 
ClearData(napi_env env, napi_callback_info info)347 napi_value SystemPasteboardNapi::ClearData(napi_env env, napi_callback_info info)
348 {
349     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "ClearData is called!");
350     return Clear(env, info);
351 }
352 
HasPasteData(napi_env env, napi_callback_info info)353 napi_value SystemPasteboardNapi::HasPasteData(napi_env env, napi_callback_info info)
354 {
355     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "HasPasteData is called!");
356     auto context = std::make_shared<HasContextInfo>();
357     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
358         // hasPasteData has 0 or 1 args
359         if (argc > 0 &&
360             !CheckArgsType(env, argv[0], napi_function, "Parameter error. The type of callback must be function.")) {
361             return napi_invalid_arg;
362         }
363         return napi_ok;
364     };
365     auto output = [context](napi_env env, napi_value *result) -> napi_status {
366         napi_status status = napi_get_boolean(env, context->hasPasteData, result);
367         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "napi_get_boolean status = %{public}d", status);
368         return status;
369     };
370     auto exec = [context](AsyncCall::Context *ctx) {
371         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "exec HasPasteData");
372         context->hasPasteData = PasteboardClient::GetInstance()->HasPasteData();
373         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "HasPasteData result = %{public}d", context->hasPasteData);
374         context->status = napi_ok;
375     };
376     context->SetAction(std::move(input), std::move(output));
377     // 0: the AsyncCall at the first position;
378     AsyncCall asyncCall(env, info, context, 0);
379     return asyncCall.Call(env, exec);
380 }
381 
HasData(napi_env env, napi_callback_info info)382 napi_value SystemPasteboardNapi::HasData(napi_env env, napi_callback_info info)
383 {
384     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "HasData is called!");
385     return HasPasteData(env, info);
386 }
387 
GetDataCommon(std::shared_ptr<GetContextInfo> &context)388 void SystemPasteboardNapi::GetDataCommon(std::shared_ptr<GetContextInfo> &context)
389 {
390     auto input = [](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
391         // 1: GetPasteData has 0 or 1 args
392         if (argc > 0 &&
393             !CheckArgsType(env, argv[0], napi_function, "Parameter error. The type of callback must be function.")) {
394             return napi_invalid_arg;
395         }
396         return napi_ok;
397     };
398 
399     auto output = [context](napi_env env, napi_value *result) -> napi_status {
400         napi_value instance = nullptr;
401         PasteDataNapi::NewInstance(env, instance);
402         PasteDataNapi *obj = nullptr;
403         napi_status ret = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
404         if ((ret == napi_ok) || (obj != nullptr)) {
405             obj->value_ = context->pasteData;
406         } else {
407             return napi_generic_failure;
408         }
409         *result = instance;
410         return napi_ok;
411     };
412     context->SetAction(std::move(input), std::move(output));
413 }
414 
GetPasteData(napi_env env, napi_callback_info info)415 napi_value SystemPasteboardNapi::GetPasteData(napi_env env, napi_callback_info info)
416 {
417     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetPasteData is called!");
418 
419     auto context = std::make_shared<GetContextInfo>();
420     context->pasteData = std::make_shared<PasteData>();
421     GetDataCommon(context);
422 
423     auto exec = [context](AsyncCall::Context *ctx) {
424         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetPasteData Begin");
425         PasteboardClient::GetInstance()->GetPasteData(*context->pasteData);
426         context->status = napi_ok;
427         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetPasteData End");
428     };
429 
430     // 0: the AsyncCall at the first position;
431     AsyncCall asyncCall(env, info, context, 0);
432     return asyncCall.Call(env, exec);
433 }
434 
GetData(napi_env env, napi_callback_info info)435 napi_value SystemPasteboardNapi::GetData(napi_env env, napi_callback_info info)
436 {
437     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetData is called!");
438 
439     auto context = std::make_shared<GetContextInfo>();
440     context->pasteData = std::make_shared<PasteData>();
441     GetDataCommon(context);
442 
443     auto exec = [context](AsyncCall::Context *ctx) {
444         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetData Begin");
445         int32_t ret = PasteboardClient::GetInstance()->GetPasteData(*context->pasteData);
446         if (ret == static_cast<int32_t>(PasteboardError::TASK_PROCESSING)) {
447             context->SetErrInfo(ret, "Another getData is being processed");
448         } else {
449             context->status = napi_ok;
450         }
451         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetData End");
452     };
453     // 0: the AsyncCall at the first position;
454     AsyncCall asyncCall(env, info, context, 0);
455     return asyncCall.Call(env, exec);
456 }
457 
SetDataCommon(std::shared_ptr<SetContextInfo> &context)458 void SystemPasteboardNapi::SetDataCommon(std::shared_ptr<SetContextInfo> &context)
459 {
460     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
461         // setData has 1 or 2 args
462         if (!CheckExpression(
463             env, argc > 0, JSErrorCode::INVALID_PARAMETERS,
464             "Parameter error. The number of arguments must be greater than zero.") ||
465             !CheckExpression(env, PasteDataNapi::IsPasteData(env, argv[0]), JSErrorCode::INVALID_PARAMETERS,
466             "Parameter error. The Type of data must be pasteData.")) {
467             return napi_invalid_arg;
468         }
469         if (argc > 1 &&
470             !CheckArgsType(env, argv[1], napi_function, "Parameter error. The type of callback must be function.")) {
471             return napi_invalid_arg;
472         }
473         PasteDataNapi *pasteData = nullptr;
474         napi_unwrap(env, argv[0], reinterpret_cast<void **>(&pasteData));
475         if (pasteData != nullptr) {
476             context->obj = pasteData->value_;
477         }
478         return napi_ok;
479     };
480     context->SetAction(std::move(input));
481 }
482 
SetPasteData(napi_env env, napi_callback_info info)483 napi_value SystemPasteboardNapi::SetPasteData(napi_env env, napi_callback_info info)
484 {
485     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SetPasteData is called!");
486     auto context = std::make_shared<SetContextInfo>();
487     SetDataCommon(context);
488 
489     auto exec = [context](AsyncCall::Context *ctx) {
490         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "exec SetPasteData");
491         if (context->obj != nullptr) {
492             PasteboardClient::GetInstance()->SetPasteData(*(context->obj));
493             context->obj = nullptr;
494         }
495         context->status = napi_ok;
496     };
497     // 1: the AsyncCall at the second position
498     AsyncCall asyncCall(env, info, context, 1);
499     return asyncCall.Call(env, exec);
500 }
501 
SetData(napi_env env, napi_callback_info info)502 napi_value SystemPasteboardNapi::SetData(napi_env env, napi_callback_info info)
503 {
504     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SetData is called!");
505     auto context = std::make_shared<SetContextInfo>();
506     SetDataCommon(context);
507 
508     auto exec = [context](AsyncCall::Context *ctx) {
509         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "exec SetPasteData");
510         int32_t ret = static_cast<int32_t>(PasteboardError::INVALID_DATA_ERROR);
511         if (context->obj != nullptr) {
512             std::map<uint32_t, std::shared_ptr<UDMF::EntryGetter>> entryGetters;
513             for (auto record : context->obj->AllRecords()) {
514                 if (record != nullptr && record->GetEntryGetter() != nullptr) {
515                     entryGetters.emplace(record->GetRecordId(), record->GetEntryGetter());
516                 }
517             }
518             ret = PasteboardClient::GetInstance()->SetPasteData(*(context->obj), nullptr, entryGetters);
519             context->obj = nullptr;
520         }
521         if (ret == static_cast<int>(PasteboardError::E_OK)) {
522             context->status = napi_ok;
523         } else if (ret == static_cast<int>(PasteboardError::PROHIBIT_COPY)) {
524             context->SetErrInfo(ret, "The system prohibits copying");
525         } else if (ret == static_cast<int>(PasteboardError::TASK_PROCESSING)) {
526             context->SetErrInfo(ret, "Another setData is being processed");
527         }
528         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "exec context->status[%{public}d]", context->status);
529     };
530     // 1: the AsyncCall at the second position
531     AsyncCall asyncCall(env, info, context, 1);
532     return asyncCall.Call(env, exec);
533 }
534 
SetUnifiedData(napi_env env, napi_callback_info info)535 napi_value SystemPasteboardNapi::SetUnifiedData(napi_env env, napi_callback_info info)
536 {
537     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SetUnifiedData is called!");
538     auto context = std::make_shared<SetUnifiedContextInfo>();
539     SetDataCommon(context);
540 
541     auto exec = [context](AsyncCall::Context* ctx) {
542         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "exec SetPasteData");
543         int32_t ret = static_cast<int32_t>(PasteboardError::INVALID_DATA_ERROR);
544         if (context->obj != nullptr) {
545             if (context->isDelay && context->delayGetter != nullptr) {
546                 ret = PasteboardClient::GetInstance()->SetUnifiedData(*(context->obj), context->delayGetter->GetStub());
547             } else {
548                 ret = PasteboardClient::GetInstance()->SetUnifiedData(*(context->obj));
549             }
550             context->obj = nullptr;
551         }
552         if (ret == static_cast<int>(PasteboardError::E_OK)) {
553             context->status = napi_ok;
554         } else if (ret == static_cast<int>(PasteboardError::PROHIBIT_COPY)) {
555             context->SetErrInfo(ret, "The system prohibits copying");
556         } else if (ret == static_cast<int>(PasteboardError::TASK_PROCESSING)) {
557             context->SetErrInfo(ret, "Another setData is being processed");
558         }
559         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "exec context->status[%{public}d]", context->status);
560     };
561     // 1: the AsyncCall at the second position
562     AsyncCall asyncCall(env, info, context, 1);
563     return asyncCall.Call(env, exec);
564 }
565 
GetUnifiedData(napi_env env, napi_callback_info info)566 napi_value SystemPasteboardNapi::GetUnifiedData(napi_env env, napi_callback_info info)
567 {
568     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetUnifiedData is called!");
569 
570     auto context = std::make_shared<GetUnifiedContextInfo>();
571     context->unifiedData = std::make_shared<UDMF::UnifiedData>();
572     GetDataCommon(context);
573 
574     auto exec = [context](AsyncCall::Context* ctx) {
575         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetUnifiedData Begin");
576         int32_t ret = PasteboardClient::GetInstance()->GetUnifiedData(*context->unifiedData);
577         if (ret == static_cast<int32_t>(PasteboardError::TASK_PROCESSING)) {
578             context->SetErrInfo(ret, "Another getData is being processed");
579         } else {
580             context->status = napi_ok;
581         }
582         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetUnifiedData End");
583     };
584     // 0: the AsyncCall at the first position;
585     AsyncCall asyncCall(env, info, context, 0);
586     return asyncCall.Call(env, exec);
587 }
588 
GetUnifiedDataSync(napi_env env, napi_callback_info info)589 napi_value SystemPasteboardNapi::GetUnifiedDataSync(napi_env env, napi_callback_info info)
590 {
591     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi GetUnifiedDataSync is called!");
592     napi_value instance = nullptr;
593     std::shared_ptr<UDMF::UnifiedData> unifiedData = std::make_shared<UDMF::UnifiedData>();
594 
595     NAPI_CALL(env, UDMF::UnifiedDataNapi::NewInstance(env, unifiedData, instance));
596     UDMF::UnifiedDataNapi* obj = nullptr;
597     napi_status status = napi_unwrap(env, instance, reinterpret_cast<void**>(&obj));
598     if ((status != napi_ok) || (obj == nullptr) || obj->value_ == nullptr) {
599         return nullptr;
600     }
601     auto block = std::make_shared<BlockObject<std::shared_ptr<int32_t>>>(SYNC_TIMEOUT);
602     std::thread thread([block, unifiedData = obj->value_]() mutable {
603         auto ret = PasteboardClient::GetInstance()->GetUnifiedData(*unifiedData);
604         std::shared_ptr<int32_t> value = std::make_shared<int32_t>(ret);
605         block->SetValue(value);
606     });
607     thread.detach();
608     auto value = block->GetValue();
609     if (!CheckExpression(env, value != nullptr, JSErrorCode::REQUEST_TIME_OUT, "request timed out.")) {
610         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "time out, GetUnifiedDataSync failed.");
611     }
612     return instance;
613 }
614 
SetUnifiedDataSync(napi_env env, napi_callback_info info)615 napi_value SystemPasteboardNapi::SetUnifiedDataSync(napi_env env, napi_callback_info info)
616 {
617     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi SetUnifiedDataSync is called!");
618     size_t argc = 1;
619     napi_value argv[1] = { 0 };
620     napi_value thisVar = nullptr;
621 
622     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
623     if (!CheckExpression(
624         env, argc > 0, JSErrorCode::INVALID_PARAMETERS, "Parameter error. Wrong number of arguments.")) {
625         return nullptr;
626     }
627     UDMF::UnifiedDataNapi* unifiedDataNapi = nullptr;
628     napi_unwrap(env, argv[0], reinterpret_cast<void**>(&unifiedDataNapi));
629     if (!CheckExpression(env, (unifiedDataNapi != nullptr && unifiedDataNapi->value_ != nullptr),
630         JSErrorCode::INVALID_PARAMETERS, "Parameter error. The Type of data must be unifiedData.")) {
631         return nullptr;
632     }
633     auto properties = unifiedDataNapi->GetPropertiesNapi(env);
634     bool isDelay = false;
635     std::shared_ptr<PasteboardDelayGetterInstance> delayGetter = nullptr;
636     if (properties != nullptr && properties->delayDataRef_ != nullptr) {
637         delayGetter = std::make_shared<PasteboardDelayGetterInstance>(env, properties->delayDataRef_);
638         delayGetter->GetStub()->SetDelayGetterWrapper(delayGetter);
639         isDelay = true;
640     }
641     auto block = std::make_shared<BlockObject<std::shared_ptr<int>>>(SYNC_TIMEOUT);
642     std::shared_ptr<UDMF::UnifiedData> unifiedData = unifiedDataNapi->value_;
643     std::thread thread([block, unifiedData, isDelay, delayGetter]() mutable {
644         int32_t ret = isDelay ?
645             PasteboardClient::GetInstance()->SetUnifiedData(*unifiedData, delayGetter->GetStub()) :
646             PasteboardClient::GetInstance()->SetUnifiedData(*unifiedData);
647         std::shared_ptr<int> value = std::make_shared<int>(static_cast<int>(ret));
648         block->SetValue(value);
649     });
650     thread.detach();
651     auto value = block->GetValue();
652     if (!CheckExpression(env, value != nullptr, JSErrorCode::REQUEST_TIME_OUT, "request timed out.")) {
653         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "time out, SetUnifiedDataSync failed.");
654         return nullptr;
655     }
656     if (*value != static_cast<int32_t>(PasteboardError::E_OK)) {
657         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "operate invalid, SetUnifiedDataSync failed");
658         return nullptr;
659     }
660     {
661         std::lock_guard<std::mutex> lck(delayMutex_);
662         delayGetter_ = delayGetter;
663     }
664     return nullptr;
665 }
666 
SetAppShareOptions(napi_env env, napi_callback_info info)667 napi_value SystemPasteboardNapi::SetAppShareOptions(napi_env env, napi_callback_info info)
668 {
669     size_t argc = 1;
670     napi_value argv[1] = {0};
671     napi_value thisArg = nullptr;
672     void *data = nullptr;
673     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, &data));
674     if (!CheckExpression(env, argc > 0, JSErrorCode::INVALID_PARAMETERS,
675         "Parameter error. Mandatory parameters are left unspecified.")) {
676         return nullptr;
677     }
678     int32_t shareOptions;
679     auto status = napi_get_value_int32(env, argv[0], &shareOptions);
680     if (!CheckExpression(env, status == napi_ok, JSErrorCode::INVALID_PARAMETERS,
681         "Parameter error. Incorrect parameter types.")) {
682         return nullptr;
683     }
684     if (!CheckExpression(env, shareOptions >= ShareOption::InApp && shareOptions <= ShareOption::CrossDevice,
685         JSErrorCode::INVALID_PARAMETERS, "Parameter error. Parameter verification failed.")) {
686         return nullptr;
687     }
688     auto result = PasteboardClient::GetInstance()->SetAppShareOptions(static_cast<ShareOption>(shareOptions));
689     if (!CheckExpression(env, result != static_cast<int32_t>(PasteboardError::PERMISSION_VERIFICATION_ERROR),
690         JSErrorCode::NO_SYSTEM_PERMISSION,
691         "Permission verification failed. A non-system application calls a system API.")) {
692         return nullptr;
693     }
694     if (!CheckExpression(env, result != static_cast<int32_t>(PasteboardError::INVALID_OPERATION_ERROR),
695         JSErrorCode::SETTINGS_ALREADY_EXIST, "Settings already exist.")) {
696         return nullptr;
697     }
698     return nullptr;
699 }
700 
RemoveAppShareOptions(napi_env env, napi_callback_info info)701 napi_value SystemPasteboardNapi::RemoveAppShareOptions(napi_env env, napi_callback_info info)
702 {
703     auto result = PasteboardClient::GetInstance()->RemoveAppShareOptions();
704     if (CheckExpression(env, result != static_cast<int32_t>(PasteboardError::PERMISSION_VERIFICATION_ERROR),
705         JSErrorCode::NO_SYSTEM_PERMISSION,
706         "Permission verification failed. A non-system application calls a system API.")) {
707         return nullptr;
708     }
709     return nullptr;
710 }
711 
SetDataCommon(std::shared_ptr<SetUnifiedContextInfo>& context)712 void SystemPasteboardNapi::SetDataCommon(std::shared_ptr<SetUnifiedContextInfo>& context)
713 {
714     auto input = [context](napi_env env, size_t argc, napi_value* argv, napi_value self) -> napi_status {
715         // setData has 1 arg
716         if (!CheckExpression(
717             env, argc > 0, JSErrorCode::INVALID_PARAMETERS, "Parameter error. Wrong number of arguments.")) {
718             return napi_invalid_arg;
719         }
720         UDMF::UnifiedDataNapi* unifiedDataNapi = nullptr;
721         context->status = napi_unwrap(env, argv[0], reinterpret_cast<void**>(&unifiedDataNapi));
722         if (!CheckExpression(env, unifiedDataNapi != nullptr,
723             JSErrorCode::INVALID_PARAMETERS, "Parameter error. The Type of data must be unifiedData.")) {
724             return napi_invalid_arg;
725         }
726         context->obj = unifiedDataNapi->value_;
727         auto properties = unifiedDataNapi->GetPropertiesNapi(env);
728         if (properties != nullptr && properties->delayDataRef_ != nullptr) {
729             context->delayGetter = std::make_shared<PasteboardDelayGetterInstance>(env, properties->delayDataRef_);
730             context->delayGetter->GetStub()->SetDelayGetterWrapper(context->delayGetter);
731             context->isDelay = true;
732         }
733         return napi_ok;
734     };
735     auto output = [context](napi_env env, napi_value *result) -> napi_status {
736         if (context->status == napi_ok) {
737             std::lock_guard<std::mutex> lck(delayMutex_);
738             delayGetter_ = std::move(context->delayGetter);
739         }
740         return napi_ok;
741     };
742     context->SetAction(std::move(input), std::move(output));
743 }
744 
GetDataCommon(std::shared_ptr<GetUnifiedContextInfo>& context)745 void SystemPasteboardNapi::GetDataCommon(std::shared_ptr<GetUnifiedContextInfo>& context)
746 {
747     auto input = [](napi_env env, size_t argc, napi_value* argv, napi_value self) -> napi_status {
748         // 1: GetPasteData has 0 or 1 args
749         if (argc > 0 &&
750             !CheckArgsType(env, argv[0], napi_function, "Parameter error. The type of callback must be function.")) {
751             return napi_invalid_arg;
752         }
753         return napi_ok;
754     };
755 
756     auto output = [context](napi_env env, napi_value* result) -> napi_status {
757         napi_value instance = nullptr;
758         std::shared_ptr<UDMF::UnifiedData> unifiedData = std::make_shared<UDMF::UnifiedData>();
759         UDMF::UnifiedDataNapi::NewInstance(env, unifiedData, instance);
760 
761         UDMF::UnifiedDataNapi* obj = nullptr;
762         napi_status ret = napi_unwrap(env, instance, reinterpret_cast<void**>(&obj));
763         if ((ret == napi_ok) || (obj != nullptr)) {
764             obj->value_ = context->unifiedData;
765         } else {
766             return napi_generic_failure;
767         }
768         *result = instance;
769         return napi_ok;
770     };
771     context->SetAction(std::move(input), std::move(output));
772 }
773 
IsRemoteData(napi_env env, napi_callback_info info)774 napi_value SystemPasteboardNapi::IsRemoteData(napi_env env, napi_callback_info info)
775 {
776     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi IsRemoteData() is called!");
777     auto block = std::make_shared<BlockObject<std::shared_ptr<int>>>(SYNC_TIMEOUT);
778     std::thread thread([block]() {
779         auto ret = PasteboardClient::GetInstance()->IsRemoteData();
780         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "value=%{public}d", ret);
781         std::shared_ptr<int> value = std::make_shared<int>(static_cast<int>(ret));
782         block->SetValue(value);
783     });
784     thread.detach();
785     auto value = block->GetValue();
786     if (!CheckExpression(env, value != nullptr, JSErrorCode::REQUEST_TIME_OUT, "Request timed out.")) {
787         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "time out, IsRemoteData failed.");
788         return nullptr;
789     }
790     napi_value result = nullptr;
791     napi_get_boolean(env, *value, &result);
792     return result;
793 }
794 
GetDataSource(napi_env env, napi_callback_info info)795 napi_value SystemPasteboardNapi::GetDataSource(napi_env env, napi_callback_info info)
796 {
797     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi GetDataSource() is called!");
798     std::string bundleName;
799     auto block = std::make_shared<BlockObject<std::shared_ptr<int>>>(SYNC_TIMEOUT);
800     std::thread thread([block, &bundleName]() mutable {
801         auto ret = PasteboardClient::GetInstance()->GetDataSource(bundleName);
802         std::shared_ptr<int> value = std::make_shared<int>(ret);
803         block->SetValue(value);
804     });
805     thread.detach();
806     auto value = block->GetValue();
807     if (!CheckExpression(env, value != nullptr, JSErrorCode::REQUEST_TIME_OUT, "Request timed out.")) {
808         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "time out, GetDataSource failed.");
809         return nullptr;
810     }
811 
812     if (*value != static_cast<int>(PasteboardError::E_OK)) {
813         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetDataSource, failed, ret = %{public}d", *value);
814         return nullptr;
815     }
816     napi_value result = nullptr;
817     napi_create_string_utf8(env, bundleName.c_str(), NAPI_AUTO_LENGTH, &result);
818     return result;
819 }
820 
HasDataType(napi_env env, napi_callback_info info)821 napi_value SystemPasteboardNapi::HasDataType(napi_env env, napi_callback_info info)
822 {
823     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi HasDataType() is called!");
824     size_t argc = 1;
825     napi_value argv[1] = { 0 };
826     napi_value thisVar = nullptr;
827 
828     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
829     if ((!CheckExpression(env, argc >= ARGC_TYPE_SET1, JSErrorCode::INVALID_PARAMETERS,
830         "Parameter error. The number of arguments must be grater than zero.")) ||
831         (!CheckArgsType(env, argv[0], napi_string, "Parameter error. The type of mimeType must be string."))) {
832         return nullptr;
833     }
834 
835     std::string mimeType;
836     if (!GetValue(env, argv[0], mimeType)) {
837         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Failed to GetValue!");
838         return nullptr;
839     }
840     auto block = std::make_shared<BlockObject<std::shared_ptr<int>>>(SYNC_TIMEOUT);
841     std::thread thread([block, mimeType]() {
842         auto ret = PasteboardClient::GetInstance()->HasDataType(mimeType);
843         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "ret = %{public}d", ret);
844         std::shared_ptr<int> value = std::make_shared<int>(static_cast<int>(ret));
845         block->SetValue(value);
846     });
847     thread.detach();
848     auto value = block->GetValue();
849     if (!CheckExpression(env, value != nullptr, JSErrorCode::REQUEST_TIME_OUT, "Request timed out.")) {
850         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "time out, HasDataType failed.");
851         return nullptr;
852     }
853     napi_value result = nullptr;
854     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "value = %{public}d", *value);
855     napi_get_boolean(env, *value, &result);
856     return result;
857 }
858 
DetectPatterns(napi_env env, napi_callback_info info)859 napi_value SystemPasteboardNapi::DetectPatterns(napi_env env, napi_callback_info info)
860 {
861     auto context = std::make_shared<DetectPatternsContextInfo>();
862     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
863         if (!CheckExpression(env, argc == ARGC_TYPE_SET1, JSErrorCode::INVALID_PARAMETERS,
864             "Parameter error. The number of arguments must be one.")) {
865             return napi_invalid_arg;
866         }
867         bool getValueRes = GetValue(env, argv[0], context->patternsToCheck);
868         if (!CheckExpression(env, getValueRes, JSErrorCode::INVALID_PARAMETERS,
869             "Parameter error. Array<Pattern> expected.")) {
870             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Failed to GetValue.");
871             return napi_invalid_arg;
872         }
873         return napi_ok;
874     };
875     auto output = [context](napi_env env, napi_value *result) -> napi_status {
876         napi_status status = SetValue(env, context->patternsDetect, *result);
877         return status;
878     };
879     auto exec = [context](AsyncCall::Context *ctx) {
880         context->patternsDetect = PasteboardClient::GetInstance()->DetectPatterns(context->patternsToCheck);
881         context->status = napi_ok;
882     };
883     context->SetAction(std::move(input), std::move(output));
884     AsyncCall asyncCall(env, info, context, 1);
885     return asyncCall.Call(env, exec);
886 }
887 
ClearDataSync(napi_env env, napi_callback_info info)888 napi_value SystemPasteboardNapi::ClearDataSync(napi_env env, napi_callback_info info)
889 {
890     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi ClearDataSync() is called!");
891     auto block = std::make_shared<BlockObject<std::shared_ptr<int>>>(SYNC_TIMEOUT);
892     std::thread thread([block]() {
893         PasteboardClient::GetInstance()->Clear();
894         std::shared_ptr<int> value = std::make_shared<int>(0);
895         block->SetValue(value);
896     });
897     thread.detach();
898     auto value = block->GetValue();
899     if (!CheckExpression(env, value != nullptr, JSErrorCode::REQUEST_TIME_OUT, "Request timed out.")) {
900         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "time out, ClearDataSync failed.");
901     }
902     return nullptr;
903 }
904 
GetDataSync(napi_env env, napi_callback_info info)905 napi_value SystemPasteboardNapi::GetDataSync(napi_env env, napi_callback_info info)
906 {
907     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi GetDataSync() is called!");
908     napi_value instance = nullptr;
909     NAPI_CALL(env, PasteDataNapi::NewInstance(env, instance));
910     PasteDataNapi *obj = nullptr;
911     napi_status status = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
912     if ((status != napi_ok) || (obj == nullptr) || obj->value_ == nullptr) {
913         return nullptr;
914     }
915     auto block = std::make_shared<BlockObject<std::shared_ptr<int32_t>>>(SYNC_TIMEOUT);
916     std::thread thread([block, pasteData = obj->value_]() mutable {
917         auto ret = PasteboardClient::GetInstance()->GetPasteData(*pasteData);
918         std::shared_ptr<int32_t> value = std::make_shared<int32_t>(ret);
919         block->SetValue(value);
920     });
921     thread.detach();
922     auto value = block->GetValue();
923     if (!CheckExpression(env, value != nullptr, JSErrorCode::REQUEST_TIME_OUT, "request timed out.")) {
924         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "time out, GetDataSync failed.");
925     }
926     return instance;
927 }
928 
SetDataSync(napi_env env, napi_callback_info info)929 napi_value SystemPasteboardNapi::SetDataSync(napi_env env, napi_callback_info info)
930 {
931     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi SetDataSync() is called!");
932     size_t argc = 1;
933     napi_value argv[1] = { 0 };
934     napi_value thisVar = nullptr;
935 
936     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
937     if (!CheckExpression(env, argc > 0, JSErrorCode::INVALID_PARAMETERS,
938         "Parameter error. The number of arguments must be one.") ||
939         !CheckExpression(env, PasteDataNapi::IsPasteData(env, argv[0]), JSErrorCode::INVALID_PARAMETERS,
940         "Parameter error. The Type of data must be pasteData.")) {
941         return nullptr;
942     }
943 
944     PasteDataNapi *pasteData = nullptr;
945     napi_unwrap(env, argv[0], reinterpret_cast<void **>(&pasteData));
946     if (pasteData == nullptr || pasteData->value_ == nullptr) {
947         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Failed to GetValue!");
948         return nullptr;
949     }
950     auto block = std::make_shared<BlockObject<std::shared_ptr<int>>>(SYNC_TIMEOUT);
951     std::shared_ptr<PasteData> data = pasteData->value_;
952     std::thread thread([block, data]() {
953         auto ret = PasteboardClient::GetInstance()->SetPasteData(*data);
954         std::shared_ptr<int> value = std::make_shared<int>(static_cast<int>(ret));
955         block->SetValue(value);
956     });
957     thread.detach();
958     auto value = block->GetValue();
959     if (!CheckExpression(env, value != nullptr, JSErrorCode::REQUEST_TIME_OUT, "request timed out.")) {
960         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "time out, SetDataSync failed.");
961         return nullptr;
962     }
963 
964     if (*value != static_cast<int32_t>(PasteboardError::E_OK)) {
965         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "operate invalid, SetDataSync failed");
966         return nullptr;
967     }
968     return nullptr;
969 }
970 
HasDataSync(napi_env env, napi_callback_info info)971 napi_value SystemPasteboardNapi::HasDataSync(napi_env env, napi_callback_info info)
972 {
973     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi HasDataSync() is called!");
974     auto block = std::make_shared<BlockObject<std::shared_ptr<int>>>(SYNC_TIMEOUT);
975     std::thread thread([block]() {
976         auto ret = PasteboardClient::GetInstance()->HasPasteData();
977         std::shared_ptr<int> value = std::make_shared<int>(static_cast<int>(ret));
978         block->SetValue(value);
979     });
980     thread.detach();
981     auto value = block->GetValue();
982     if (!CheckExpression(env, value != nullptr, JSErrorCode::REQUEST_TIME_OUT, "request timed out.")) {
983         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "time out, HasDataSync failed.");
984         return nullptr;
985     }
986     napi_value result = nullptr;
987     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "value=%{public}d", *value);
988     napi_get_boolean(env, *value, &result);
989     return result;
990 }
991 
SystemPasteboardInit(napi_env env, napi_value exports)992 napi_value SystemPasteboardNapi::SystemPasteboardInit(napi_env env, napi_value exports)
993 {
994     napi_status status = napi_ok;
995     napi_property_descriptor descriptors[] = {
996         DECLARE_NAPI_FUNCTION("on", On),
997         DECLARE_NAPI_FUNCTION("off", Off),
998         DECLARE_NAPI_FUNCTION("clear", Clear),
999         DECLARE_NAPI_FUNCTION("getPasteData", GetPasteData),
1000         DECLARE_NAPI_FUNCTION("hasPasteData", HasPasteData),
1001         DECLARE_NAPI_FUNCTION("setPasteData", SetPasteData),
1002         DECLARE_NAPI_FUNCTION("clearData", ClearData),
1003         DECLARE_NAPI_FUNCTION("getData", GetData),
1004         DECLARE_NAPI_FUNCTION("hasData", HasData),
1005         DECLARE_NAPI_FUNCTION("setData", SetData),
1006         DECLARE_NAPI_FUNCTION("isRemoteData", IsRemoteData),
1007         DECLARE_NAPI_FUNCTION("getDataSource", GetDataSource),
1008         DECLARE_NAPI_FUNCTION("hasDataType", HasDataType),
1009         DECLARE_NAPI_FUNCTION("detectPatterns", DetectPatterns),
1010         DECLARE_NAPI_FUNCTION("clearDataSync", ClearDataSync),
1011         DECLARE_NAPI_FUNCTION("getDataSync", GetDataSync),
1012         DECLARE_NAPI_FUNCTION("hasDataSync", HasDataSync),
1013         DECLARE_NAPI_FUNCTION("setDataSync", SetDataSync),
1014         DECLARE_NAPI_FUNCTION("setUnifiedData", SetUnifiedData),
1015         DECLARE_NAPI_FUNCTION("getUnifiedData", GetUnifiedData),
1016         DECLARE_NAPI_FUNCTION("setUnifiedDataSync", SetUnifiedDataSync),
1017         DECLARE_NAPI_FUNCTION("getUnifiedDataSync", GetUnifiedDataSync),
1018         DECLARE_NAPI_FUNCTION("setAppShareOptions", SetAppShareOptions),
1019         DECLARE_NAPI_FUNCTION("removeAppShareOptions", RemoveAppShareOptions),
1020 
1021     };
1022     napi_value constructor;
1023     napi_define_class(env, "SystemPasteboard", NAPI_AUTO_LENGTH, New, nullptr,
1024         sizeof(descriptors) / sizeof(napi_property_descriptor), descriptors, &constructor);
1025     if (status != napi_ok) {
1026         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Failed to define class at SystemPasteboardInit");
1027         return nullptr;
1028     }
1029     napi_create_reference(env, constructor, 1, &g_systemPasteboard);
1030     status = napi_set_named_property(env, exports, "SystemPasteboard", constructor);
1031     if (status != napi_ok) {
1032         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Set property failed when SystemPasteboardInit");
1033         return nullptr;
1034     }
1035     return exports;
1036 }
1037 
SystemPasteboardNapi()1038 SystemPasteboardNapi::SystemPasteboardNapi() : env_(nullptr)
1039 {
1040     value_ = std::make_shared<PasteDataNapi>();
1041 }
1042 
~SystemPasteboardNapi()1043 SystemPasteboardNapi::~SystemPasteboardNapi()
1044 {
1045 }
1046 
Destructor(napi_env env, void *nativeObject, void *finalize_hint)1047 void SystemPasteboardNapi::Destructor(napi_env env, void *nativeObject, void *finalize_hint)
1048 {
1049     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "Destructor");
1050     SystemPasteboardNapi *obj = static_cast<SystemPasteboardNapi *>(nativeObject);
1051     delete obj;
1052 }
1053 
New(napi_env env, napi_callback_info info)1054 napi_value SystemPasteboardNapi::New(napi_env env, napi_callback_info info)
1055 {
1056     size_t argc = MAX_ARGS;
1057     napi_value argv[MAX_ARGS] = { 0 };
1058     napi_value thisVar = nullptr;
1059     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1060     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "proc.");
1061     // get native object
1062     SystemPasteboardNapi *obj = new (std::nothrow) SystemPasteboardNapi();
1063     if (!obj) {
1064         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "New obj is null");
1065         return nullptr;
1066     }
1067     obj->env_ = env;
1068     NAPI_CALL(env, napi_wrap(env, thisVar, obj, SystemPasteboardNapi::Destructor,
1069                        nullptr, // finalize_hint
1070                        nullptr));
1071     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "end.");
1072     return thisVar;
1073 }
1074 
NewInstance(napi_env env, napi_value &instance)1075 napi_status SystemPasteboardNapi::NewInstance(napi_env env, napi_value &instance)
1076 {
1077     napi_status status;
1078     if (g_systemPasteboard_instance != nullptr) {
1079         status = napi_get_reference_value(env, g_systemPasteboard_instance, &instance);
1080         if (status != napi_ok) {
1081             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "get instance failed");
1082             return status;
1083         }
1084         return napi_ok;
1085     }
1086 
1087     napi_value constructor;
1088     status = napi_get_reference_value(env, g_systemPasteboard, &constructor);
1089     if (status != napi_ok) {
1090         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "get reference failed");
1091         return status;
1092     }
1093 
1094     status = napi_new_instance(env, constructor, 0, nullptr, &instance);
1095     if (status != napi_ok) {
1096         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "new instance failed");
1097         return status;
1098     }
1099     napi_create_reference(env, instance, 1, &g_systemPasteboard_instance);
1100     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "new instance ok");
1101 
1102     return napi_ok;
1103 }
1104 
GetObserver(napi_env env, napi_value observer)1105 std::shared_ptr<PasteboardObserverInstance> SystemPasteboardNapi::GetObserver(napi_env env, napi_value observer)
1106 {
1107     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetObserver start");
1108     for (auto &[refKey, observerValue] : observers_) {
1109         napi_value callback = nullptr;
1110         napi_get_reference_value(env, refKey, &callback);
1111         bool isEqual = false;
1112         napi_strict_equals(env, observer, callback, &isEqual);
1113         if (isEqual) {
1114             return observerValue;
1115         }
1116     }
1117     return nullptr;
1118 }
1119 
DeleteObserver(const std::shared_ptr<PasteboardObserverInstance> &observer)1120 void SystemPasteboardNapi::DeleteObserver(const std::shared_ptr<PasteboardObserverInstance> &observer)
1121 {
1122     PASTEBOARD_HILOGI(PASTEBOARD_MODULE_JS_NAPI, "observer == null: %{public}d, size: %{public}zu",
1123         observer == nullptr, observers_.size());
1124     std::vector<std::shared_ptr<PasteboardObserverInstance>> observers;
1125     {
1126         for (auto it = observers_.begin(); it != observers_.end();) {
1127             if (it->second == observer) {
1128                 observers.push_back(observer);
1129                 observers_.erase(it++);
1130                 break;
1131             }
1132             if (observer == nullptr) {
1133                 observers.push_back(it->second);
1134                 observers_.erase(it++);
1135             } else {
1136                 it++;
1137             }
1138         }
1139     }
1140     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "delete observer size: %{public}zu", observers.size());
1141     for (auto &delObserver : observers) {
1142         PasteboardClient::GetInstance()->Unsubscribe(PasteboardObserverType::OBSERVER_LOCAL,
1143             delObserver->GetStub());
1144     }
1145 }
1146 
OnPasteboardChanged()1147 void PasteboardObserverInstance::PasteboardObserverImpl::OnPasteboardChanged()
1148 {
1149     std::shared_ptr<PasteboardObserverInstance> observerInstance(wrapper_.lock());
1150     if (observerInstance == nullptr) {
1151         PASTEBOARD_HILOGW(PASTEBOARD_MODULE_JS_NAPI, "expired callback");
1152         return;
1153     }
1154     observerInstance->OnPasteboardChanged();
1155 }
1156 
SetObserverWrapper( const std::shared_ptr<PasteboardObserverInstance> &observerInstance)1157 void PasteboardObserverInstance::PasteboardObserverImpl::SetObserverWrapper(
1158     const std::shared_ptr<PasteboardObserverInstance> &observerInstance)
1159 {
1160     wrapper_ = observerInstance;
1161 }
1162 
GetUnifiedData( const std::string &type, UDMF::UnifiedData &data)1163 void PasteboardDelayGetterInstance::PasteboardDelayGetterImpl::GetUnifiedData(
1164     const std::string &type, UDMF::UnifiedData &data)
1165 {
1166     std::shared_ptr<PasteboardDelayGetterInstance> delayGetterInstance(wrapper_.lock());
1167     if (delayGetterInstance == nullptr) {
1168         PASTEBOARD_HILOGW(PASTEBOARD_MODULE_JS_NAPI, "no delay getter");
1169         return;
1170     }
1171     delayGetterInstance->GetUnifiedData(type, data);
1172 }
1173 
GetPasteData( const std::string &type, MiscServices::PasteData &data)1174 void PasteboardDelayGetterInstance::PasteboardDelayGetterImpl::GetPasteData(
1175     const std::string &type, MiscServices::PasteData &data)
1176 {
1177 }
1178 
SetDelayGetterWrapper( const std::shared_ptr<PasteboardDelayGetterInstance> delayGetterInstance)1179 void PasteboardDelayGetterInstance::PasteboardDelayGetterImpl::SetDelayGetterWrapper(
1180     const std::shared_ptr<PasteboardDelayGetterInstance> delayGetterInstance)
1181 {
1182     wrapper_ = delayGetterInstance;
1183 }
1184 } // namespace MiscServicesNapi
1185 } // namespace OHOS