1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "cloud_sync_napi.h"
17
18 #include <sys/types.h>
19
20 #include "cloud_sync_manager.h"
21 #include "dfs_error.h"
22 #include "utils_log.h"
23 #include "async_work.h"
24 #include "uv.h"
25
26 namespace OHOS::FileManagement::CloudSync {
27 using namespace FileManagement::LibN;
28 using namespace std;
29
CloudSyncCallbackImpl(napi_env env,napi_value fun)30 CloudSyncCallbackImpl::CloudSyncCallbackImpl(napi_env env, napi_value fun) : env_(env)
31 {
32 if (fun != nullptr) {
33 napi_create_reference(env_, fun, 1, &cbOnRef_);
34 }
35 }
36
OnComplete(UvChangeMsg * msg)37 void CloudSyncCallbackImpl::OnComplete(UvChangeMsg *msg)
38 {
39 auto cloudSyncCallback = msg->cloudSyncCallback_.lock();
40 if (cloudSyncCallback == nullptr || cloudSyncCallback->cbOnRef_ == nullptr) {
41 LOGE("cloudSyncCallback->cbOnRef_ is nullptr");
42 return;
43 }
44 auto env = cloudSyncCallback->env_;
45 auto ref = cloudSyncCallback->cbOnRef_;
46 napi_handle_scope scope = nullptr;
47 napi_open_handle_scope(env, &scope);
48 napi_value jsCallback = nullptr;
49 napi_status status = napi_get_reference_value(env, ref, &jsCallback);
50 if (status != napi_ok) {
51 LOGE("Create reference failed, status: %{public}d", status);
52 napi_close_handle_scope(env, scope);
53 return;
54 }
55 NVal obj = NVal::CreateObject(env);
56 obj.AddProp("state", NVal::CreateInt32(env, (int32_t)msg->state_).val_);
57 obj.AddProp("error", NVal::CreateInt32(env, (int32_t)msg->error_).val_);
58 napi_value retVal = nullptr;
59 napi_value global = nullptr;
60 napi_get_global(env, &global);
61 status = napi_call_function(env, global, jsCallback, ARGS_ONE, &(obj.val_), &retVal);
62 if (status != napi_ok) {
63 LOGE("napi call function failed, status: %{public}d", status);
64 }
65 napi_close_handle_scope(env, scope);
66 }
67
OnSyncStateChanged(CloudSyncState state,ErrorType error)68 void CloudSyncCallbackImpl::OnSyncStateChanged(CloudSyncState state, ErrorType error)
69 {
70 uv_loop_s *loop = nullptr;
71 napi_get_uv_event_loop(env_, &loop);
72 if (loop == nullptr) {
73 return;
74 }
75
76 uv_work_t *work = new (nothrow) uv_work_t;
77 if (work == nullptr) {
78 LOGE("Failed to create uv work");
79 return;
80 }
81
82 UvChangeMsg *msg = new (std::nothrow) UvChangeMsg(shared_from_this(), state, error);
83 if (msg == nullptr) {
84 delete work;
85 return;
86 }
87
88 work->data = reinterpret_cast<void *>(msg);
89 int ret = uv_queue_work(
90 loop, work, [](uv_work_t *work) {},
91 [](uv_work_t *work, int status) {
92 auto msg = reinterpret_cast<UvChangeMsg *>(work->data);
93 OnComplete(msg);
94 delete msg;
95 delete work;
96 });
97 if (ret != 0) {
98 LOGE("Failed to execute libuv work queue, ret: %{public}d", ret);
99 delete msg;
100 delete work;
101 }
102 }
103
DeleteReference()104 void CloudSyncCallbackImpl::DeleteReference()
105 {
106 if (cbOnRef_ != nullptr) {
107 napi_delete_reference(env_, cbOnRef_);
108 cbOnRef_ = nullptr;
109 }
110 }
111
OnSyncStateChanged(SyncType type,SyncPromptState state)112 void CloudSyncCallbackImpl::OnSyncStateChanged(SyncType type, SyncPromptState state)
113 {
114 return;
115 }
116
Constructor(napi_env env,napi_callback_info info)117 napi_value CloudSyncNapi::Constructor(napi_env env, napi_callback_info info)
118 {
119 NFuncArg funcArg(env, info);
120 if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
121 NError(E_PARAMS).ThrowErr(env, "Number of arguments unmatched");
122 return nullptr;
123 }
124
125 return funcArg.GetThisVar();
126 }
127
OnCallback(napi_env env,napi_callback_info info)128 napi_value CloudSyncNapi::OnCallback(napi_env env, napi_callback_info info)
129 {
130 NFuncArg funcArg(env, info);
131 if (!funcArg.InitArgs(NARG_CNT::TWO)) {
132 NError(E_PARAMS).ThrowErr(env, "Number of arguments unmatched");
133 LOGE("OnCallback Number of arguments unmatched");
134 return nullptr;
135 }
136
137 auto [succ, type, ignore] = NVal(env, funcArg[(int)NARG_POS::FIRST]).ToUTF8String();
138 if (!(succ && (type.get() == std::string("progress")))) {
139 NError(E_PARAMS).ThrowErr(env);
140 return nullptr;
141 }
142
143 if (!NVal(env, funcArg[(int)NARG_POS::SECOND]).TypeIs(napi_function)) {
144 LOGE("Argument type mismatch");
145 NError(E_PARAMS).ThrowErr(env);
146 return nullptr;
147 }
148
149 if (callback_ != nullptr) {
150 LOGI("callback already exist");
151 return NVal::CreateUndefined(env).val_;
152 }
153
154 callback_ = make_shared<CloudSyncCallbackImpl>(env, NVal(env, funcArg[(int)NARG_POS::SECOND]).val_);
155 int32_t ret = CloudSyncManager::GetInstance().RegisterCallback(callback_);
156 if (ret != E_OK) {
157 LOGE("OnCallback Register error, result: %{public}d", ret);
158 NError(Convert2JsErrNum(ret)).ThrowErr(env);
159 return nullptr;
160 }
161
162 return NVal::CreateUndefined(env).val_;
163 }
164
OffCallback(napi_env env,napi_callback_info info)165 napi_value CloudSyncNapi::OffCallback(napi_env env, napi_callback_info info)
166 {
167 NFuncArg funcArg(env, info);
168 if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
169 NError(E_PARAMS).ThrowErr(env, "Number of arguments unmatched");
170 LOGE("OffCallback Number of arguments unmatched");
171 return nullptr;
172 }
173
174 auto [succ, type, ignore] = NVal(env, funcArg[(int)NARG_POS::FIRST]).ToUTF8String();
175 if (!(succ && (type.get() == std::string("progress")))) {
176 NError(E_PARAMS).ThrowErr(env);
177 return nullptr;
178 }
179
180 if (funcArg.GetArgc() == (uint)NARG_CNT::TWO && !NVal(env, funcArg[(int)NARG_POS::SECOND]).TypeIs(napi_function)) {
181 LOGE("Argument type mismatch");
182 NError(E_PARAMS).ThrowErr(env);
183 return nullptr;
184 }
185
186 int32_t ret = CloudSyncManager::GetInstance().UnRegisterCallback();
187 if (ret != E_OK) {
188 LOGE("OffCallback UnRegister error, result: %{public}d", ret);
189 NError(Convert2JsErrNum(ret)).ThrowErr(env);
190 return nullptr;
191 }
192 if (callback_ != nullptr) {
193 /* napi delete reference */
194 callback_->DeleteReference();
195 callback_ = nullptr;
196 }
197 return NVal::CreateUndefined(env).val_;
198 }
199
Start(napi_env env,napi_callback_info info)200 napi_value CloudSyncNapi::Start(napi_env env, napi_callback_info info)
201 {
202 NFuncArg funcArg(env, info);
203 if (!funcArg.InitArgs(NARG_CNT::ZERO, NARG_CNT::ONE)) {
204 NError(E_PARAMS).ThrowErr(env);
205 }
206
207 auto cbExec = []() -> NError {
208 int32_t ret = CloudSyncManager::GetInstance().StartSync();
209 if (ret != E_OK) {
210 LOGE("Start Sync error, result: %{public}d", ret);
211 return NError(Convert2JsErrNum(ret));
212 }
213 return NError(ERRNO_NOERR);
214 };
215
216 auto cbComplete = [](napi_env env, NError err) -> NVal {
217 if (err) {
218 return {env, err.GetNapiErr(env)};
219 }
220 return NVal::CreateUndefined(env);
221 };
222
223 std::string procedureName = "Start";
224 auto asyncWork = GetPromiseOrCallBackWork(env, funcArg, static_cast<size_t>(NARG_CNT::TWO));
225 return asyncWork == nullptr ? nullptr : asyncWork->Schedule(procedureName, cbExec, cbComplete).val_;
226 }
227
Stop(napi_env env,napi_callback_info info)228 napi_value CloudSyncNapi::Stop(napi_env env, napi_callback_info info)
229 {
230 NFuncArg funcArg(env, info);
231 if (!funcArg.InitArgs(NARG_CNT::ZERO, NARG_CNT::ONE)) {
232 NError(E_PARAMS).ThrowErr(env);
233 return nullptr;
234 }
235
236 auto cbExec = []() -> NError {
237 int32_t ret = CloudSyncManager::GetInstance().StopSync();
238 if (ret != E_OK) {
239 LOGE("Stop Sync error, result: %{public}d", ret);
240 return NError(Convert2JsErrNum(ret));
241 }
242 return NError(ERRNO_NOERR);
243 };
244
245 auto cbComplete = [](napi_env env, NError err) -> NVal {
246 if (err) {
247 return {env, err.GetNapiErr(env)};
248 }
249 return NVal::CreateUndefined(env);
250 };
251
252 std::string procedureName = "Stop";
253 auto asyncWork = GetPromiseOrCallBackWork(env, funcArg, static_cast<size_t>(NARG_CNT::TWO));
254 return asyncWork == nullptr ? nullptr : asyncWork->Schedule(procedureName, cbExec, cbComplete).val_;
255 }
256
SetClassName(const std::string classname)257 void CloudSyncNapi::SetClassName(const std::string classname)
258 {
259 className_ = classname;
260 }
261
GetClassName()262 std::string CloudSyncNapi::GetClassName()
263 {
264 return className_;
265 }
266
ToExport(std::vector<napi_property_descriptor> props)267 bool CloudSyncNapi::ToExport(std::vector<napi_property_descriptor> props)
268 {
269 std::string className = GetClassName();
270 auto [succ, classValue] =
271 NClass::DefineClass(exports_.env_, className, Constructor, std::move(props));
272 if (!succ) {
273 NError(E_GETRESULT).ThrowErr(exports_.env_);
274 LOGE("Failed to define CloudSyncNapi class");
275 return false;
276 }
277
278 succ = NClass::SaveClass(exports_.env_, className, classValue);
279 if (!succ) {
280 NError(E_GETRESULT).ThrowErr(exports_.env_);
281 LOGE("Failed to save CloudSyncNapi class");
282 return false;
283 }
284
285 return exports_.AddProp(className, classValue);
286 }
287
Export()288 bool CloudSyncNapi::Export()
289 {
290 std::vector<napi_property_descriptor> props = {
291 NVal::DeclareNapiFunction("on", OnCallback),
292 NVal::DeclareNapiFunction("off", OffCallback),
293 NVal::DeclareNapiFunction("start", Start),
294 NVal::DeclareNapiFunction("stop", Stop),
295 };
296 std::string className = GetClassName();
297 auto [succ, classValue] =
298 NClass::DefineClass(exports_.env_, className, CloudSyncNapi::Constructor, std::move(props));
299 if (!succ) {
300 NError(E_GETRESULT).ThrowErr(exports_.env_);
301 LOGE("Failed to define GallerySync class");
302 return false;
303 }
304
305 succ = NClass::SaveClass(exports_.env_, className, classValue);
306 if (!succ) {
307 NError(E_GETRESULT).ThrowErr(exports_.env_);
308 LOGE("Failed to save GallerySync class");
309 return false;
310 }
311
312 return exports_.AddProp(className, classValue);
313 }
314
315 } // namespace OHOS::FileManagement::CloudSync
316