1 /*
2 * Copyright (c) 2021-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 #include "listener_base.h"
16
17 #include <memory>
18 #include <uv.h>
19
20 #include "camera_log.h"
21 #include "js_native_api.h"
22 #include "js_native_api_types.h"
23
24 namespace OHOS {
25 namespace CameraStandard {
ListenerBase(napi_env env)26 ListenerBase::ListenerBase(napi_env env) : env_(env)
27 {
28 MEDIA_DEBUG_LOG("ListenerBase is called.");
29 }
30
~ListenerBase()31 ListenerBase::~ListenerBase()
32 {
33 MEDIA_DEBUG_LOG("~ListenerBase is called.");
34 }
35
ExecuteCallbackData(napi_env env,napi_value errCode,napi_value returnData)36 ListenerBase::ExecuteCallbackData::ExecuteCallbackData(napi_env env, napi_value errCode, napi_value returnData)
37 : env_(env), errCode_(errCode), returnData_(returnData) {};
38
SaveCallbackReference(const std::string eventName,napi_value callback,bool isOnce)39 void ListenerBase::SaveCallbackReference(const std::string eventName, napi_value callback, bool isOnce)
40 {
41 CHECK_ERROR_RETURN_LOG(callback == nullptr,
42 "SaveCallbackReference:%s js callback is nullptr, save nothing", eventName.c_str());
43 napi_valuetype valueType = napi_undefined;
44 napi_typeof(env_, callback, &valueType);
45 CHECK_ERROR_RETURN_LOG(valueType != napi_function,
46 "SaveCallbackReference:%s js callback valueType is not function", eventName.c_str());
47 auto& callbackList = GetCallbackList(eventName);
48 std::lock_guard<std::mutex> lock(callbackList.listMutex);
49 for (auto it = callbackList.refList.begin(); it != callbackList.refList.end(); ++it) {
50 bool isSameCallback = CameraNapiUtils::IsSameNapiValue(env_, callback, it->GetCallbackFunction());
51 CHECK_ERROR_RETURN_LOG(isSameCallback, "SaveCallbackReference: has same callback, nothing to do");
52 }
53 callbackList.refList.emplace_back(AutoRef(env_, callback, isOnce));
54 MEDIA_DEBUG_LOG("Save callback reference success, %s callback list size [%{public}zu]", eventName.c_str(),
55 callbackList.refList.size());
56 }
57
RemoveCallbackRef(const std::string eventName,napi_value callback)58 void ListenerBase::RemoveCallbackRef(const std::string eventName, napi_value callback)
59 {
60 if (callback == nullptr) {
61 MEDIA_INFO_LOG("RemoveCallbackReference: js callback is nullptr, remove all callback reference");
62 RemoveAllCallbacks(eventName);
63 return;
64 }
65 auto& callbackList = GetCallbackList(eventName);
66 std::lock_guard<std::mutex> lock(callbackList.listMutex);
67 for (auto it = callbackList.refList.begin(); it != callbackList.refList.end(); ++it) {
68 bool isSameCallback = CameraNapiUtils::IsSameNapiValue(env_, callback, it->GetCallbackFunction());
69 if (isSameCallback) {
70 MEDIA_INFO_LOG("RemoveCallbackReference: find %s callback, delete it", eventName.c_str());
71 callbackList.refList.erase(it);
72 return;
73 }
74 }
75 MEDIA_INFO_LOG("RemoveCallbackReference: %s callback not find", eventName.c_str());
76 }
77
ExecuteCallback(const std::string eventName,const ExecuteCallbackNapiPara & callbackPara) const78 void ListenerBase::ExecuteCallback(const std::string eventName, const ExecuteCallbackNapiPara& callbackPara) const
79 {
80 MEDIA_DEBUG_LOG("ListenerBase::ExecuteCallback is called");
81 auto& callbackList = GetCallbackList(eventName);
82 std::lock_guard<std::mutex> lock(callbackList.listMutex);
83 for (auto it = callbackList.refList.begin(); it != callbackList.refList.end();) {
84 napi_call_function(env_, callbackPara.recv, it->GetCallbackFunction(), callbackPara.argc, callbackPara.argv,
85 callbackPara.result);
86 if (it->isOnce_) {
87 callbackList.refList.erase(it);
88 } else {
89 it++;
90 }
91 }
92 MEDIA_DEBUG_LOG("ListenerBase::ExecuteCallback, %s callback list size [%{public}zu]", eventName.c_str(),
93 callbackList.refList.size());
94 }
95
ExecuteCallbackScopeSafe(const std::string eventName,const std::function<ExecuteCallbackData ()> fun) const96 void ListenerBase::ExecuteCallbackScopeSafe(
97 const std::string eventName, const std::function<ExecuteCallbackData()> fun) const
98 {
99 napi_handle_scope scope_ = nullptr;
100 napi_open_handle_scope(env_, &scope_);
101
102 MEDIA_DEBUG_LOG("ListenerBase::ExecuteCallback %{public}s is called", eventName.c_str());
103 auto& callbackList = GetCallbackList(eventName);
104 std::lock_guard<std::mutex> lock(callbackList.listMutex);
105 for (auto it = callbackList.refList.begin(); it != callbackList.refList.end();) {
106 // Do not move this call out of loop.
107 ExecuteCallbackData callbackData = fun();
108 if (callbackData.env_ == nullptr) {
109 MEDIA_ERR_LOG("ExecuteCallback %{public}s env is null ", eventName.c_str());
110 continue;
111 }
112
113 napi_value result[ARGS_TWO] = { nullptr, nullptr };
114 napi_value retVal;
115 result[0] = callbackData.errCode_;
116 result[1] = callbackData.returnData_;
117
118 napi_call_function(callbackData.env_, nullptr, it->GetCallbackFunction(), ARGS_TWO, result, &retVal);
119 if (it->isOnce_) {
120 callbackList.refList.erase(it);
121 } else {
122 it++;
123 }
124 }
125 MEDIA_DEBUG_LOG("ListenerBase::ExecuteCallback, %s callback list size [%{public}zu]", eventName.c_str(),
126 callbackList.refList.size());
127
128 napi_close_handle_scope(env_, scope_);
129 }
130
RemoveAllCallbacks(const std::string eventName)131 void ListenerBase::RemoveAllCallbacks(const std::string eventName)
132 {
133 auto& callbackList = GetCallbackList(eventName);
134 std::lock_guard<std::mutex> lock(callbackList.listMutex);
135 callbackList.refList.clear();
136 MEDIA_INFO_LOG("RemoveAllCallbacks: remove all js callbacks success");
137 }
138
IsEmpty(const std::string eventName) const139 bool ListenerBase::IsEmpty(const std::string eventName) const
140 {
141 auto& callbackList = GetCallbackList(eventName);
142 std::lock_guard<std::mutex> lock(callbackList.listMutex);
143 return callbackList.refList.empty();
144 }
145 } // namespace CameraStandard
146 } // namespace OHOS
147