1 /*
2  * Copyright (C) 2023-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  * Description: supply napi callback realization for interfaces.
15  * Author: zhangjingnan
16  * Create: 2023-4-11
17  */
18 
19 #include <memory>
20 #include "cast_engine_log.h"
21 #include "napi_callback.h"
22 
23 namespace OHOS {
24 namespace CastEngine {
25 namespace CastEngineClient {
26 DEFINE_CAST_ENGINE_LABEL("Cast-Napi-Callback");
27 
NapiCallback(napi_env env)28 NapiCallback::NapiCallback(napi_env env) : env_(env)
29 {
30     if (env != nullptr) {
31         NAPI_CALL_RETURN_VOID(env, napi_get_uv_event_loop(env, &loop_));
32     }
33 }
34 
~NapiCallback()35 NapiCallback::~NapiCallback()
36 {
37     CLOGD("no memory leak for queue-callback");
38     env_ = nullptr;
39 }
40 
GetEnv() const41 napi_env NapiCallback::GetEnv() const
42 {
43     return env_;
44 }
45 
AfterWorkCallback(uv_work_t *work, int status)46 void NapiCallback::AfterWorkCallback(uv_work_t *work, int status)
47 {
48     std::shared_ptr<DataContext> context(static_cast<DataContext *>(work->data), [work](DataContext *ptr) {
49         delete ptr;
50         delete work;
51     });
52 
53     int argc = 0;
54     napi_handle_scope scope = nullptr;
55     napi_open_handle_scope(context->env, &scope);
56     napi_value argv[ARGC_MAX] = { nullptr };
57     if (context->getter) {
58         argc = ARGC_MAX;
59         context->getter(context->env, argc, argv);
60     }
61 
62     napi_value undefined = nullptr;
63     if (napi_get_undefined(context->env, &undefined) != napi_ok) {
64         CLOGE("napi_get_undefined failed");
65         napi_close_handle_scope(context->env, scope);
66         return;
67     }
68     napi_value callback = nullptr;
69     if (napi_get_reference_value(context->env, context->method, &callback) != napi_ok) {
70         CLOGE("napi_get_reference_value failed");
71         napi_close_handle_scope(context->env, scope);
72         return;
73     }
74     napi_value callResult = nullptr;
75     if (napi_call_function(context->env, undefined, callback, argc, argv, &callResult) != napi_ok) {
76         CLOGE("napi_call_function failed");
77     }
78     napi_close_handle_scope(context->env, scope);
79 }
80 
Call(napi_ref method, NapiArgsGetter getter)81 void NapiCallback::Call(napi_ref method, NapiArgsGetter getter)
82 {
83     CLOGD("Start to have JS call");
84     if (loop_ == nullptr) {
85         CLOGE("loop_ is nullptr");
86         return;
87     }
88     if (method == nullptr) {
89         CLOGE("method is nullptr");
90         return;
91     }
92 
93     auto *work = new (std::nothrow) uv_work_t;
94     if (work == nullptr) {
95         CLOGE("no memory for uv_work_t");
96         return;
97     }
98 
99     work->data = new DataContext { env_, method, std::move(getter) };
100     int res = uv_queue_work(
101         loop_, work, [](uv_work_t *work) {}, AfterWorkCallback);
102     if (res != 0) {
103         CLOGE("uv queue work failed");
104         delete work;
105         return;
106     }
107 }
108 } // namespace CastEngineClient
109 } // namespace CastEngine
110 } // namespace OHOS