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