hs-clientmanager: Do not store always the client context
[apps/agl-service-homescreen.git] / src / hs-clientmanager.cpp
1 /*
2  * Copyright (c) 2018 TOYOTA MOTOR CORPORATION
3  * Copyright (C) 2020 Konsulko Group
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include <cstring>
19 #include <algorithm>
20 #include "hs-clientmanager.h"
21
22 static const char _homescreen[] = "homescreen";
23
24 HS_ClientManager* HS_ClientManager::me = nullptr;
25
26 static void cbRemoveClientCtxt(void *data)
27 {
28     HS_ClientManager::instance()->removeClientCtxt(data);
29 }
30
31 /**
32  * HS_ClientManager construction function
33  *
34  * #### Parameters
35  *  - Nothing
36  *
37  * #### Return
38  * None
39  *
40  */
41 HS_ClientManager::HS_ClientManager()
42 {
43 }
44
45 /**
46  * get instance
47  *
48  * #### Parameters
49  *  - Nothing
50  *
51  * #### Return
52  * HS_ClientManager instance pointer
53  *
54  */
55 HS_ClientManager* HS_ClientManager::instance(void)
56 {
57     if(me == nullptr)
58         me = new HS_ClientManager();
59
60     return me;
61 }
62
63 /**
64  * HS_ClientManager init function
65  *
66  * #### Parameters
67  *  - Nothing
68  *
69  * #### Return
70  * init result
71  *
72  */
73 int HS_ClientManager::init(void)
74 {
75     return 0;
76 }
77
78 /**
79  * create client's afb_req_context
80  *
81  * #### Parameters
82  *  - appid: app's id
83  *
84  * #### Return
85  * HS_ClientCtxt pointer
86  *
87  */
88 HS_ClientCtxt* HS_ClientManager::createClientCtxt(afb_req_t req, std::string appid)
89 {
90     HS_ClientCtxt *ctxt = (HS_ClientCtxt *)afb_req_context_get(req);
91     if (!ctxt)
92     {
93         AFB_INFO( "create new session for %s", appid.c_str());
94         ctxt = new HS_ClientCtxt(appid);
95         afb_req_session_set_LOA(req, 1);
96         afb_req_context_set(req, ctxt, cbRemoveClientCtxt);
97
98         appid2ctxt[appid] = ctxt;
99     }
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     std::lock_guard<std::mutex> lock(this->mtx);
179     if(appid == nullptr) {
180         for(auto m : client_list) {
181             m.second->handleRequest(request, verb);
182         }
183     }
184     else {
185         std::string id(appid);
186         auto ip = client_list.find(id);
187         if(ip != client_list.end()) {
188             // FIXME: do another verification here in case the application died
189             ret = ip->second->handleRequest(request, verb);
190         }
191         else {
192             if(!strcasecmp(verb, "subscribe")) {
193                 createClientCtxt(request, id);
194                 HS_Client* client = addClient(request, id);
195                 ret = client->handleRequest(request, "subscribe");
196             }
197             else {
198                 AFB_NOTICE("not exist session");
199                 ret = AFB_REQ_NOT_STARTED_APPLICATION;
200             }
201         }
202     }
203     return ret;
204 }
205
206 /**
207  * push event
208  *
209  * #### Parameters
210  *  - event : the event want to push
211  *  - param : the parameter contents of event
212  *  - appid : the destination application's id
213  *
214  * #### Return
215  * 0 : success
216  * others : fail
217  *
218  */
219 int HS_ClientManager::pushEvent(const char *event, struct json_object *param, std::string appid)
220 {
221     if(event == nullptr) {
222         AFB_WARNING("event name is null.");
223         return -1;
224     }
225
226     std::lock_guard<std::mutex> lock(this->mtx);
227     if(appid.empty()) { // broadcast event to clients who subscribed this event
228         for(auto m : client_list) {
229             m.second->pushEvent(event, param);
230         }
231     }
232     else {  // push event to specific client
233         auto ip = client_list.find(appid);
234         if(ip != client_list.end()) {
235             ip->second->pushEvent(event, param);
236         }
237     }
238
239     return 0;
240 }