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