• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <thread>
16 
17 #include "napi_pasteboard_common.h"
18 #include "pasteboard_hilog.h"
19 using namespace OHOS::MiscServices;
20 using namespace OHOS::Media;
21 
22 namespace OHOS {
23 namespace MiscServicesNapi {
24 static thread_local napi_ref g_systemPasteboard = nullptr;
25 static thread_local napi_ref g_systemPasteboard_instance = nullptr;
26 thread_local std::map<napi_ref, std::shared_ptr<PasteboardObserverInstance>> SystemPasteboardNapi::observers_;
27 std::shared_ptr<PasteboardDelayGetterInstance> SystemPasteboardNapi::delayGetter_;
28 std::mutex SystemPasteboardNapi::delayMutex_;
29 constexpr int ARGC_TYPE_SET1 = 1;
30 constexpr size_t MAX_ARGS = 6;
31 constexpr size_t SYNC_TIMEOUT = 3500;
32 constexpr size_t DELAY_TIMEOUT = 2;
33 const std::string STRING_UPDATE = "update";
34 std::recursive_mutex SystemPasteboardNapi::listenerMutex_;
35 std::map<std::string, std::shared_ptr<ProgressListenerFn>> SystemPasteboardNapi::listenerMap_;
36 
PasteboardObserverInstance(const napi_env & env,const napi_ref & ref)37 PasteboardObserverInstance::PasteboardObserverInstance(const napi_env &env, const napi_ref &ref) : env_(env), ref_(ref)
38 {
39     stub_ = new (std::nothrow) PasteboardObserverInstance::PasteboardObserverImpl();
40 }
41 
~PasteboardObserverInstance()42 PasteboardObserverInstance::~PasteboardObserverInstance()
43 {
44     napi_delete_reference(env_, ref_);
45 }
46 
GetStub()47 sptr<PasteboardObserverInstance::PasteboardObserverImpl> PasteboardObserverInstance::GetStub()
48 {
49     return stub_;
50 }
51 
UvQueueWorkOnPasteboardChanged(uv_work_t * work,int status)52 void UvQueueWorkOnPasteboardChanged(uv_work_t *work, int status)
53 {
54     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "UvQueueWorkOnPasteboardChanged start");
55     if (UV_ECANCELED == status || work == nullptr || work->data == nullptr) {
56         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "invalid parameter");
57         return;
58     }
59     PasteboardDataWorker *pasteboardDataWorker = (PasteboardDataWorker *)work->data;
60     if (pasteboardDataWorker == nullptr || pasteboardDataWorker->observer == nullptr) {
61         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "pasteboardDataWorker or ref is null");
62         delete work;
63         work = nullptr;
64         return;
65     }
66 
67     auto env = pasteboardDataWorker->observer->GetEnv();
68     auto ref = pasteboardDataWorker->observer->GetRef();
69 
70     napi_handle_scope scope = nullptr;
71     napi_open_handle_scope(env, &scope);
72     if (scope == nullptr) {
73         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "scope null");
74         return;
75     }
76     napi_value undefined = nullptr;
77     napi_get_undefined(env, &undefined);
78 
79     napi_value callback = nullptr;
80     napi_value resultOut = nullptr;
81     napi_get_reference_value(env, ref, &callback);
82     napi_value result = NapiGetNull(env);
83     napi_call_function(env, undefined, callback, 0, &result, &resultOut);
84 
85     napi_close_handle_scope(env, scope);
86     delete pasteboardDataWorker;
87     pasteboardDataWorker = nullptr;
88     delete work;
89 }
90 
OnPasteboardChanged()91 void PasteboardObserverInstance::OnPasteboardChanged()
92 {
93     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "OnPasteboardChanged is called!");
94     uv_loop_s *loop = nullptr;
95     napi_get_uv_event_loop(env_, &loop);
96     if (loop == nullptr) {
97         PASTEBOARD_HILOGW(PASTEBOARD_MODULE_JS_NAPI, "loop instance is nullptr");
98         return;
99     }
100 
101     uv_work_t *work = new (std::nothrow) uv_work_t;
102     if (work == nullptr) {
103         PASTEBOARD_HILOGW(PASTEBOARD_MODULE_JS_NAPI, "work is null");
104         return;
105     }
106     PasteboardDataWorker *pasteboardDataWorker = new (std::nothrow) PasteboardDataWorker();
107     if (pasteboardDataWorker == nullptr) {
108         PASTEBOARD_HILOGW(PASTEBOARD_MODULE_JS_NAPI, "pasteboardDataWorker is null");
109         delete work;
110         work = nullptr;
111         return;
112     }
113     pasteboardDataWorker->observer = shared_from_this();
114 
115     work->data = (void *)pasteboardDataWorker;
116 
117     int ret = uv_queue_work(
118         loop, work, [](uv_work_t *work) {
119             PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "OnPasteboardChanged callback");
120         }, UvQueueWorkOnPasteboardChanged);
121     if (ret != 0) {
122         delete pasteboardDataWorker;
123         pasteboardDataWorker = nullptr;
124         delete work;
125         work = nullptr;
126     }
127     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "OnPasteboardChanged end");
128 }
129 
PasteboardDelayGetterInstance(const napi_env & env,const napi_ref & ref)130 PasteboardDelayGetterInstance::PasteboardDelayGetterInstance(const napi_env &env, const napi_ref &ref)
131     : env_(env), ref_(ref)
132 {
133     stub_ = std::make_shared<PasteboardDelayGetterInstance::PasteboardDelayGetterImpl>();
134 }
135 
~PasteboardDelayGetterInstance()136 PasteboardDelayGetterInstance::~PasteboardDelayGetterInstance()
137 {
138     ref_ = nullptr;
139 }
140 
UvQueueWorkGetDelayPasteData(uv_work_t * work,int status)141 void UvQueueWorkGetDelayPasteData(uv_work_t *work, int status)
142 {
143     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "UvQueueWorkGetDelayPasteData start");
144     if (UV_ECANCELED == status || work == nullptr || work->data == nullptr) {
145         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "invalid parameter");
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 
ReleasePasteboardResource(PasteboardDelayWorker ** pasteboardDelayWorker,uv_work_t ** work)193 static void ReleasePasteboardResource(PasteboardDelayWorker **pasteboardDelayWorker, uv_work_t **work)
194 {
195     if (pasteboardDelayWorker == nullptr || work == nullptr ||
196         *pasteboardDelayWorker == nullptr || *work == nullptr) {
197         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "invalid parameter");
198         return;
199     }
200     delete *pasteboardDelayWorker;
201     *pasteboardDelayWorker = nullptr;
202     delete *work;
203     *work = nullptr;
204 }
205 
GetUnifiedData(const std::string & type,UDMF::UnifiedData & data)206 void PasteboardDelayGetterInstance::GetUnifiedData(const std::string &type, UDMF::UnifiedData &data)
207 {
208     uv_loop_s *loop = nullptr;
209     napi_get_uv_event_loop(env_, &loop);
210     if (loop == nullptr) {
211         PASTEBOARD_HILOGW(PASTEBOARD_MODULE_JS_NAPI, "loop instance is nullptr");
212         return;
213     }
214     uv_work_t *work = new (std::nothrow) uv_work_t;
215     if (work == nullptr) {
216         PASTEBOARD_HILOGW(PASTEBOARD_MODULE_JS_NAPI, "work is null");
217         return;
218     }
219     PasteboardDelayWorker *pasteboardDelayWorker = new (std::nothrow) PasteboardDelayWorker();
220     if (pasteboardDelayWorker == nullptr) {
221         PASTEBOARD_HILOGW(PASTEBOARD_MODULE_JS_NAPI, "pasteboardDataWorker is null");
222         delete work;
223         work = nullptr;
224         return;
225     }
226     pasteboardDelayWorker->delayGetter = shared_from_this();
227     pasteboardDelayWorker->dataType = type;
228     work->data = (void *)pasteboardDelayWorker;
229     bool noNeedClean = false;
230     {
231         std::unique_lock<std::mutex> lock(pasteboardDelayWorker->mutex);
232         int ret = uv_queue_work(loop, work, [](uv_work_t *work) {
233             PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetUnifiedData callback");
234         }, UvQueueWorkGetDelayPasteData);
235         if (ret != 0) {
236             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "uv_queue_work ret is not 0");
237             ReleasePasteboardResource(&pasteboardDelayWorker, &work);
238             return;
239         }
240         if (pasteboardDelayWorker->cv.wait_for(lock, std::chrono::seconds(DELAY_TIMEOUT),
241             [pasteboardDelayWorker] { return pasteboardDelayWorker->complete; }) &&
242             pasteboardDelayWorker->unifiedData != nullptr) {
243             data = *(pasteboardDelayWorker->unifiedData);
244         }
245         if (!pasteboardDelayWorker->complete && uv_cancel((uv_req_t*)work) != 0) {
246             pasteboardDelayWorker->clean = true;
247             noNeedClean = true;
248         }
249     }
250     if (!noNeedClean) {
251         ReleasePasteboardResource(&pasteboardDelayWorker, &work);
252     }
253 }
254 
CheckArgsOfOnAndOff(napi_env env,bool checkArgsCount,napi_value * argv,size_t argc)255 bool SystemPasteboardNapi::CheckArgsOfOnAndOff(napi_env env, bool checkArgsCount, napi_value *argv, size_t argc)
256 {
257     if (!CheckExpression(
258         env, checkArgsCount, JSErrorCode::INVALID_PARAMETERS, "Parameter error. The number of arguments is wrong.") ||
259         !CheckArgsType(env, argv[0], napi_string, "Parameter error. The type of mimeType must be string.")) {
260         return false;
261     }
262     std::string mimeType;
263     bool ret = GetValue(env, argv[0], mimeType);
264     if (!ret) {
265         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "GetValue failed");
266         return false;
267     }
268     if (!CheckExpression(env, mimeType == STRING_UPDATE, JSErrorCode::INVALID_PARAMETERS,
269         "Parameter error. The value of type must be update")) {
270         return false;
271     }
272     return true;
273 }
274 
On(napi_env env,napi_callback_info info)275 napi_value SystemPasteboardNapi::On(napi_env env, napi_callback_info info)
276 {
277     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi on() is called!");
278     size_t argc = MAX_ARGS;
279     napi_value argv[MAX_ARGS] = { 0 };
280     napi_value thisVar = 0;
281     void *data = nullptr;
282     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
283     // on(type: 'update', callback: () => void) has 2 args
284     if (!CheckArgsOfOnAndOff(env, argc >= 2, argv, argc) ||
285         !CheckArgsType(env, argv[1], napi_function, "Parameter error. The type of callback must be function.")) {
286         return nullptr;
287     }
288 
289     napi_value result = nullptr;
290     napi_get_undefined(env, &result);
291     auto observer = GetObserver(env, argv[1]);
292     if (observer != nullptr) {
293         PASTEBOARD_HILOGW(PASTEBOARD_MODULE_JS_NAPI, "observer exist.");
294         return result;
295     }
296     napi_ref ref = nullptr;
297     napi_create_reference(env, argv[1], 1, &ref);
298     observer = std::make_shared<PasteboardObserverInstance>(env, ref);
299     if (observer == nullptr || observer->GetStub() == nullptr) {
300         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "invalid parameter observer.");
301         return nullptr;
302     }
303     observer->GetStub()->SetObserverWrapper(observer);
304     PasteboardClient::GetInstance()->Subscribe(PasteboardObserverType::OBSERVER_LOCAL, observer->GetStub());
305     observers_[ref] = observer;
306     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi on() is end!");
307     return result;
308 }
309 
Off(napi_env env,napi_callback_info info)310 napi_value SystemPasteboardNapi::Off(napi_env env, napi_callback_info info)
311 {
312     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi off () is called!");
313     size_t argc = MAX_ARGS;
314     napi_value argv[MAX_ARGS] = { 0 };
315     napi_value thisVar = 0;
316     void *data = nullptr;
317     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
318     // off(type: 'update', callback?: () => void) has at least 1 arg
319     if (!CheckArgsOfOnAndOff(env, argc >= 1, argv, argc)) {
320         return nullptr;
321     }
322 
323     std::shared_ptr<PasteboardObserverInstance> observer = nullptr;
324     // 1: is the observer parameter
325     if (argc > 1) {
326         if (!CheckArgsType(env, argv[1], napi_function, "Parameter error. The type of callback must be function.")) {
327             return nullptr;
328         }
329         observer = GetObserver(env, argv[1]);
330     }
331 
332     DeleteObserver(observer);
333     napi_value result = nullptr;
334     napi_get_undefined(env, &result);
335     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi off () is called!");
336     return result;
337 }
338 
Clear(napi_env env,napi_callback_info info)339 napi_value SystemPasteboardNapi::Clear(napi_env env, napi_callback_info info)
340 {
341     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "Clear is called!");
342     auto context = std::make_shared<AsyncCall::Context>();
343     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
344         // clear has 0 or 1 args
345         if (argc > 0 &&
346             !CheckArgsType(env, argv[0], napi_function, "Parameter error. The type of callback must be function.")) {
347             return napi_invalid_arg;
348         }
349         return napi_ok;
350     };
351     auto exec = [context](AsyncCall::Context *ctx) {
352         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "exec Clear");
353         PasteboardClient::GetInstance()->Clear();
354     };
355     context->SetAction(std::move(input));
356     // 0: the AsyncCall at the first position;
357     AsyncCall asyncCall(env, info, context, 0);
358     return asyncCall.Call(env, exec);
359 }
360 
ClearData(napi_env env,napi_callback_info info)361 napi_value SystemPasteboardNapi::ClearData(napi_env env, napi_callback_info info)
362 {
363     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "ClearData is called!");
364     return Clear(env, info);
365 }
366 
HasPasteData(napi_env env,napi_callback_info info)367 napi_value SystemPasteboardNapi::HasPasteData(napi_env env, napi_callback_info info)
368 {
369     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "HasPasteData is called!");
370     auto context = std::make_shared<HasContextInfo>();
371     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
372         // hasPasteData has 0 or 1 args
373         if (argc > 0 &&
374             !CheckArgsType(env, argv[0], napi_function, "Parameter error. The type of callback must be function.")) {
375             return napi_invalid_arg;
376         }
377         return napi_ok;
378     };
379     auto output = [context](napi_env env, napi_value *result) -> napi_status {
380         napi_status status = napi_get_boolean(env, context->hasPasteData, result);
381         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "napi_get_boolean status = %{public}d", status);
382         return status;
383     };
384     auto exec = [context](AsyncCall::Context *ctx) {
385         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "exec HasPasteData");
386         context->hasPasteData = PasteboardClient::GetInstance()->HasPasteData();
387         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "HasPasteData result = %{public}d", context->hasPasteData);
388         context->status = napi_ok;
389     };
390     context->SetAction(std::move(input), std::move(output));
391     // 0: the AsyncCall at the first position;
392     AsyncCall asyncCall(env, info, context, 0);
393     return asyncCall.Call(env, exec);
394 }
395 
HasData(napi_env env,napi_callback_info info)396 napi_value SystemPasteboardNapi::HasData(napi_env env, napi_callback_info info)
397 {
398     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "HasData is called!");
399     return HasPasteData(env, info);
400 }
401 
GetDataCommon(std::shared_ptr<GetContextInfo> & context)402 void SystemPasteboardNapi::GetDataCommon(std::shared_ptr<GetContextInfo> &context)
403 {
404     auto input = [](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
405         // 1: GetPasteData has 0 or 1 args
406         if (argc > 0 &&
407             !CheckArgsType(env, argv[0], napi_function, "Parameter error. The type of callback must be function.")) {
408             return napi_invalid_arg;
409         }
410         return napi_ok;
411     };
412 
413     auto output = [context](napi_env env, napi_value *result) -> napi_status {
414         napi_value instance = nullptr;
415         napi_status status = PasteDataNapi::NewInstance(env, instance);
416         if (status != napi_ok) {
417             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "NewInstance failed");
418             return status;
419         }
420         PasteDataNapi *obj = nullptr;
421         napi_status ret = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
422         if ((ret == napi_ok) && (obj != nullptr)) {
423             obj->value_ = context->pasteData;
424         } else {
425             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "obj is null or ret not ok");
426             return napi_generic_failure;
427         }
428         *result = instance;
429         return napi_ok;
430     };
431     context->SetAction(std::move(input), std::move(output));
432 }
433 
GetPasteData(napi_env env,napi_callback_info info)434 napi_value SystemPasteboardNapi::GetPasteData(napi_env env, napi_callback_info info)
435 {
436     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetPasteData is called!");
437 
438     auto context = std::make_shared<GetContextInfo>();
439     context->pasteData = std::make_shared<PasteData>();
440     GetDataCommon(context);
441 
442     auto exec = [context](AsyncCall::Context *ctx) {
443         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetPasteData Begin");
444         PasteboardClient::GetInstance()->GetPasteData(*context->pasteData);
445         context->status = napi_ok;
446         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetPasteData End");
447     };
448 
449     // 0: the AsyncCall at the first position;
450     AsyncCall asyncCall(env, info, context, 0);
451     return asyncCall.Call(env, exec);
452 }
453 
GetData(napi_env env,napi_callback_info info)454 napi_value SystemPasteboardNapi::GetData(napi_env env, napi_callback_info info)
455 {
456     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetData is called!");
457 
458     auto context = std::make_shared<GetContextInfo>();
459     context->pasteData = std::make_shared<PasteData>();
460     GetDataCommon(context);
461 
462     auto exec = [context](AsyncCall::Context *ctx) {
463         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetData Begin");
464         int32_t ret = PasteboardClient::GetInstance()->GetPasteData(*context->pasteData);
465         if (ret == static_cast<int32_t>(PasteboardError::TASK_PROCESSING)) {
466             ret = static_cast<int32_t>(JSErrorCode::OTHER_COPY_OR_PASTE_IN_PROCESSING);
467         }
468         if (ret == static_cast<int32_t>(JSErrorCode::OTHER_COPY_OR_PASTE_IN_PROCESSING)) {
469             context->SetErrInfo(ret, "Another getData is being processed");
470         } else {
471             context->status = napi_ok;
472         }
473         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetData End");
474     };
475     // 0: the AsyncCall at the first position;
476     AsyncCall asyncCall(env, info, context, 0);
477     return asyncCall.Call(env, exec);
478 }
479 
SetDataCommon(std::shared_ptr<SetContextInfo> & context)480 void SystemPasteboardNapi::SetDataCommon(std::shared_ptr<SetContextInfo> &context)
481 {
482     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
483         // setData has 1 or 2 args
484         if (!CheckExpression(
485             env, argc > 0, JSErrorCode::INVALID_PARAMETERS,
486             "Parameter error. The number of arguments must be greater than zero.") ||
487             !CheckExpression(env, PasteDataNapi::IsPasteData(env, argv[0]), JSErrorCode::INVALID_PARAMETERS,
488             "Parameter error. The Type of data must be pasteData.")) {
489             return napi_invalid_arg;
490         }
491         if (argc > 1 &&
492             !CheckArgsType(env, argv[1], napi_function, "Parameter error. The type of callback must be function.")) {
493             return napi_invalid_arg;
494         }
495         PasteDataNapi *pasteData = nullptr;
496         napi_unwrap(env, argv[0], reinterpret_cast<void **>(&pasteData));
497         if (pasteData != nullptr) {
498             context->obj = pasteData->value_;
499         }
500         return napi_ok;
501     };
502     context->SetAction(std::move(input));
503 }
504 
SetPasteData(napi_env env,napi_callback_info info)505 napi_value SystemPasteboardNapi::SetPasteData(napi_env env, napi_callback_info info)
506 {
507     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SetPasteData is called!");
508     auto context = std::make_shared<SetContextInfo>();
509     SetDataCommon(context);
510 
511     auto exec = [context](AsyncCall::Context *ctx) {
512         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "exec SetPasteData");
513         if (context->obj != nullptr) {
514             PasteboardClient::GetInstance()->SetPasteData(*(context->obj));
515             context->obj = nullptr;
516         }
517         context->status = napi_ok;
518     };
519     // 1: the AsyncCall at the second position
520     AsyncCall asyncCall(env, info, context, 1);
521     return asyncCall.Call(env, exec);
522 }
523 
SetData(napi_env env,napi_callback_info info)524 napi_value SystemPasteboardNapi::SetData(napi_env env, napi_callback_info info)
525 {
526     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SetData is called!");
527     auto context = std::make_shared<SetContextInfo>();
528     SetDataCommon(context);
529 
530     auto exec = [context](AsyncCall::Context *ctx) {
531         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "exec SetPasteData");
532         int32_t ret = static_cast<int32_t>(PasteboardError::INVALID_DATA_ERROR);
533         if (context->obj != nullptr) {
534             std::map<uint32_t, std::shared_ptr<UDMF::EntryGetter>> entryGetters;
535             for (auto record : context->obj->AllRecords()) {
536                 if (record != nullptr && record->GetEntryGetter() != nullptr) {
537                     entryGetters.emplace(record->GetRecordId(), record->GetEntryGetter());
538                 }
539             }
540             ret = PasteboardClient::GetInstance()->SetPasteData(*(context->obj), nullptr, entryGetters);
541             context->obj = nullptr;
542         }
543         if (ret == static_cast<int>(PasteboardError::E_OK)) {
544             context->status = napi_ok;
545         } else if (ret == static_cast<int>(PasteboardError::PROHIBIT_COPY)) {
546             context->SetErrInfo(ret, "The system prohibits copying");
547         } else if (ret == static_cast<int>(PasteboardError::TASK_PROCESSING)) {
548             context->SetErrInfo(ret, "Another setData is being processed");
549         }
550         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "exec context->status[%{public}d]", context->status);
551     };
552     // 1: the AsyncCall at the second position
553     AsyncCall asyncCall(env, info, context, 1);
554     return asyncCall.Call(env, exec);
555 }
556 
SetUnifiedData(napi_env env,napi_callback_info info)557 napi_value SystemPasteboardNapi::SetUnifiedData(napi_env env, napi_callback_info info)
558 {
559     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SetUnifiedData is called!");
560     auto context = std::make_shared<SetUnifiedContextInfo>();
561     SetDataCommon(context);
562 
563     auto exec = [context](AsyncCall::Context* ctx) {
564         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "exec SetPasteData");
565         int32_t ret = static_cast<int32_t>(PasteboardError::INVALID_DATA_ERROR);
566         if (context->obj != nullptr) {
567             if (context->isDelay && context->delayGetter != nullptr && context->delayGetter->GetStub() != nullptr) {
568                 ret = PasteboardClient::GetInstance()->SetUnifiedData(*(context->obj), context->delayGetter->GetStub());
569             } else {
570                 ret = PasteboardClient::GetInstance()->SetUnifiedData(*(context->obj));
571             }
572             context->obj = nullptr;
573         }
574         if (ret == static_cast<int>(PasteboardError::E_OK)) {
575             context->status = napi_ok;
576         } else if (ret == static_cast<int>(PasteboardError::PROHIBIT_COPY)) {
577             context->SetErrInfo(ret, "The system prohibits copying");
578         } else if (ret == static_cast<int>(PasteboardError::TASK_PROCESSING)) {
579             context->SetErrInfo(ret, "Another setData is being processed");
580         }
581         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "exec context->status[%{public}d]", context->status);
582     };
583     // 1: the AsyncCall at the second position
584     AsyncCall asyncCall(env, info, context, 1);
585     return asyncCall.Call(env, exec);
586 }
587 
GetUnifiedData(napi_env env,napi_callback_info info)588 napi_value SystemPasteboardNapi::GetUnifiedData(napi_env env, napi_callback_info info)
589 {
590     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetUnifiedData is called!");
591 
592     auto context = std::make_shared<GetUnifiedContextInfo>();
593     context->unifiedData = std::make_shared<UDMF::UnifiedData>();
594     GetDataCommon(context);
595 
596     auto exec = [context](AsyncCall::Context* ctx) {
597         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetUnifiedData Begin");
598         int32_t ret = PasteboardClient::GetInstance()->GetUnifiedData(*context->unifiedData);
599         if (ret == static_cast<int32_t>(PasteboardError::TASK_PROCESSING)) {
600             context->SetErrInfo(ret, "Another getData is being processed");
601         } else {
602             context->status = napi_ok;
603         }
604         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetUnifiedData End");
605     };
606     // 0: the AsyncCall at the first position;
607     AsyncCall asyncCall(env, info, context, 0);
608     return asyncCall.Call(env, exec);
609 }
610 
GetUnifiedDataSync(napi_env env,napi_callback_info info)611 napi_value SystemPasteboardNapi::GetUnifiedDataSync(napi_env env, napi_callback_info info)
612 {
613     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi GetUnifiedDataSync is called!");
614     napi_value instance = nullptr;
615     std::shared_ptr<UDMF::UnifiedData> unifiedData = std::make_shared<UDMF::UnifiedData>();
616 
617     NAPI_CALL(env, UDMF::UnifiedDataNapi::NewInstance(env, unifiedData, instance));
618     UDMF::UnifiedDataNapi* obj = nullptr;
619     napi_status status = napi_unwrap(env, instance, reinterpret_cast<void**>(&obj));
620     if ((status != napi_ok) || (obj == nullptr) || obj->value_ == nullptr) {
621         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "GetUnifiedDataSync get obj failed.");
622         return nullptr;
623     }
624     auto block = std::make_shared<BlockObject<std::shared_ptr<int32_t>>>(SYNC_TIMEOUT);
625     std::thread thread([block, unifiedData = obj->value_]() mutable {
626         auto ret = PasteboardClient::GetInstance()->GetUnifiedData(*unifiedData);
627         std::shared_ptr<int32_t> value = std::make_shared<int32_t>(ret);
628         block->SetValue(value);
629     });
630     thread.detach();
631     auto value = block->GetValue();
632     if (!CheckExpression(env, value != nullptr, JSErrorCode::REQUEST_TIME_OUT, "request timed out.")) {
633         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "time out, GetUnifiedDataSync failed.");
634     }
635     return instance;
636 }
637 
SetUnifiedDataSync(napi_env env,napi_callback_info info)638 napi_value SystemPasteboardNapi::SetUnifiedDataSync(napi_env env, napi_callback_info info)
639 {
640     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi SetUnifiedDataSync is called!");
641     size_t argc = ARGC_TYPE_SET1;
642     napi_value argv[ARGC_TYPE_SET1] = {0};
643     napi_value thisVar = nullptr;
644 
645     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
646     if (!CheckExpression(
647         env, argc > 0, JSErrorCode::INVALID_PARAMETERS, "Parameter error. Wrong number of arguments.")) {
648         return nullptr;
649     }
650     UDMF::UnifiedDataNapi* unifiedDataNapi = nullptr;
651     napi_unwrap(env, argv[0], reinterpret_cast<void**>(&unifiedDataNapi));
652     if (!CheckExpression(env, (unifiedDataNapi != nullptr && unifiedDataNapi->value_ != nullptr),
653         JSErrorCode::INVALID_PARAMETERS, "Parameter error. The Type of data must be unifiedData.")) {
654         return nullptr;
655     }
656     auto properties = unifiedDataNapi->GetPropertiesNapi(env);
657     bool isDelay = false;
658     std::shared_ptr<PasteboardDelayGetterInstance> delayGetter = nullptr;
659     if (properties != nullptr && properties->delayDataRef_ != nullptr) {
660         delayGetter = std::make_shared<PasteboardDelayGetterInstance>(env, properties->delayDataRef_);
661         delayGetter->GetStub()->SetDelayGetterWrapper(delayGetter);
662         isDelay = true;
663     }
664     auto block = std::make_shared<BlockObject<std::shared_ptr<int>>>(SYNC_TIMEOUT);
665     std::shared_ptr<UDMF::UnifiedData> unifiedData = unifiedDataNapi->value_;
666     std::thread thread([block, unifiedData, isDelay, delayGetter]() mutable {
667         int32_t ret = isDelay ?
668             PasteboardClient::GetInstance()->SetUnifiedData(*unifiedData, delayGetter->GetStub()) :
669             PasteboardClient::GetInstance()->SetUnifiedData(*unifiedData);
670         std::shared_ptr<int> value = std::make_shared<int>(static_cast<int>(ret));
671         block->SetValue(value);
672     });
673     thread.detach();
674     auto value = block->GetValue();
675     if (!CheckExpression(env, value != nullptr, JSErrorCode::REQUEST_TIME_OUT, "request timed out.")) {
676         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "time out, SetUnifiedDataSync failed.");
677         return nullptr;
678     }
679     if (*value != static_cast<int32_t>(PasteboardError::E_OK)) {
680         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "operate invalid, SetUnifiedDataSync failed");
681         return nullptr;
682     }
683     {
684         std::lock_guard<std::mutex> lck(delayMutex_);
685         delayGetter_ = delayGetter;
686     }
687     return nullptr;
688 }
689 
SetAppShareOptions(napi_env env,napi_callback_info info)690 napi_value SystemPasteboardNapi::SetAppShareOptions(napi_env env, napi_callback_info info)
691 {
692     size_t argc = ARGC_TYPE_SET1;
693     napi_value argv[ARGC_TYPE_SET1] = {0};
694     napi_value thisArg = nullptr;
695     void *data = nullptr;
696     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, &data));
697     if (!CheckExpression(env, argc > 0, JSErrorCode::INVALID_PARAMETERS,
698         "Parameter error. Mandatory parameters are left unspecified.")) {
699         return nullptr;
700     }
701     int32_t shareOptions;
702     auto status = napi_get_value_int32(env, argv[0], &shareOptions);
703     if (!CheckExpression(env, status == napi_ok, JSErrorCode::INVALID_PARAMETERS,
704         "Parameter error. Incorrect parameter types.")) {
705         return nullptr;
706     }
707     auto result = PasteboardClient::GetInstance()->SetAppShareOptions(static_cast<ShareOption>(shareOptions));
708     if (!CheckExpression(env, result != static_cast<int32_t>(PasteboardError::INVALID_PARAM_ERROR),
709         JSErrorCode::INVALID_PARAMETERS, "Parameter error. Parameter verification failed.")) {
710         return nullptr;
711     }
712     if (!CheckExpression(env, result != static_cast<int32_t>(PasteboardError::PERMISSION_VERIFICATION_ERROR),
713         JSErrorCode::NO_PERMISSION,
714         "Permission verification failed. A non-permission application calls a API.")) {
715         return nullptr;
716     }
717     if (!CheckExpression(env, result != static_cast<int32_t>(PasteboardError::INVALID_OPERATION_ERROR),
718         JSErrorCode::SETTINGS_ALREADY_EXIST, "Settings already exist.")) {
719         return nullptr;
720     }
721     return nullptr;
722 }
723 
RemoveAppShareOptions(napi_env env,napi_callback_info info)724 napi_value SystemPasteboardNapi::RemoveAppShareOptions(napi_env env, napi_callback_info info)
725 {
726     auto result = PasteboardClient::GetInstance()->RemoveAppShareOptions();
727     if (CheckExpression(env, result != static_cast<int32_t>(PasteboardError::PERMISSION_VERIFICATION_ERROR),
728         JSErrorCode::NO_PERMISSION,
729         "Permission verification failed. A non-permission application calls a API.")) {
730         return nullptr;
731     }
732     return nullptr;
733 }
734 
SetDataCommon(std::shared_ptr<SetUnifiedContextInfo> & context)735 void SystemPasteboardNapi::SetDataCommon(std::shared_ptr<SetUnifiedContextInfo>& context)
736 {
737     auto input = [context](napi_env env, size_t argc, napi_value* argv, napi_value self) -> napi_status {
738         // setData has 1 arg
739         if (!CheckExpression(
740             env, argc > 0, JSErrorCode::INVALID_PARAMETERS, "Parameter error. Wrong number of arguments.")) {
741             return napi_invalid_arg;
742         }
743         UDMF::UnifiedDataNapi* unifiedDataNapi = nullptr;
744         context->status = napi_unwrap(env, argv[0], reinterpret_cast<void**>(&unifiedDataNapi));
745         if (!CheckExpression(env, unifiedDataNapi != nullptr,
746             JSErrorCode::INVALID_PARAMETERS, "Parameter error. The Type of data must be unifiedData.")) {
747             return napi_invalid_arg;
748         }
749         context->obj = unifiedDataNapi->value_;
750         auto properties = unifiedDataNapi->GetPropertiesNapi(env);
751         if (properties != nullptr && properties->delayDataRef_ != nullptr) {
752             context->delayGetter = std::make_shared<PasteboardDelayGetterInstance>(env, properties->delayDataRef_);
753             if (context->delayGetter == nullptr || context->delayGetter->GetStub() == nullptr) {
754                 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "SetDataCommon delayGetter is null");
755                 return napi_invalid_arg;
756             }
757             context->delayGetter->GetStub()->SetDelayGetterWrapper(context->delayGetter);
758             context->isDelay = true;
759         }
760         return napi_ok;
761     };
762     auto output = [context](napi_env env, napi_value *result) -> napi_status {
763         if (context->status == napi_ok) {
764             std::lock_guard<std::mutex> lck(delayMutex_);
765             delayGetter_ = std::move(context->delayGetter);
766         }
767         return napi_ok;
768     };
769     context->SetAction(std::move(input), std::move(output));
770 }
771 
GetDataCommon(std::shared_ptr<GetUnifiedContextInfo> & context)772 void SystemPasteboardNapi::GetDataCommon(std::shared_ptr<GetUnifiedContextInfo>& context)
773 {
774     auto input = [](napi_env env, size_t argc, napi_value* argv, napi_value self) -> napi_status {
775         // 1: GetPasteData has 0 or 1 args
776         if (argc > 0 &&
777             !CheckArgsType(env, argv[0], napi_function, "Parameter error. The type of callback must be function.")) {
778             return napi_invalid_arg;
779         }
780         return napi_ok;
781     };
782 
783     auto output = [context](napi_env env, napi_value* result) -> napi_status {
784         napi_value instance = nullptr;
785         std::shared_ptr<UDMF::UnifiedData> unifiedData = std::make_shared<UDMF::UnifiedData>();
786         napi_status status = UDMF::UnifiedDataNapi::NewInstance(env, unifiedData, instance);
787         if (status != napi_ok) {
788             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "NewInstance failed");
789             return status;
790         }
791 
792         UDMF::UnifiedDataNapi* obj = nullptr;
793         napi_status ret = napi_unwrap(env, instance, reinterpret_cast<void**>(&obj));
794         if ((ret == napi_ok) && (obj != nullptr)) {
795             obj->value_ = context->unifiedData;
796         } else {
797             return napi_generic_failure;
798         }
799         *result = instance;
800         return napi_ok;
801     };
802     context->SetAction(std::move(input), std::move(output));
803 }
804 
IsRemoteData(napi_env env,napi_callback_info info)805 napi_value SystemPasteboardNapi::IsRemoteData(napi_env env, napi_callback_info info)
806 {
807     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi IsRemoteData() is called!");
808     auto block = std::make_shared<BlockObject<std::shared_ptr<int>>>(SYNC_TIMEOUT);
809     std::thread thread([block]() {
810         auto ret = PasteboardClient::GetInstance()->IsRemoteData();
811         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "value=%{public}d", ret);
812         std::shared_ptr<int> value = std::make_shared<int>(static_cast<int>(ret));
813         block->SetValue(value);
814     });
815     thread.detach();
816     auto value = block->GetValue();
817     if (!CheckExpression(env, value != nullptr, JSErrorCode::REQUEST_TIME_OUT, "Request timed out.")) {
818         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "time out, IsRemoteData failed.");
819         return nullptr;
820     }
821     napi_value result = nullptr;
822     napi_get_boolean(env, *value, &result);
823     return result;
824 }
825 
GetDataSource(napi_env env,napi_callback_info info)826 napi_value SystemPasteboardNapi::GetDataSource(napi_env env, napi_callback_info info)
827 {
828     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi GetDataSource() is called!");
829     std::string bundleName;
830     auto block = std::make_shared<BlockObject<std::shared_ptr<int>>>(SYNC_TIMEOUT);
831     std::thread thread([block, &bundleName]() mutable {
832         auto ret = PasteboardClient::GetInstance()->GetDataSource(bundleName);
833         std::shared_ptr<int> value = std::make_shared<int>(ret);
834         block->SetValue(value);
835     });
836     thread.detach();
837     auto value = block->GetValue();
838     if (!CheckExpression(env, value != nullptr, JSErrorCode::REQUEST_TIME_OUT, "Request timed out.")) {
839         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "time out, GetDataSource failed.");
840         return nullptr;
841     }
842 
843     if (*value != static_cast<int>(PasteboardError::E_OK)) {
844         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "GetDataSource, failed, ret = %{public}d", *value);
845         return nullptr;
846     }
847     napi_value result = nullptr;
848     napi_create_string_utf8(env, bundleName.c_str(), NAPI_AUTO_LENGTH, &result);
849     return result;
850 }
851 
GetMimeTypes(napi_env env,napi_callback_info info)852 napi_value SystemPasteboardNapi::GetMimeTypes(napi_env env, napi_callback_info info)
853 {
854     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi GetMimeTypes() is called!");
855     auto context = std::make_shared<GetMimeTypesContextInfo>();
856     auto input = [](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
857         if (argc > 0 &&
858             !CheckArgsType(env, argv[0], napi_function, "Parameter error. The type of callback must be function.")) {
859             return napi_invalid_arg;
860         }
861         return napi_ok;
862     };
863     auto output = [context](napi_env env, napi_value *result) -> napi_status {
864         napi_status status = NapiDataUtils::SetValue(env, context->mimeTypes, *result);
865         return status;
866     };
867     auto exec = [context](AsyncCall::Context *ctx) {
868         context->mimeTypes = PasteboardClient::GetInstance()->GetMimeTypes();
869         context->status = napi_ok;
870     };
871     context->SetAction(std::move(input), std::move(output));
872     AsyncCall asyncCall(env, info, context, 1);
873     return asyncCall.Call(env, exec);
874 }
875 
GetChangeCount(napi_env env,napi_callback_info info)876 napi_value SystemPasteboardNapi::GetChangeCount(napi_env env, napi_callback_info info)
877 {
878     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi GetChangeCount() is called!");
879     uint32_t changeCount = 0;
880     PasteboardClient::GetInstance()->GetChangeCount(changeCount);
881     napi_value result = nullptr;
882     napi_create_uint32(env, changeCount, &result);
883     return result;
884 }
885 
HasDataType(napi_env env,napi_callback_info info)886 napi_value SystemPasteboardNapi::HasDataType(napi_env env, napi_callback_info info)
887 {
888     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi HasDataType() is called!");
889     size_t argc = ARGC_TYPE_SET1;
890     napi_value argv[ARGC_TYPE_SET1] = {0};
891     napi_value thisVar = nullptr;
892 
893     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
894     if ((!CheckExpression(env, argc >= ARGC_TYPE_SET1, JSErrorCode::INVALID_PARAMETERS,
895         "Parameter error. The number of arguments must be grater than zero.")) ||
896         (!CheckArgsType(env, argv[0], napi_string, "Parameter error. The type of mimeType must be string."))) {
897         return nullptr;
898     }
899 
900     std::string mimeType;
901     if (!GetValue(env, argv[0], mimeType)) {
902         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Failed to GetValue!");
903         return nullptr;
904     }
905     bool ret = PasteboardClient::GetInstance()->HasDataType(mimeType);
906     napi_value result = nullptr;
907     napi_get_boolean(env, ret, &result);
908     return result;
909 }
910 
DetectPatterns(napi_env env,napi_callback_info info)911 napi_value SystemPasteboardNapi::DetectPatterns(napi_env env, napi_callback_info info)
912 {
913     auto context = std::make_shared<DetectPatternsContextInfo>();
914     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
915         if (!CheckExpression(env, argc == ARGC_TYPE_SET1, JSErrorCode::INVALID_PARAMETERS,
916             "Parameter error. The number of arguments must be one.")) {
917             return napi_invalid_arg;
918         }
919         bool getValueRes = GetValue(env, argv[0], context->patternsToCheck);
920         if (!CheckExpression(env, getValueRes, JSErrorCode::INVALID_PARAMETERS,
921             "Parameter error. Array<Pattern> expected.")) {
922             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Failed to GetValue.");
923             return napi_invalid_arg;
924         }
925         return napi_ok;
926     };
927     auto output = [context](napi_env env, napi_value *result) -> napi_status {
928         napi_status status = SetValue(env, context->patternsDetect, *result);
929         return status;
930     };
931     auto exec = [context](AsyncCall::Context *ctx) {
932         context->patternsDetect = PasteboardClient::GetInstance()->DetectPatterns(context->patternsToCheck);
933         context->status = napi_ok;
934     };
935     context->SetAction(std::move(input), std::move(output));
936     AsyncCall asyncCall(env, info, context, 1);
937     return asyncCall.Call(env, exec);
938 }
939 
ClearDataSync(napi_env env,napi_callback_info info)940 napi_value SystemPasteboardNapi::ClearDataSync(napi_env env, napi_callback_info info)
941 {
942     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi ClearDataSync() is called!");
943     auto block = std::make_shared<BlockObject<std::shared_ptr<int>>>(SYNC_TIMEOUT);
944     std::thread thread([block]() {
945         PasteboardClient::GetInstance()->Clear();
946         std::shared_ptr<int> value = std::make_shared<int>(0);
947         block->SetValue(value);
948     });
949     thread.detach();
950     auto value = block->GetValue();
951     if (!CheckExpression(env, value != nullptr, JSErrorCode::REQUEST_TIME_OUT, "Request timed out.")) {
952         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "time out, ClearDataSync failed.");
953     }
954     return nullptr;
955 }
956 
GetDataSync(napi_env env,napi_callback_info info)957 napi_value SystemPasteboardNapi::GetDataSync(napi_env env, napi_callback_info info)
958 {
959     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi GetDataSync() is called!");
960     napi_value instance = nullptr;
961     NAPI_CALL(env, PasteDataNapi::NewInstance(env, instance));
962     PasteDataNapi *obj = nullptr;
963     napi_status status = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
964     if ((status != napi_ok) || (obj == nullptr) || obj->value_ == nullptr) {
965         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "GetDataSync napi_unwrap failed");
966         return nullptr;
967     }
968     auto block = std::make_shared<BlockObject<std::shared_ptr<int32_t>>>(SYNC_TIMEOUT);
969     std::thread thread([block, pasteData = obj->value_]() mutable {
970         auto ret = PasteboardClient::GetInstance()->GetPasteData(*pasteData);
971         std::shared_ptr<int32_t> value = std::make_shared<int32_t>(ret);
972         block->SetValue(value);
973     });
974     thread.detach();
975     auto value = block->GetValue();
976     if (!CheckExpression(env, value != nullptr, JSErrorCode::REQUEST_TIME_OUT, "request timed out.")) {
977         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "time out, GetDataSync failed.");
978     }
979     return instance;
980 }
981 
SetDataSync(napi_env env,napi_callback_info info)982 napi_value SystemPasteboardNapi::SetDataSync(napi_env env, napi_callback_info info)
983 {
984     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi SetDataSync() is called!");
985     size_t argc = ARGC_TYPE_SET1;
986     napi_value argv[ARGC_TYPE_SET1] = {0};
987     napi_value thisVar = nullptr;
988 
989     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
990     if (!CheckExpression(env, argc > 0, JSErrorCode::INVALID_PARAMETERS,
991         "Parameter error. The number of arguments must be one.") ||
992         !CheckExpression(env, PasteDataNapi::IsPasteData(env, argv[0]), JSErrorCode::INVALID_PARAMETERS,
993         "Parameter error. The Type of data must be pasteData.")) {
994         return nullptr;
995     }
996 
997     PasteDataNapi *pasteData = nullptr;
998     napi_unwrap(env, argv[0], reinterpret_cast<void **>(&pasteData));
999     if (pasteData == nullptr || pasteData->value_ == nullptr) {
1000         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Failed to GetValue!");
1001         return nullptr;
1002     }
1003     auto block = std::make_shared<BlockObject<std::shared_ptr<int>>>(SYNC_TIMEOUT);
1004     std::shared_ptr<PasteData> data = pasteData->value_;
1005     std::thread thread([block, data]() {
1006         auto ret = PasteboardClient::GetInstance()->SetPasteData(*data);
1007         std::shared_ptr<int> value = std::make_shared<int>(static_cast<int>(ret));
1008         block->SetValue(value);
1009     });
1010     thread.detach();
1011     auto value = block->GetValue();
1012     if (!CheckExpression(env, value != nullptr, JSErrorCode::REQUEST_TIME_OUT, "request timed out.")) {
1013         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "time out, SetDataSync failed.");
1014         return nullptr;
1015     }
1016 
1017     if (*value != static_cast<int32_t>(PasteboardError::E_OK)) {
1018         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "operate invalid, SetDataSync failed");
1019         return nullptr;
1020     }
1021     return nullptr;
1022 }
1023 
HasDataSync(napi_env env,napi_callback_info info)1024 napi_value SystemPasteboardNapi::HasDataSync(napi_env env, napi_callback_info info)
1025 {
1026     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi HasDataSync() is called!");
1027     auto block = std::make_shared<BlockObject<std::shared_ptr<int>>>(SYNC_TIMEOUT);
1028     std::thread thread([block]() {
1029         auto ret = PasteboardClient::GetInstance()->HasPasteData();
1030         std::shared_ptr<int> value = std::make_shared<int>(static_cast<int>(ret));
1031         block->SetValue(value);
1032     });
1033     thread.detach();
1034     auto value = block->GetValue();
1035     if (!CheckExpression(env, value != nullptr, JSErrorCode::REQUEST_TIME_OUT, "request timed out.")) {
1036         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "time out, HasDataSync failed.");
1037         return nullptr;
1038     }
1039     napi_value result = nullptr;
1040     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "value=%{public}d", *value);
1041     napi_get_boolean(env, *value, &result);
1042     return result;
1043 }
1044 
ProgressNotify(std::shared_ptr<GetDataParams> params)1045 void SystemPasteboardNapi::ProgressNotify(std::shared_ptr<GetDataParams> params)
1046 {
1047     if (params == nullptr) {
1048         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "params is null!");
1049         return;
1050     }
1051 
1052     if (params->info == nullptr) {
1053         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "params->info is null!");
1054         return;
1055     }
1056     std::shared_ptr<ProgressListenerFn> listenerFn = nullptr;
1057     std::lock_guard<std::recursive_mutex> lock(listenerMutex_);
1058     auto it = listenerMap_.find("progressNotify");
1059     if (it != listenerMap_.end()) {
1060         listenerFn = it->second;
1061     }
1062 
1063     if (listenerFn == nullptr || listenerFn->tsFunction == nullptr) {
1064         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "thread safe function is nullptr!");
1065         return;
1066     }
1067 
1068     napi_status status = napi_acquire_threadsafe_function(listenerFn->tsFunction);
1069     if (status != napi_ok) {
1070         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "acquire progressNotify failed!");
1071         return;
1072     }
1073 
1074     MiscServices::ProgressInfo *progress = new ProgressInfo();
1075     progress->percentage = params->info->percentage;
1076     status = napi_call_threadsafe_function(listenerFn->tsFunction, static_cast<void *>(progress), napi_tsfn_blocking);
1077     if (status != napi_ok) {
1078         delete progress;
1079         progress = nullptr;
1080         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "call progressNotify failed!");
1081         return;
1082     }
1083 
1084     status = napi_release_threadsafe_function(listenerFn->tsFunction, napi_tsfn_release);
1085     if (status != napi_ok) {
1086         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "release progressNotify failed!");
1087         return;
1088     }
1089 }
1090 
CallJsProgressNotify(napi_env env,napi_value jsFunction,void * context,void * data)1091 void SystemPasteboardNapi::CallJsProgressNotify(napi_env env, napi_value jsFunction, void *context, void *data)
1092 {
1093     #define AGR_COUNT 1
1094     #define DEVICE_NAME_LEN 512
1095     (void)context;
1096     ProgressInfo *info = (ProgressInfo *)data;
1097     if (info == nullptr) {
1098         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "progressInfo is nullptr!");
1099         return;
1100     }
1101 
1102     int progress = info->percentage;
1103     delete info;
1104     info = nullptr;
1105 
1106     napi_value percentage;
1107     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, progress, &percentage));
1108 
1109     napi_value progressInfo = nullptr;
1110     NAPI_CALL_RETURN_VOID(env, napi_create_object(env, &progressInfo));
1111     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, progressInfo, "progress", percentage));
1112 
1113     napi_value argv[AGR_COUNT] = { progressInfo };
1114     NAPI_CALL_RETURN_VOID(env, napi_call_function(env, NULL, jsFunction, AGR_COUNT, argv, NULL));
1115 }
1116 
CreateThreadSafeFunc(napi_env env,const std::shared_ptr<ProgressListenerFn> listenerFn)1117 bool SystemPasteboardNapi::CreateThreadSafeFunc(napi_env env, const std::shared_ptr<ProgressListenerFn> listenerFn)
1118 {
1119     #define MAX_LINTENER_LEN 20
1120     napi_value name = nullptr;
1121     if (listenerFn->jsCallback == nullptr) {
1122         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "jsCallback is null!");
1123         return false;
1124     }
1125 
1126     NAPI_CALL_BASE(env, napi_create_string_utf8(env, "progressNotify", MAX_LINTENER_LEN, &name), false);
1127     napi_status status = napi_create_threadsafe_function(env, listenerFn->jsCallback, NULL, name, 0, 1, NULL,
1128         NULL, NULL, CallJsProgressNotify, &listenerFn->tsFunction);
1129     if (status != napi_ok) {
1130         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "create threadsafe failed!");
1131         return false;
1132     }
1133     return true;
1134 }
1135 
AddProgressListener(napi_env env,std::shared_ptr<MiscServices::GetDataParams> getDataParam,const std::shared_ptr<ProgressListenerFn> listenerFn)1136 bool SystemPasteboardNapi::AddProgressListener(napi_env env, std::shared_ptr<MiscServices::GetDataParams> getDataParam,
1137     const std::shared_ptr<ProgressListenerFn> listenerFn)
1138 {
1139     std::lock_guard<std::recursive_mutex> lock(listenerMutex_);
1140     auto it = listenerMap_.find("progressNotify");
1141     if (it == listenerMap_.end()) {
1142         listenerMap_.insert({ "progressNotify", listenerFn });
1143     }
1144 
1145     if (!CreateThreadSafeFunc(env, listenerFn)) {
1146         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "CreateThreadSafeFunc failed!");
1147         listenerMap_.erase("progressNotify");
1148         return false;
1149     }
1150 
1151     getDataParam->listener.ProgressNotify = ProgressNotify;
1152     return true;
1153 }
1154 
CheckParamsType(napi_env env,napi_value in,napi_valuetype expectedType)1155 bool SystemPasteboardNapi::CheckParamsType(napi_env env, napi_value in, napi_valuetype expectedType)
1156 {
1157     napi_valuetype type = napi_undefined;
1158     NAPI_CALL_BASE(env, napi_typeof(env, in, &type), false);
1159     if (type != expectedType) {
1160         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "invalid parametrs!");
1161         return false;
1162     }
1163     return true;
1164 }
1165 
ParseJsGetDataWithProgress(napi_env env,napi_value in,std::shared_ptr<MiscServices::GetDataParams> & getDataParam)1166 bool SystemPasteboardNapi::ParseJsGetDataWithProgress(napi_env env, napi_value in,
1167     std::shared_ptr<MiscServices::GetDataParams> &getDataParam)
1168 {
1169     #define MAX_DESTURI_LEN 250
1170     napi_value destUri = nullptr;
1171     NAPI_CALL_BASE(env, napi_get_named_property(env, in, "destUri", &destUri), false);
1172     if (CheckParamsType(env, destUri, napi_string)) {
1173         size_t destUriLen = 0;
1174         NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, destUri, nullptr, 0, &destUriLen), false);
1175         if (destUriLen <= 0 || destUriLen > MAX_DESTURI_LEN) {
1176             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "destUriLen check failed!");
1177             return false;
1178         }
1179         char *uri = (char *)malloc(destUriLen + 1);
1180         if (uri == nullptr) {
1181             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "malloc failed, uri is nullptr.");
1182             return false;
1183         }
1184         NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, destUri, uri, destUriLen + 1, &destUriLen), false);
1185         getDataParam->destUri = uri;
1186         free(uri);
1187     }
1188     napi_value fileConflictOption;
1189     NAPI_CALL_BASE(env, napi_get_named_property(env, in, "fileConflictOptions", &fileConflictOption), false);
1190     getDataParam->fileConflictOption = FILE_OVERWRITE;
1191     if (CheckParamsType(env, fileConflictOption, napi_number)) {
1192         NAPI_CALL_BASE(env, napi_get_value_int32(env, fileConflictOption,
1193             reinterpret_cast<int *>(&getDataParam->fileConflictOption)), false);
1194     }
1195     napi_value progressIndicator;
1196     NAPI_CALL_BASE(env, napi_get_named_property(env, in, "progressIndicator", &progressIndicator), false);
1197     NAPI_CALL_BASE(env, napi_get_value_int32(env, progressIndicator,
1198         reinterpret_cast<int *>(&getDataParam->progressIndicator)), false);
1199 
1200     std::shared_ptr<ProgressListenerFn> listenerFn = std::make_shared<ProgressListenerFn>();
1201     NAPI_CALL_BASE(env, napi_get_named_property(env, in, "progressListener", &listenerFn->jsCallback), false);
1202     if (CheckParamsType(env, listenerFn->jsCallback, napi_function)) {
1203         if (!AddProgressListener(env, getDataParam, listenerFn)) {
1204             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "add listener failed!");
1205             return false;
1206         }
1207     }
1208     return true;
1209 }
1210 
GetDataWithProgressParam(std::shared_ptr<GetDataParamsContextInfo> & context)1211 void SystemPasteboardNapi::GetDataWithProgressParam(std::shared_ptr<GetDataParamsContextInfo> &context)
1212 {
1213     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
1214         // 1: GetPasteData has 0 or 1 args
1215         if (argc > 0 &&
1216             !CheckArgsType(env, argv[0], napi_object, "Parameter error. The type of object must be function.")) {
1217             return napi_invalid_arg;
1218         }
1219         if (!CheckExpression(env, ParseJsGetDataWithProgress(env, argv[0], context->getDataParams),
1220             JSErrorCode::INVALID_PARAMETERS, "Parameter error. parse param failed!")) {
1221             return napi_invalid_arg;
1222         }
1223         return napi_ok;
1224     };
1225 
1226     auto output = [context](napi_env env, napi_value *result) -> napi_status {
1227         napi_value instance = nullptr;
1228         napi_status status = PasteDataNapi::NewInstance(env, instance);
1229         if (status != napi_ok) {
1230             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "NewInstance failed!");
1231             return napi_invalid_arg;
1232         }
1233         PasteDataNapi *obj = nullptr;
1234         napi_status ret = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
1235         if ((ret == napi_ok) && (obj != nullptr)) {
1236             obj->value_ = context->pasteData;
1237         } else {
1238             return napi_generic_failure;
1239         }
1240         *result = instance;
1241         return napi_ok;
1242     };
1243     context->SetAction(std::move(input), std::move(output));
1244 }
1245 
GetDataWithProgress(napi_env env,napi_callback_info info)1246 napi_value SystemPasteboardNapi::GetDataWithProgress(napi_env env, napi_callback_info info)
1247 {
1248     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetDataWithProgress is called!");
1249 
1250     auto context = std::make_shared<GetDataParamsContextInfo>();
1251     context->pasteData = std::make_shared<PasteData>();
1252     context->getDataParams = std::make_shared<GetDataParams>();
1253     GetDataWithProgressParam(context);
1254 
1255     auto exec = [context](AsyncCall::Context *ctx) {
1256         context->getDataParams->info = new (std::nothrow)ProgressInfo();
1257         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetDataWithProgress Begin");
1258         int32_t ret = PasteboardClient::GetInstance()->GetDataWithProgress(*context->pasteData,
1259             context->getDataParams);
1260         auto it = ErrorCodeMap.find(PasteboardError(ret));
1261         if (it != ErrorCodeMap.end()) {
1262             context->SetErrInfo(static_cast<int32_t>(it->second), "getDataWithProgress is failed!");
1263         } else {
1264             if (ret != static_cast<int32_t>(PasteboardError::E_OK)) {
1265                 context->SetErrInfo(static_cast<int32_t>(JSErrorCode::ERR_GET_DATA_FAILED),
1266                     "getDataWithProgress is failed!");
1267             } else {
1268                 context->status = napi_ok;
1269             }
1270         }
1271         listenerMap_.erase("progressNotify");
1272         if (context->getDataParams->info != nullptr) {
1273             delete context->getDataParams->info;
1274             context->getDataParams->info = nullptr;
1275         }
1276         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetDataWithProgress End");
1277     };
1278     // 0: the AsyncCall at the first position;
1279     AsyncCall asyncCall(env, info, context, 0);
1280     return asyncCall.Call(env, exec);
1281 }
1282 
SystemPasteboardInit(napi_env env,napi_value exports)1283 napi_value SystemPasteboardNapi::SystemPasteboardInit(napi_env env, napi_value exports)
1284 {
1285     napi_status status = napi_ok;
1286     napi_property_descriptor descriptors[] = {
1287         DECLARE_NAPI_FUNCTION("on", On),
1288         DECLARE_NAPI_FUNCTION("off", Off),
1289         DECLARE_NAPI_FUNCTION("clear", Clear),
1290         DECLARE_NAPI_FUNCTION("getPasteData", GetPasteData),
1291         DECLARE_NAPI_FUNCTION("hasPasteData", HasPasteData),
1292         DECLARE_NAPI_FUNCTION("setPasteData", SetPasteData),
1293         DECLARE_NAPI_FUNCTION("clearData", ClearData),
1294         DECLARE_NAPI_FUNCTION("getData", GetData),
1295         DECLARE_NAPI_FUNCTION("hasData", HasData),
1296         DECLARE_NAPI_FUNCTION("setData", SetData),
1297         DECLARE_NAPI_FUNCTION("isRemoteData", IsRemoteData),
1298         DECLARE_NAPI_FUNCTION("getDataSource", GetDataSource),
1299         DECLARE_NAPI_FUNCTION("getMimeTypes", GetMimeTypes),
1300         DECLARE_NAPI_FUNCTION("hasDataType", HasDataType),
1301         DECLARE_NAPI_FUNCTION("detectPatterns", DetectPatterns),
1302         DECLARE_NAPI_FUNCTION("clearDataSync", ClearDataSync),
1303         DECLARE_NAPI_FUNCTION("getDataSync", GetDataSync),
1304         DECLARE_NAPI_FUNCTION("hasDataSync", HasDataSync),
1305         DECLARE_NAPI_FUNCTION("setDataSync", SetDataSync),
1306         DECLARE_NAPI_FUNCTION("setUnifiedData", SetUnifiedData),
1307         DECLARE_NAPI_FUNCTION("getUnifiedData", GetUnifiedData),
1308         DECLARE_NAPI_FUNCTION("setUnifiedDataSync", SetUnifiedDataSync),
1309         DECLARE_NAPI_FUNCTION("getUnifiedDataSync", GetUnifiedDataSync),
1310         DECLARE_NAPI_FUNCTION("setAppShareOptions", SetAppShareOptions),
1311         DECLARE_NAPI_FUNCTION("removeAppShareOptions", RemoveAppShareOptions),
1312         DECLARE_NAPI_FUNCTION("getDataWithProgress", GetDataWithProgress),
1313         DECLARE_NAPI_FUNCTION("getChangeCount", GetChangeCount),
1314     };
1315     napi_value constructor;
1316     napi_define_class(env, "SystemPasteboard", NAPI_AUTO_LENGTH, New, nullptr,
1317         sizeof(descriptors) / sizeof(napi_property_descriptor), descriptors, &constructor);
1318     if (status != napi_ok) {
1319         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Failed to define class at SystemPasteboardInit");
1320         return nullptr;
1321     }
1322     napi_create_reference(env, constructor, 1, &g_systemPasteboard);
1323     status = napi_set_named_property(env, exports, "SystemPasteboard", constructor);
1324     if (status != napi_ok) {
1325         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Set property failed when SystemPasteboardInit");
1326         return nullptr;
1327     }
1328     return exports;
1329 }
1330 
SystemPasteboardNapi()1331 SystemPasteboardNapi::SystemPasteboardNapi() : env_(nullptr)
1332 {
1333     value_ = std::make_shared<PasteDataNapi>();
1334 }
1335 
~SystemPasteboardNapi()1336 SystemPasteboardNapi::~SystemPasteboardNapi()
1337 {
1338     value_ = nullptr;
1339 }
1340 
Destructor(napi_env env,void * nativeObject,void * finalize_hint)1341 void SystemPasteboardNapi::Destructor(napi_env env, void *nativeObject, void *finalize_hint)
1342 {
1343     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "Destructor");
1344     (void)nativeObject;
1345     SystemPasteboardNapi *obj = static_cast<SystemPasteboardNapi *>(nativeObject);
1346     delete obj;
1347 }
1348 
New(napi_env env,napi_callback_info info)1349 napi_value SystemPasteboardNapi::New(napi_env env, napi_callback_info info)
1350 {
1351     size_t argc = MAX_ARGS;
1352     napi_value argv[MAX_ARGS] = { 0 };
1353     napi_value thisVar = nullptr;
1354     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1355     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "proc.");
1356     // get native object
1357     SystemPasteboardNapi *obj = new (std::nothrow) SystemPasteboardNapi();
1358     if (!obj) {
1359         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "New obj is null");
1360         return nullptr;
1361     }
1362     obj->env_ = env;
1363     ASSERT_CALL(env, napi_wrap(env, thisVar, obj, SystemPasteboardNapi::Destructor,
1364                        nullptr, // finalize_hint
1365                        nullptr), obj);
1366     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "end.");
1367     return thisVar;
1368 }
1369 
NewInstance(napi_env env,napi_value & instance)1370 napi_status SystemPasteboardNapi::NewInstance(napi_env env, napi_value &instance)
1371 {
1372     napi_status status;
1373     if (g_systemPasteboard_instance != nullptr) {
1374         status = napi_get_reference_value(env, g_systemPasteboard_instance, &instance);
1375         if (status != napi_ok) {
1376             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "get instance failed");
1377             return status;
1378         }
1379         return napi_ok;
1380     }
1381 
1382     napi_value constructor;
1383     status = napi_get_reference_value(env, g_systemPasteboard, &constructor);
1384     if (status != napi_ok) {
1385         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "get reference failed");
1386         return status;
1387     }
1388 
1389     status = napi_new_instance(env, constructor, 0, nullptr, &instance);
1390     if (status != napi_ok) {
1391         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "new instance failed");
1392         return status;
1393     }
1394     napi_create_reference(env, instance, 1, &g_systemPasteboard_instance);
1395     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "new instance ok");
1396 
1397     return napi_ok;
1398 }
1399 
GetObserver(napi_env env,napi_value observer)1400 std::shared_ptr<PasteboardObserverInstance> SystemPasteboardNapi::GetObserver(napi_env env, napi_value observer)
1401 {
1402     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetObserver start");
1403     for (const auto &[refKey, observerValue] : observers_) {
1404         napi_value callback = nullptr;
1405         napi_get_reference_value(env, refKey, &callback);
1406         bool isEqual = false;
1407         napi_strict_equals(env, observer, callback, &isEqual);
1408         if (isEqual) {
1409             return observerValue;
1410         }
1411     }
1412     return nullptr;
1413 }
1414 
DeleteObserver(const std::shared_ptr<PasteboardObserverInstance> & observer)1415 void SystemPasteboardNapi::DeleteObserver(const std::shared_ptr<PasteboardObserverInstance> &observer)
1416 {
1417     PASTEBOARD_HILOGI(PASTEBOARD_MODULE_JS_NAPI, "observer == null: %{public}d, size: %{public}zu",
1418         observer == nullptr, observers_.size());
1419     std::vector<std::shared_ptr<PasteboardObserverInstance>> observers;
1420     {
1421         for (auto it = observers_.begin(); it != observers_.end();) {
1422             if (it->second == observer) {
1423                 observers.push_back(observer);
1424                 observers_.erase(it++);
1425                 break;
1426             }
1427             if (observer == nullptr) {
1428                 observers.push_back(it->second);
1429                 observers_.erase(it++);
1430             } else {
1431                 it++;
1432             }
1433         }
1434     }
1435     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "delete observer size: %{public}zu", observers.size());
1436     for (auto &delObserver : observers) {
1437         PasteboardClient::GetInstance()->Unsubscribe(PasteboardObserverType::OBSERVER_LOCAL,
1438             delObserver->GetStub());
1439     }
1440 }
1441 
OnPasteboardChanged()1442 void PasteboardObserverInstance::PasteboardObserverImpl::OnPasteboardChanged()
1443 {
1444     std::shared_ptr<PasteboardObserverInstance> observerInstance(wrapper_.lock());
1445     if (observerInstance == nullptr) {
1446         PASTEBOARD_HILOGW(PASTEBOARD_MODULE_JS_NAPI, "expired callback");
1447         return;
1448     }
1449     observerInstance->OnPasteboardChanged();
1450 }
1451 
SetObserverWrapper(const std::shared_ptr<PasteboardObserverInstance> & observerInstance)1452 void PasteboardObserverInstance::PasteboardObserverImpl::SetObserverWrapper(
1453     const std::shared_ptr<PasteboardObserverInstance> &observerInstance)
1454 {
1455     wrapper_ = observerInstance;
1456 }
1457 
GetUnifiedData(const std::string & type,UDMF::UnifiedData & data)1458 void PasteboardDelayGetterInstance::PasteboardDelayGetterImpl::GetUnifiedData(
1459     const std::string &type, UDMF::UnifiedData &data)
1460 {
1461     std::shared_ptr<PasteboardDelayGetterInstance> delayGetterInstance(wrapper_.lock());
1462     if (delayGetterInstance == nullptr) {
1463         PASTEBOARD_HILOGW(PASTEBOARD_MODULE_JS_NAPI, "no delay getter");
1464         return;
1465     }
1466     delayGetterInstance->GetUnifiedData(type, data);
1467 }
1468 
GetPasteData(const std::string & type,MiscServices::PasteData & data)1469 void PasteboardDelayGetterInstance::PasteboardDelayGetterImpl::GetPasteData(
1470     const std::string &type, MiscServices::PasteData &data)
1471 {
1472 }
1473 
SetDelayGetterWrapper(const std::shared_ptr<PasteboardDelayGetterInstance> delayGetterInstance)1474 void PasteboardDelayGetterInstance::PasteboardDelayGetterImpl::SetDelayGetterWrapper(
1475     const std::shared_ptr<PasteboardDelayGetterInstance> delayGetterInstance)
1476 {
1477     wrapper_ = delayGetterInstance;
1478 }
1479 } // namespace MiscServicesNapi
1480 } // namespace OHOS