• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 "media_scanner_napi.h"
17 
18 #include "hilog/log.h"
19 
20 using OHOS::HiviewDFX::HiLog;
21 using OHOS::HiviewDFX::HiLogLabel;
22 using namespace std;
23 
24 namespace {
25     constexpr HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "MediaScannerNapi"};
26 }
27 
28 namespace OHOS {
29 namespace Media {
30 napi_ref MediaScannerNapi::sConstructor_ = nullptr;
31 
MediaScannerNapi()32 MediaScannerNapi::MediaScannerNapi()
33     : mediaScanner_(nullptr), env_(nullptr), wrapper_(nullptr) {}
34 
~MediaScannerNapi()35 MediaScannerNapi::~MediaScannerNapi()
36 {
37     if (mediaScanner_ != nullptr) {
38         mediaScanner_->Release();
39         mediaScanner_ = nullptr;
40     }
41 
42     if (wrapper_ != nullptr) {
43         napi_delete_reference(env_, wrapper_);
44     }
45 }
46 
Init(napi_env env,napi_value exports)47 napi_value MediaScannerNapi::Init(napi_env env, napi_value exports)
48 {
49     napi_status status;
50     napi_value ctorObj;
51     int32_t refCount = 1;
52 
53     napi_property_descriptor scanner_props[] = {
54         DECLARE_NAPI_FUNCTION("scanDir", ScanDir),
55         DECLARE_NAPI_FUNCTION("scanFile", ScanFile)
56     };
57 
58     napi_property_descriptor static_prop[] = {
59         DECLARE_NAPI_STATIC_FUNCTION("getScannerInstance", GetMediaScannerInstance)
60     };
61 
62     status = napi_define_class(env, SCANNER_HELPER_NAPI_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH,
63         MediaScannerNapiConstructor, nullptr, sizeof(scanner_props) / sizeof(scanner_props[PARAM0]),
64         scanner_props, &ctorObj);
65     if (status == napi_ok) {
66         if (napi_create_reference(env, ctorObj, refCount, &sConstructor_) == napi_ok) {
67             status = napi_set_named_property(env, exports, SCANNER_HELPER_NAPI_CLASS_NAME.c_str(), ctorObj);
68             if (status == napi_ok && napi_define_properties(env, exports,
69                 sizeof(static_prop) / sizeof(static_prop[PARAM0]), static_prop) == napi_ok) {
70                 return exports;
71             }
72         }
73     }
74     return nullptr;
75 }
76 
MediaScannerNapiConstructor(napi_env env,napi_callback_info info)77 napi_value MediaScannerNapi::MediaScannerNapiConstructor(napi_env env, napi_callback_info info)
78 {
79     napi_status status;
80     napi_value result = nullptr;
81     napi_value thisVar = nullptr;
82 
83     napi_get_undefined(env, &result);
84     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
85 
86     if (status == napi_ok && thisVar != nullptr) {
87         unique_ptr<MediaScannerNapi> obj = make_unique<MediaScannerNapi>();
88         if (obj != nullptr) {
89             obj->env_ = env;
90             obj->mediaScanner_ = MediaScannerHelperFactory::CreateScannerHelper();
91             if (obj->mediaScanner_ == nullptr) {
92                 HiLog::Error(LABEL, "MediaScanner client instance creation failed!");
93                 return result;
94             }
95 
96             obj->mediaScannerNapiCallbackObj_ = std::make_shared<MediaScannerNapiCallback>(env);
97             if (obj->mediaScannerNapiCallbackObj_ == nullptr) {
98                 HiLog::Error(LABEL, "MediaScanner callback instance creation failed!");
99                 return result;
100             }
101 
102             status = napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()),
103                                MediaScannerNapi::MediaScannerNapiDestructor, nullptr, &(obj->wrapper_));
104             if (status == napi_ok) {
105                 obj.release();
106                 return thisVar;
107             } else {
108                 HiLog::Error(LABEL, "Failed to wrap the native media scanner client object with JS");
109             }
110         }
111     }
112 
113     return result;
114 }
115 
MediaScannerNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)116 void MediaScannerNapi::MediaScannerNapiDestructor(napi_env env, void *nativeObject, void *finalize_hint)
117 {
118     MediaScannerNapi *scannerHelper = reinterpret_cast<MediaScannerNapi*>(nativeObject);
119     if (scannerHelper != nullptr) {
120         scannerHelper->~MediaScannerNapi();
121     }
122 }
123 
GetMediaScannerInstance(napi_env env,napi_callback_info info)124 napi_value MediaScannerNapi::GetMediaScannerInstance(napi_env env, napi_callback_info info)
125 {
126     napi_status status;
127     napi_value result = nullptr;
128     napi_value ctor;
129 
130     status = napi_get_reference_value(env, sConstructor_, &ctor);
131     if (status == napi_ok) {
132         status = napi_new_instance(env, ctor, 0, nullptr, &result);
133         if (status == napi_ok) {
134             return result;
135         } else {
136             HiLog::Error(LABEL, "New instance could not be obtained");
137         }
138     }
139 
140     napi_get_undefined(env, &result);
141     return result;
142 }
143 
InvokeJSCallback(napi_env env,const int32_t errCode,const std::string & uri,napi_ref callbackRef)144 void InvokeJSCallback(napi_env env, const int32_t errCode, const std::string &uri, napi_ref callbackRef)
145 {
146     napi_value retVal = nullptr;
147     napi_value results[ARGS_TWO] = {nullptr};
148     napi_get_undefined(env, &results[PARAM0]);
149     napi_create_object(env, &results[PARAM1]);
150 
151     napi_value jsStatus = 0;
152     napi_create_int32(env, errCode, &jsStatus);
153     napi_set_named_property(env, results[PARAM1], "status", jsStatus);
154 
155     napi_value jsUri = 0;
156     napi_create_string_utf8(env, uri.c_str(), NAPI_AUTO_LENGTH, &jsUri);
157     napi_set_named_property(env, results[PARAM1], "fileUri", jsUri);
158 
159     napi_value callback = nullptr;
160     napi_get_reference_value(env, callbackRef, &callback);
161     napi_call_function(env, nullptr, callback, ARGS_TWO, results, &retVal);
162 }
163 
NapiScanUtils(napi_env env,napi_callback_info info,const string & scanType)164 napi_value MediaScannerNapi::NapiScanUtils(napi_env env, napi_callback_info info, const string &scanType)
165 {
166     char buffer[PATH_MAX];
167     napi_status status;
168     napi_value result = nullptr;
169     size_t argc = ARGS_TWO;
170     napi_value argv[ARGS_TWO] = {0};
171     napi_value thisVar = nullptr;
172     MediaScannerNapi *obj = nullptr;
173     string path = "";
174     napi_ref callbackRef = nullptr;
175     const int32_t refCount = 1;
176     size_t res = 0;
177     int32_t errCode = 0;
178 
179     GET_JS_ARGS(env, info, argc, argv, thisVar);
180     NAPI_ASSERT(env, argc == ARGS_TWO, "requires 2 parameters");
181 
182     napi_get_undefined(env, &result);
183     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
184     if (status == napi_ok && obj != nullptr) {
185         if (argc == ARGS_TWO) {
186             napi_valuetype valueType = napi_undefined;
187             napi_typeof(env, argv[PARAM0], &valueType);
188             if (valueType == napi_string) {
189                 napi_get_value_string_utf8(env, argv[PARAM0], buffer, PATH_MAX, &res);
190                 path = string(buffer);
191             } else {
192                 HiLog::Error(LABEL, "Invalid arg");
193                 return result;
194             }
195             napi_typeof(env, argv[PARAM1], &valueType);
196             if (valueType == napi_function) {
197                 napi_create_reference(env, argv[PARAM1], refCount, &callbackRef);
198             } else {
199                 HiLog::Error(LABEL, "Invalid arg");
200                 return result;
201             }
202         }
203 
204         if (scanType == "FILE") {
205             errCode = obj->mediaScanner_->ScanFile(path, obj->mediaScannerNapiCallbackObj_);
206         } else if (scanType == "DIR") {
207             errCode = obj->mediaScanner_->ScanDir(path, obj->mediaScannerNapiCallbackObj_);
208         }
209 
210         if (errCode == 0) {
211             obj->mediaScannerNapiCallbackObj_->SetToMap(path, callbackRef);
212         } else {
213             // Invoke JS callback functions based on results
214             InvokeJSCallback(env, errCode, "", callbackRef);
215         }
216     }
217 
218     return result;
219 }
220 
ScanFile(napi_env env,napi_callback_info info)221 napi_value MediaScannerNapi::ScanFile(napi_env env, napi_callback_info info)
222 {
223     return NapiScanUtils(env, info, "FILE");
224 }
225 
ScanDir(napi_env env,napi_callback_info info)226 napi_value MediaScannerNapi::ScanDir(napi_env env, napi_callback_info info)
227 {
228     return NapiScanUtils(env, info, "DIR");
229 }
230 
OnScanFinished(const int32_t status,const std::string & uri,const std::string & path)231 void MediaScannerNapiCallback::OnScanFinished(const int32_t status, const std::string &uri, const std::string &path)
232 {
233     auto itr = scannerMap_.find(path);
234     if (itr != scannerMap_.end()) {
235         // Invoke JS callback functions based on results
236         InvokeJSCallback(env_, status, uri, itr->second);
237         scannerMap_.erase(path);
238         HiLog::Debug(LABEL, "OnScanFinished exit");
239     }
240 }
241 
SetToMap(const std::string & path,const napi_ref & cbRef)242 void MediaScannerNapiCallback::SetToMap(const std::string &path, const napi_ref &cbRef)
243 {
244     scannerMap_.insert(std::make_pair(path, cbRef));
245 }
246 } // namespace Media
247 } // namespace OHOS
248