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