aae2c289d3ff4a4b5b7e0c0499dd9605bbd9ee20
[platform/core/appfw/librua.git] / src / rua_dbus.c
1 /*
2  * Copyright (c) 2017 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 <stdio.h>
18 #include <stdlib.h>
19
20 #include <glib.h>
21 #include <gio/gio.h>
22 #include <dlog.h>
23 #include <sqlite3.h>
24
25 #include "rua.h"
26 #include "rua_dbus.h"
27 #include "rua_private.h"
28
29 #define RUA_INTERFACE "org.tizen.rua"
30 #define RUA_PATH "/org/tizen/rua"
31 #define RUA_SIGNAL_DATA_UPDATE "dataupdate"
32
33 struct cb_data {
34         int callback_id;
35         rua_history_update_cb callback;
36         void *user_data;
37 };
38
39 static GDBusConnection *conn;
40 static guint s_id;
41
42 static gint atomic_callback_id;
43 static GHashTable *callback_hash_table;
44
45 static void __foreach_callback(gpointer key, gpointer value,
46                 gpointer user_data);
47 static void __signal_handler(GDBusConnection *connection,
48                                         const gchar *sender_name,
49                                         const gchar *object_path,
50                                         const gchar *interface_name,
51                                         const gchar *signal_name,
52                                         GVariant *parameters,
53                                         gpointer user_data);
54 static void __rua_dbus_init(void);
55 static void __rua_dbus_exit(void);
56
57 int rua_dbus_send_update_signal(update_type type)
58 {
59         __rua_dbus_init();
60         GError *err = NULL;
61
62         if (g_dbus_connection_emit_signal(conn,
63                                 NULL,
64                                 RUA_PATH,
65                                 RUA_INTERFACE,
66                                 RUA_SIGNAL_DATA_UPDATE,
67                                 g_variant_new("(i)", type),
68                                 &err) == FALSE) {
69                 LOGE("g_dbus_connection_emit_signal() is failed. %s",
70                                 err->message);
71                 g_clear_error(&err);
72                 __rua_dbus_exit();
73                 return -1;
74         }
75
76         if (g_dbus_connection_flush_sync(conn, NULL, &err) == FALSE) {
77                 LOGE("g_dbus_connection_flush_sync() is failed. %s",
78                                 err->message);
79                 g_clear_error(&err);
80                 __rua_dbus_exit();
81                 return -1;
82         }
83
84         g_clear_error(&err);
85
86         __rua_dbus_exit();
87
88         return 0;
89 }
90
91 int rua_dbus_signal_subscribe(rua_history_update_cb callback,
92                 void *user_data, int *callback_id)
93 {
94         struct cb_data *cd = NULL;
95
96         if (s_id == 0) {
97                 __rua_dbus_init();
98
99                 s_id = g_dbus_connection_signal_subscribe(conn,
100                                 NULL,
101                                 RUA_INTERFACE,
102                                 RUA_SIGNAL_DATA_UPDATE,
103                                 RUA_PATH,
104                                 NULL,
105                                 G_DBUS_SIGNAL_FLAGS_NONE,
106                                 __signal_handler,
107                                 NULL,
108                                 NULL);
109
110                 if (s_id == 0) {
111                         LOGE("g_dbus_connection_signal_subscribe() is failed.");
112                         __rua_dbus_exit();
113                         return -1;
114                 }
115
116                 if (!callback_hash_table) {
117                         callback_hash_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
118                                         NULL, free);
119                         if (!callback_hash_table) {
120                                 LOGE("out of memory : g_hash_table_new() is failed");
121                                 __rua_dbus_exit();
122                                 return -1;
123                         }
124                 }
125         }
126
127         cd = (struct cb_data *)malloc(sizeof(struct cb_data));
128         if (!cd) {
129                 LOGE("out of memory : malloc() is failed");
130                 return -1;
131         }
132
133         g_atomic_int_inc(&atomic_callback_id);
134
135         cd->callback = callback;
136         cd->user_data = user_data;
137         cd->callback_id = atomic_callback_id;
138
139         g_hash_table_insert(callback_hash_table,
140                         GINT_TO_POINTER(cd->callback_id), (gpointer)cd);
141
142         *callback_id = cd->callback_id;
143
144         return 0;
145 }
146
147 int rua_dbus_signal_unsubscribe(int callback_id)
148 {
149         gboolean result = FALSE;
150         guint table_size = 0;
151
152         result = g_hash_table_remove(callback_hash_table, GINT_TO_POINTER(callback_id));
153         if (!result) {
154                 LOGE("g_hash_table_remove failed(%d is wrong)", callback_id);
155                 return -1;
156         }
157
158         table_size = g_hash_table_size(callback_hash_table);
159         if (s_id && table_size == 0) {
160                 g_dbus_connection_signal_unsubscribe(conn, s_id);
161                 g_hash_table_destroy(callback_hash_table);
162                 __rua_dbus_exit();
163                 callback_hash_table = NULL;
164                 s_id = 0;
165         }
166
167         return 0;
168 }
169
170 static void __foreach_callback(gpointer key, gpointer value,
171                 gpointer user_data)
172 {
173         char **table = NULL;
174         int nrows = 0;
175         int ncols = 0;
176         int r = 0;
177
178         struct cb_data *cd = (struct cb_data *)value;
179
180         r = rua_history_load_db(&table, &nrows, &ncols);
181         if (r == -1)
182                 return;
183
184         if (cd->callback)
185                 cd->callback(table, nrows, ncols, cd->user_data);
186
187         sqlite3_free_table(table);
188 }
189
190 static void __signal_handler(GDBusConnection *connection,
191                                         const gchar *sender_name,
192                                         const gchar *object_path,
193                                         const gchar *interface_name,
194                                         const gchar *signal_name,
195                                         GVariant *parameters,
196                                         gpointer user_data)
197 {
198         int update_type;
199
200         LOGI("__signal_handler");
201         if (g_strcmp0(signal_name, RUA_SIGNAL_DATA_UPDATE))
202                 return;
203
204         g_variant_get(parameters, "(i)", &update_type);
205
206         g_hash_table_foreach(callback_hash_table, __foreach_callback, NULL);
207 }
208
209 static void __rua_dbus_init(void)
210 {
211         if (!conn) {
212                 GError *err = NULL;
213                 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
214                 if (!conn) {
215                         LOGE("g_bus_get_sync() is failed. %s", err->message);
216                         g_error_free(err);
217                         return;
218                 }
219         }
220 }
221
222 static void __rua_dbus_exit(void)
223 {
224         if (conn) {
225                 g_object_unref(conn);
226                 conn = NULL;
227         }
228 }