1 /*
2 * Copyright (c) 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 */
15
16 #include "session_manager.h"
17
18 #include <uv.h>
19
20 #include "node_api.h"
21
22 #include "client_helper.h"
23 #include "update_define.h"
24 #include "update_helper.h"
25 #include "update_session.h"
26
27 using namespace std;
28
29 namespace OHOS::UpdateEngine {
SessionManager(napi_env env,napi_ref thisReference)30 SessionManager::SessionManager(napi_env env, napi_ref thisReference) : env_(env), thisReference_(thisReference)
31 {
32 ENGINE_LOGI("SessionManager constructor");
33 }
34
~SessionManager()35 SessionManager::~SessionManager()
36 {
37 ENGINE_LOGI("SessionManager destructor");
38 if (thisReference_ != nullptr) {
39 napi_delete_reference(env_, thisReference_);
40 thisReference_ = nullptr;
41 }
42 }
43
AddSession(std::shared_ptr<BaseSession> session)44 void SessionManager::AddSession(std::shared_ptr<BaseSession> session)
45 {
46 PARAM_CHECK(session != nullptr, return, "Invalid param");
47 std::lock_guard<std::recursive_mutex> guard(sessionMutex_);
48 sessions_.insert(make_pair(session->GetSessionId(), session));
49 }
50
RemoveSession(uint32_t sessionId)51 void SessionManager::RemoveSession(uint32_t sessionId)
52 {
53 ENGINE_LOGI("RemoveSession sess");
54 std::lock_guard<std::recursive_mutex> guard(sessionMutex_);
55 sessions_.erase(sessionId);
56 }
57
GetFirstSessionId(uint32_t & sessionId)58 bool SessionManager::GetFirstSessionId(uint32_t &sessionId)
59 {
60 std::lock_guard<std::recursive_mutex> guard(sessionMutex_);
61 {
62 if (sessions_.empty()) {
63 return false;
64 }
65 sessionId = sessions_.begin()->second->GetSessionId();
66 return true;
67 }
68 }
69
GetNextSessionId(uint32_t & sessionId)70 bool SessionManager::GetNextSessionId(uint32_t &sessionId)
71 {
72 std::lock_guard<std::recursive_mutex> guard(sessionMutex_);
73 {
74 auto iter = sessions_.find(sessionId);
75 if (iter == sessions_.end()) {
76 return false;
77 }
78 iter++;
79 if (iter == sessions_.end()) {
80 return false;
81 }
82 sessionId = iter->second->GetSessionId();
83 }
84 return true;
85 }
86
ProcessUnsubscribe(const std::string & eventType,size_t argc,napi_value arg)87 int32_t SessionManager::ProcessUnsubscribe(const std::string &eventType, size_t argc, napi_value arg)
88 {
89 napi_handle_scope scope;
90 napi_status status = napi_open_handle_scope(env_, &scope);
91 PARAM_CHECK(status == napi_ok, return -1, "Error open handle");
92
93 uint32_t nextSessId = 0;
94 bool hasNext = GetFirstSessionId(nextSessId);
95 while (hasNext) {
96 uint32_t currSessId = nextSessId;
97 auto iter = sessions_.find(currSessId);
98 if (iter == sessions_.end()) {
99 break;
100 }
101 hasNext = GetNextSessionId(nextSessId);
102
103 UpdateListener *listener = static_cast<UpdateListener *>(iter->second.get());
104 if (listener->GetType() != SessionType::SESSION_SUBSCRIBE ||
105 eventType.compare(listener->GetEventType()) != 0) {
106 continue;
107 }
108 ENGINE_LOGI("ProcessUnsubscribe remove session");
109 if (argc == 1) {
110 listener->RemoveHandlerRef(env_);
111 RemoveSession(currSessId);
112 } else if (listener->CheckEqual(env_, arg, eventType)) {
113 listener->RemoveHandlerRef(env_);
114 RemoveSession(currSessId);
115 break;
116 }
117 }
118 napi_close_handle_scope(env_, scope);
119 return 0;
120 }
121
Unsubscribe(const EventClassifyInfo & eventClassifyInfo,napi_value handle)122 void SessionManager::Unsubscribe(const EventClassifyInfo &eventClassifyInfo, napi_value handle)
123 {
124 std::lock_guard<std::recursive_mutex> guard(sessionMutex_);
125 for (auto iter = sessions_.begin(); iter != sessions_.end();) {
126 if (iter->second == nullptr) {
127 iter = sessions_.erase(iter); // erase nullptr
128 continue;
129 }
130
131 if (iter->second->GetType() != SessionType::SESSION_SUBSCRIBE) {
132 ++iter;
133 continue;
134 }
135
136 auto listener = static_cast<UpdateListener *>(iter->second.get());
137 if (handle == nullptr && listener->IsSubscribeEvent(eventClassifyInfo)) {
138 ENGINE_LOGI("Unsubscribe, remove session %{public}d without handle", listener->GetSessionId());
139 iter = sessions_.erase(iter);
140 listener->RemoveHandlerRef(env_);
141 continue;
142 }
143
144 if (listener->IsSameListener(env_, eventClassifyInfo, handle)) {
145 ENGINE_LOGI("Unsubscribe, remove session %{public}d", listener->GetSessionId());
146 iter = sessions_.erase(iter);
147 listener->RemoveHandlerRef(env_);
148 continue;
149 }
150
151 ++iter;
152 }
153 }
154
FindSessionByHandle(napi_env env,const std::string & eventType,napi_value arg)155 BaseSession *SessionManager::FindSessionByHandle(napi_env env, const std::string &eventType, napi_value arg)
156 {
157 uint32_t nextSessId = 0;
158 bool hasNext = GetFirstSessionId(nextSessId);
159 while (hasNext) {
160 uint32_t currSessId = nextSessId;
161 auto iter = sessions_.find(currSessId);
162 if (iter == sessions_.end()) {
163 break;
164 }
165 hasNext = GetNextSessionId(nextSessId);
166
167 UpdateListener *listener = static_cast<UpdateListener *>(iter->second.get());
168 if (listener->GetType() != SessionType::SESSION_SUBSCRIBE) {
169 continue;
170 }
171 if ((eventType.compare(listener->GetEventType()) == 0) && listener->CheckEqual(env_, arg, eventType)) {
172 return listener;
173 }
174 }
175 return nullptr;
176 }
177
FindSessionByHandle(napi_env env,const EventClassifyInfo & eventClassifyInfo,napi_value arg)178 BaseSession *SessionManager::FindSessionByHandle(napi_env env, const EventClassifyInfo &eventClassifyInfo,
179 napi_value arg)
180 {
181 std::lock_guard<std::recursive_mutex> guard(sessionMutex_);
182 for (auto &iter : sessions_) {
183 if (iter.second == nullptr) {
184 continue;
185 }
186
187 if (iter.second->GetType() != SessionType::SESSION_SUBSCRIBE) {
188 continue;
189 }
190
191 auto listener = static_cast<UpdateListener *>(iter.second.get());
192 if (listener->IsSameListener(env, eventClassifyInfo, arg)) {
193 return listener;
194 }
195 }
196 return nullptr;
197 }
198
PublishToJS(const EventClassifyInfo & eventClassifyInfo,const EventInfo & eventInfo)199 void SessionManager::PublishToJS(const EventClassifyInfo &eventClassifyInfo, const EventInfo &eventInfo)
200 {
201 napi_handle_scope scope;
202 napi_status status = napi_open_handle_scope(env_, &scope);
203 PARAM_CHECK_NAPI_CALL(env_, status == napi_ok, return, "Error open_handle_scope");
204 napi_value thisVar = nullptr;
205 status = napi_get_reference_value(env_, thisReference_, &thisVar);
206 PARAM_CHECK_NAPI_CALL(env_, status == napi_ok, napi_close_handle_scope(env_, scope); return,
207 "Error get_reference");
208
209 std::lock_guard<std::recursive_mutex> guard(sessionMutex_);
210 for (auto &iter : sessions_) {
211 if (iter.second == nullptr) {
212 continue;
213 }
214
215 if (iter.second->GetType() != SessionType::SESSION_SUBSCRIBE) {
216 continue;
217 }
218
219 UpdateListener *listener = static_cast<UpdateListener *>(iter.second.get());
220 if (!listener->IsSubscribeEvent(eventClassifyInfo)) {
221 continue;
222 }
223
224 listener->NotifyJS(env_, thisVar, eventInfo);
225 }
226 napi_close_handle_scope(env_, scope);
227 }
228
Emit(const EventClassifyInfo & eventClassifyInfo,const EventInfo & eventInfo)229 void SessionManager::Emit(const EventClassifyInfo &eventClassifyInfo, const EventInfo &eventInfo)
230 {
231 ENGINE_LOGI("SessionManager::Emit 0x%{public}x", CAST_INT(eventClassifyInfo.eventClassify));
232 uv_loop_s *loop = nullptr;
233 napi_get_uv_event_loop(env_, &loop);
234 PARAM_CHECK(loop != nullptr, return, "get event loop failed.");
235
236 using UvWorkData = std::tuple<SessionManager*, EventClassifyInfo, EventInfo>;
237 UvWorkData *data = new (std::nothrow) std::tuple(this, eventClassifyInfo, eventInfo);
238 PARAM_CHECK(data != nullptr, return, "alloc data failed.");
239
240 uv_work_t *work = new (std::nothrow) uv_work_t;
241 PARAM_CHECK(work != nullptr, delete data; return, "alloc work failed.");
242
243 work->data = static_cast<void *>(data);
244 uv_queue_work_with_qos(
245 loop,
246 work,
247 [](uv_work_t *work) {},
248 [](uv_work_t *work, int status) {
249 UvWorkData *data = static_cast<UvWorkData*>(work->data);
250 auto &[mgr, eventClassifyInfo, eventInfo] = *data;
251 mgr->PublishToJS(eventClassifyInfo, eventInfo);
252 delete data;
253 delete work;
254 },
255 uv_qos_default);
256 }
257 } // namespace OHOS::UpdateEngine