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