1 /*
2  * Copyright (C) 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 #define MLOG_TAG "CloudMediaAssetManagerNapi"
17 
18 #include "cloud_media_asset_manager_napi.h"
19 
20 #include "media_column.h"
21 #include "medialibrary_client_errno.h"
22 #include "medialibrary_errno.h"
23 #include "medialibrary_napi_log.h"
24 #include "medialibrary_tracer.h"
25 #include "userfile_client.h"
26 #include "userfile_manager_types.h"
27 #include "media_library_napi.h"
28 #include "media_file_uri.h"
29 #include "media_file_utils.h"
30 #include "result_set_utils.h"
31 #include "cloud_media_asset_types.h"
32 #include "cloud_media_asset_status_napi.h"
33 
34 using namespace std;
35 namespace OHOS::Media {
36 static const string CLOUD_MEDIA_ASSET_MANAGER_CLASS = "CloudMediaAssetManager";
37 thread_local napi_ref CloudMediaAssetManagerNapi::constructor_ = nullptr;
38 const size_t TYPE_SIZE = 6;
39 const int32_t INDEX_ZERO = 0;
40 const int32_t INDEX_ONE = 1;
41 const int32_t INDEX_TWO = 2;
42 const int32_t INDEX_THREE = 3;
43 const int32_t INDEX_FOUR = 4;
44 const int32_t INDEX_FIVE = 5;
45 
Init(napi_env env,napi_value exports)46 napi_value CloudMediaAssetManagerNapi::Init(napi_env env, napi_value exports)
47 {
48     NapiClassInfo info = {
49         .name = CLOUD_MEDIA_ASSET_MANAGER_CLASS,
50         .ref = &constructor_,
51         .constructor = Constructor,
52         .props = {
53             DECLARE_NAPI_STATIC_FUNCTION("getCloudMediaAssetManagerInstance", JSGetCloudMediaAssetManagerInstance),
54             DECLARE_NAPI_FUNCTION("startDownloadCloudMedia", JSStartDownloadCloudMedia),
55             DECLARE_NAPI_FUNCTION("pauseDownloadCloudMedia", JSPauseDownloadCloudMedia),
56             DECLARE_NAPI_FUNCTION("cancelDownloadCloudMedia", JSCancelDownloadCloudMedia),
57             DECLARE_NAPI_FUNCTION("retainCloudMediaAsset", JSRetainCloudMediaAsset),
58             DECLARE_NAPI_FUNCTION("getCloudMediaAssetStatus", JSGetCloudMediaAssetStatus),
59         } };
60     MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
61     return exports;
62 }
63 
Constructor(napi_env env,napi_callback_info info)64 napi_value CloudMediaAssetManagerNapi::Constructor(napi_env env, napi_callback_info info)
65 {
66     if (!MediaLibraryNapiUtils::IsSystemApp()) {
67         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL,
68             "The cloud media asset manager instance can be called only by system apps");
69         return nullptr;
70     }
71     napi_value newTarget = nullptr;
72     CHECK_ARGS(env, napi_get_new_target(env, info, &newTarget), JS_INNER_FAIL);
73     CHECK_COND_RET(newTarget != nullptr, nullptr, "Failed to check new.target");
74 
75     size_t argc = ARGS_ONE;
76     napi_value argv[ARGS_ONE] = { 0 };
77     napi_value thisVar = nullptr;
78     CHECK_ARGS(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr), JS_INNER_FAIL);
79     CHECK_COND_WITH_MESSAGE(env, argc == ARGS_ONE, "Number of args is invalid");
80     if (!InitUserFileClient(env, info)) {
81         NAPI_ERR_LOG("Failed to init UserFileClient");
82         return nullptr;
83     }
84 
85     unique_ptr<CloudMediaAssetManagerNapi> obj = make_unique<CloudMediaAssetManagerNapi>();
86     CHECK_COND(env, obj != nullptr, JS_INNER_FAIL);
87     CHECK_ARGS(env,
88         napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()), CloudMediaAssetManagerNapi::Destructor, nullptr,
89             nullptr),
90         JS_INNER_FAIL);
91     obj.release();
92     return thisVar;
93 }
94 
Destructor(napi_env env,void * nativeObject,void * finalizeHint)95 void CloudMediaAssetManagerNapi::Destructor(napi_env env, void* nativeObject, void* finalizeHint)
96 {
97     auto* cloudMediaAssetManager = reinterpret_cast<CloudMediaAssetManagerNapi*>(nativeObject);
98     if (cloudMediaAssetManager == nullptr) {
99         NAPI_ERR_LOG("cloudMediaAssetManager is nullptr");
100         return;
101     }
102     delete cloudMediaAssetManager;
103     cloudMediaAssetManager = nullptr;
104 }
105 
CheckWhetherInitSuccess(napi_env env,napi_value value,bool checkIsValid)106 static bool CheckWhetherInitSuccess(napi_env env, napi_value value, bool checkIsValid)
107 {
108     napi_value propertyNames;
109     uint32_t propertyLength;
110     napi_valuetype valueType = napi_undefined;
111     NAPI_CALL_BASE(env, napi_typeof(env, value, &valueType), false);
112     if (valueType != napi_object) {
113         NAPI_ERR_LOG("valueType is not valid");
114         return false;
115     }
116 
117     NAPI_CALL_BASE(env, napi_get_property_names(env, value, &propertyNames), false);
118     NAPI_CALL_BASE(env, napi_get_array_length(env, propertyNames, &propertyLength), false);
119     if (propertyLength == 0) {
120         NAPI_ERR_LOG("propertyLength is 0");
121         return false;
122     }
123     if (checkIsValid && (!UserFileClient::IsValid())) {
124         NAPI_ERR_LOG("UserFileClient is not valid");
125         return false;
126     }
127     return true;
128 }
129 
JSGetCloudMediaAssetManagerInstance(napi_env env,napi_callback_info info)130 napi_value CloudMediaAssetManagerNapi::JSGetCloudMediaAssetManagerInstance(napi_env env, napi_callback_info info)
131 {
132     MediaLibraryTracer tracer;
133     tracer.Start("GetCloudMediaAssetManagerInstance");
134 
135     constexpr size_t ARG_CONTEXT = 1;
136     size_t argc = ARG_CONTEXT;
137     napi_value argv[ARGS_TWO] = {0};
138 
139     napi_value thisVar = nullptr;
140     napi_value ctor = nullptr;
141     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
142     NAPI_CALL(env, napi_get_reference_value(env, constructor_, &ctor));
143 
144     napi_value result = nullptr;
145     NAPI_CALL(env, napi_new_instance(env, ctor, argc, argv, &result));
146     if (!CheckWhetherInitSuccess(env, result, false)) {
147         NAPI_ERR_LOG("Init Cloud Media Asset Manager Instance is failed");
148         NAPI_CALL(env, napi_get_undefined(env, &result));
149     }
150     return result;
151 }
152 
InitUserFileClient(napi_env env,napi_callback_info info)153 bool CloudMediaAssetManagerNapi::InitUserFileClient(napi_env env, napi_callback_info info)
154 {
155     if (UserFileClient::IsValid()) {
156         return true;
157     }
158 
159     std::unique_lock<std::mutex> helperLock(MediaLibraryNapi::sUserFileClientMutex_);
160     if (!UserFileClient::IsValid()) {
161         UserFileClient::Init(env, info);
162     }
163     helperLock.unlock();
164     return UserFileClient::IsValid();
165 }
166 
ParseArgCloudMediaDownloadType(napi_env env,napi_callback_info info,unique_ptr<CloudMediaAssetAsyncContext> & context)167 static napi_status ParseArgCloudMediaDownloadType(napi_env env, napi_callback_info info,
168     unique_ptr<CloudMediaAssetAsyncContext>& context)
169 {
170     CHECK_STATUS_RET(MediaLibraryNapiUtils::AsyncContextGetArgs(env, info, context, ARGS_ONE, ARGS_ONE),
171         "Failed to get args");
172     napi_valuetype valueType = napi_undefined;
173     CHECK_STATUS_RET(napi_typeof(env, context->argv[ARGS_ZERO], &valueType), "Failed to get type");
174     CHECK_COND_RET(valueType == napi_number, napi_number_expected, "Type is not as expected number");
175     CHECK_STATUS_RET(napi_get_value_int32(env, context->argv[ARGS_ZERO], &context->cloudMediaDownloadType),
176         "Failed to get int32 value");
177     return napi_ok;
178 }
179 
ParseArgCloudMediaRetainType(napi_env env,napi_callback_info info,unique_ptr<CloudMediaAssetAsyncContext> & context)180 static napi_status ParseArgCloudMediaRetainType(napi_env env, napi_callback_info info,
181     unique_ptr<CloudMediaAssetAsyncContext>& context)
182 {
183     CHECK_STATUS_RET(MediaLibraryNapiUtils::AsyncContextGetArgs(env, info, context, ARGS_ONE, ARGS_ONE),
184         "Failed to get args");
185     napi_valuetype valueType = napi_undefined;
186     CHECK_STATUS_RET(napi_typeof(env, context->argv[ARGS_ZERO], &valueType), "Failed to get type");
187     CHECK_COND_RET(valueType == napi_number, napi_number_expected, "Type is not as expected number");
188     CHECK_STATUS_RET(napi_get_value_int32(env, context->argv[ARGS_ZERO], &context->cloudMediaRetainType),
189         "Failed to get int32 value");
190     return napi_ok;
191 }
192 
StartDownloadCloudMediaExecute(napi_env env,void * data)193 static void StartDownloadCloudMediaExecute(napi_env env, void* data)
194 {
195     MediaLibraryTracer tracer;
196     tracer.Start("StartDownloadCloudMediaExecute");
197     NAPI_INFO_LOG("enter StartDownloadCloudMediaExecute");
198 
199     auto* context = static_cast<CloudMediaAssetAsyncContext*>(data);
200     auto downloadType = context->cloudMediaDownloadType;
201     string uriStr;
202     if (downloadType == static_cast<int32_t>(CloudMediaDownloadType::DOWNLOAD_FORCE)) {
203         uriStr = CMAM_CLOUD_MEDIA_ASSET_TASK_START_FORCE;
204     } else if (downloadType == static_cast<int32_t>(CloudMediaDownloadType::DOWNLOAD_GENTLE)) {
205         uriStr = CMAM_CLOUD_MEDIA_ASSET_TASK_START_GENTLE;
206     } else {
207         NAPI_ERR_LOG("cloudMediaDownloadType error, err type: %{public}d", downloadType);
208         return;
209     }
210     Uri startUri(uriStr);
211     int32_t changedRows = UserFileClient::Update(startUri, context->predicates, context->valuesBucket);
212     if (changedRows < 0) {
213         context->SaveError(changedRows);
214         NAPI_ERR_LOG("Start download cloud media failed, err: %{public}d", changedRows);
215     }
216 }
217 
StartDownloadCloudMediaCompleteCallback(napi_env env,napi_status status,void * data)218 static void StartDownloadCloudMediaCompleteCallback(napi_env env, napi_status status, void* data)
219 {
220     auto* context = static_cast<CloudMediaAssetAsyncContext*>(data);
221     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
222     auto jsContext = make_unique<JSAsyncContextOutput>();
223     jsContext->status = false;
224     napi_get_undefined(env, &jsContext->data);
225     napi_get_undefined(env, &jsContext->error);
226     if (context->error == ERR_DEFAULT) {
227         jsContext->status = true;
228     } else {
229         context->HandleError(env, jsContext->error);
230     }
231 
232     if (context->work != nullptr) {
233         MediaLibraryNapiUtils::InvokeJSAsyncMethod(
234             env, context->deferred, context->callbackRef, context->work, *jsContext);
235     }
236     delete context;
237 }
238 
JSStartDownloadCloudMedia(napi_env env,napi_callback_info info)239 napi_value CloudMediaAssetManagerNapi::JSStartDownloadCloudMedia(napi_env env, napi_callback_info info)
240 {
241     if (!MediaLibraryNapiUtils::IsSystemApp()) {
242         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
243         return nullptr;
244     }
245     MediaLibraryTracer tracer;
246     tracer.Start("JSStartDownloadCloudMedia");
247 
248     auto asyncContext = make_unique<CloudMediaAssetAsyncContext>();
249     CHECK_COND_WITH_MESSAGE(env, ParseArgCloudMediaDownloadType(env, info, asyncContext) == napi_ok,
250         "Failed to parse args");
251     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "StartDownloadCloudMedia",
252         StartDownloadCloudMediaExecute, StartDownloadCloudMediaCompleteCallback);
253 }
254 
PauseDownloadCloudMediaExecute(napi_env env,void * data)255 static void PauseDownloadCloudMediaExecute(napi_env env, void* data)
256 {
257     MediaLibraryTracer tracer;
258     tracer.Start("PauseDownloadCloudMediaExecute");
259     NAPI_INFO_LOG("enter PauseDownloadCloudMediaExecute");
260 
261     auto* context = static_cast<CloudMediaAssetAsyncContext*>(data);
262     Uri pauseUri(CMAM_CLOUD_MEDIA_ASSET_TASK_PAUSE);
263     int32_t changedRows = UserFileClient::Update(pauseUri, context->predicates, context->valuesBucket);
264     if (changedRows < 0) {
265         context->SaveError(changedRows);
266         NAPI_ERR_LOG("Pause download cloud media failed, err: %{public}d", changedRows);
267     }
268 }
269 
PauseDownloadCloudMediaCompleteCallback(napi_env env,napi_status status,void * data)270 static void PauseDownloadCloudMediaCompleteCallback(napi_env env, napi_status status, void* data)
271 {
272     auto* context = static_cast<CloudMediaAssetAsyncContext*>(data);
273     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
274     auto jsContext = make_unique<JSAsyncContextOutput>();
275     jsContext->status = false;
276     napi_get_undefined(env, &jsContext->data);
277     napi_get_undefined(env, &jsContext->error);
278     if (context->error == ERR_DEFAULT) {
279         jsContext->status = true;
280     } else {
281         context->HandleError(env, jsContext->error);
282     }
283 
284     if (context->work != nullptr) {
285         MediaLibraryNapiUtils::InvokeJSAsyncMethod(
286             env, context->deferred, context->callbackRef, context->work, *jsContext);
287     }
288     delete context;
289 }
290 
JSPauseDownloadCloudMedia(napi_env env,napi_callback_info info)291 napi_value CloudMediaAssetManagerNapi::JSPauseDownloadCloudMedia(napi_env env, napi_callback_info info)
292 {
293     if (!MediaLibraryNapiUtils::IsSystemApp()) {
294         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
295         return nullptr;
296     }
297     MediaLibraryTracer tracer;
298     tracer.Start("JSPauseDownloadCloudMedia");
299 
300     auto asyncContext = make_unique<CloudMediaAssetAsyncContext>();
301     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PauseDownloadCloudMedia",
302         PauseDownloadCloudMediaExecute, PauseDownloadCloudMediaCompleteCallback);
303 }
304 
CancelDownloadCloudMediaExecute(napi_env env,void * data)305 static void CancelDownloadCloudMediaExecute(napi_env env, void* data)
306 {
307     MediaLibraryTracer tracer;
308     tracer.Start("CancelDownloadCloudMediaExecute");
309     NAPI_INFO_LOG("enter CancelDownloadCloudMediaExecute");
310 
311     auto* context = static_cast<CloudMediaAssetAsyncContext*>(data);
312     Uri cancelUri(CMAM_CLOUD_MEDIA_ASSET_TASK_CANCEL);
313     int32_t changedRows = UserFileClient::Update(cancelUri, context->predicates, context->valuesBucket);
314     if (changedRows < 0) {
315         context->SaveError(changedRows);
316         NAPI_ERR_LOG("Cancel download cloud media failed, err: %{public}d", changedRows);
317     }
318 }
319 
CancelDownloadCloudMediaCompleteCallback(napi_env env,napi_status status,void * data)320 static void CancelDownloadCloudMediaCompleteCallback(napi_env env, napi_status status, void* data)
321 {
322     auto* context = static_cast<CloudMediaAssetAsyncContext*>(data);
323     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
324     auto jsContext = make_unique<JSAsyncContextOutput>();
325     jsContext->status = false;
326     napi_get_undefined(env, &jsContext->data);
327     napi_get_undefined(env, &jsContext->error);
328     if (context->error == ERR_DEFAULT) {
329         jsContext->status = true;
330     } else {
331         context->HandleError(env, jsContext->error);
332     }
333 
334     if (context->work != nullptr) {
335         MediaLibraryNapiUtils::InvokeJSAsyncMethod(
336             env, context->deferred, context->callbackRef, context->work, *jsContext);
337     }
338     delete context;
339 }
340 
JSCancelDownloadCloudMedia(napi_env env,napi_callback_info info)341 napi_value CloudMediaAssetManagerNapi::JSCancelDownloadCloudMedia(napi_env env, napi_callback_info info)
342 {
343     if (!MediaLibraryNapiUtils::IsSystemApp()) {
344         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
345         return nullptr;
346     }
347     MediaLibraryTracer tracer;
348     tracer.Start("JSCancelDownloadCloudMedia");
349 
350     auto asyncContext = make_unique<CloudMediaAssetAsyncContext>();
351     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "CancelDownloadCloudMedia",
352         CancelDownloadCloudMediaExecute, CancelDownloadCloudMediaCompleteCallback);
353 }
354 
RetainCloudMediaAssetExecute(napi_env env,void * data)355 static void RetainCloudMediaAssetExecute(napi_env env, void* data)
356 {
357     MediaLibraryTracer tracer;
358     tracer.Start("RetainCloudMediaAssetExecute");
359     NAPI_INFO_LOG("enter RetainCloudMediaAssetExecute");
360 
361     auto* context = static_cast<CloudMediaAssetAsyncContext*>(data);
362     auto retainType = context->cloudMediaRetainType;
363     string uriStr;
364     if (retainType == static_cast<int32_t>(CloudMediaRetainType::RETAIN_FORCE)) {
365         uriStr = CMAM_CLOUD_MEDIA_ASSET_TASK_RETAIN_FORCE;
366     } else {
367         NAPI_ERR_LOG("cloudMediaRetainType error, err type: %{public}d", retainType);
368         return;
369     }
370     Uri retainUri(uriStr);
371     int32_t changedRows = UserFileClient::Update(retainUri, context->predicates, context->valuesBucket);
372     if (changedRows < 0) {
373         context->SaveError(changedRows);
374         NAPI_ERR_LOG("Retain cloud media asset failed, err: %{public}d", changedRows);
375     }
376 }
377 
RetainCloudMediaAssetCompleteCallback(napi_env env,napi_status status,void * data)378 static void RetainCloudMediaAssetCompleteCallback(napi_env env, napi_status status, void* data)
379 {
380     auto* context = static_cast<CloudMediaAssetAsyncContext*>(data);
381     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
382     auto jsContext = make_unique<JSAsyncContextOutput>();
383     jsContext->status = false;
384     napi_get_undefined(env, &jsContext->data);
385     napi_get_undefined(env, &jsContext->error);
386     if (context->error == ERR_DEFAULT) {
387         jsContext->status = true;
388     } else {
389         context->HandleError(env, jsContext->error);
390     }
391 
392     if (context->work != nullptr) {
393         MediaLibraryNapiUtils::InvokeJSAsyncMethod(
394             env, context->deferred, context->callbackRef, context->work, *jsContext);
395     }
396     delete context;
397 }
398 
JSRetainCloudMediaAsset(napi_env env,napi_callback_info info)399 napi_value CloudMediaAssetManagerNapi::JSRetainCloudMediaAsset(napi_env env, napi_callback_info info)
400 {
401     if (!MediaLibraryNapiUtils::IsSystemApp()) {
402         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
403         return nullptr;
404     }
405     MediaLibraryTracer tracer;
406     tracer.Start("JSRetainCloudMediaAsset");
407 
408     auto asyncContext = make_unique<CloudMediaAssetAsyncContext>();
409     CHECK_COND_WITH_MESSAGE(env, ParseArgCloudMediaRetainType(env, info, asyncContext) == napi_ok,
410         "Failed to parse args");
411     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "RetainCloudMediaAsset",
412         RetainCloudMediaAssetExecute, RetainCloudMediaAssetCompleteCallback);
413 }
414 
CanConvertToInt32(const std::string & str)415 static bool CanConvertToInt32(const std::string &str)
416 {
417     std::istringstream stringStream(str);
418     int32_t num = 0;
419     stringStream >> num;
420     return stringStream.eof() && !stringStream.fail();
421 }
422 
SplitUriString(const std::string & str,std::vector<std::string> & type)423 static bool SplitUriString(const std::string& str, std::vector<std::string> &type)
424 {
425     std::stringstream ss(str);
426     std::string item;
427     while (std::getline(ss, item, ',')) {
428         if (item.empty()) {
429             return false;
430         }
431         type.emplace_back(item);
432     }
433     return type.size() == TYPE_SIZE;
434 }
435 
GetCloudMediaAssetStatusExecute(napi_env env,void * data)436 static void GetCloudMediaAssetStatusExecute(napi_env env, void* data)
437 {
438     MediaLibraryTracer tracer;
439     tracer.Start("GetCloudMediaAssetStatusExecute");
440     NAPI_INFO_LOG("enter GetCloudMediaAssetStatusExecute");
441 
442     auto* context = static_cast<CloudMediaAssetAsyncContext*>(data);
443     Uri getUri(CMAM_CLOUD_MEDIA_ASSET_TASK_STATUS_QUERY);
444     string result = UserFileClient::GetType(getUri);
445     NAPI_INFO_LOG("Get cloud media asset, res: %{public}s.", result.c_str());
446     std::vector<std::string> type;
447     if (!SplitUriString(result, type)) {
448         NAPI_ERR_LOG("GetType failed");
449         return;
450     }
451     if (!CanConvertToInt32(type[INDEX_ZERO]) || !CanConvertToInt32(type[INDEX_FIVE])) {
452         NAPI_ERR_LOG("GetType failed");
453         return;
454     }
455     context->cloudMediaAssetTaskStatus_ = static_cast<CloudMediaAssetTaskStatus>(std::stoi(type[INDEX_ZERO]));
456     context->cloudMediaTaskPauseCause_ = static_cast<CloudMediaTaskPauseCause>(std::stoi(type[INDEX_FIVE]));
457     std::string taskInfo = "totalcount: " + type[INDEX_ONE] + "," +
458                            "totalSize: " + type[INDEX_TWO] + "," +
459                            "remainCount: " + type[INDEX_THREE] + "," +
460                            "remainSize: " + type[INDEX_FOUR];
461     context->taskInfo_ = taskInfo;
462 }
463 
GetCloudMediaAssetStatusCompleteCallback(napi_env env,napi_status status,void * data)464 static void GetCloudMediaAssetStatusCompleteCallback(napi_env env, napi_status status, void* data)
465 {
466     auto* context = static_cast<CloudMediaAssetAsyncContext*>(data);
467     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
468     auto jsContext = make_unique<JSAsyncContextOutput>();
469     jsContext->status = false;
470     napi_get_undefined(env, &jsContext->data);
471     napi_get_undefined(env, &jsContext->error);
472     if (context->error == ERR_DEFAULT) {
473         napi_value cloudMediaAssetStatus = CloudMediaAssetStatusNapi::NewCloudMediaAssetStatusNapi(env, context);
474         jsContext->data = cloudMediaAssetStatus;
475         jsContext->status = true;
476     } else {
477         context->HandleError(env, jsContext->error);
478     }
479 
480     if (context->work != nullptr) {
481         MediaLibraryNapiUtils::InvokeJSAsyncMethod(
482             env, context->deferred, context->callbackRef, context->work, *jsContext);
483     }
484     delete context;
485 }
486 
JSGetCloudMediaAssetStatus(napi_env env,napi_callback_info info)487 napi_value CloudMediaAssetManagerNapi::JSGetCloudMediaAssetStatus(napi_env env, napi_callback_info info)
488 {
489     if (!MediaLibraryNapiUtils::IsSystemApp()) {
490         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
491         return nullptr;
492     }
493     MediaLibraryTracer tracer;
494     tracer.Start("JSGetCloudMediaAssetStatus");
495 
496     auto asyncContext = make_unique<CloudMediaAssetAsyncContext>();
497     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetCloudMediaAssetStatus",
498         GetCloudMediaAssetStatusExecute, GetCloudMediaAssetStatusCompleteCallback);
499 }
500 } // namespace OHOS::Media