1 /*
2 * Copyright (c) 2022 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 <mutex>
17 #include "napi_base_context.h"
18 #include "napi_print_utils.h"
19 #include "print_async_call.h"
20 #include "print_log.h"
21 #include "print_manager_client.h"
22 #include "print_task.h"
23 #include "napi_print_task.h"
24 #include "print_attributes_helper.h"
25 #include "print_callback.h"
26 #include "iprint_callback.h"
27
28 static constexpr const char *FUNCTION_ON = "on";
29 static constexpr const char *FUNCTION_OFF = "off";
30
31 namespace OHOS::Print {
32 __thread napi_ref NapiPrintTask::globalCtor = nullptr;
33 std::mutex g_printTaskMutex;
34
Print(napi_env env,napi_callback_info info)35 napi_value NapiPrintTask::Print(napi_env env, napi_callback_info info)
36 {
37 napi_value argv[NapiPrintUtils::MAX_ARGC] = { nullptr };
38 size_t paramCount = NapiPrintUtils::GetJsVal(env, info, argv, NapiPrintUtils::MAX_ARGC);
39 napi_valuetype type;
40 PRINT_CALL(env, napi_typeof(env, argv[0], &type));
41 if ((paramCount > NapiPrintUtils::ARGC_THREE) && type == napi_string) {
42 return PrintByAdapter(env, info);
43 }
44
45 auto context = std::make_shared<PrintTaskContext>();
46 auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
47 PRINT_ASSERT_BASE(env, argc == NapiPrintUtils::ARGC_ONE || argc == NapiPrintUtils::ARGC_TWO,
48 "need 1 or 2 parameter!", napi_invalid_arg);
49 napi_status checkStatus = VerifyParameters(env, argc, argv, context);
50 if (checkStatus != napi_ok) {
51 return checkStatus;
52 }
53
54 napi_value proxy = nullptr;
55 napi_status status = napi_new_instance(env, GetCtor(env), argc, argv, &proxy);
56 if ((proxy == nullptr) || (status != napi_ok)) {
57 PRINT_HILOGE("Failed to create print task");
58 context->SetErrorIndex(E_PRINT_GENERIC_FAILURE);
59 return napi_generic_failure;
60 }
61
62 PrintTask *task;
63 PRINT_CALL_BASE(env, napi_unwrap(env, proxy, reinterpret_cast<void **>(&task)), napi_invalid_arg);
64 uint32_t ret = E_PRINT_GENERIC_FAILURE;
65 if (task != nullptr) {
66 ret = task->Start();
67 }
68 if (ret != E_PRINT_NONE) {
69 PRINT_HILOGE("Failed to start print task");
70 context->SetErrorIndex(ret);
71 return napi_generic_failure;
72 }
73 napi_create_reference(env, proxy, 1, &(context->ref));
74 return napi_ok;
75 };
76 auto output = [context](napi_env env, napi_value *result) -> napi_status {
77 if (context->ref == nullptr) {
78 *result = NapiPrintUtils::GetUndefined(env);
79 return napi_generic_failure;
80 }
81 napi_status status = napi_get_reference_value(env, context->ref, result);
82 napi_delete_reference(env, context->ref);
83 return status;
84 };
85 context->SetAction(std::move(input), std::move(output));
86 PrintAsyncCall asyncCall(env, info, std::dynamic_pointer_cast<PrintAsyncCall::Context>(context));
87 return asyncCall.Call(env);
88 }
89
PrintByAdapter(napi_env env,napi_callback_info info)90 napi_value NapiPrintTask::PrintByAdapter(napi_env env, napi_callback_info info)
91 {
92 PRINT_HILOGI("PrintByAdapter start ---->");
93 auto context = std::make_shared<PrintTaskContext>();
94 auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
95 PRINT_ASSERT_BASE(env, argc == NapiPrintUtils::ARGC_FOUR, "need 4 parameter!", napi_invalid_arg);
96 napi_status checkStatus = VerifyParameters(env, argc, argv, context);
97 if (checkStatus != napi_ok) {
98 return checkStatus;
99 }
100
101 napi_value proxy = nullptr;
102 napi_status status = napi_new_instance(env, GetCtor(env), argc, argv, &proxy);
103 if ((proxy == nullptr) || (status != napi_ok)) {
104 PRINT_HILOGE("Failed to create print task");
105 context->SetErrorIndex(E_PRINT_GENERIC_FAILURE);
106 return napi_generic_failure;
107 }
108
109 PrintTask *task;
110 PRINT_CALL_BASE(env, napi_unwrap(env, proxy, reinterpret_cast<void **>(&task)), napi_invalid_arg);
111 uint32_t ret = E_PRINT_GENERIC_FAILURE;
112 if (task != nullptr) {
113 ret = task->StartPrintAdapter();
114 }
115 if (ret != E_PRINT_NONE) {
116 PRINT_HILOGE("Failed to start print task");
117 context->SetErrorIndex(ret);
118 return napi_generic_failure;
119 }
120 napi_create_reference(env, proxy, 1, &(context->ref));
121 return napi_ok;
122 };
123 auto output = [context](napi_env env, napi_value *result) -> napi_status {
124 if (context->ref == nullptr) {
125 *result = NapiPrintUtils::GetUndefined(env);
126 return napi_generic_failure;
127 }
128 napi_status status = napi_get_reference_value(env, context->ref, result);
129 napi_delete_reference(env, context->ref);
130 return status;
131 };
132 context->SetAction(std::move(input), std::move(output));
133 PrintAsyncCall asyncCall(env, info, std::dynamic_pointer_cast<PrintAsyncCall::Context>(context));
134 return asyncCall.Call(env);
135 }
136
ParsePrintAdapterParameter(napi_env env,size_t argc,napi_value * argv,napi_value self)137 napi_value NapiPrintTask::ParsePrintAdapterParameter(napi_env env, size_t argc, napi_value *argv, napi_value self)
138 {
139 if (argc > NapiPrintUtils::ARGC_THREE && argc > NapiPrintUtils::ARGC_TWO) {
140 std::string printJobName = NapiPrintUtils::GetStringFromValueUtf8(env, argv[0]);
141
142 std::shared_ptr<PrintAttributes> printAttributes =
143 PrintAttributesHelper::BuildFromJs(env, argv[NapiPrintUtils::ARGC_TWO]);
144 if (printAttributes == nullptr) {
145 PRINT_HILOGE("printAdapter parameter error");
146 return nullptr;
147 }
148
149 napi_ref adapterRef = NapiPrintUtils::CreateReference(env, argv[1]);
150 sptr<IPrintCallback> callback = new (std::nothrow) PrintCallback(env, adapterRef);
151 if (callback == nullptr) {
152 PRINT_HILOGE("callback parameter error");
153 return nullptr;
154 }
155
156 std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext;
157 sptr<IRemoteObject> callerToken = nullptr;
158 if (GetAbilityContext(env, argv[NapiPrintUtils::ARGC_THREE], abilityContext) != nullptr) {
159 callerToken = abilityContext->GetToken();
160 }
161 auto task = new (std::nothrow) PrintTask(printJobName, callback, printAttributes, callerToken);
162
163 if (task == nullptr) {
164 PRINT_HILOGE("print task fail");
165 return nullptr;
166 }
167 auto finalize = [](napi_env env, void *data, void *hint) {
168 PRINT_HILOGD("destructed print task");
169 PrintTask *task = reinterpret_cast<PrintTask *>(data);
170 delete task;
171 };
172 if (napi_wrap(env, self, task, finalize, nullptr, nullptr) != napi_ok) {
173 finalize(env, task, nullptr);
174 return nullptr;
175 }
176 PRINT_HILOGD("Succeed to allocate print task");
177 return self;
178 }
179 return nullptr;
180 }
181
GetAbilityContext(napi_env env,napi_value value,std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> & abilityContext)182 napi_value NapiPrintTask::GetAbilityContext(
183 napi_env env, napi_value value, std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> &abilityContext)
184 {
185 bool stageMode = false;
186 napi_status status = OHOS::AbilityRuntime::IsStageContext(env, value, stageMode);
187 if (status != napi_ok || !stageMode) {
188 PRINT_HILOGE("GetAbilityContext it is not a stage mode");
189 return nullptr;
190 } else {
191 auto context = OHOS::AbilityRuntime::GetStageModeContext(env, value);
192 if (context == nullptr) {
193 PRINT_HILOGE("GetAbilityContext get context failed");
194 return nullptr;
195 }
196 abilityContext = OHOS::AbilityRuntime::Context::ConvertTo<OHOS::AbilityRuntime::AbilityContext>(context);
197 if (abilityContext == nullptr) {
198 PRINT_HILOGE("GetAbilityContext get Stage model ability context failed.");
199 return nullptr;
200 }
201 return WrapVoidToJS(env);
202 }
203 }
204
WrapVoidToJS(napi_env env)205 napi_value NapiPrintTask::WrapVoidToJS(napi_env env)
206 {
207 napi_value result = nullptr;
208 NAPI_CALL(env, napi_get_null(env, &result));
209 return result;
210 }
211
GetCtor(napi_env env)212 napi_value NapiPrintTask::GetCtor(napi_env env)
213 {
214 std::lock_guard<std::mutex> lock(g_printTaskMutex);
215 napi_value cons;
216 if (globalCtor != nullptr) {
217 PRINT_CALL(env, napi_get_reference_value(env, globalCtor, &cons));
218 return cons;
219 }
220
221 napi_property_descriptor clzDes[] = {
222 { FUNCTION_ON, 0, PrintTask::On, 0, 0, 0, napi_default, 0 },
223 { FUNCTION_OFF, 0, PrintTask::Off, 0, 0, 0, napi_default, 0 },
224 };
225 PRINT_CALL(env, napi_define_class(env, "NapiPrintTask", NAPI_AUTO_LENGTH, Initialize, nullptr,
226 sizeof(clzDes) / sizeof(napi_property_descriptor), clzDes, &cons));
227 PRINT_CALL(env, napi_create_reference(env, cons, 1, &globalCtor));
228 return cons;
229 }
230
Initialize(napi_env env,napi_callback_info info)231 napi_value NapiPrintTask::Initialize(napi_env env, napi_callback_info info)
232 {
233 PRINT_HILOGD("constructor print task!");
234 napi_value self = nullptr;
235 size_t argc = NapiPrintUtils::MAX_ARGC;
236 napi_value argv[NapiPrintUtils::MAX_ARGC] = { nullptr };
237 PRINT_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr));
238
239 if (argc > NapiPrintUtils::ARGC_THREE) {
240 return ParsePrintAdapterParameter(env, argc, argv, self);
241 } else {
242 std::vector<std::string> printfiles;
243 uint32_t arrayReLength = 0;
244 PRINT_CALL(env, napi_get_array_length(env, argv[0], &arrayReLength));
245 for (uint32_t index = 0; index < arrayReLength; index++) {
246 napi_value filesValue;
247 napi_get_element(env, argv[0], index, &filesValue);
248 std::string files = NapiPrintUtils::GetStringFromValueUtf8(env, filesValue);
249 PRINT_HILOGD("file[%{public}d] %{private}s.", index, files.c_str());
250 if (IsValidFile(files)) {
251 printfiles.emplace_back(files);
252 }
253 }
254
255 std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext;
256 sptr<IRemoteObject> callerToken;
257 if (argc == NapiPrintUtils::ARGC_TWO && GetAbilityContext(env, argv[1], abilityContext) != nullptr) {
258 callerToken = abilityContext->GetToken();
259 PRINT_HILOGI("get callerToken:%{public}s", callerToken != nullptr ? "success" : "failed");
260 }
261 auto task = new (std::nothrow) PrintTask(printfiles, callerToken);
262 if (task == nullptr) {
263 PRINT_HILOGE("print task fail");
264 return nullptr;
265 }
266 auto finalize = [](napi_env env, void *data, void *hint) {
267 PRINT_HILOGD("destructed print task");
268 PrintTask *task = reinterpret_cast<PrintTask *>(data);
269 delete task;
270 };
271 if (napi_wrap(env, self, task, finalize, nullptr, nullptr) != napi_ok) {
272 finalize(env, task, nullptr);
273 return nullptr;
274 }
275 PRINT_HILOGD("Succeed to allocate print task");
276 return self;
277 }
278 }
279
IsValidFile(const std::string & fileName)280 bool NapiPrintTask::IsValidFile(const std::string &fileName)
281 {
282 if (fileName == "") {
283 PRINT_HILOGE("invalid file name");
284 return false;
285 }
286 auto file = fopen(fileName.c_str(), "rb");
287 if (file != nullptr) {
288 fclose(file);
289 return true;
290 }
291 if (fileName.find("file://") == 0 || fileName.find("fd://") == 0) {
292 return true;
293 }
294 PRINT_HILOGE("invalid file name");
295 return false;
296 }
297
VerifyParameters(napi_env env,size_t argc,napi_value * argv,const std::shared_ptr<PrintTaskContext> context)298 napi_status NapiPrintTask::VerifyParameters(napi_env env, size_t argc, napi_value *argv,
299 const std::shared_ptr<PrintTaskContext> context)
300 {
301 if (argc > NapiPrintUtils::ARGC_THREE) {
302 std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext;
303 if (GetAbilityContext(env, argv[NapiPrintUtils::ARGC_THREE], abilityContext) == nullptr) {
304 PRINT_HILOGE("Print adapter Ability Context is null.");
305 context->SetErrorIndex(E_PRINT_INVALID_PARAMETER);
306 }
307 return napi_ok;
308 }
309
310 bool isFileArray = false;
311
312 napi_is_array(env, argv[0], &isFileArray);
313 PRINT_ASSERT_BASE(env, isFileArray == true, "parameter type isn't list", napi_invalid_arg);
314
315 uint32_t len = 0;
316 PRINT_CALL_BASE(env, napi_get_array_length(env, argv[0], &len), napi_invalid_arg);
317
318 if (!isFileArray || len == 0) {
319 context->SetErrorIndex(E_PRINT_INVALID_PARAMETER);
320 return napi_invalid_arg;
321 }
322
323 std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext;
324 if (argc == NapiPrintUtils::ARGC_TWO) {
325 if (GetAbilityContext(env, argv[1], abilityContext) == nullptr) {
326 PRINT_HILOGE("Print, Ability Context is null.");
327 }
328 }
329 return napi_ok;
330 }
331 } // namespace OHOS::Print
332