• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "connectdfs.h"
17 
18 #include <cstring>
19 #include <dirent.h>
20 #include <fcntl.h>
21 #include <memory>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include <tuple>
25 #include <unistd.h>
26 
27 #include "common_func.h"
28 #include "filemgmt_libhilog.h"
29 #include "distributed_file_daemon_manager.h"
30 
31 namespace OHOS {
32 namespace FileManagement {
33 namespace ModuleFileIO {
34 namespace fs = std::filesystem;
35 
CreateConnectDfsCBCBInfo(napi_env & env)36 ConnectDfsCB *ConnectDfs::CreateConnectDfsCBCBInfo(napi_env &env)
37 {
38     HILOGI("CreateConnectDfsCBCBInfo called");
39     auto connectDfsCB = new(std::nothrow) ConnectDfsCB;
40     if (connectDfsCB == nullptr) {
41         HILOGE("CreateConnectDfsCBCBInfo failed, connectDfsCB == nullptr");
42         return nullptr;
43     }
44     connectDfsCB->cbBase.cbInfo.env = env;
45     connectDfsCB->cbBase.asyncWork = nullptr;
46     connectDfsCB->cbBase.deferred = nullptr;
47     connectDfsCB->callbackRef = nullptr;
48     HILOGI("CreateConnectDfsCBCBInfo end");
49     return connectDfsCB;
50 }
51 
cbExec(napi_env env,void * data)52 void cbExec(napi_env env, void *data)
53 {
54     HILOGI("cbExec for connectDfs called");
55     auto connectDfsCB = static_cast<ConnectDfsCB *>(data);
56     sptr<NAPIDfsListener> dfsListeners(new (std::nothrow) NAPIDfsListener());
57     connectDfsCB->jsCallbackObject = dfsListeners;
58     if (connectDfsCB->jsCallbackObject == nullptr) {
59         return;
60     }
61     connectDfsCB->jsCallbackObject->SetConnectDfsEnv(env);
62     HILOGI("connectDfsCB set env success");
63     if (connectDfsCB->dfsConnectCB.callback != nullptr) {
64         connectDfsCB->jsCallbackObject->
65             SetConnectDfsCBRef(connectDfsCB->dfsConnectCB.callback);
66         HILOGI("connectDfsCB set callback success");
67     } else {
68         connectDfsCB->jsCallbackObject->
69             SetConnectDfsPromiseRef(connectDfsCB->cbBase.deferred);
70         HILOGI("connectDfsCB set promise success");
71     }
72 
73     connectDfsCB->result = Storage::DistributedFile::DistributedFileDaemonManager::GetInstance().
74         OpenP2PConnectionEx(connectDfsCB->networkId, connectDfsCB->jsCallbackObject);
75     HILOGI(" cbExec end ret = %{public}d", connectDfsCB->result);
76 }
77 
cbCompl(napi_env env,napi_status status,void * data)78 void cbCompl(napi_env env, napi_status status, void *data)
79 {
80     HILOGI("cbCompl for connectDfs called");
81     auto connectDfsCB = static_cast<ConnectDfsCB *>(data);
82     napi_value result[NARG_CNT::TWO] = { nullptr };
83     napi_get_undefined(env, &result[NARG_POS::SECOND]);
84     if (connectDfsCB->result == ERRNO_NOERR) {
85         napi_get_undefined(env, &result[NARG_POS::FIRST]);
86         napi_resolve_deferred(env, connectDfsCB->cbBase.deferred, result[NARG_POS::SECOND]);
87     } else {
88         result[NARG_POS::FIRST] = NError(connectDfsCB->result).GetNapiErr(env);
89         napi_reject_deferred(env, connectDfsCB->cbBase.deferred, result[NARG_POS::FIRST]);
90     }
91     napi_delete_async_work(env, connectDfsCB->cbBase.asyncWork);
92     delete connectDfsCB;
93     connectDfsCB = nullptr;
94     HILOGI("cbCompl for connectDfs end");
95 }
96 
GetListenerFromOptionArg(napi_env env,const NFuncArg & funcArg)97 tuple<bool, NVal> ConnectDfs::GetListenerFromOptionArg(napi_env env, const NFuncArg &funcArg)
98 {
99     NVal op(env, funcArg[NARG_POS::SECOND]);
100     if (!op.HasProp("onStatus") || op.GetProp("onStatus").TypeIs(napi_undefined)) {
101         return { true, NVal() };
102     }
103     NVal onStatus = op.GetProp("onStatus");
104     if (!onStatus.TypeIs(napi_function)) {
105         HILOGE("Illegal dfsListeners.onStatus type");
106         return { false, NVal() };
107     }
108     return { true, onStatus };
109 }
110 
ParseJsOperand(napi_env env,NVal paramFromJsArg)111 tuple<bool, std::string> ConnectDfs::ParseJsOperand(napi_env env, NVal paramFromJsArg)
112 {
113     auto [succ, param, ignore] = paramFromJsArg.ToUTF8String();
114     if (!succ) {
115         HILOGE("parse parameter failed.");
116         return { false, "" };
117     }
118     std::string paramStr = std::string(param.get());
119     return { true, paramStr };
120 }
121 
ParseJsParam(napi_env env,NFuncArg & funcArg,ConnectDfsCB * connectDfsCB)122 int ConnectDfs::ParseJsParam(napi_env env, NFuncArg &funcArg, ConnectDfsCB *connectDfsCB)
123 {
124     if (!funcArg.InitArgs(NARG_CNT::TWO)) {
125         HILOGE("Number of arguments unmatched");
126         return E_PARAMS;
127     }
128     auto [succNetworkId, networkId] = ParseJsOperand(env, { env, funcArg[NARG_POS::FIRST] });
129     auto [succDfsListeners, dfsListeners] = GetListenerFromOptionArg(env, funcArg);
130     if (!succNetworkId || !succDfsListeners) {
131         HILOGE("The first/second argument requires string/napi_function");
132         return E_PARAMS;
133     }
134     connectDfsCB->networkId = networkId;
135     napi_create_reference(env, dfsListeners.val_, 1, &connectDfsCB->dfsConnectCB.callback);
136     return ERRNO_NOERR;
137 }
138 
Async(napi_env env,napi_callback_info info)139 napi_value ConnectDfs::Async(napi_env env, napi_callback_info info)
140 {
141     HILOGI("ConnectDfs::Async called");
142     ConnectDfsCB *connectDfsCB = CreateConnectDfsCBCBInfo(env);
143     if (connectDfsCB == nullptr) {
144         NError(E_PARAMS).ThrowErr(env);
145         return nullptr;
146     }
147     NFuncArg funcArg(env, info);
148     auto result = ParseJsParam(env, funcArg, connectDfsCB);
149     if (result != ERRNO_NOERR) {
150         NError(result).ThrowErr(env);
151         delete connectDfsCB;
152         connectDfsCB = nullptr;
153         return nullptr;
154     }
155 
156     napi_value ret = nullptr;
157     napi_status status = napi_create_promise(env, &connectDfsCB->cbBase.deferred, &ret);
158     if (status != napi_ok) {
159         HILOGE("INNER BUG. Cannot create promise for %{public}d", status);
160         delete connectDfsCB;
161         connectDfsCB = nullptr;
162         return nullptr;
163     }
164 
165     status = napi_create_async_work(env, nullptr, NVal::CreateUTF8String(env, "ResourceName").val_,
166         cbExec, cbCompl, static_cast<void *>(connectDfsCB), &connectDfsCB->cbBase.asyncWork);
167     if (status != napi_ok) {
168         HILOGE("INNER BUG. Failed to create async work for %{public}d", status);
169         delete connectDfsCB;
170         connectDfsCB = nullptr;
171         return nullptr;
172     }
173 
174     status = napi_queue_async_work(env, connectDfsCB->cbBase.asyncWork);
175     if (status != napi_ok) {
176         HILOGE("INNER BUG. Failed to queue async work for %{public}d", status);
177         delete connectDfsCB;
178         connectDfsCB = nullptr;
179         return nullptr;
180     }
181 
182     if (ret == nullptr) {
183         HILOGE("napi_async_work ret = nullptr");
184         NError(E_PARAMS).ThrowErr(env);
185         return NVal::CreateUndefined(env).val_;
186     }
187     HILOGI("ConnectDfs end");
188     return ret;
189 }
190 
CheckAndGetParameters(ConnectDfsCB * connectDfsCB,napi_handle_scope * scope)191 ConnectDfsCB *CheckAndGetParameters(ConnectDfsCB *connectDfsCB, napi_handle_scope *scope)
192 {
193     HILOGI("ConnectDfsCB::CheckAndGetParameters GetParam called");
194 
195     if (connectDfsCB == nullptr) {
196         HILOGE("ConnectDfsCB, GetParam connectDfsCB is null");
197         return nullptr;
198     }
199     napi_open_handle_scope(connectDfsCB->cbBase.cbInfo.env, scope);
200     if (scope == nullptr) {
201         delete connectDfsCB;
202         connectDfsCB = nullptr;
203         return nullptr;
204     }
205     HILOGI("ConnectDfsCB::CheckAndGetParameters GetParam end");
206     return connectDfsCB;
207 }
208 
SetConnectDfsEnv(const napi_env & env)209 void NAPIDfsListener::SetConnectDfsEnv(const napi_env &env)
210 {
211     env_ = env;
212 }
213 
SetConnectDfsCBRef(const napi_ref & ref)214 void NAPIDfsListener::SetConnectDfsCBRef(const napi_ref &ref)
215 {
216     onStatusRef_ = ref;
217 }
218 
SetConnectDfsPromiseRef(const napi_deferred & promiseDeferred)219 void NAPIDfsListener::SetConnectDfsPromiseRef(const napi_deferred &promiseDeferred)
220 {
221     promiseDeferred_ = promiseDeferred;
222 }
223 
WrapInt32(napi_env & env,int32_t num,const std::string & paramName)224 napi_value WrapInt32(napi_env &env, int32_t num, const std::string &paramName)
225 {
226     HILOGI("WrapInt32 called");
227     napi_value jsObject = nullptr;
228     napi_create_object(env, &jsObject);
229     napi_value jsValue = nullptr;
230     HILOGD("WrapInt32 called. %{public}s = %{public}d", paramName.c_str(), num);
231     napi_create_int32(env, num, &jsValue);
232     napi_set_named_property(env, jsObject, paramName.c_str(), jsValue);
233 
234     return jsObject;
235 }
236 
WrapString(napi_env & env,const std::string & param,const std::string & paramName)237 napi_value WrapString(napi_env &env, const std::string &param, const std::string &paramName)
238 {
239     HILOGI("WrapString called");
240     napi_value jsValue = nullptr;
241     HILOGD("WrapString called. %{public}s = %{public}s", paramName.c_str(), param.c_str());
242     napi_create_string_utf8(env, param.c_str(), NAPI_AUTO_LENGTH, &jsValue);
243 
244     return jsValue;
245 }
246 
UvWorkAfterOnStaus(ConnectDfsCB * connectDfsCB)247 void UvWorkAfterOnStaus(ConnectDfsCB *connectDfsCB)
248 {
249     HILOGI("UvWorkAfterOnStaus called");
250     napi_handle_scope scope = nullptr;
251     connectDfsCB = CheckAndGetParameters(connectDfsCB, &scope);
252     if (connectDfsCB == nullptr) {
253         return;
254     }
255     HILOGI("UvWorkAfterOnStaus, status = %{public}d", connectDfsCB->status);
256 
257     napi_value result[NARG_CNT::TWO] = {nullptr};
258     result[NARG_POS::FIRST] = WrapString(connectDfsCB->cbBase.cbInfo.env, connectDfsCB->networkId.c_str(), "networkId");
259     result[NARG_POS::SECOND] = WrapInt32(connectDfsCB->cbBase.cbInfo.env, connectDfsCB->status, "status");
260     if (connectDfsCB->cbBase.deferred == nullptr) {
261         napi_value callback = nullptr;
262         napi_value undefined = nullptr;
263         napi_get_undefined(connectDfsCB->cbBase.cbInfo.env, &undefined);
264         napi_value callResult = nullptr;
265         napi_get_reference_value(connectDfsCB->cbBase.cbInfo.env,
266             connectDfsCB->cbBase.cbInfo.callback, &callback);
267         napi_call_function(connectDfsCB->cbBase.cbInfo.env, undefined, callback, NARG_CNT::TWO, result, &callResult);
268         if (connectDfsCB->cbBase.cbInfo.callback != nullptr) {
269             napi_delete_reference(connectDfsCB->cbBase.cbInfo.env, connectDfsCB->cbBase.cbInfo.callback);
270         }
271     } else {
272         napi_value res[NARG_CNT::TWO] = { nullptr };
273         napi_get_undefined(connectDfsCB->cbBase.cbInfo.env, &res[NARG_POS::SECOND]);
274         if (connectDfsCB->status == ERRNO_NOERR) {
275             napi_resolve_deferred(connectDfsCB->cbBase.cbInfo.env,
276                 connectDfsCB->cbBase.deferred, res[NARG_POS::SECOND]);
277         } else {
278             res[NARG_POS::FIRST] = NError(connectDfsCB->status).GetNapiErr(connectDfsCB->cbBase.cbInfo.env);
279             napi_reject_deferred(connectDfsCB->cbBase.cbInfo.env, connectDfsCB->cbBase.deferred, res[NARG_POS::FIRST]);
280         }
281     }
282 
283     napi_close_handle_scope(connectDfsCB->cbBase.cbInfo.env, scope);
284     delete connectDfsCB;
285     connectDfsCB = nullptr;
286     HILOGI("UvWorkAfterOnStaus end");
287 }
288 
OnStatus(const std::string & networkId,int32_t status)289 void NAPIDfsListener::OnStatus(const std::string &networkId, int32_t status)
290 {
291     HILOGI("NAPIDfsListener::OnStatus called");
292 
293     auto connectDfsCB = new (std::nothrow) ConnectDfsCB;
294     if (connectDfsCB == nullptr) {
295         HILOGE("NAPIDfsListener::OnStatus, connectDfsCb == nullptr");
296         return;
297     }
298     connectDfsCB->cbBase.cbInfo.env = env_;
299     if (onStatusRef_ != nullptr) {
300         connectDfsCB->cbBase.cbInfo.callback = onStatusRef_;
301     } else {
302         connectDfsCB->cbBase.deferred = promiseDeferred_;
303     }
304     connectDfsCB->networkId = networkId;
305     connectDfsCB->status = status;
306 
307     auto task = [connectDfsCB] () {
308         UvWorkAfterOnStaus(connectDfsCB);
309     };
310     auto rev = napi_send_event(env_, task, napi_eprio_immediate);
311     if (rev != ERRNO_NOERR) {
312         delete connectDfsCB;
313         connectDfsCB = nullptr;
314     }
315     HILOGI("NAPIDfsListener::OnStatus end");
316 }
317 
318 } // namespace ModuleFileIO
319 } // namespace FileManagement
320 } // namespace OHOS