• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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