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 "gallery_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 "uv.h"
24
25 namespace OHOS::FileManagement::CloudSync {
26 using namespace FileManagement::LibN;
27 using namespace std;
28
CloudSyncCallbackImpl(napi_env env,napi_value fun)29 CloudSyncCallbackImpl::CloudSyncCallbackImpl(napi_env env, napi_value fun) : env_(env)
30 {
31 if (fun != nullptr) {
32 napi_create_reference(env_, fun, 1, &cbOnRef_);
33 }
34 }
35
OnComplete(UvChangeMsg * msg)36 void CloudSyncCallbackImpl::OnComplete(UvChangeMsg *msg)
37 {
38 auto cloudSyncCallback = msg->cloudSyncCallback_.lock();
39 if (cloudSyncCallback == nullptr || cloudSyncCallback->cbOnRef_ == nullptr) {
40 LOGE("cloudSyncCallback->cbOnRef_ is nullptr");
41 return;
42 }
43 auto env = cloudSyncCallback->env_;
44 auto ref = cloudSyncCallback->cbOnRef_;
45 napi_handle_scope scope = nullptr;
46 napi_open_handle_scope(env, &scope);
47 napi_value jsCallback = nullptr;
48 napi_status status = napi_get_reference_value(env, ref, &jsCallback);
49 if (status != napi_ok) {
50 LOGE("Create reference failed, status: %{public}d", status);
51 return;
52 }
53 NVal obj = NVal::CreateObject(env);
54 obj.AddProp("state", NVal::CreateInt32(env, (int32_t)msg->state_).val_);
55 obj.AddProp("error", NVal::CreateInt32(env, (int32_t)msg->error_).val_);
56 napi_value retVal = nullptr;
57 napi_value global = nullptr;
58 napi_get_global(env, &global);
59 status = napi_call_function(env, global, jsCallback, ARGS_ONE, &(obj.val_), &retVal);
60 if (status != napi_ok) {
61 LOGE("napi call function failed, status: %{public}d", status);
62 }
63 }
64
OnSyncStateChanged(CloudSyncState state,ErrorType error)65 void CloudSyncCallbackImpl::OnSyncStateChanged(CloudSyncState state, ErrorType error)
66 {
67 uv_loop_s *loop = nullptr;
68 napi_get_uv_event_loop(env_, &loop);
69 if (loop == nullptr) {
70 return;
71 }
72
73 uv_work_t *work = new (nothrow) uv_work_t;
74 if (work == nullptr) {
75 LOGE("Failed to create uv work");
76 return;
77 }
78
79 UvChangeMsg *msg = new (std::nothrow) UvChangeMsg(shared_from_this(), state, error);
80 if (msg == nullptr) {
81 delete work;
82 return;
83 }
84
85 work->data = reinterpret_cast<void *>(msg);
86 int ret = uv_queue_work(
87 loop, work, [](uv_work_t *work) {},
88 [](uv_work_t *work, int status) {
89 auto msg = reinterpret_cast<UvChangeMsg *>(work->data);
90 OnComplete(msg);
91 delete msg;
92 delete work;
93 });
94 if (ret != 0) {
95 LOGE("Failed to execute libuv work queue, ret: %{public}d", ret);
96 delete msg;
97 delete work;
98 }
99 }
100
DeleteReference()101 void CloudSyncCallbackImpl::DeleteReference()
102 {
103 if (cbOnRef_ != nullptr) {
104 napi_delete_reference(env_, cbOnRef_);
105 cbOnRef_ = nullptr;
106 }
107 }
108
OnSyncStateChanged(SyncType type,SyncPromptState state)109 void CloudSyncCallbackImpl::OnSyncStateChanged(SyncType type, SyncPromptState state)
110 {
111 return;
112 }
113
Constructor(napi_env env,napi_callback_info info)114 napi_value GallerySyncNapi::Constructor(napi_env env, napi_callback_info info)
115 {
116 NFuncArg funcArg(env, info);
117 if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
118 NError(E_PARAMS).ThrowErr(env, "Number of arguments unmatched");
119 return nullptr;
120 }
121
122 return funcArg.GetThisVar();
123 }
124
OnCallback(napi_env env,napi_callback_info info)125 napi_value GallerySyncNapi::OnCallback(napi_env env, napi_callback_info info)
126 {
127 NFuncArg funcArg(env, info);
128 if (!funcArg.InitArgs(NARG_CNT::TWO)) {
129 NError(E_PARAMS).ThrowErr(env, "Number of arguments unmatched");
130 LOGE("OnCallback Number of arguments unmatched");
131 return nullptr;
132 }
133
134 auto [succ, type, ignore] = NVal(env, funcArg[(int)NARG_POS::FIRST]).ToUTF8String();
135 if (!(succ && (type.get() == std::string("progress")))) {
136 NError(E_PARAMS).ThrowErr(env);
137 return nullptr;
138 }
139
140 if (callback_ != nullptr) {
141 LOGI("callback already exist");
142 return NVal::CreateUndefined(env).val_;
143 }
144
145 callback_ = make_shared<CloudSyncCallbackImpl>(env, NVal(env, funcArg[(int)NARG_POS::SECOND]).val_);
146 int32_t ret = CloudSyncManager::GetInstance().RegisterCallback(callback_);
147 if (ret != E_OK) {
148 LOGE("OnCallback Register error, result: %{public}d", ret);
149 NError(Convert2JsErrNum(ret)).ThrowErr(env);
150 return nullptr;
151 }
152
153 return NVal::CreateUndefined(env).val_;
154 }
155
OffCallback(napi_env env,napi_callback_info info)156 napi_value GallerySyncNapi::OffCallback(napi_env env, napi_callback_info info)
157 {
158 NFuncArg funcArg(env, info);
159 if (!funcArg.InitArgs(NARG_CNT::ONE)) {
160 NError(E_PARAMS).ThrowErr(env, "Number of arguments unmatched");
161 LOGE("OffCallback Number of arguments unmatched");
162 return nullptr;
163 }
164
165 auto [succ, type, ignore] = NVal(env, funcArg[(int)NARG_POS::FIRST]).ToUTF8String();
166 if (!(succ && (type.get() == std::string("progress")))) {
167 NError(E_PARAMS).ThrowErr(env);
168 return nullptr;
169 }
170
171 int32_t ret = CloudSyncManager::GetInstance().UnRegisterCallback();
172 if (ret != E_OK) {
173 LOGE("OffCallback UnRegister error, result: %{public}d", ret);
174 NError(Convert2JsErrNum(ret)).ThrowErr(env);
175 return nullptr;
176 }
177 if (callback_ != nullptr) {
178 /* napi delete reference */
179 callback_->DeleteReference();
180 callback_ = nullptr;
181 }
182 return NVal::CreateUndefined(env).val_;
183 }
184
Start(napi_env env,napi_callback_info info)185 napi_value GallerySyncNapi::Start(napi_env env, napi_callback_info info)
186 {
187 NFuncArg funcArg(env, info);
188 if (!funcArg.InitArgs(NARG_CNT::ZERO, NARG_CNT::ONE)) {
189 NError(E_PARAMS).ThrowErr(env);
190 }
191
192 auto cbExec = []() -> NError {
193 int32_t ret = CloudSyncManager::GetInstance().StartSync();
194 if (ret != E_OK) {
195 LOGE("Start Sync error, result: %{public}d", ret);
196 return NError(Convert2JsErrNum(ret));
197 }
198 return NError(ERRNO_NOERR);
199 };
200
201 auto cbComplete = [](napi_env env, NError err) -> NVal {
202 if (err) {
203 return {env, err.GetNapiErr(env)};
204 }
205 return NVal::CreateUndefined(env);
206 };
207
208 std::string PROCEDURE_NAME = "Start";
209 NVal thisVar(env, funcArg.GetThisVar());
210 if (funcArg.GetArgc() == NARG_CNT::ZERO) {
211 return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_NAME, cbExec, cbComplete).val_;
212 } else {
213 NVal cb(env, funcArg[NARG_POS::FIRST]);
214 return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_NAME, cbExec, cbComplete).val_;
215 }
216 }
217
Stop(napi_env env,napi_callback_info info)218 napi_value GallerySyncNapi::Stop(napi_env env, napi_callback_info info)
219 {
220 NFuncArg funcArg(env, info);
221 if (!funcArg.InitArgs(NARG_CNT::ZERO, NARG_CNT::ONE)) {
222 NError(E_PARAMS).ThrowErr(env);
223 return nullptr;
224 }
225
226 auto cbExec = []() -> NError {
227 int32_t ret = CloudSyncManager::GetInstance().StopSync();
228 if (ret != E_OK) {
229 LOGE("Stop Sync error, result: %{public}d", ret);
230 return NError(Convert2JsErrNum(ret));
231 }
232 return NError(ERRNO_NOERR);
233 };
234
235 auto cbComplete = [](napi_env env, NError err) -> NVal {
236 if (err) {
237 return {env, err.GetNapiErr(env)};
238 }
239 return NVal::CreateUndefined(env);
240 };
241
242 std::string PROCEDURE_NAME = "Stop";
243 NVal thisVar(env, funcArg.GetThisVar());
244 if (funcArg.GetArgc() == NARG_CNT::ZERO) {
245 return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_NAME, cbExec, cbComplete).val_;
246 } else {
247 NVal cb(env, funcArg[NARG_POS::FIRST]);
248 return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_NAME, cbExec, cbComplete).val_;
249 }
250 }
251
GetClassName()252 std::string GallerySyncNapi::GetClassName()
253 {
254 return GallerySyncNapi::className_;
255 }
256
Export()257 bool GallerySyncNapi::Export()
258 {
259 std::vector<napi_property_descriptor> props = {
260 NVal::DeclareNapiFunction("on", OnCallback),
261 NVal::DeclareNapiFunction("off", OffCallback),
262 NVal::DeclareNapiFunction("start", Start),
263 NVal::DeclareNapiFunction("stop", Stop),
264 };
265
266 std::string className = GetClassName();
267 auto [succ, classValue] =
268 NClass::DefineClass(exports_.env_, className, GallerySyncNapi::Constructor, std::move(props));
269 if (!succ) {
270 NError(E_GETRESULT).ThrowErr(exports_.env_);
271 LOGE("Failed to define GallerySync class");
272 return false;
273 }
274
275 succ = NClass::SaveClass(exports_.env_, className, classValue);
276 if (!succ) {
277 NError(E_GETRESULT).ThrowErr(exports_.env_);
278 LOGE("Failed to save GallerySync class");
279 return false;
280 }
281
282 return exports_.AddProp(className, classValue);
283 }
284 } // namespace OHOS::FileManagement::CloudSync
285