1 /*
2 * Copyright (c) 2025 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 "multi_download_progress_ani.h"
17
18 #include "ani_utils.h"
19 #include "dfs_error.h"
20 #include "error_handler.h"
21 #include "multi_download_progress_core.h"
22 #include "utils_log.h"
23
24 namespace OHOS::FileManagement::CloudSync {
25 using namespace arkts::ani_signature;
26 using namespace std;
27 const static string STATE_SETTER = Builder::BuildSetterName("state");
28 const static string TAKSKID_SETTER = Builder::BuildSetterName("taskId");
29 const static string SUCC_COUNT_SETTER = Builder::BuildSetterName("successfulCount");
30 const static string FAILED_COUNT_SETTER = Builder::BuildSetterName("failedCount");
31 const static string TOTAL_COUNT_SETTER = Builder::BuildSetterName("totalCount");
32 const static string DOWNLOAD_SIZE_SETTER = Builder::BuildSetterName("downloadedSize");
33 const static string TOTAL_SIZE_SETTER = Builder::BuildSetterName("totalSize");
34 const static string ERROR_SETTER = Builder::BuildSetterName("errType");
35
SetEnumState(ani_env * env,const ani_class & cls,ani_object & object,const char * name,int32_t value)36 static ani_status SetEnumState(ani_env *env, const ani_class &cls, ani_object &object, const char *name, int32_t value)
37 {
38 ani_method setter;
39 ani_status ret;
40 if ((ret = env->Class_FindMethod(cls, name, nullptr, &setter)) != ANI_OK) {
41 LOGE("Class_FindMethod Fail %{public}s, err: %{public}d", name, ret);
42 return ret;
43 }
44 ani_enum stateEnum;
45 std::string classDesc = Builder::BuildClass("@ohos.file.cloudSync.cloudSync.State").Descriptor();
46 ret = env->FindEnum(classDesc.c_str(), &stateEnum);
47 if (ret != ANI_OK) {
48 LOGE("FindEnum %{public}s failed, err: %{public}d", classDesc.c_str(), ret);
49 return ret;
50 }
51
52 ani_enum_item enumItem;
53 ret = env->Enum_GetEnumItemByIndex(stateEnum, value, &enumItem);
54 if (ret != ANI_OK) {
55 LOGE("Enum_GetEnumItemByIndex failed, err: %{public}d", ret);
56 return ret;
57 }
58
59 return env->Object_CallMethod_Void(object, setter, enumItem);
60 }
61
SetEnumErrType(ani_env * env,const ani_class & cls,ani_object & object,const char * name,int32_t value)62 static ani_status SetEnumErrType(ani_env *env, const ani_class &cls, ani_object &object, const char *name,
63 int32_t value)
64 {
65 ani_method setter;
66 ani_status ret;
67 if ((ret = env->Class_FindMethod(cls, name, nullptr, &setter)) != ANI_OK) {
68 LOGE("Class_FindMethod Fail %{public}s, err: %{public}d", name, ret);
69 return ret;
70 }
71 ani_enum stateEnum;
72 std::string classDesc = Builder::BuildClass("@ohos.file.cloudSync.cloudSync.DownloadErrorType").Descriptor();
73 ret = env->FindEnum(classDesc.c_str(), &stateEnum);
74 if (ret != ANI_OK) {
75 LOGE("FindEnum %{public}s failed, err: %{public}d", classDesc.c_str(), ret);
76 return ret;
77 }
78
79 ani_enum_item enumItem;
80 ret = env->Enum_GetEnumItemByIndex(stateEnum, value, &enumItem);
81 if (ret != ANI_OK) {
82 LOGE("Enum_GetEnumItemByIndex failed, err: %{public}d", ret);
83 return ret;
84 }
85
86 return env->Object_CallMethod_Void(object, setter, enumItem);
87 }
88
SetProperties(ani_env * env,const ani_class & cls,ani_object & pg,MultiDlProgressCore * progressCore)89 static ani_status SetProperties(ani_env *env, const ani_class &cls, ani_object &pg, MultiDlProgressCore *progressCore)
90 {
91 vector<pair<string_view, ani_double>> numProperties = {
92 {TAKSKID_SETTER, ani_double(static_cast<double>(progressCore->GetTaskId()))},
93 {SUCC_COUNT_SETTER, ani_double(static_cast<double>(progressCore->GetDownloadedNum()))},
94 {FAILED_COUNT_SETTER, ani_double(static_cast<double>(progressCore->GetFailedNum()))},
95 {TOTAL_COUNT_SETTER, ani_double(static_cast<double>(progressCore->GetTotalNum()))},
96 {DOWNLOAD_SIZE_SETTER, ani_double(static_cast<double>(progressCore->GetDownloadedSize()))},
97 {TOTAL_SIZE_SETTER, ani_double(static_cast<double>(progressCore->GetTotalSize()))},
98 };
99 ani_status ret;
100 for (auto iter : numProperties) {
101 auto key = iter.first.data();
102 ani_method setter;
103 if ((ret = env->Class_FindMethod(cls, key, nullptr, &setter)) != ANI_OK) {
104 LOGE("Class_FindMethod Fail %{public}s, err: %{public}d", key, ret);
105 return ret;
106 }
107 if ((ret = env->Object_CallMethod_Void(pg, setter, iter.second)) != ANI_OK) {
108 LOGE("Object_CallMethod_Void Fail %{public}s, err: %{public}d", key, ret);
109 return ret;
110 }
111 }
112
113 if ((ret = SetEnumState(env, cls, pg, STATE_SETTER.data(), progressCore->GetStatus())) != ANI_OK) {
114 LOGE("Failed to get state enum, err: %{public}d", ret);
115 return ret;
116 }
117 if ((ret = SetEnumErrType(env, cls, pg, ERROR_SETTER.data(), progressCore->GetErrorType())) != ANI_OK) {
118 LOGE("Failed to get errType enum, err: %{public}d", ret);
119 return ret;
120 }
121 return ANI_OK;
122 }
123
Unwrap(ani_env * env,ani_object object)124 MultiDlProgressCore *MultiDlProgressWrapper::Unwrap(ani_env *env, ani_object object)
125 {
126 ani_long nativePtr;
127 auto ret = env->Object_GetFieldByName_Long(object, "nativePtr", &nativePtr);
128 if (ret != ANI_OK) {
129 LOGE("Unwrap MultiDlProgressCore err: %{public}d", static_cast<int32_t>(ret));
130 return nullptr;
131 }
132 std::uintptr_t ptrValue = static_cast<std::uintptr_t>(nativePtr);
133 MultiDlProgressCore *multiDlProgress = reinterpret_cast<MultiDlProgressCore *>(ptrValue);
134 return multiDlProgress;
135 }
136
Wrap(ani_env * env,MultiDlProgressCore * multiDlProgress)137 ani_object MultiDlProgressWrapper::Wrap(ani_env *env, MultiDlProgressCore *multiDlProgress)
138 {
139 if (multiDlProgress == nullptr) {
140 LOGE("MultiDlProgressCore pointer is null!");
141 return nullptr;
142 }
143
144 ani_status ret;
145 ani_class cls;
146 std::string classDesc = Builder::BuildClass("@ohos.file.cloudSync.cloudSync.MultiDownloadProgress").Descriptor();
147 if ((ret = env->FindClass(classDesc.c_str(), &cls)) != ANI_OK) {
148 LOGE("Cannot find class %{public}s, err: %{public}d", classDesc.c_str(), ret);
149 return nullptr;
150 }
151
152 ani_method ctor;
153 auto ctorDesc = Builder::BuildConstructorName();
154 auto ctorSig = Builder::BuildSignatureDescriptor({Builder::BuildLong()});
155 if ((ret = env->Class_FindMethod(cls, ctorDesc.c_str(), ctorSig.c_str(), &ctor)) != ANI_OK) {
156 LOGE("Cannot find class %{public}s constructor method, err: %{public}d", classDesc.c_str(), ret);
157 return nullptr;
158 }
159
160 ani_object progressObject;
161 if ((ret = env->Object_New(cls, ctor, &progressObject, reinterpret_cast<ani_long>(multiDlProgress))) != ANI_OK) {
162 LOGE("New StatInner Fail, err: %{public}d", ret);
163 return nullptr;
164 }
165
166 if ((ret = SetProperties(env, cls, progressObject, multiDlProgress)) != ANI_OK) {
167 LOGE("SetProperties Fail, err: %{public}d", ret);
168 return nullptr;
169 }
170
171 return progressObject;
172 }
173
Constructor(ani_env * env,ani_object object)174 void MultiDlProgressAni::Constructor(ani_env *env, ani_object object)
175 {
176 ani_status ret;
177 ani_class cls;
178 std::string classDesc = Builder::BuildClass("@ohos.file.cloudSync.cloudSync.MultiDownloadProgress").Descriptor();
179 if ((ret = env->FindClass(classDesc.c_str(), &cls)) != ANI_OK) {
180 LOGE("Cannot find class %{public}s, err: %{public}d", classDesc.c_str(), ret);
181 ErrorHandler::Throw(env, JsErrCode::E_INNER_FAILED);
182 return;
183 }
184
185 ani_method ctor;
186 auto ctorDesc = Builder::BuildConstructorName();
187 std::string bindSign = Builder::BuildSignatureDescriptor({Builder::BuildLong()});
188 ret = env->Class_FindMethod(cls, ctorDesc.c_str(), bindSign.c_str(), &ctor);
189 if (ret != ANI_OK) {
190 LOGE("find class ctor. ret = %{public}d", static_cast<int32_t>(ret));
191 ErrorHandler::Throw(env, JsErrCode::E_INNER_FAILED);
192 return;
193 }
194
195 FsResult<MultiDlProgressCore *> data = MultiDlProgressCore::Constructor();
196 if (!data.IsSuccess()) {
197 LOGE("MultiDlProgress constructor failed.");
198 const auto &err = data.GetError();
199 ErrorHandler::Throw(env, err);
200 return;
201 }
202
203 const MultiDlProgressCore *multiDlProgress = data.GetData().value();
204 ret = env->Object_CallMethod_Void(object, ctor, reinterpret_cast<ani_long>(multiDlProgress));
205 if (ret != ANI_OK) {
206 LOGE("bindNativePtr failed.");
207 delete multiDlProgress;
208 ErrorHandler::Throw(env, JsErrCode::E_INNER_FAILED);
209 }
210 }
211
ToFailedFileInfo(ani_env * env,ani_class cls,ani_method ctor,const FailedFileInfo & files)212 static tuple<bool, ani_object> ToFailedFileInfo(ani_env *env, ani_class cls, ani_method ctor,
213 const FailedFileInfo &files)
214 {
215 auto [succ, fileUri] = ANIUtils::ToAniString(env, files.uri);
216 if (!succ) {
217 LOGE("Convert FailedFileInfo uri to ani string failed!");
218 return {false, nullptr};
219 }
220
221 ani_status ret;
222 ani_enum downloadErrorEnum;
223 Type errorSign = Builder::BuildEnum("@ohos.file.cloudSync.cloudSync.DownloadErrorType");
224 if ((ret = env->FindEnum(errorSign.Descriptor().c_str(), &downloadErrorEnum)) != ANI_OK) {
225 LOGE("Find DownloadErrorType enum failed!, err: %{public}d", ret);
226 return {false, nullptr};
227 }
228 ani_enum_item downloadErrorEnumItem;
229 if ((ret = env->Enum_GetEnumItemByIndex(downloadErrorEnum, files.error, &downloadErrorEnumItem)) != ANI_OK) {
230 LOGE("Find DownloadErrorType enum failed!, err: %{public}d", ret);
231 return {false, nullptr};
232 }
233
234 ani_object obj;
235 if ((ret = env->Object_New(cls, ctor, &obj, fileUri, downloadErrorEnumItem)) != ANI_OK) {
236 LOGE("Create FailedFileInfo object failed!, err: %{public}d", ret);
237 return {false, nullptr};
238 }
239
240 return {true, obj};
241 }
242
ToAniObjectArray(ani_env * env,const std::vector<FailedFileInfo> & objList)243 static std::tuple<bool, ani_array_ref> ToAniObjectArray(ani_env *env, const std::vector<FailedFileInfo> &objList)
244 {
245 ani_status ret;
246 ani_class cls;
247 std::string classDesc = Builder::BuildClass("@ohos.file.cloudSync.cloudSync.FailedFileInfoInner").Descriptor();
248 if ((ret = env->FindClass(classDesc.c_str(), &cls)) != ANI_OK) {
249 LOGE("Cannot find class %{public}s, err: %{public}d", classDesc.c_str(), ret);
250 return {false, nullptr};
251 }
252
253 ani_method ctor;
254 auto ctorDesc = Builder::BuildConstructorName();
255 auto ctorSig =
256 Builder::BuildSignatureDescriptor({Builder::BuildClass("std.core.String"),
257 Builder::BuildEnum("@ohos.file.cloudSync.cloudSync.DownloadErrorType")});
258 if ((ret = env->Class_FindMethod(cls, ctorDesc.c_str(), ctorSig.c_str(), &ctor)) != ANI_OK) {
259 LOGE("Cannot find class %{public}s constructor method, err: %{public}d", classDesc.c_str(), ret);
260 return {false, nullptr};
261 }
262
263 size_t length = objList.size();
264 const FailedFileInfo *objArray = objList.data();
265 ani_array_ref result = nullptr;
266 if (env->Array_New_Ref(cls, length, nullptr, &result) != ANI_OK) {
267 LOGE("Failed to new array");
268 return {false, nullptr};
269 }
270 for (size_t i = 0; i < length; i++) {
271 auto [succ, item] = ToFailedFileInfo(env, cls, ctor, objArray[i]);
272 if (!succ) {
273 LOGE("Failed to get element for array");
274 return {false, nullptr};
275 }
276 if (env->Array_Set_Ref(result, i, item) != ANI_OK) {
277 LOGE("Failed to set element for array");
278 return {false, nullptr};
279 }
280 }
281 return {true, result};
282 }
283
GetFailedFileList(ani_env * env,ani_object object)284 ani_array_ref MultiDlProgressAni::GetFailedFileList(ani_env *env, ani_object object)
285 {
286 auto multiDlProgress = MultiDlProgressWrapper::Unwrap(env, object);
287 if (multiDlProgress == nullptr) {
288 LOGE("Cannot wrap multiDlProgress.");
289 ErrorHandler::Throw(env, JsErrCode::E_INNER_FAILED);
290 return nullptr;
291 }
292 auto data = multiDlProgress->GetFailedFileList();
293 if (!data.IsSuccess()) {
294 const auto &err = data.GetError();
295 LOGE("multiDlProgress get failed list failed, ret = %{public}d", err.GetErrNo());
296 ErrorHandler::Throw(env, err);
297 return nullptr;
298 }
299
300 auto [succ, res] = ToAniObjectArray(env, data.GetData().value());
301 if (!succ) {
302 ErrorHandler::Throw(env, JsErrCode::E_INNER_FAILED);
303 return nullptr;
304 }
305 return res;
306 }
307
GetDownloadedFileList(ani_env * env,ani_object object)308 ani_array_ref MultiDlProgressAni::GetDownloadedFileList(ani_env *env, ani_object object)
309 {
310 auto multiDlProgress = MultiDlProgressWrapper::Unwrap(env, object);
311 if (multiDlProgress == nullptr) {
312 LOGE("Cannot wrap multiDlProgress.");
313 ErrorHandler::Throw(env, JsErrCode::E_INNER_FAILED);
314 return nullptr;
315 }
316 auto data = multiDlProgress->GetDownloadedFileList();
317 if (!data.IsSuccess()) {
318 const auto &err = data.GetError();
319 LOGE("multiDlProgress get downloaded list failed, ret = %{public}d", err.GetErrNo());
320 ErrorHandler::Throw(env, err);
321 return nullptr;
322 }
323
324 auto [succ, res] = ANIUtils::ToAniStringArray(env, data.GetData().value());
325 if (!succ) {
326 ErrorHandler::Throw(env, JsErrCode::E_INNER_FAILED);
327 return nullptr;
328 }
329 return res;
330 }
331 } // namespace OHOS::FileManagement::CloudSync