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 "print_callback.h"
17 #include "napi_print_utils.h"
18 #include "print_job_helper.h"
19 #include "printer_info_helper.h"
20 #include "print_attributes_helper.h"
21 #include "print_log.h"
22 
23 namespace OHOS::Print {
PrintCallback(napi_env env,napi_ref ref)24 PrintCallback::PrintCallback(napi_env env, napi_ref ref) : env_(env), ref_(ref), adapter_(nullptr)
25 {
26 }
27 
PrintCallback(PrintDocumentAdapter * adapter)28 PrintCallback::PrintCallback(PrintDocumentAdapter* adapter) : env_(nullptr), ref_(nullptr), adapter_(adapter)
29 {
30 }
31 
~PrintCallback()32 PrintCallback::~PrintCallback()
33 {
34     if (adapter_ != nullptr) {
35         delete adapter_;
36         adapter_ = nullptr;
37     } else if (nativePrinterChange_cb != nullptr) {
38         nativePrinterChange_cb = nullptr;
39     } else {
40         std::lock_guard<std::mutex> autoLock(mutex_);
41         PRINT_HILOGD("callback has been destroyed");
42 
43         uv_loop_s *loop = nullptr;
44         napi_get_uv_event_loop(env_, &loop);
45         Param *param = new (std::nothrow) Param;
46         if (param == nullptr) {
47             return;
48         }
49         param->env = env_;
50         param->callbackRef = ref_;
51         uv_work_t *work = new (std::nothrow) uv_work_t;
52         if (work == nullptr) {
53             delete param;
54             return;
55         }
56         work->data = reinterpret_cast<void*>(param);
57         int retVal = uv_queue_work(loop, work, [](uv_work_t *work) {}, [](uv_work_t *work, int _status) {
58             PRINT_HILOGD("uv_queue_work PrintCallback DeleteReference");
59             Param *param_ = reinterpret_cast<Param*>(work->data);
60             if (param_ == nullptr) {
61                 delete work;
62                 return;
63             }
64             napi_handle_scope scope = nullptr;
65             napi_open_handle_scope(param_->env, &scope);
66             if (scope == nullptr) {
67                 delete param_;
68                 delete work;
69                 return;
70             }
71             napi_ref callbackRef_ = param_->callbackRef;
72             NapiPrintUtils::DeleteReference(param_->env, callbackRef_);
73             napi_close_handle_scope(param_->env, scope);
74             delete param_;
75             delete work;
76         });
77         if (retVal != 0) {
78             PRINT_HILOGE("Failed to get uv_queue_work.");
79             delete param;
80             delete work;
81             return;
82         }
83     }
84 }
85 
InitUvWorkCallbackEnv(uv_work_t * work,napi_handle_scope & scope)86 static bool InitUvWorkCallbackEnv(uv_work_t *work, napi_handle_scope &scope)
87 {
88     if (work == nullptr) {
89         PRINT_HILOGE("work is nullptr");
90         return false;
91     }
92     if (work->data == nullptr) {
93         PRINT_HILOGE("data is nullptr");
94         delete work;
95         work = nullptr;
96         return false;
97     }
98     CallbackParam *cbParam = reinterpret_cast<CallbackParam *>(work->data);
99     napi_open_handle_scope(cbParam->env, &scope);
100     if (scope == nullptr) {
101         PRINT_HILOGE("fail to open scope");
102         delete cbParam;
103         cbParam = nullptr;
104         delete work;
105         work = nullptr;
106         return false;
107     }
108     return true;
109 }
110 
PrintTaskAfterCallFun(uv_work_t * work,int status)111 static void PrintTaskAfterCallFun(uv_work_t *work, int status)
112 {
113     PRINT_HILOGI("OnCallback start run PrintTaskAfterCallFun");
114     napi_handle_scope scope = nullptr;
115     if (!InitUvWorkCallbackEnv(work, scope)) {
116         return;
117     }
118     CallbackParam *cbParam = static_cast<CallbackParam*>(work->data);
119     if (cbParam != nullptr) {
120         std::lock_guard<std::mutex> autoLock(*cbParam->mutexPtr);
121         napi_value callbackFunc = NapiPrintUtils::GetReference(cbParam->env, cbParam->ref);
122         napi_value callbackResult = nullptr;
123         napi_value callbackValues[NapiPrintUtils::ARGC_ONE] = { 0 };
124         callbackValues[0] = NapiPrintUtils::GetUndefined(cbParam->env);
125         napi_call_function(cbParam->env, nullptr, callbackFunc, NapiPrintUtils::ARGC_ZERO,
126             callbackValues, &callbackResult);
127         napi_close_handle_scope(cbParam->env, scope);
128         PRINT_HILOGI("OnCallback end run PrintTaskAfterCallFun success");
129         delete cbParam;
130         cbParam = nullptr;
131     }
132     if (work != nullptr) {
133         delete work;
134         work = nullptr;
135     }
136 }
137 
PrinterAfterCallFun(uv_work_t * work,int status)138 static void PrinterAfterCallFun(uv_work_t *work, int status)
139 {
140     PRINT_HILOGI("OnCallback start run PrinterAfterCallFun");
141     napi_handle_scope scope = nullptr;
142     if (!InitUvWorkCallbackEnv(work, scope)) {
143         return;
144     }
145     CallbackParam *cbParam = static_cast<CallbackParam*>(work->data);
146     if (cbParam != nullptr) {
147         std::lock_guard<std::mutex> autoLock(*cbParam->mutexPtr);
148         napi_value callbackFunc = NapiPrintUtils::GetReference(cbParam->env, cbParam->ref);
149         napi_value callbackResult = nullptr;
150         napi_value callbackValues[NapiPrintUtils::ARGC_TWO] = { 0 };
151         callbackValues[0] = NapiPrintUtils::CreateUint32(cbParam->env, cbParam->state);
152         callbackValues[1] = PrinterInfoHelper::MakeJsObject(cbParam->env, cbParam->printerInfo);
153         napi_call_function(cbParam->env, nullptr, callbackFunc, NapiPrintUtils::ARGC_TWO,
154             callbackValues, &callbackResult);
155         napi_close_handle_scope(cbParam->env, scope);
156         PRINT_HILOGI("OnCallback end run PrinterAfterCallFun success");
157         delete cbParam;
158         cbParam = nullptr;
159     }
160     if (work != nullptr) {
161         delete work;
162         work = nullptr;
163     }
164 }
165 
PrintJobAfterCallFun(uv_work_t * work,int status)166 static void PrintJobAfterCallFun(uv_work_t *work, int status)
167 {
168     PRINT_HILOGI("OnCallback start run PrintJobAfterCallFun");
169     napi_handle_scope scope = nullptr;
170     if (!InitUvWorkCallbackEnv(work, scope)) {
171         return;
172     }
173     CallbackParam *cbParam = static_cast<CallbackParam*>(work->data);
174     if (cbParam != nullptr) {
175         std::lock_guard<std::mutex> autoLock(*cbParam->mutexPtr);
176         napi_value callbackFunc = NapiPrintUtils::GetReference(cbParam->env, cbParam->ref);
177         napi_value callbackResult = nullptr;
178         napi_value callbackValues[NapiPrintUtils::ARGC_TWO] = { 0 };
179         callbackValues[0] = NapiPrintUtils::CreateUint32(cbParam->env, cbParam->state);
180         callbackValues[1] = cbParam->jobInfo.GetPrinterId().length() == 0
181             ? PrintJobHelper::MakeJsSimpleObject(cbParam->env, cbParam->jobInfo)
182             : PrintJobHelper::MakeJsObject(cbParam->env, cbParam->jobInfo);
183         napi_call_function(cbParam->env, nullptr, callbackFunc, NapiPrintUtils::ARGC_TWO,
184             callbackValues, &callbackResult);
185         napi_close_handle_scope(cbParam->env, scope);
186         PRINT_HILOGI("OnCallback end run PrintJobAfterCallFun success");
187         delete cbParam;
188         cbParam = nullptr;
189     }
190     if (work != nullptr) {
191         delete work;
192         work = nullptr;
193     }
194 }
195 
ExtensionAfterCallFun(uv_work_t * work,int status)196 static void ExtensionAfterCallFun(uv_work_t *work, int status)
197 {
198     PRINT_HILOGI("OnCallback start run ExtensionAfterCallFun");
199     napi_handle_scope scope = nullptr;
200     if (!InitUvWorkCallbackEnv(work, scope)) {
201         return;
202     }
203     CallbackParam *cbParam = static_cast<CallbackParam*>(work->data);
204     if (cbParam != nullptr) {
205         std::lock_guard<std::mutex> autoLock(*cbParam->mutexPtr);
206         napi_value callbackFunc = NapiPrintUtils::GetReference(cbParam->env, cbParam->ref);
207         napi_value callbackResult = nullptr;
208         napi_value callbackValues[NapiPrintUtils::ARGC_TWO] = { 0 };
209         callbackValues[0] =
210             NapiPrintUtils::CreateStringUtf8(cbParam->env, cbParam->extensionId);
211         callbackValues[1] =
212             NapiPrintUtils::CreateStringUtf8(cbParam->env, cbParam->info);
213         napi_call_function(cbParam->env, nullptr, callbackFunc, NapiPrintUtils::ARGC_TWO,
214             callbackValues, &callbackResult);
215         napi_close_handle_scope(cbParam->env, scope);
216         PRINT_HILOGI("OnCallback end run ExtensionAfterCallFun success");
217         delete cbParam;
218         cbParam = nullptr;
219     }
220     if (work != nullptr) {
221         delete work;
222         work = nullptr;
223     }
224 }
225 
PrintAdapterAfterCallFun(uv_work_t * work,int status)226 static void PrintAdapterAfterCallFun(uv_work_t *work, int status)
227 {
228     PRINT_HILOGI("OnCallback start run PrintAdapterAfterCallFun");
229     napi_handle_scope scope = nullptr;
230     if (!InitUvWorkCallbackEnv(work, scope)) {
231         return;
232     }
233     CallbackParam *cbParam = static_cast<CallbackParam*>(work->data);
234     if (cbParam != nullptr) {
235         std::lock_guard<std::mutex> autoLock(*cbParam->mutexPtr);
236         napi_value adapterObj = NapiPrintUtils::GetReference(cbParam->env, cbParam->ref);
237 
238         napi_value layoutWriteFunc = NapiPrintUtils::GetNamedProperty(cbParam->env, adapterObj, "onStartLayoutWrite");
239         auto successCallback = [](napi_env env, napi_callback_info info) -> napi_value {
240             PRINT_HILOGI("parse from js callback data start");
241             size_t argc = NapiPrintUtils::ARGC_TWO;
242             napi_value args[NapiPrintUtils::ARGC_TWO] = {nullptr};
243 
244             napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
245             std::string jobId = NapiPrintUtils::GetStringFromValueUtf8(env, args[0]);
246             uint32_t replyState = NapiPrintUtils::GetUint32FromValue(env, args[1]);
247 
248             PrintManagerClient::GetInstance()->UpdatePrintJobStateForNormalApp(
249                 jobId, PRINT_JOB_CREATE_FILE_COMPLETED, replyState);
250             PRINT_HILOGI("from js return jobId:%{public}s, replyState:%{public}d", jobId.c_str(), replyState);
251             return nullptr;
252         };
253 
254         napi_value callbackResult = nullptr;
255         napi_value callbackValues[NapiPrintUtils::ARGC_FIVE] = { 0 };
256         callbackValues[0] = NapiPrintUtils::CreateStringUtf8(cbParam->env, cbParam->jobId);
257         callbackValues[1] = PrintAttributesHelper::MakeJsObject(cbParam->env, cbParam->oldAttrs);
258         callbackValues[NapiPrintUtils::ARGC_TWO] =
259             PrintAttributesHelper::MakeJsObject(cbParam->env, cbParam->newAttrs);
260         callbackValues[NapiPrintUtils::ARGC_THREE] =
261             NapiPrintUtils::CreateUint32(cbParam->env, cbParam->fd);
262         callbackValues[NapiPrintUtils::ARGC_FOUR] =
263             NapiPrintUtils::CreateFunction(cbParam->env, "writeResultCallback", successCallback, nullptr);
264 
265         napi_call_function(cbParam->env, adapterObj, layoutWriteFunc, NapiPrintUtils::ARGC_FIVE,
266             callbackValues, &callbackResult);
267 
268         napi_close_handle_scope(cbParam->env, scope);
269         PRINT_HILOGI("OnCallback end run PrintAdapterAfterCallFun success");
270         delete cbParam;
271         cbParam = nullptr;
272     }
273     if (work != nullptr) {
274         delete work;
275         work = nullptr;
276     }
277 }
278 
PrintAdapterJobStateChangedAfterCallFun(uv_work_t * work,int status)279 static void PrintAdapterJobStateChangedAfterCallFun(uv_work_t *work, int status)
280 {
281     PRINT_HILOGI("OnCallback start run PrintAdapterJobStateChangedAfterCallFun");
282     napi_handle_scope scope = nullptr;
283     if (!InitUvWorkCallbackEnv(work, scope)) {
284         return;
285     }
286     CallbackParam *cbParam = static_cast<CallbackParam*>(work->data);
287     if (cbParam != nullptr) {
288         std::lock_guard<std::mutex> autoLock(*cbParam->mutexPtr);
289         napi_value adapterObj = NapiPrintUtils::GetReference(cbParam->env, cbParam->ref);
290 
291         napi_value jobStateChangedFunc = NapiPrintUtils::GetNamedProperty(cbParam->env, adapterObj,
292             "onJobStateChanged");
293 
294         napi_value callbackResult = nullptr;
295         napi_value callbackValues[NapiPrintUtils::ARGC_TWO] = { 0 };
296         callbackValues[0] = NapiPrintUtils::CreateStringUtf8(cbParam->env, cbParam->jobId);
297         callbackValues[1] = NapiPrintUtils::CreateUint32(cbParam->env, cbParam->state);
298 
299         napi_call_function(cbParam->env, adapterObj, jobStateChangedFunc, NapiPrintUtils::ARGC_TWO,
300             callbackValues, &callbackResult);
301 
302         napi_close_handle_scope(cbParam->env, scope);
303         PRINT_HILOGI("OnCallback end run PrintAdapterJobStateChangedAfterCallFun success");
304         delete cbParam;
305         cbParam = nullptr;
306     }
307     if (work != nullptr) {
308         delete work;
309         work = nullptr;
310     }
311 }
312 
PrintAdapterGetFileAfterCallFun(uv_work_t * work,int status)313 static void PrintAdapterGetFileAfterCallFun(uv_work_t *work, int status)
314 {
315     PRINT_HILOGI("OnCallback start run PrintAdapterGetFileAfterCallFun");
316     napi_handle_scope scope = nullptr;
317     if (!InitUvWorkCallbackEnv(work, scope)) {
318         return;
319     }
320     CallbackParam *cbParam = static_cast<CallbackParam*>(work->data);
321     if (cbParam != nullptr) {
322         std::lock_guard<std::mutex> autoLock(*cbParam->mutexPtr);
323         napi_value callbackFunc = NapiPrintUtils::GetReference(cbParam->env, cbParam->ref);
324         napi_value callbackResult = nullptr;
325         napi_value callbackValues[1] = { 0 };
326         callbackValues[0] = NapiPrintUtils::CreateUint32(cbParam->env, cbParam->state);
327         napi_call_function(cbParam->env, nullptr, callbackFunc, 1,
328             callbackValues, &callbackResult);
329         napi_close_handle_scope(cbParam->env, scope);
330         PRINT_HILOGI("OnCallback end run PrintAdapterGetFileAfterCallFun success");
331         delete cbParam;
332         cbParam = nullptr;
333     }
334     if (work != nullptr) {
335         delete work;
336         work = nullptr;
337     }
338 }
339 
onBaseCallback(std::function<void (CallbackParam *)> paramFun,uv_after_work_cb after_work_cb)340 bool PrintCallback::onBaseCallback(std::function<void(CallbackParam*)> paramFun, uv_after_work_cb after_work_cb)
341 {
342     uv_loop_s *loop = nullptr;
343     napi_get_uv_event_loop(env_, &loop);
344     if (loop == nullptr) {
345         PRINT_HILOGE("Failed to get uv event loop");
346         return false;
347     }
348 
349     uv_work_t *work = new (std::nothrow) uv_work_t;
350     if (work == nullptr) {
351         PRINT_HILOGE("Failed to create uv work");
352         return false;
353     }
354     CallbackParam *param = new (std::nothrow) CallbackParam;
355     if (param == nullptr) {
356         PRINT_HILOGE("Failed to create callback parameter");
357         delete work;
358         return false;
359     } else {
360         std::lock_guard<std::mutex> lock(mutex_);
361 
362         param->env = env_;
363         param->ref = ref_;
364         param->mutexPtr = &mutex_;
365 
366         paramFun(param);
367     }
368 
369     work->data = param;
370     int retVal = uv_queue_work(loop, work, [](uv_work_t *work) {}, after_work_cb);
371     if (retVal != 0) {
372         PRINT_HILOGE("Failed to get uv_queue_work.");
373         delete param;
374         delete work;
375         return false;
376     }
377     return true;
378 }
379 
OnCallback()380 bool PrintCallback::OnCallback()
381 {
382     PRINT_HILOGI("PrintTask Notification in");
383     return onBaseCallback([](CallbackParam* param) {}, PrintTaskAfterCallFun);
384 }
385 
OnCallback(uint32_t state,const PrinterInfo & info)386 bool PrintCallback::OnCallback(uint32_t state, const PrinterInfo &info)
387 {
388     PRINT_HILOGI("Printer Notification in");
389     if (nativePrinterChange_cb != nullptr) {
390         return nativePrinterChange_cb(state, info);
391     }
392     return onBaseCallback(
393         [state, info](CallbackParam* param) {
394             param->state = state;
395             param->printerInfo = info;
396         }, PrinterAfterCallFun);
397 }
398 
OnCallback(uint32_t state,const PrintJob & info)399 bool PrintCallback::OnCallback(uint32_t state, const PrintJob &info)
400 {
401     PRINT_HILOGI("PrintJob Notification in");
402     return onBaseCallback(
403         [state, info](CallbackParam* param) {
404             param->state = state;
405             param->jobInfo = info;
406         }, PrintJobAfterCallFun);
407 }
408 
OnCallback(const std::string & extensionId,const std::string & info)409 bool PrintCallback::OnCallback(const std::string &extensionId, const std::string &info)
410 {
411     PRINT_HILOGI("ExtensionInfo Notification in");
412     return onBaseCallback(
413         [extensionId, info](CallbackParam* param) {
414             param->extensionId = extensionId;
415             param->info = info;
416         }, ExtensionAfterCallFun);
417 }
418 
OnCallbackAdapterLayout(const std::string & jobId,const PrintAttributes & oldAttrs,const PrintAttributes & newAttrs,uint32_t fd)419 bool PrintCallback::OnCallbackAdapterLayout(
420     const std::string &jobId, const PrintAttributes &oldAttrs, const PrintAttributes &newAttrs, uint32_t fd)
421 {
422     PRINT_HILOGI("PrintCallback OnCallbackAdapterLayout Notification in, jobId:%{public}s newAttrs copyNum:%{public}d",
423         jobId.c_str(),
424         newAttrs.GetCopyNumber());
425     if (adapter_ != nullptr) {
426         PRINT_HILOGI("OnCallbackAdapterLayout run c++");
427         adapter_->onStartLayoutWrite(jobId, oldAttrs, newAttrs, fd, [](std::string jobId, uint32_t state) {
428             PRINT_HILOGI("onStartLayoutWrite write over, jobId:%{public}s state: %{public}d", jobId.c_str(), state);
429             PrintManagerClient::GetInstance()->UpdatePrintJobStateForNormalApp(
430                 jobId, PRINT_JOB_CREATE_FILE_COMPLETED, state);
431         });
432         return true;
433     } else {
434         PRINT_HILOGI("OnCallbackAdapterLayout run ets");
435         return onBaseCallback(
436             [jobId, oldAttrs, newAttrs, fd](CallbackParam *param) {
437                 param->jobId = jobId;
438                 param->oldAttrs = oldAttrs;
439                 param->newAttrs = newAttrs;
440                 param->fd = fd;
441             },
442             PrintAdapterAfterCallFun);
443     }
444 }
445 
onCallbackAdapterJobStateChanged(const std::string jobId,const uint32_t state,const uint32_t subState)446 bool PrintCallback::onCallbackAdapterJobStateChanged(const std::string jobId, const uint32_t state,
447     const uint32_t subState)
448 {
449     PRINT_HILOGI("PrintCallback onCallbackAdapterJobStateChanged Notification in, jobId:%{public}s subState:%{public}d",
450         jobId.c_str(), subState);
451     if (adapter_ != nullptr) {
452         PRINT_HILOGI("onCallbackAdapterJobStateChanged run c++");
453         adapter_->onJobStateChanged(jobId, subState);
454         return true;
455     } else {
456         PRINT_HILOGI("onCallbackAdapterJobStateChanged run ets");
457         return onBaseCallback(
458             [jobId, subState](CallbackParam* param) {
459                 param->jobId = jobId;
460                 param->state = subState;
461             }, PrintAdapterJobStateChangedAfterCallFun);
462     }
463 }
464 
OnCallbackAdapterGetFile(uint32_t state)465 bool PrintCallback::OnCallbackAdapterGetFile(uint32_t state)
466 {
467     PRINT_HILOGI("OnCallbackAdapterGetFile in");
468     return onBaseCallback(
469         [state](CallbackParam* param) {
470             param->state = state;
471         }, PrintAdapterGetFileAfterCallFun);
472 }
473 }  // namespace OHOS::Print
474