Fix RequestBroker
[platform/core/appfw/tizen-theme-manager.git] / src / theme / dbus / request_broker.cc
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
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 <gio/gio.h>
18
19 #include <string>
20 #include <utility>
21
22 #include "theme/dbus/request_broker.h"
23 #include "theme/utils/logging.h"
24
25 namespace {
26
27 const char kDbusBusName[] = "org.tizen.ThemeManager";
28 const char kDbusInterfaceName[] = "org.tizen.ThemeManager";
29 const char kDbusObjectPath[] = "/org/tizen/ThemeManager";
30 const char kDBusMethodSendData[] = "SendData";
31
32 tizen_base::Bundle ErrorResultBundle() {
33   tizen_base::Bundle b;
34   b.Add(ttm::dbus::kCmdResultKey, "error");
35   return b;
36 }
37
38 }  // namespace
39
40 namespace ttm {
41 namespace dbus {
42
43 void RequestBroker::OnReceiveDbusMethod(GDBusConnection* connection,
44     const gchar* sender, const gchar* object_path, const gchar* interface_name,
45     const gchar* method_name, GVariant* parameters,
46     GDBusMethodInvocation* invocation, gpointer user_data) {
47   GVariant* reply_body = nullptr;
48   int command;
49   char* serialized = nullptr;
50   g_variant_get(parameters, "(i&s)", &command, &serialized);
51
52   Command cmd = static_cast<Command>(command);
53   tizen_base::Bundle b(serialized);
54
55   auto it = filters_.find(cmd);
56   if (it == filters_.end()) {
57     LOG(ERROR) << "UnKnown command";
58     g_dbus_method_invocation_return_value(invocation, nullptr);
59     return;
60   }
61
62   tizen_base::Bundle result = it->second.GetHandler()->OnRequest(cmd, b);
63   reply_body = g_variant_new("(s)", result.ToRaw().first.get());
64   g_dbus_method_invocation_return_value(invocation, reply_body);
65 }
66
67 bool RequestBroker::Init() {
68   GError* error = nullptr;
69   connection_ = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &error);
70   if (connection_ == nullptr) {
71     if (error != nullptr) {
72       LOG(ERROR) << "Failed to get dbus [" << error->message << "]";
73       g_error_free(error);
74     }
75     return false;
76   }
77
78   return true;
79 }
80
81 RequestBroker& RequestBroker::GetInst() {
82   static RequestBroker sBroker;
83   if (sBroker.connection_ == nullptr)
84     sBroker.Init();
85   return sBroker;
86 }
87
88 GDBusConnection* RequestBroker::GetConnection() {
89   return connection_;
90 }
91
92 int RequestBroker::RegisterRequestFilter(RequestFilter filter) {
93   filters_.emplace(filter.GetCmd(), filter);
94   return 0;
95 }
96
97 bool RequestBroker::EmitSignal(std::string signal_name,
98     Command cmd, tizen_base::Bundle data) {
99   GError* err = nullptr;
100   gboolean result = TRUE;
101   GVariant *serialized = nullptr;
102
103   serialized = g_variant_new("(is)", static_cast<int>(cmd),
104       reinterpret_cast<char*>(data.ToRaw().first.get()));
105
106   result = g_dbus_connection_emit_signal(connection_,
107       nullptr, kDbusObjectPath, kDbusInterfaceName, signal_name.c_str(),
108       serialized, &err);
109   if (result == FALSE) {
110     LOG(ERROR) << "g_dbus_connection_emit_signal() is failed";
111     if (err != nullptr) {
112       LOG(ERROR) << "g_dbus_connection_emit_signal() err : " <<  err->message;
113       g_error_free(err);
114     }
115   } else {
116     LOG(INFO) << "Successfully emit signal";
117   }
118   return result;
119 }
120
121 bool RequestBroker::Listen() {
122   const GDBusInterfaceVTable interface_vtable = {
123     [](GDBusConnection* connection, const gchar* sender,
124         const gchar* object_path, const gchar* interface_name,
125         const gchar* method_name, GVariant* parameters,
126         GDBusMethodInvocation* invocation, gpointer user_data) {
127       reinterpret_cast<RequestBroker*>(user_data)->OnReceiveDbusMethod(
128           connection, sender, object_path, interface_name, method_name,
129           parameters, invocation, user_data);
130     },
131     nullptr,
132     nullptr
133   };
134   gchar introspection_xml[] =
135     "<node>"
136     "  <interface name='org.tizen.ThemeManager'>"
137     "    <method name='SendData'>"
138     "      <arg type='i' name='command' direction='in'/>"
139     "      <arg type='s' name='serialized' direction='in'/>"
140     "      <arg type='s' name='serialized' direction='out'/>"
141     "    </method>"
142     "  </interface>"
143     "</node>";
144   GError* error = nullptr;
145   GDBusNodeInfo* introspection_data =
146       g_dbus_node_info_new_for_xml(introspection_xml, &error);
147   if (introspection_data == nullptr) {
148     LOG(ERROR) << "g_dbus_node_info_new_for_xml is failed";
149     if (error != nullptr) {
150       LOG(ERROR) << "g_dbus_node_info_new_for_xml err ["
151                  << error->message << "]";
152       g_error_free(error);
153     }
154     return false;
155   }
156
157   registration_id_ = g_dbus_connection_register_object(
158       connection_, kDbusObjectPath, introspection_data->interfaces[0],
159       &interface_vtable, this, nullptr, nullptr);
160   g_dbus_node_info_unref(introspection_data);
161   if (registration_id_ == 0) {
162     LOG(ERROR) << "register object fail";
163     return false;
164   }
165
166   int owner_id = g_bus_own_name_on_connection(connection_,
167       kDbusBusName, G_BUS_NAME_OWNER_FLAGS_NONE,
168       nullptr, nullptr, nullptr, nullptr);
169   if (owner_id == 0) {
170     g_object_unref(connection_);
171     LOG(ERROR) << "g_bus_own_name_on_connection error";
172     return false;
173   }
174
175   return true;
176 }
177
178 bool RequestBroker::Subscribe() {
179   subscribe_id_ = g_dbus_connection_signal_subscribe(connection_, nullptr,
180       kDbusInterfaceName, nullptr, kDbusObjectPath, nullptr,
181       G_DBUS_SIGNAL_FLAGS_NONE,
182       [](GDBusConnection* connection, const gchar* sender_name,
183           const gchar* object_path, const gchar* interface_name,
184           const gchar* signal_name, GVariant* parameters, void* user_data) {
185         RequestBroker* broker = static_cast<RequestBroker*>(user_data);
186         char* serialized = nullptr;
187         int command;
188         g_variant_get(parameters, "(i&s)", &command, &serialized);
189
190         Command cmd = static_cast<Command>(command);
191         tizen_base::Bundle b(serialized);
192
193         auto it = broker->filters_.find(cmd);
194         if (it == broker->filters_.end())
195           return;
196
197         tizen_base::Bundle result = it->second.GetHandler()->OnRequest(cmd, b);
198       },
199       this, nullptr);
200
201   return subscribe_id_ > 0;
202 }
203
204 tizen_base::Bundle RequestBroker::SendData(Command cmd,
205     tizen_base::Bundle& data) {
206   GError* err = nullptr;
207   GDBusMessage* msg = g_dbus_message_new_method_call(kDbusInterfaceName,
208       kDbusObjectPath, kDbusInterfaceName, kDBusMethodSendData);
209   if (msg == nullptr) {
210     LOG(ERROR) << "Can't allocate new method call";
211     return ErrorResultBundle();
212   }
213   g_dbus_message_set_body(msg,
214       g_variant_new("(is)",
215         static_cast<int>(cmd),
216         reinterpret_cast<char*>(data.ToRaw().first.get())));
217
218   GDBusMessage* reply = g_dbus_connection_send_message_with_reply_sync(
219       connection_, msg, G_DBUS_SEND_MESSAGE_FLAGS_NONE,
220       -1, nullptr, nullptr, &err);
221   if (reply == nullptr) {
222     LOG(ERROR) << "g_dbus_connection_send_message_with_reply_sync() is failed";
223     if (err) {
224       LOG(ERROR) << "error[" <<  err->message << "]";
225       g_error_free(err);
226     }
227     return ErrorResultBundle();
228   }
229   GVariant* reply_body = g_dbus_message_get_body(reply);
230   if (reply_body == nullptr) {
231     LOG(ERROR) << "g_dbus_message_get_body() is failed";
232     return ErrorResultBundle();
233   }
234
235   char* serialized = nullptr;
236   g_variant_get(reply_body, "(&s)", &serialized);
237   tizen_base::Bundle result(serialized);
238   return result;
239 }
240
241 void RequestBroker::SendDataAsync(Command cmd, tizen_base::Bundle& data) {
242   GDBusMessage* msg = g_dbus_message_new_method_call(
243       kDbusBusName, kDbusObjectPath, kDbusInterfaceName, kDBusMethodSendData);
244   if (msg == nullptr) {
245     LOG(ERROR) << "Can't allocate new method call";
246     return;
247   }
248
249   g_dbus_message_set_body(msg, g_variant_new("(is)", static_cast<int>(cmd),
250           reinterpret_cast<char*>(data.ToRaw().first.get())));
251
252   std::pair<Command, RequestBroker*> param = std::make_pair(cmd, this);
253
254   g_dbus_connection_send_message_with_reply(connection_, msg,
255       G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, nullptr, nullptr,
256       [](GObject* source_object, GAsyncResult* res, gpointer user_data) {
257         auto param =
258             static_cast<std::pair<Command, RequestBroker*>*>(user_data);
259         GDBusConnection* conn =
260             reinterpret_cast<GDBusConnection*>(source_object);
261         GError* err = nullptr;
262         GDBusMessage* reply =
263             g_dbus_connection_send_message_with_reply_finish(conn, res, &err);
264         if (reply == nullptr) {
265           LOG(ERROR) << "No reply. err["
266                      << (err ? err->message : "Unknown") << "]";
267           return;
268         }
269
270         char* serialized = nullptr;
271
272         GVariant* reply_body = g_dbus_message_get_body(reply);
273         g_variant_get(reply_body, "(&s)", &serialized);
274         RequestBroker* broker = param->second;
275         tizen_base::Bundle b(serialized);
276         g_object_unref(reply);
277
278         auto it = broker->filters_.find(param->first);
279         if (it == broker->filters_.end())
280           return;
281         it->second.GetHandler()->OnRequest(Command::RESULT, b);
282       },
283       &param);
284 }
285
286 }  // namespace dbus
287 }  // namespace ttm