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