Refactor App Com
[platform/core/appfw/aul-1.git] / src / app_com.cc
1 /*
2  * Copyright (c) 2015 - 2021 Samsung Electronics Co., Ltd. All rights reserved.
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 <bundle_cpp.h>
18 #include <bundle_internal.h>
19
20 #include <list>
21 #include <mutex>
22 #include <string>
23
24 #include "aul_api.h"
25 #include "aul_util.h"
26 #include "include/aul.h"
27 #include "include/aul_app_com.h"
28 #include "include/aul_cmd.h"
29 #include "launch.h"
30
31 namespace {
32
33 class AppComConnection {
34  public:
35   AppComConnection(std::string endpoint, app_com_cb cb, void* user_data)
36       : endpoint_(std::move(endpoint)),
37         cb_(cb),
38         user_data_(user_data) {
39   }
40
41   ~AppComConnection() = default;
42
43   const std::string& GetEndpoint() const {
44     return endpoint_;
45   }
46
47   void Invoke(aul_app_com_result_e result, bundle* envelope) {
48     if (cb_)
49       cb_(endpoint_.c_str(), result, envelope, user_data_);
50   }
51
52  private:
53   std::string endpoint_;
54   app_com_cb cb_;
55   void* user_data_;
56 };
57
58 class AppComPermission {
59  public:
60   AppComPermission() {}
61   ~AppComPermission() {}
62
63   void SetPrivilege(std::string privilege) {
64     privilege_ = std::move(privilege);
65   }
66
67   void SetPropagationOption(aul_app_com_propagate_option_e option) {
68     option_ = option;
69   }
70
71   const std::string& GetPrivilege() const {
72     return privilege_;
73   }
74
75   aul_app_com_propagate_option_e GetPropagationOption() const {
76     return option_;
77   }
78
79  private:
80   std::string privilege_;
81   aul_app_com_propagate_option_e option_;
82 };
83
84 class Context {
85  public:
86   Context() {}
87   ~Context() {}
88
89   int Receive(bundle* b) {
90     const char* val = bundle_get_val(b, AUL_K_COM_ENDPOINT);
91     if (val == nullptr)
92       return -1;
93
94     size_t result_size = 0;
95     aul_app_com_result_e* result = nullptr;
96     int ret = bundle_get_byte(b, AUL_K_COM_RESULT,
97         reinterpret_cast<void**>(&result), &result_size);
98     if (ret != BUNDLE_ERROR_NONE)
99       return -1;
100
101     std::string endpoint(val);
102
103     std::lock_guard<std::recursive_mutex> lock(mutex_);
104     for (auto& conn : conns_) {
105       if (conn->GetEndpoint() == endpoint)
106         conn->Invoke(*result, b);
107     }
108
109     return 0;
110   }
111
112   AppComConnection* AddConnection(std::string endpoint, app_com_cb cb,
113       void* user_data) {
114     auto* conn = new (std::nothrow) AppComConnection(endpoint, cb, user_data);
115     if (conn == nullptr)
116       return nullptr;
117
118     std::lock_guard<std::recursive_mutex> lock(mutex_);
119     conns_.emplace_back(conn);
120     return conn;
121   }
122
123   void RemoveConnection(AppComConnection* conn) {
124     std::lock_guard<std::recursive_mutex> lock(mutex_);
125     auto iter = conns_.begin();
126     while (iter != conns_.end()) {
127       if ((*iter).get() == conn) {
128         iter = conns_.erase(iter);
129         break;
130       } else {
131         iter++;
132       }
133     }
134   }
135
136   bool ExistConnection(const std::string& endpoint) {
137     std::lock_guard<std::recursive_mutex> lock(mutex_);
138     for (auto& conn : conns_) {
139       if (conn->GetEndpoint() == endpoint)
140         return true;
141     }
142
143     return false;
144   }
145
146   bool ExistConnection(AppComConnection* conn) {
147     std::lock_guard<std::recursive_mutex> lock(mutex_);
148     for (auto& i : conns_) {
149       if (i.get() == conn)
150         return true;
151     }
152
153     return false;
154   }
155
156  private:
157   std::list<std::unique_ptr<AppComConnection>> conns_;
158   mutable std::recursive_mutex mutex_;
159 };
160
161 Context context;
162
163 }  // namespace
164
165 int app_com_recv(bundle* b) {
166   if (b == nullptr)
167     return -1;
168
169   return context.Receive(b);
170 }
171
172 extern "C" API aul_app_com_permission_h aul_app_com_permission_create() {
173   auto* handle = new (std::nothrow) AppComPermission();
174   return static_cast<aul_app_com_permission_h>(handle);
175 }
176
177 extern "C" API void aul_app_com_permission_destroy(
178     aul_app_com_permission_h permission) {
179   if (permission == nullptr)
180     return;
181
182   auto* handle = static_cast<AppComPermission*>(permission);
183   delete handle;
184 }
185
186 extern "C" API int aul_app_com_permission_set_propagation(
187     aul_app_com_permission_h permission,
188     aul_app_com_propagate_option_e option) {
189   if (permission == nullptr)
190     return AUL_R_EINVAL;
191
192   auto* handle = static_cast<AppComPermission*>(permission);
193   handle->SetPropagationOption(option);
194   return AUL_R_OK;
195 }
196
197 extern "C" API int aul_app_com_permission_set_privilege(
198     aul_app_com_permission_h permission, const char* privilege) {
199   if (permission == nullptr || privilege == nullptr)
200     return AUL_R_EINVAL;
201
202   auto* handle = static_cast<AppComPermission*>(permission);
203   handle->SetPrivilege(privilege);
204   return AUL_R_OK;
205 }
206
207 static int AppComCreate(const char* endpoint,
208     aul_app_com_permission_h permission, app_com_cb callback, void* user_data,
209     bool sync, aul_app_com_connection_h* connection) {
210   if (endpoint == nullptr || callback == nullptr || connection == nullptr) {
211     _E("Invalid parameter");
212     return AUL_R_EINVAL;
213   }
214
215   if (!aul_is_initialized()) {
216     if (aul_launch_init(nullptr, nullptr) < 0)
217       return AUL_R_ENOINIT;
218   }
219
220   tizen_base::Bundle b;
221   b.Add(AUL_K_COM_ENDPOINT, endpoint);
222
223   if (permission) {
224     auto* handle = static_cast<AppComPermission*>(permission);
225     auto option = handle->GetPropagationOption();
226     if (option) {
227       auto* p = reinterpret_cast<unsigned char*>(&option);
228       std::vector<unsigned char> bytes;
229       std::copy(p, p + sizeof(option), std::back_inserter(bytes));
230       b.Add(AUL_K_COM_PROPAGATE, bytes);
231     }
232
233     if (!handle->GetPrivilege().empty())
234       b.Add(AUL_K_COM_PRIVILEGE, handle->GetPrivilege());
235   }
236
237   int ret;
238   if (sync) {
239     ret = app_send_cmd(AUL_UTIL_PID, APP_COM_CREATE, b.GetHandle());
240   } else {
241     ret = app_send_cmd_with_noreply(AUL_UTIL_PID, APP_COM_CREATE,
242         b.GetHandle());
243   }
244
245   if (ret == 0) {
246     *connection = static_cast<aul_app_com_connection_h>(
247         context.AddConnection(endpoint, callback, user_data));
248   }
249
250   return ret;
251 }
252
253 extern "C" API int aul_app_com_create(const char* endpoint,
254     aul_app_com_permission_h permission, app_com_cb callback,
255     void* user_data, aul_app_com_connection_h* connection) {
256   return AppComCreate(endpoint, permission, callback, user_data,
257       true, connection);
258 }
259
260 extern "C" API int aul_app_com_create_async(const char* endpoint,
261     aul_app_com_permission_h permission, app_com_cb callback,
262     void* user_data, aul_app_com_connection_h* connection) {
263   return AppComCreate(endpoint, permission, callback, user_data,
264       false, connection);
265 }
266
267 extern "C" API int aul_app_com_join(const char* endpoint, const char* filter,
268     app_com_cb callback, void* user_data,
269     aul_app_com_connection_h* connection) {
270   if (endpoint == nullptr || callback == nullptr || connection == nullptr) {
271     _E("Invalid parameter");
272     return AUL_R_EINVAL;
273   }
274
275   if (!aul_is_initialized()) {
276     if (aul_launch_init(nullptr, nullptr) < 0)
277       return AUL_R_ENOINIT;
278   }
279
280   tizen_base::Bundle b;
281   b.Add(AUL_K_COM_ENDPOINT, endpoint);
282   if (filter)
283     b.Add(AUL_K_COM_FILTER, filter);
284
285   int ret = app_send_cmd(AUL_UTIL_PID, APP_COM_JOIN, b.GetHandle());
286   if (ret == 0) {
287     *connection = static_cast<aul_app_com_connection_h>(
288         context.AddConnection(endpoint, callback, user_data));
289   }
290
291   return ret;
292 }
293
294 extern "C" API int aul_app_com_send(const char* endpoint, bundle* envelope) {
295   if (endpoint == nullptr || envelope == nullptr)
296     return AUL_R_EINVAL;
297
298   bundle_del(envelope, AUL_K_COM_ENDPOINT);
299   bundle_add(envelope, AUL_K_COM_ENDPOINT, endpoint);
300   return app_send_cmd(AUL_UTIL_PID, APP_COM_SEND, envelope);
301 }
302
303 extern "C" API int aul_app_com_leave(aul_app_com_connection_h connection) {
304   if (connection == nullptr)
305     return AUL_R_EINVAL;
306
307   auto* conn = static_cast<AppComConnection*>(connection);
308   if (!context.ExistConnection(conn)) {
309     _E("Invalid parameter");
310     return AUL_R_EINVAL;
311   }
312
313   std::string endpoint = conn->GetEndpoint();
314   context.RemoveConnection(conn);
315
316   if (context.ExistConnection(endpoint))
317     return AUL_R_OK;
318
319   tizen_base::Bundle b;
320   b.Add(AUL_K_COM_ENDPOINT, endpoint);
321   return app_send_cmd(AUL_UTIL_PID, APP_COM_LEAVE, b.GetHandle());
322 }