~ubuntu-branches/ubuntu/quantal/zeitgeist/quantal

« back to all changes in this revision

Viewing changes to src/zeitgeist-daemon.vala

  • Committer: Package Import Robot
  • Author(s): Didier Roche
  • Date: 2011-11-15 11:15:56 UTC
  • mfrom: (1.1.13)
  • Revision ID: package-import@ubuntu.com-20111115111556-4lmc5wdvjrsdm0ss
Tags: 0.8.99~alpha1-1ubuntu1
Upload to ubuntu the new zeitgeist rewritten in vala

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* zeitgeist-daemon.vala
 
2
 *
 
3
 * Copyright © 2011 Seif Lotfy <seif@lotfy.com>
 
4
 * Copyright © 2011 Michal Hruby <michal.mhr@gmail.com>
 
5
 * Copyright © 2011 Collabora Ltd.
 
6
 *             By Siegfried-Angel Gevatter Pujals <siegfried@gevatter.com>
 
7
 *             By Seif Lotfy <seif@lotfy.com>
 
8
 *
 
9
 * This program is free software: you can redistribute it and/or modify
 
10
 * it under the terms of the GNU Lesser General Public License as published by
 
11
 * the Free Software Foundation, either version 2.1 of the License, or
 
12
 * (at your option) any later version.
 
13
 *
 
14
 * This program is distributed in the hope that it will be useful,
 
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
 * GNU General Public License for more details.
 
18
 *
 
19
 * You should have received a copy of the GNU Lesser General Public License
 
20
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
21
 *
 
22
 */
 
23
 
 
24
namespace Zeitgeist
 
