d84d07b67953b059c2c35a4e418c4cbdcff973da
[apps/agl-service-homescreen.git] / src / hs-clientmanager.cpp
1 /*
2  * Copyright (c) 2018 TOYOTA MOTOR CORPORATION
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <cstring>
18 #include <algorithm>
19 #include "hs-clientmanager.h"
20 #include "hs-apprecover.h"
21
22 static const char _homescreen[] = "homescreen";
23 const std::string _listen_all("all");
24
25 HS_ClientManager* HS_ClientManager::me = nullptr;
26
27 static void cbRemoveClientCtxt(void *data)
28 {
29     HS_ClientManager::instance()->removeClientCtxt(data);
30 }
31
32 /**
33  * HS_ClientManager construction function
34  *
35  * #### Parameters
36  *  - Nothing
37  *
38  * #### Return
39  * None
40  *
41  */
42 HS_ClientManager::HS_ClientManager()
43 {
44 }
45
46 /**
47  * get instance
48  *
49  * #### Parameters
50  *  - Nothing
51  *
52  * #### Return
53  * HS_ClientManager instance pointer
54  *
55  */
56 HS_ClientManager* HS_ClientManager::instance(void)
57 {
58     if(me == nullptr)
59         me = new HS_ClientManager();
60
61     return me;
62 }
63
64 /**
65  * HS_ClientManager init function
66  *
67  * #### Parameters
68  *  - Nothing
69  *
70  * #### Return
71  * init result
72  *
73  */
74 int HS_ClientManager::init(void)
75 {
76     listener_list.clear();
77     std::list<listener_interface*> interface_list;
78     listener_list[_listen_all] = std::move(interface_list);
79 }
80
81 /**
82  * create client's afb_req_context
83  *
84  * #### Parameters
85  *  - appid: app's id
86  *
87  * #### Return
88  * HS_ClientCtxt pointer
89  *
90  */
91 HS_ClientCtxt* HS_ClientManager::createClientCtxt(afb_req_t req, std::string appid)
92 {
93     HS_ClientCtxt *ctxt = (HS_ClientCtxt *)afb_req_context_get(req);
94     if (!ctxt)
95     {
96         AFB_INFO( "create new session for %s", appid.c_str());
97         HS_ClientCtxt *ctxt = new HS_ClientCtxt(appid.c_str());
98         afb_req_session_set_LOA(req, 1);
99         afb_req_context_set(req, ctxt, cbRemoveClientCtxt);
100     }
101     return ctxt;
102 }
103
104 /**
105  * add Client
106  *
107  * #### Parameters
108  *  - ctxt: app's id
109  *
110  * #### Return
111  * HS_Client pointer
112  *
113  */
114 HS_Client* HS_ClientManager::addClient(afb_req_t req, std::string appid)
115 {
116     return (client_list[appid] = new HS_Client(req, appid));
117 }
118
119 /**
120  * remove Client
121  *
122  * #### Parameters
123  *  - appid: app's id
124  *
125  * #### Return
126  * None
127  *
128  */
129 void HS_ClientManager::removeClient(std::string appid)
130 {
131     delete client_list[appid];
132     client_list.erase(appid);
133 }
134
135 /**
136  * remove Client from list
137  *
138  * #### Parameters
139  *  - data: HS_ClientCtxt pointer
140  *
141  * #### Return
142  * None
143  *
144  */
145 void HS_ClientManager::removeClientCtxt(void *data)
146 {
147     HS_ClientCtxt *ctxt = (HS_ClientCtxt *)data;
148     if(ctxt == nullptr)
149     {
150         AFB_WARNING( "data is nullptr");
151         return;
152     }
153
154     AFB_INFO( "remove app %s", ctxt->id.c_str());
155     std::lock_guard<std::mutex> lock(this->mtx);
156     removeClient(ctxt->id);
157     delete appid2ctxt[ctxt->id];
158     appid2ctxt.erase(ctxt->id);
159 }
160
161 /**
162  * handle homescreen request
163  *
164  * #### Parameters
165  *  - request : the request
166  *  - verb : the verb name
167  *  - appid : to which application
168  *
169  * #### Return
170  * 0 : success
171  * others : fail
172  *
173  */
174 int HS_ClientManager::handleRequest(afb_req_t request, const char *verb, const char *appid)
175 {
176     AFB_INFO("verb=[%s],appid=[%s].", verb, appid);
177     int ret = 0;
178     bool isRegisterApp = false;
179     if(appid == nullptr) {
180         std::lock_guard<std::mutex> lock(this->mtx);
181         for(auto m : client_list) {
182             m.second->handleRequest(request, verb);
183         }
184     }
185     else {
186         std::lock_guard<std::mutex> lock(this->mtx);
187         auto ip = client_list.find(std::string(appid));
188         if(ip != client_list.end()) {
189             ret = ip->second->handleRequest(request, verb);
190         }
191         else {
192             if(!strcasecmp(verb, "subscribe")) {
193                 appid2ctxt[appid] = createClientCtxt(request, appid);
194                 HS_Client* client = addClient(request, appid);
195                 ret = client->handleRequest(request, "subscribe");
196                 isRegisterApp = true;
197             }
198             else {
199                 AFB_NOTICE("not exist session");
200                 ret = AFB_REQ_NOT_STARTED_APPLICATION;
201             }
202         }
203     }
204     if(isRegisterApp) {
205         notifyListener(request->api, std::string(appid));
206     }
207     return ret;
208 }
209
210 /**
211  * push event
212  *
213  * #### Parameters
214  *  - event : the event want to push
215  *  - param : the parameter contents of event
216  *  - appid : the destination application's id
217  *
218  * #### Return
219  * 0 : success
220  * others : fail
221  *
222  */
223 int HS_ClientManager::pushEvent(const char *event, struct json_object *param, std::string appid)
224 {
225     AFB_INFO("event=[%s], appid=[%s].", event, appid.c_str());
226     if(event == nullptr) {
227         AFB_WARNING("event name is null.");
228         return -1;
229     }
230
231     std::lock_guard<std::mutex> lock(this->mtx);
232     if(appid.empty()) { // broadcast event to clients who subscribed this event
233         for(auto m : client_list) {
234             m.second->pushEvent(event, param);
235         }
236     }
237     else {  // push event to specific client
238         auto ip = client_list.find(appid);
239         if(ip != client_list.end()) {
240             ip->second->pushEvent(event, param);
241         }
242     }
243
244     return 0;
245 }
246
247 /**
248  * check register application
249  *
250  * #### Parameters
251  *  - api : the api
252  *  - appid : register application's id
253  *
254  * #### Return
255  * true : checked
256  * false : not checked
257  *
258  */
259 bool HS_ClientManager::checkRegisterApp(afb_api_t api, const std::string &appid)
260 {
261     bool ret = true;
262     auto &ip = listener_list[_listen_all];
263     if(!ip.empty()) {
264         for(auto &it : ip) {
265             it->notify(api, appid);
266         }
267     }
268     else if(startup_appid == appid) {
269         startup_appid.clear();
270         pushEvent("showWindow", nullptr, appid);
271     }
272     else {
273         ret = false;
274     }
275     return ret;
276 }
277
278 /**
279  * check whether application was started
280  *
281  * #### Parameters
282  *  - appid : application's id
283  *
284  * #### Return
285  * true : started
286  * false : not start
287  *
288  */
289 bool HS_ClientManager::isAppStarted(const std::string &appid)
290 {
291     auto it = client_list.find(appid);
292     return it != client_list.end() ? true : false;
293 }
294
295 /**
296  * add app register listener
297  *
298  * #### Parameters
299  *  - listener_interface : listener interface
300  *
301  * #### Return
302  * None
303  *
304  */
305 void HS_ClientManager::addListener(listener_interface* listener)
306 {
307     for (auto &it : listener->listenAppSet()) {
308         auto ip = listener_list.find(it);
309         if(ip != listener_list.end()) {
310             ip->second.push_back(listener);
311         }
312         else {
313             std::list<listener_interface*> lst;
314             lst.push_back(listener);
315             listener_list[it] = std::move(lst);
316         }
317     }
318 }
319
320 /**
321  * remove app register listener
322  *
323  * #### Parameters
324  *  - listener_interface : listener interface
325  *
326  * #### Return
327  * None
328  *
329  */
330 void HS_ClientManager::removeListener(listener_interface* listener)
331 {
332     for (auto &iter : listener->listenAppSet()) {
333         auto it = listener_list.find(iter);
334         if(it != listener_list.end()) {
335             auto ip = it->second.begin();
336             for(; ip != it->second.end(); ++ip) {
337                 if(listener->myUid() == (*ip)->myUid()) {
338                     break;
339                 }
340             }
341             it->second.erase(ip);
342             if(it->second.empty()) {
343                 listener_list.erase(it->first);
344             }
345         }
346     }
347 }
348
349 /**
350  * notify listener
351  *
352  * #### Parameters
353  *  - api : the api
354  *  - appid : register application's id
355  *
356  * #### Return
357  * None
358  *
359  */
360 void HS_ClientManager::notifyListener(afb_api_t api, const std::string &appid)
361 {
362     if (checkRegisterApp(api, appid)) {
363         return;
364     }
365
366     AFB_INFO("listen %s, notified", appid.c_str());
367     std::list<listener_interface*> interface_list;
368     auto ip = listener_list.find(appid);
369     if(ip != listener_list.end()) {
370         if(!ip->second.empty()) {
371             interface_list = ip->second;
372         }
373         else {
374             AFB_WARNING("listener is null.");
375             return;
376         }
377     }
378
379     for(auto &it : interface_list) {
380         it->notify(api, appid);
381     }
382
383 }