1 /*
2 * Copyright (C) 2024 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 #ifndef LOG_TAG
16 #define LOG_TAG "bt_napi_event_subscribe"
17 #endif
18
19 #include "napi_event_subscribe_module.h"
20
21 #include <algorithm>
22 #include "../parser/napi_parser_utils.h"
23 #include "string_ex.h"
24
25 namespace OHOS {
26 namespace Bluetooth {
ToLogString(const std::vector<std::string> & validNameVec)27 static std::string ToLogString(const std::vector<std::string> &validNameVec)
28 {
29 std::string str = "[";
30 for (const auto &s : validNameVec) {
31 str += s;
32 str += ", ";
33 }
34 str += "]";
35 return str;
36 }
37
NapiEventSubscribeModule(const char * validEventName,const char * moduleName)38 NapiEventSubscribeModule::NapiEventSubscribeModule(const char *validEventName, const char *moduleName)
39 : validEventNameVec_(std::vector<std::string>{validEventName}), moduleName_(moduleName)
40 {}
NapiEventSubscribeModule(std::vector<std::string> validEventNameVec,const char * moduleName)41 NapiEventSubscribeModule::NapiEventSubscribeModule(std::vector<std::string> validEventNameVec, const char *moduleName)
42 : validEventNameVec_(validEventNameVec), moduleName_(moduleName)
43 {}
44
Register(napi_env env,napi_callback_info info)45 napi_status NapiEventSubscribeModule::Register(napi_env env, napi_callback_info info)
46 {
47 size_t argc = ARGS_SIZE_TWO;
48 napi_value argv[ARGS_SIZE_TWO] = {nullptr};
49 napi_value thisVar = nullptr;
50 NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
51 NAPI_BT_RETURN_IF(argc != ARGS_SIZE_TWO, "Requires 2 arguments", napi_invalid_arg);
52
53 std::string name {};
54 NAPI_BT_CALL_RETURN(NapiParseString(env, argv[PARAM0], name));
55 if (!IsValidEventName(name)) {
56 HILOGE("Invalid name %{public}s, valid name is %{public}s",
57 name.c_str(), ToLogString(validEventNameVec_).c_str());
58 return napi_invalid_arg;
59 }
60
61 napi_value callback = argv[PARAM1];
62 NAPI_BT_CALL_RETURN(NapiIsFunction(env, callback));
63
64 eventSubscribeMap_.ChangeValueByLambda(name, [this, &env, &name, &callback](auto &callbackVec) {
65 if (IsNapiCallbackExist(callbackVec, callback)) {
66 HILOGW("The %{public}s callback is registered, no need to re-registered", name.c_str());
67 return;
68 }
69 auto napiCallback = std::make_shared<NapiCallback>(env, callback);
70 if (napiCallback) {
71 callbackVec.push_back(napiCallback);
72 }
73 HILOGI("Register one %{public}s callback in %{public}s module, %{public}zu callback left",
74 name.c_str(), moduleName_.c_str(), callbackVec.size());
75 });
76 return napi_ok;
77 }
78
Deregister(napi_env env,napi_callback_info info)79 napi_status NapiEventSubscribeModule::Deregister(napi_env env, napi_callback_info info)
80 {
81 size_t argc = ARGS_SIZE_TWO;
82 napi_value argv[ARGS_SIZE_TWO] = {nullptr};
83 napi_value thisVar = nullptr;
84 NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
85 NAPI_BT_RETURN_IF(
86 argc != ARGS_SIZE_ONE && argc != ARGS_SIZE_TWO, "Requires 1 or 2 arguments", napi_invalid_arg);
87
88 std::string name {};
89 NAPI_BT_CALL_RETURN(NapiParseString(env, argv[PARAM0], name));
90 if (!IsValidEventName(name)) {
91 HILOGE("Invalid name %{public}s, valid name is %{public}s",
92 name.c_str(), ToLogString(validEventNameVec_).c_str());
93 return napi_invalid_arg;
94 }
95
96 if (argc == ARGS_SIZE_ONE) {
97 HILOGI("Deregister all %{public}s callback in %{public}s module", name.c_str(), moduleName_.c_str());
98 eventSubscribeMap_.Erase(name);
99 return napi_ok;
100 }
101 // The argc is ARGS_SIZE_TWO
102 napi_value callback = argv[PARAM1];
103 NAPI_BT_CALL_RETURN(NapiIsFunction(env, callback));
104 eventSubscribeMap_.ChangeValueByLambda(name, [this, &name, &callback](auto &callbackVec) {
105 auto it = std::find_if(callbackVec.begin(), callbackVec.end(),
106 [&callback](auto &napiCallback) { return napiCallback->Equal(callback); });
107 if (it != callbackVec.end()) {
108 callbackVec.erase(it);
109 }
110 HILOGI("Deregister one %{public}s callback in %{public}s module, %{public}zu callback left",
111 name.c_str(), moduleName_.c_str(), callbackVec.size());
112 });
113 return napi_ok;
114 }
115
IsValidEventName(const std::string & eventName) const116 bool NapiEventSubscribeModule::IsValidEventName(const std::string &eventName) const
117 {
118 auto it = std::find(validEventNameVec_.begin(), validEventNameVec_.end(), eventName);
119 return it != validEventNameVec_.end();
120 }
121
IsNapiCallbackExist(const std::vector<std::shared_ptr<NapiCallback>> & napiCallbackVec,napi_value & callback) const122 bool NapiEventSubscribeModule::IsNapiCallbackExist(
123 const std::vector<std::shared_ptr<NapiCallback>> &napiCallbackVec, napi_value &callback) const
124 {
125 auto it = std::find_if(napiCallbackVec.begin(), napiCallbackVec.end(),
126 [&callback](const std::shared_ptr<NapiCallback> &napiCallback) { return napiCallback->Equal(callback); });
127 return it != napiCallbackVec.end();
128 }
129
CallFunction(std::shared_ptr<NapiNativeObject> nativeObject,std::vector<std::shared_ptr<NapiCallback>> napiCallbackVec)130 void NapiEventSubscribeModule::CallFunction(
131 std::shared_ptr<NapiNativeObject> nativeObject, std::vector<std::shared_ptr<NapiCallback>> napiCallbackVec)
132 {
133 for (const auto &callback : napiCallbackVec) {
134 if (callback == nullptr) {
135 continue;
136 }
137 auto func = [nativeObject, callback]() {
138 callback->CallFunction(nativeObject);
139 };
140 DoInJsMainThread(callback->GetNapiEnv(), std::move(func));
141 }
142 }
143
PublishEvent(std::string eventName,const std::shared_ptr<NapiNativeObject> & nativeObject)144 void NapiEventSubscribeModule::PublishEvent(
145 std::string eventName, const std::shared_ptr<NapiNativeObject> &nativeObject)
146 {
147 eventSubscribeMap_.Iterate([this, &eventName, &nativeObject](
148 const std::string &name, std::vector<std::shared_ptr<NapiCallback>> &napiCallbackVec) {
149 if (name != eventName) {
150 return;
151 }
152 CallFunction(nativeObject, napiCallbackVec);
153 });
154 }
155 } // namespace Bluetooth
156 } // namespace OHOS
157