25
{
 
26
 
 
27
    [DBus (name = "org.freedesktop.DBus")]
 
28
    public interface RemoteDBus : Object
 
29
    {
 
30
        public abstract bool name_has_owner (string name) throws IOError;
 
31
    }
 
32
 
 
33
    public class Daemon : Object, RemoteLog
 
34
    {
 
35
        const string DBUS_NAME = "org.gnome.zeitgeist.Engine";
 
36
        private static bool show_version_info = false;
 
37
        private static bool show_options = false;
 
38
        private static bool no_datahub = false;
 
39
        private static bool replace_mode = false;
 
40
        private static bool quit_daemon = false;
 
41
        private static string log_level = "";
 
42
 
 
43
        const OptionEntry[] options =
 
44
        {
 
45
            {
 
46
                "version", 'v', 0, OptionArg.NONE, out show_version_info,
 
47
                "Print program's version number and exit", null
 
48
            },
 
49
            {
 
50
                "no-datahub", 0, 0, OptionArg.NONE, out no_datahub,
 
51
                "Do not start zeitgeist-datahub automatically", null
 
52
            },
 
53
            {
 
54
                "no-passive-loggers", 0, OptionFlags.HIDDEN, OptionArg.NONE,
 
55
                out no_datahub, null, null
 
56
            },
 
57
            {
 
58
                "replace", 'r', 0, OptionArg.NONE, out replace_mode,
 
59
                "If another Zeitgeist instance is already running, replace it",
 
60
                null
 
61
            },
 
62
            {
 
63
                "quit", 0, 0, OptionArg.NONE, out quit_daemon,
 
64
                "Quit running Zeitgeist daemon instance", null
 
65
            },
 
66
            {
 
67
                "log-level", 0, 0, OptionArg.STRING, out log_level,
 
68
                "How much information should be printed; possible values: " +
 
69
                "DEBUG, INFO, WARNING, ERROR, CRITICAL", "LEVEL"
 
70
            },
 
71
            {
 
72
                "shell-completion", 0, OptionFlags.HIDDEN, OptionArg.NONE,
 
73
                out show_options, null, null
 
74
            },
 
75
            {
 
76
                null
 
77
            }
 
78
        };
 
79
 
 
80
        private static Daemon? instance;
 
81
        private static MainLoop mainloop;
 
82
        private static bool name_acquired = false;
 
83
 
 
84
        private Engine engine;
 
85
        private MonitorManager notifications;
 
86
 
 
87
        private uint log_register_id;
 
88
        private unowned DBusConnection connection;
 
89
 
 
90
        public string[] extensions
 
91
        {
 
92
            owned get
 
93
            {
 
94
                string[] ext = engine.get_extension_names ();
 
95
                return ext;
 
96
            }
 
97
        }
 
98
 
 
99
        public VersionStruct version
 
100
        {
 
101
            owned get
 
102
            {
 
103
                var s = VersionStruct ();
 
104
                string[] ver = Config.VERSION.split (".");
 
105
                if (ver.length >= 3)
 
106
                {
 
107
                    s.major = int.parse (ver[0]);
 
108
                    s.minor = int.parse (ver[1]);
 
109
                    s.micro = int.parse (ver[2]);
 
110
                }
 
111
                else
 
112
                {
 
113
                    warning ("Unable to parse version info!");
 
114
                    s.major = 0;
 
115
                    s.minor = 8;
 
116
                    s.micro = 99;
 
117
                }
 
118
                return s;
 
119
            }
 
120
        }
 
121
 
 
122
        public Daemon () throws EngineError
 
123
        {
 
124
            engine = new Engine ();
 
125
            notifications = new MonitorManager ();
 
126
        }
 
127
 
 
128
        public Variant get_events (uint32[] event_ids, BusName sender)
 
129
            throws Error
 
130
        {
 
131
            var timer = new Timer ();
 
132
            GenericArray<Event> events = engine.get_events (event_ids);
 
133
            debug ("%s executed in %f seconds", Log.METHOD, timer.elapsed ());
 
134
            return Events.to_variant (events);
 
135
        }
 
136
 
 
137
        public string[] find_related_uris (Variant time_range,
 
138
                Variant event_templates,
 
139
                Variant result_event_templates,
 
140
                uint storage_state, uint num_events, uint result_type,
 
141
                BusName sender) throws Error
 
142
        {
 
143
            return engine.find_related_uris (
 
144
                new TimeRange.from_variant (time_range),
 
145
                Events.from_variant (event_templates),
 
146
                Events.from_variant (result_event_templates),
 
147
                storage_state, num_events, result_type);
 
148
        }
 
149
 
 
150
        public uint32[] find_event_ids (Variant time_range,
 
151
                Variant event_templates,
 
152
                uint storage_state, uint num_events, uint result_type,
 
153
                BusName sender) throws Error
 
154
        {
 
155
            return engine.find_event_ids (
 
156
                new TimeRange.from_variant (time_range),
 
157
                Events.from_variant(event_templates),
 
158
                storage_state, num_events, result_type, sender);
 
159
        }
 
160
 
 
161
        public Variant find_events (Variant time_range,
 
162
                Variant event_templates,
 
163
                uint storage_state, uint num_events, uint result_type,
 
164
                BusName sender) throws Error
 
165
        {
 
166
            var timer = new Timer ();
 
167
            var events = engine.find_events (
 
168
                new TimeRange.from_variant (time_range),
 
169
                Events.from_variant (event_templates),
 
170
                storage_state, num_events, result_type, sender);
 
171
            debug ("%s executed in %f seconds", Log.METHOD, timer.elapsed ());
 
172
            return Events.to_variant (events);
 
173
        }
 
174
 
 
175
        public uint32[] insert_events (
 
176
                Variant vevents,
 
177
                BusName sender) throws Error
 
178
        {
 
179
            var events = Events.from_variant (vevents);
 
180
 
 
181
            uint32[] event_ids = engine.insert_events (events, sender);
 
182
            var min_timestamp = int64.MAX;
 
183
            var max_timestamp = int64.MIN;
 
184
            for (int i = 0; i < events.length; i++)
 
185
            {
 
186
                if (events[i] == null) continue;
 
187
                min_timestamp = int64.min (min_timestamp, events[i].timestamp);
 
188
                max_timestamp = int64.max (max_timestamp, events[i].timestamp);
 
189
            }
 
190
 
 
191
            if (min_timestamp < int64.MAX)
 
192
            {
 
193
                notifications.notify_insert (
 
194
                    new TimeRange (min_timestamp, max_timestamp), events);
 
195
            }
 
196
            /* else { there's not even one valid event } */
 
197
 
 
198
            return event_ids;
 
199
        }
 
200
 
 
201
        public Variant delete_events (uint32[] event_ids, BusName sender)
 
202
            throws Error
 
203
        {
 
204
            TimeRange? time_range = engine.delete_events (event_ids, sender);
 
205
            if (time_range != null)
 
206
            {
 
207
                notifications.notify_delete (time_range, event_ids);
 
208
            }
 
209
            else
 
210
            {
 
211
                // All the given event_ids are invalod or the events
 
212
                // have already been deleted before!
 
213
                time_range = new TimeRange (-1, -1);
 
214
            }
 
215
            return time_range.to_variant ();
 
216
        }
 
217
 
 
218
        public void quit () throws Error
 
219
        {
 
220
            do_quit ();
 
221
        }
 
222
 
 
223
        private void do_quit ()
 
224
        {
 
225
            engine.close ();
 
226
            mainloop.quit ();
 
227
        }
 
228
 
 
229
        public void install_monitor (ObjectPath monitor_path,
 
230
                Variant time_range,
 
231
                Variant event_templates,
 
232
                BusName owner) throws Error
 
233
        {
 
234
            notifications.install_monitor (owner, monitor_path,
 
235
                new TimeRange.from_variant (time_range),
 
236
                Events.from_variant (event_templates));
 
237
        }
 
238
 
 
239
        public void remove_monitor (ObjectPath monitor_path, BusName owner)
 
240
            throws Error
 
241
        {
 
242
            notifications.remove_monitor (owner, monitor_path);
 
243
        }
 
244
 
 
245
        public void register_dbus_object (DBusConnection conn) throws IOError
 
246
        {
 
247
            connection = conn;
 
248
            log_register_id = conn.register_object<RemoteLog> (
 
249
                    "/org/gnome/zeitgeist/log/activity", this);
 
250
        }
 
251
 
 
252
        public void unregister_dbus_object ()
 
253
        {
 
254
            if (log_register_id != 0)
 
255
            {
 
256
                connection.unregister_object (log_register_id);
 
257
                log_register_id = 0;
 
258
            }
 
259
        }
 
260
 
 
261
        private static bool quit_running_instance (DBusConnection conn)
 
262
        {
 
263
            try
 
264
            {
 
265
                var running_instance = conn.get_proxy_sync<RemoteLog> (
 
266
                    DBUS_NAME, "/org/gnome/zeitgeist/log/activity");
 
267
                running_instance.quit ();
 
268
                return true;
 
269
            }
 
270
            catch (Error err)
 
271
            {
 
272
                warning ("%s", err.message);
 
273
            }
 
274
 
 
275
            return false;
 
276
        }
 
277
 
 
278
        private static void name_acquired_callback (DBusConnection conn)
 
279
        {
 
280
            name_acquired = true;
 
281
 
 
282
            // only run datahub when we acquire bus name
 
283
            if (!no_datahub)
 
284
            {
 
285
                try
 
286
                {
 
287
                    Process.spawn_command_line_async ("zeitgeist-datahub");
 
288
                }
 
289
                catch (SpawnError err)
 
290
                {
 
291
                    warning ("%s", err.message);
 
292
                }
 
293
            }
 
294
        }
 
295
 
 
296
        private static void name_lost_callback (DBusConnection? conn)
 
297
        {
 
298
            if (conn == null)
 
299
            {
 
300
                // something happened to our bus connection
 
301
                mainloop.quit ();
 
302
            }
 
303
            else if (instance != null && !name_acquired)
 
304
            {
 
305
                // we acquired bus connection, but couldn't own the name
 
306
                if (!replace_mode)
 
307
                {
 
308
                }
 
309
 
 
310
                debug ("Waiting 10 seconds to acquire name...");
 
311
                // we already called Quit, let's wait a while
 
312
                // for the running instance to quit, bail out
 
313
                // if it doesn't
 
314
                Timeout.add (10000, () =>
 
315
                {
 
316
                    if (!name_acquired)
 
317
                    {
 
318
                        warning ("Timeout reached, unable to acquire name!");
 
319
                        mainloop.quit ();
 
320
                    }
 
321
                    return false;
 
322
                });
 
323
            }
 
324
            else if (instance != null && name_acquired)
 
325
            {
 
326
                // we owned the name and we lost it... what to do?
 
327
                mainloop.quit ();
 
328
            }
 
329
        }
 
330
 
 
331
        static void run ()
 
332
        {
 
333
            DBusConnection connection;
 
334
            bool name_owned;
 
335
            try
 
336
            {
 
337
                connection = Bus.get_sync (BusType.SESSION);
 
338
                var proxy = connection.get_proxy_sync<RemoteDBus> (
 
339
                    "org.freedesktop.DBus", "/org/freedesktop/DBus",
 
340
                    DBusProxyFlags.DO_NOT_LOAD_PROPERTIES);
 
341
                name_owned = proxy.name_has_owner (DBUS_NAME);
 
342
            }
 
343
            catch (IOError err)
 
344
            {
 
345
                critical ("%s", err.message);
 
346
                return;
 
347
            }
 
348
            if (name_owned)
 
349
            {
 
350
                if (replace_mode || quit_daemon)
 
351
                {
 
352
                    quit_running_instance (connection);
 
353
                }
 
354
                else
 
355
                {
 
356
                    critical ("An existing instance was found. Please use " +
 
357
                        "--replace to stop it and start a new instance.");
 
358
                    Posix.exit (10);
 
359
                }
 
360
            }
 
361
 
 
362
            /* don't do anything else if we were called with --quit param */
 
363
            if (quit_daemon) return;
 
364
 
 
365
            /* setup Engine instance and register objects on dbus */
 
366
            try
 
367
            {
 
368
                instance = new Daemon ();
 
369
                instance.register_dbus_object (connection);
 
370
            }
 
371
            catch (Error err)
 
372
            {
 
373
                critical ("%s", err.message);
 
374
                return;
 
375
            }
 
376
 
 
377
            uint owner_id = Bus.own_name_on_connection (connection,
 
378
                DBUS_NAME,
 
379
                BusNameOwnerFlags.NONE,
 
380
                name_acquired_callback,
 
381
                name_lost_callback);
 
382
 
 
383
            mainloop = new MainLoop ();
 
384
            mainloop.run ();
 
385
 
 
386
            if (instance != null)
 
387
            {
 
388
                Bus.unown_name (owner_id);
 
389
                instance.unregister_dbus_object ();
 
390
                instance = null;
 
391
 
 
392
                // make sure we send quit reply
 
393
                try
 
394
                {
 
395
                    connection.flush_sync ();
 
396
                }
 
397
                catch (Error e)
 
398
                {
 
399
                    warning ("%s", e.message);
 
400
                }
 
401
            }
 
402
        }
 
403
 
 
404
        static void safe_exit ()
 
405
        {
 
406
            instance.do_quit ();
 
407
        }
 
408
 
 
409
        static int main (string[] args)
 
410
        {
 
411
            Posix.signal (Posix.SIGHUP, safe_exit);
 
412
            Posix.signal (Posix.SIGINT, safe_exit);
 
413
            Posix.signal (Posix.SIGTERM, safe_exit);
 
414
 
 
415
            var opt_context = new OptionContext (" - Zeitgeist daemon");
 
416
            opt_context.add_main_entries (options, null);
 
417
 
 
418
            try
 
419
            {
 
420
                opt_context.parse (ref args);
 
421
 
 
422
                if (show_version_info)
 
423
                {
 
424
                    stdout.printf (Config.VERSION + "\n");
 
425
                    return 0;
 
426
                }
 
427
                if (show_options)
 
428
                {
 
429
                    foreach (unowned OptionEntry? entry in options)
 
430
                    {
 
431
                        if (entry.long_name != null)
 
432
                            stdout.printf ("--%s ", entry.long_name);
 
433
                        if (entry.short_name != 0)
 
434
                            stdout.printf ("-%c ", entry.short_name);
 
435
                    }
 
436
                    stdout.printf ("--help\n");
 
437
 
 
438
                    return 0;
 
439
                }
 
440
                run ();
 
441
            }
 
442
            catch (Error err)
 
443
            {
 
444
                warning ("%s", err.message);
 
445
            }
 
446
 
 
447
            return 0;
 
448
        }
 
449
 
 
450
    }
 
451
 
 
452
}
 
453
// vim:expandtab:ts=4:sw=4