1 /*
2  * Copyright (c) 2024-2024 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 
16 #include "uv.h"
17 #include "native_reference.h"
18 #include "native_value.h"
19 #include "b_error/b_error.h"
20 #include "general_callbacks.h"
21 
22 namespace OHOS::FileManagement::Backup {
23 using namespace std;
24 
BackupRestoreCallback(napi_env env,LibN::NVal thisPtr,LibN::NVal cb)25 BackupRestoreCallback::BackupRestoreCallback(napi_env env, LibN::NVal thisPtr, LibN::NVal cb) : env_(env)
26 {
27     ctx_ = new LibN::NAsyncContextCallback(thisPtr, cb);
28 }
29 
~BackupRestoreCallback()30 BackupRestoreCallback::~BackupRestoreCallback()
31 {
32     if (!ctx_) {
33         return;
34     }
35 
36     unique_ptr<LibN::NAsyncContextCallback> ptr(ctx_);
37     uv_loop_s *loop = nullptr;
38     napi_status status = napi_get_uv_event_loop(env_, &loop);
39     if (status != napi_ok) {
40         HILOGE("Failed to get uv event loop");
41         ptr->cb_.CleanJsEnv();
42         return;
43     }
44 
45     auto work = make_unique<uv_work_t>();
46     if (work == nullptr) {
47         HILOGE("Failed to new uv_work_t");
48         return;
49     }
50     work->data = static_cast<void *>(ctx_);
51 
52     int ret = uv_queue_work(
53         loop, work.get(), [](uv_work_t *work) {},
54         [](uv_work_t *work, int status) {
55             LibN::NAsyncContextCallback *ctx = static_cast<LibN::NAsyncContextCallback *>(work->data);
56             delete ctx;
57             delete work;
58         });
59     if (ret) {
60         HILOGE("Failed to call uv_queue_work %{public}d", status);
61         return;
62     }
63     ptr.release();
64     work.release();
65     ctx_ = nullptr;
66 }
67 
68 BackupRestoreCallback::operator bool() const
69 {
70     return bool(ctx_->cb_);
71 }
72 
DoCallJsMethod(napi_env env,void * data,InputArgsParser argParser)73 static void DoCallJsMethod(napi_env env, void *data, InputArgsParser argParser)
74 {
75     HILOGI("Start execute DoCallJsMethod");
76     napi_handle_scope scope = nullptr;
77     napi_open_handle_scope(env, &scope);
78     if (scope == nullptr) {
79         HILOGE("scope is nullptr");
80         return;
81     }
82     auto ctx = static_cast<LibN::NAsyncContextCallback *>(data);
83     if (ctx == nullptr) {
84         HILOGE("This pointer address is empty");
85         napi_close_handle_scope(env, scope);
86         return;
87     }
88     vector<napi_value> argv = {};
89     if (argParser != nullptr) {
90         if (!argParser(env, argv)) {
91             HILOGE("failed to get params.");
92             napi_close_handle_scope(env, scope);
93             return;
94         }
95     }
96     napi_value global = nullptr;
97     napi_get_global(env, &global);
98     napi_value callback = ctx->cb_.Deref(env).val_;
99     napi_value result = nullptr;
100     napi_status status = napi_call_function(env, global, callback, argv.size(), argv.data(), &result);
101     if (status != napi_ok) {
102         HILOGE("Failed to call function for %{public}d.", status);
103     }
104     napi_close_handle_scope(env, scope);
105     HILOGI("End execute DoCallJsMethod");
106 }
107 
CallJsMethod(InputArgsParser argParser)108 void BackupRestoreCallback::CallJsMethod(InputArgsParser argParser)
109 {
110     HILOGI("call BackupRestoreCallback CallJsMethod begin.");
111     uv_loop_s *loop = nullptr;
112     napi_status status = napi_get_uv_event_loop(env_, &loop);
113     if (status != napi_ok) {
114         HILOGE("failed to get uv event loop.");
115         return;
116     }
117     auto workArgs = make_shared<WorkArgs>();
118     auto work = make_unique<uv_work_t>();
119     if (workArgs == nullptr || work == nullptr) {
120         HILOGE("failed to new workArgs or uv_work_t.");
121         return;
122     }
123     workArgs->ptr = this;
124     workArgs->argParser = argParser;
125     work->data = reinterpret_cast<void *>(workArgs.get());
126     HILOGI("Will execute current js method");
127     int ret = uv_queue_work(
128         loop, work.get(), [](uv_work_t *work) {},
129         [](uv_work_t *work, int status) {
130             auto workArgs = reinterpret_cast<WorkArgs *>(work->data);
131             do {
132                 if (workArgs == nullptr) {
133                     HILOGE("failed to get workArgs.");
134                     break;
135                 }
136                 DoCallJsMethod(workArgs->ptr->env_, workArgs->ptr->ctx_, workArgs->argParser);
137             } while (false);
138             HILOGI("will notify current thread info");
139             std::unique_lock<std::mutex> lock(workArgs->callbackMutex);
140             workArgs->isReady.store(true);
141             workArgs->callbackCondition.notify_all();
142             delete work;
143         });
144     if (ret != 0) {
145         HILOGE("failed to exec uv_queue_work.");
146         work.reset();
147         return;
148     }
149     std::unique_lock<std::mutex> lock(workArgs->callbackMutex);
150     HILOGI("Wait execute callback method end");
151     workArgs->callbackCondition.wait(lock, [workArgs]() { return workArgs->isReady.load(); });
152     work.release();
153     HILOGI("call BackupRestoreCallback CallJsMethod end.");
154 }
155 } // namespace OHOS::FileManagement::Backup