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