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 "sendfile_napi.h"
17
18 #include "filemgmt_libn.h"
19 #include "send_file.h"
20 #include "trans_event.h"
21 #include "utils_log.h"
22
23 namespace OHOS {
24 namespace Storage {
25 namespace DistributedFile {
26 using namespace FileManagement::LibN;
27
GetJsPath(napi_env env,napi_value param)28 std::vector<std::string> GetJsPath(napi_env env, napi_value param)
29 {
30 std::vector<std::string> jsPath;
31 jsPath.clear();
32
33 bool isArray = false;
34 if (napi_is_array(env, param, &isArray) != napi_ok || isArray == false) {
35 LOGE("JS sendFile filename must be a string array.");
36 return jsPath;
37 }
38
39 uint32_t arraySize = 0;
40 if (napi_get_array_length(env, param, &arraySize) != napi_ok) {
41 LOGE("JS sendFile get filename array size failed.");
42 return jsPath;
43 }
44 if (arraySize > 1) {
45 return jsPath;
46 }
47 for (uint32_t i = 0; i < arraySize; ++i) {
48 napi_value result = nullptr;
49 napi_status status = napi_get_element(env, param, i, &result);
50 if (status == napi_ok && result != nullptr) {
51 bool succ = false;
52 std::unique_ptr<char []> path;
53 std::tie(succ, path, std::ignore) = NVal(env, result).ToUTF8String();
54 if (succ) {
55 jsPath.push_back(path.get());
56 } else {
57 LOGE("JS sendFile: only string array were accepted as filename para.");
58 }
59 }
60 }
61 return jsPath;
62 }
63
JsSendFile(napi_env env,napi_callback_info info)64 napi_value JsSendFile(napi_env env, napi_callback_info info)
65 {
66 NFuncArg funcArg(env, info);
67 if (!funcArg.InitArgs(DFS_ARG_CNT::FOUR, DFS_ARG_CNT::FIVE)) {
68 NError(EINVAL).ThrowErr(env, "Number of arguments unmatched");
69 return nullptr;
70 }
71
72 bool succ = false;
73 std::unique_ptr<char []> deviceId;
74 std::tie(succ, deviceId, std::ignore) = NVal(env, funcArg[DFS_ARG_POS::FIRST]).ToUTF8String();
75 std::string deviceIdString = "";
76 if (succ) {
77 deviceIdString = std::string(deviceId.get());
78 }
79
80 uint32_t fileCount = 0;
81 napi_status status = napi_get_value_uint32(env, funcArg[DFS_ARG_POS::FOURTH], &fileCount);
82 if (status != napi_ok && fileCount != 1) {
83 LOGE("JS sendFile: param fileCounts only accecpt 1.");
84 return nullptr;
85 }
86
87 std::vector<std::string> sourPath = GetJsPath(env, funcArg[DFS_ARG_POS::SECOND]);
88 std::vector<std::string> destPath = GetJsPath(env, funcArg[DFS_ARG_POS::THIRD]);
89
90 auto resultCode = std::make_shared<int32_t>();
91 auto cbExec = [deviceIdString, sourPath, destPath, fileCount, resultCode]() -> NError {
92 *resultCode = SendFile::ExecSendFile(deviceIdString.c_str(), sourPath, destPath, fileCount);
93 return NError(*resultCode);
94 };
95
96 auto cbComplete = [resultCode](napi_env env, NError err) -> NVal {
97 if (err) {
98 return { env, err.GetNapiErr(env) };
99 }
100 return { NVal::CreateInt64(env, *resultCode) };
101 };
102
103 std::string procedureName = "SendFile";
104 NVal thisVar(env, funcArg.GetThisVar());
105 if (funcArg.GetArgc() == DFS_ARG_CNT::FOUR) {
106 return NAsyncWorkPromise(env, thisVar).Schedule(procedureName, cbExec, cbComplete).val_;
107 } else if (funcArg.GetArgc() == DFS_ARG_CNT::FIVE) {
108 NVal cb(env, funcArg[DFS_ARG_POS::FIFTH]);
109 return NAsyncWorkCallback(env, thisVar, cb).Schedule(procedureName, cbExec, cbComplete).val_;
110 }
111
112 return NVal::CreateUndefined(env).val_;
113 }
114
JsOn(napi_env env,napi_callback_info cbinfo)115 napi_value JsOn(napi_env env, napi_callback_info cbinfo)
116 {
117 size_t requireArgc = 2;
118 size_t argc = 2;
119 napi_value argv[2] = { 0 };
120 napi_value thisVar = 0;
121 void* data = nullptr;
122 napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, &data);
123
124 EventAgent* agent = nullptr;
125 napi_unwrap(env, thisVar, (void**)&agent);
126
127 NAPI_ASSERT(env, argc >= requireArgc, "requires 2 parameter");
128
129 napi_valuetype eventValueType = napi_undefined;
130 napi_typeof(env, argv[0], &eventValueType);
131 NAPI_ASSERT(env, eventValueType == napi_string, "type mismatch for parameter 1");
132
133 napi_valuetype eventHandleType = napi_undefined;
134 napi_typeof(env, argv[1], &eventHandleType);
135 NAPI_ASSERT(env, eventHandleType == napi_function, "type mismatch for parameter 2");
136
137 char type[64] = { 0 };
138 size_t typeLen = 0;
139
140 napi_get_value_string_utf8(env, argv[0], type, sizeof(type), &typeLen);
141
142 agent->On((const char*)type, argv[1]);
143
144 napi_value result = nullptr;
145 napi_get_undefined(env, &result);
146 return result;
147 }
148
JsOff(napi_env env,napi_callback_info cbinfo)149 napi_value JsOff(napi_env env, napi_callback_info cbinfo)
150 {
151 size_t requireArgc = 1;
152 size_t argc = 1;
153 napi_value argv[1] = { 0 };
154 napi_value thisVar = 0;
155 void* data = nullptr;
156 napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, &data);
157
158 EventAgent* agent = nullptr;
159 napi_unwrap(env, thisVar, (void**)&agent);
160
161 NAPI_ASSERT(env, argc == requireArgc, "requires 1 parameter");
162
163 napi_valuetype eventValueType = napi_undefined;
164 napi_typeof(env, argv[0], &eventValueType);
165 NAPI_ASSERT(env, eventValueType == napi_string, "type mismatch for parameter 1");
166
167 char* type = nullptr;
168 size_t typeLen = 0;
169 napi_get_value_string_utf8(env, argv[0], nullptr, 0, &typeLen);
170
171 NAPI_ASSERT(env, typeLen > 0, "typeLen == 0");
172 type = new char[typeLen + 1];
173
174 napi_get_value_string_utf8(env, argv[0], type, typeLen + 1, &typeLen);
175
176 agent->Off(type);
177
178 delete[] type;
179 napi_value result = nullptr;
180 napi_get_undefined(env, &result);
181 return result;
182 }
183
JsConstructor(napi_env env,napi_callback_info cbinfo)184 napi_value JsConstructor(napi_env env, napi_callback_info cbinfo)
185 {
186 size_t argc = 2;
187 napi_value argv[2] = { nullptr };
188 napi_value thisVar = nullptr;
189 napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, nullptr);
190
191 char bundleName[SendFile::SENDFILE_NAPI_BUF_LENGTH] = { 0 };
192 size_t typeLen = 0;
193 napi_get_value_string_utf8(env, argv[0], bundleName, sizeof(bundleName), &typeLen);
194 LOGI("JsConstructor. [%{public}s]", bundleName);
195
196 EventAgent* agent = new EventAgent(env, thisVar);
197 {
198 std::unique_lock<std::mutex> lock(SendFile::g_uidMutex);
199 if (SendFile::mapUidToEventAgent_.end() != SendFile::mapUidToEventAgent_.find(SendFile::BUNDLE_ID_)) {
200 delete SendFile::mapUidToEventAgent_[SendFile::BUNDLE_ID_];
201 SendFile::mapUidToEventAgent_.erase(SendFile::BUNDLE_ID_);
202 }
203 if (SendFile::mapUidToEventAgent_.size() <= SendFile::MAX_SEND_FILE_HAP_NUMBER) {
204 auto [ignored, inserted] = SendFile::mapUidToEventAgent_.insert(make_pair(SendFile::BUNDLE_ID_, agent));
205 if (!inserted) {
206 LOGE("map env to event agent error.");
207 return nullptr;
208 } else {
209 LOGI("map size %{public}d", SendFile::mapUidToEventAgent_.size());
210 }
211 }
212 }
213
214 napi_wrap(env, thisVar, agent,
215 [](napi_env env, void* data, void* hint) {
216 auto iter = SendFile::mapUidToEventAgent_.find(SendFile::BUNDLE_ID_);
217 if (SendFile::mapUidToEventAgent_.end() != iter) {
218 auto agent = (EventAgent*)data;
219 if (agent != nullptr) {
220 std::unique_lock<std::mutex> lock(SendFile::g_uidMutex);
221 agent->ClearDevice();
222 SendFile::mapUidToEventAgent_.erase(SendFile::BUNDLE_ID_);
223 delete agent;
224 }
225 }
226 },
227 nullptr, nullptr);
228
229 return thisVar;
230 }
231
232 /***********************************************
233 * Module export and register
234 ***********************************************/
SendFileExport(napi_env env,napi_value exports)235 napi_value SendFileExport(napi_env env, napi_value exports)
236 {
237 const char className[] = "SendFile";
238 static napi_property_descriptor desc[] = {
239 DECLARE_NAPI_FUNCTION("sendFile", JsSendFile),
240 DECLARE_NAPI_FUNCTION("on", JsOn),
241 DECLARE_NAPI_FUNCTION("off", JsOff),
242 };
243 napi_value sendFileClass = nullptr;
244
245 napi_define_class(env, className, sizeof(className), JsConstructor, nullptr,
246 sizeof(desc) / sizeof(desc[0]), desc, &sendFileClass);
247
248 napi_set_named_property(env, exports, "SendFile", sendFileClass);
249
250 SendFile::RegisterCallback();
251 return exports;
252 }
253
254 NAPI_MODULE(sendfile, SendFileExport)
255 } // namespace DistributedFile
256 } // namespace Storage
257 } // namespace OHOS