1 /*
2 * Copyright (c) 2023 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 "watcher_n_exporter.h"
17
18 #include <cstdio>
19 #include <cstdlib>
20 #include <cstring>
21 #include <memory>
22
23 #include "../common_func.h"
24 #include "file_utils.h"
25 #include "filemgmt_libn.h"
26 #include "filemgmt_libhilog.h"
27 #include "securec.h"
28
29 namespace OHOS::FileManagement::ModuleFileIO {
30 using namespace std;
31 using namespace OHOS::FileManagement::LibN;
32
Constructor(napi_env env,napi_callback_info info)33 napi_value WatcherNExporter::Constructor(napi_env env, napi_callback_info info)
34 {
35 NFuncArg funcArg(env, info);
36 if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
37 HILOGE("Failed to get param.");
38 NError(EINVAL).ThrowErr(env);
39 return nullptr;
40 }
41
42 auto watcherEntity = CreateUniquePtr<WatcherEntity>();
43 if (watcherEntity == nullptr) {
44 HILOGE("Failed to request heap memory.");
45 NError(ENOMEM).ThrowErr(env);
46 return nullptr;
47 }
48 if (!NClass::SetEntityFor<WatcherEntity>(env, funcArg.GetThisVar(), move(watcherEntity))) {
49 HILOGE("Failed to set watcherEntity.");
50 NError(EIO).ThrowErr(env);
51 return nullptr;
52 }
53 return funcArg.GetThisVar();
54 }
55
Stop(napi_env env,napi_callback_info info)56 napi_value WatcherNExporter::Stop(napi_env env, napi_callback_info info)
57 {
58 NFuncArg funcArg(env, info);
59 if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
60 HILOGE("Failed to get param when stop.");
61 NError(EINVAL).ThrowErr(env);
62 return nullptr;
63 }
64
65 auto watchEntity = NClass::GetEntityOf<WatcherEntity>(env, funcArg.GetThisVar());
66 if (!watchEntity) {
67 HILOGE("Failed to get watcherEntity when stop.");
68 NError(EINVAL).ThrowErr(env);
69 return nullptr;
70 }
71 int ret = FileWatcher::GetInstance().StopNotify(watchEntity->data_);
72 if (ret != ERRNO_NOERR) {
73 HILOGE("Failed to stopNotify errno:%{public}d", errno);
74 NError(ret).ThrowErr(env);
75 return nullptr;
76 }
77 return NVal::CreateUndefined(env).val_;
78 }
79
Start(napi_env env,napi_callback_info info)80 napi_value WatcherNExporter::Start(napi_env env, napi_callback_info info)
81 {
82 NFuncArg funcArg(env, info);
83 if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
84 HILOGE("Failed to get param when start.");
85 NError(EINVAL).ThrowErr(env);
86 return nullptr;
87 }
88
89 auto watchEntity = NClass::GetEntityOf<WatcherEntity>(env, funcArg.GetThisVar());
90 if (!watchEntity) {
91 HILOGE("Failed to get watcherEntity when start.");
92 NError(EINVAL).ThrowErr(env);
93 return nullptr;
94 }
95
96 int ret = FileWatcher::GetInstance().StartNotify(watchEntity->data_);
97 if (ret != ERRNO_NOERR) {
98 HILOGE("Failed to startNotify.");
99 NError(ret).ThrowErr(env);
100 return nullptr;
101 }
102
103 auto cbExec = []() -> NError {
104 FileWatcher::GetInstance().GetNotifyEvent(WatcherCallback);
105 return NError(ERRNO_NOERR);
106 };
107
108 auto cbCompl = [](napi_env env, NError err) -> NVal {
109 if (err) {
110 HILOGE("Failed to execute complete.");
111 return {env, err.GetNapiErr(env)};
112 }
113 return {NVal::CreateUndefined(env)};
114 };
115
116 const string procedureName = "FileIOStartWatcher";
117 NVal thisVar(env, funcArg.GetThisVar());
118 return NAsyncWorkPromise(env, thisVar).Schedule(procedureName, cbExec, cbCompl).val_;
119 }
120
WatcherCallbackComplete(WatcherNExporter::JSCallbackContext * callbackContext)121 static void WatcherCallbackComplete(WatcherNExporter::JSCallbackContext *callbackContext)
122 {
123 do {
124 if (callbackContext == nullptr) {
125 HILOGE("Failed to create context pointer");
126 break;
127 }
128 if (!callbackContext->ref_) {
129 HILOGE("Failed to get nref reference");
130 break;
131 }
132 napi_handle_scope scope = nullptr;
133 napi_status status = napi_open_handle_scope(callbackContext->env_, &scope);
134 if (status != napi_ok) {
135 HILOGE("Failed to open handle scope, status: %{public}d", status);
136 break;
137 }
138 napi_env env = callbackContext->env_;
139 napi_value jsCallback = callbackContext->ref_.Deref(env).val_;
140 NVal objn = NVal::CreateObject(env);
141 objn.AddProp("fileName", NVal::CreateUTF8String(env, callbackContext->fileName_).val_);
142 objn.AddProp("event", NVal::CreateUint32(env, callbackContext->event_).val_);
143 objn.AddProp("cookie", NVal::CreateUint32(env, callbackContext->cookie_).val_);
144 napi_value retVal = nullptr;
145 status = napi_call_function(env, nullptr, jsCallback, 1, &(objn.val_), &retVal);
146 if (status != napi_ok) {
147 HILOGE("Failed to call napi_call_function, status: %{public}d", status);
148 }
149 status = napi_close_handle_scope(callbackContext->env_, scope);
150 if (status != napi_ok) {
151 HILOGE("Failed to close handle scope, status: %{public}d", status);
152 }
153 } while (0);
154 delete callbackContext;
155 }
156
WatcherCallback(napi_env env,NRef & callback,const std::string & fileName,const uint32_t & event,const uint32_t & cookie)157 void WatcherNExporter::WatcherCallback(napi_env env, NRef &callback, const std::string &fileName,
158 const uint32_t &event, const uint32_t &cookie)
159 {
160 if (!callback) {
161 HILOGE("Failed to parse watcher callback");
162 return;
163 }
164
165 JSCallbackContext *callbackContext = new (std::nothrow) JSCallbackContext(callback);
166 if (callbackContext == nullptr) {
167 return;
168 }
169 callbackContext->env_ = env;
170 callbackContext->fileName_ = fileName;
171 callbackContext->event_ = event;
172 callbackContext->cookie_ = cookie;
173 auto task = [callbackContext] () {
174 WatcherCallbackComplete(callbackContext);
175 };
176 auto ret = napi_send_event(env, task, napi_eprio_immediate);
177 if (ret != 0) {
178 HILOGE("Failed to execute libuv work queue, ret: %{public}d", ret);
179 delete callbackContext;
180 }
181 }
182
Export()183 bool WatcherNExporter::Export()
184 {
185 vector<napi_property_descriptor> props = {
186 NVal::DeclareNapiFunction("start", Start),
187 NVal::DeclareNapiFunction("stop", Stop),
188 };
189
190 string className = GetClassName();
191 auto [resDefineClass, classValue] =
192 NClass::DefineClass(exports_.env_, className, WatcherNExporter::Constructor, std::move(props));
193 if (!resDefineClass) {
194 HILOGE("Failed to DefineClass");
195 NError(EIO).ThrowErr(exports_.env_);
196 return false;
197 }
198
199 bool succ = NClass::SaveClass(exports_.env_, className, classValue);
200 if (!succ) {
201 HILOGE("Failed to SaveClass");
202 NError(EIO).ThrowErr(exports_.env_);
203 return false;
204 }
205
206 return exports_.AddProp(className, classValue);
207 }
208
GetClassName()209 string WatcherNExporter::GetClassName()
210 {
211 return WatcherNExporter::className_;
212 }
213
WatcherNExporter(napi_env env,napi_value exports)214 WatcherNExporter::WatcherNExporter(napi_env env, napi_value exports) : NExporter(env, exports) {}
215
~WatcherNExporter()216 WatcherNExporter::~WatcherNExporter() {}
217 } // namespace OHOS::FileManagement::ModuleFileIO
218