3
* Copyright © 2011 Michal Hruby <michal.mhr@gmail.com>
4
* Copyright © 2011 Collabora Ltd.
5
* By Siegfried-Angel Gevatter Pujals <siegfried@gevatter.com>
7
* Based upon a Python implementation (2009-2010) by:
8
* Siegfried-Angel Gevatter Pujals <siegfried@gevatter.com>
9
* Mikkel Kamstrup Erlandsen <mikkel.kamstrup@gmail.com>
11
* This program is free software: you can redistribute it and/or modify
12
* it under the terms of the GNU Lesser General Public License as published by
13
* the Free Software Foundation, either version 2.1 of the License, or
14
* (at your option) any later version.
16
* This program is distributed in the hope that it will be useful,
17
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
* GNU General Public License for more details.
21
* You should have received a copy of the GNU Lesser General Public License
22
* along with this program. If not, see <http://www.gnu.org/licenses/>.
28
[DBus (name = "org.gnome.zeitgeist.DataSourceRegistry")]
29
public interface RemoteRegistry: Object
31
[DBus (signature = "a(sssa(asaasay)bxb)")]
32
public abstract Variant get_data_sources () throws Error;
33
public abstract bool register_data_source (string unique_id,
34
string name, string description,
35
[DBus (signature = "a(asaasay)")] Variant event_templates, BusName? sender)
37
public abstract void set_data_source_enabled (string unique_id,
38
bool enabled) throws Error;
39
[DBus (signature = "(sssa(asaasay)bxb)")]
40
public abstract Variant get_data_source_from_id (string id) throws Error;
42
public signal void data_source_disconnected (
43
[DBus (signature = "(sssa(asaasay)bxb)")] Variant data_source);
44
public signal void data_source_enabled (string unique_id,
46
public signal void data_source_registered (
47
[DBus (signature = "(sssa(asaasay)bxb)")] Variant data_source);
50
class DataSource: Object
52
public string unique_id { get; set; }
53
public string name { get; set; }
54
public string description { get; set; }
56
public GenericArray<Event>? event_templates { get; set; }
58
public bool enabled { get; set; }
59
public bool running { get; set; }
60
public int64 timestamp { get; set; }
67
public DataSource.full (string unique_id, string name,
68
string description, GenericArray<Event> templates)
70
Object (unique_id: unique_id, name: name, description: description,
71
event_templates: templates);
74
public DataSource.from_variant (Variant variant,
75
bool reset_running=false)
78
variant.get_type_string () == "(sssa("+Utils.SIG_EVENT+")bxb)"
79
|| variant.get_type_string () == "sssa("+Utils.SIG_EVENT+")");
80
var iter = variant.iterator ();
82
assert (iter.n_children () >= 4);
83
unique_id = iter.next_value ().get_string ();
84
name = iter.next_value ().get_string ();
85
description = iter.next_value ().get_string ();
86
event_templates = Events.from_variant (iter.next_value ());
88
if (iter.n_children () > 4)
90
running = iter.next_value ().get_boolean ();
93
timestamp = iter.next_value ().get_int64 ();
94
enabled = iter.next_value ().get_boolean ();
98
public Variant to_variant ()
100
var vb = new VariantBuilder (new VariantType (
101
"(sssa("+Utils.SIG_EVENT+")bxb)"));
103
vb.add ("s", unique_id);
105
vb.add ("s", description);
106
if (event_templates != null && event_templates.length > 0)
108
vb.add_value (Events.to_variant (event_templates));
112
vb.open (new VariantType ("a("+Utils.SIG_EVENT+")"));
116
vb.add ("b", running);
117
vb.add ("x", timestamp);
118
vb.add ("b", enabled);
124
namespace DataSources
126
private const string SIG_DATASOURCES =
127
"a(sssa("+Utils.SIG_EVENT+")bxb)";
129
private static HashTable<string, DataSource> from_variant (
130
Variant sources_variant, bool reset_running=false)
132
var registry = new HashTable<string, DataSource> (
133
str_hash, str_equal);
136
sources_variant.get_type_string() == SIG_DATASOURCES);
137
foreach (Variant ds_variant in sources_variant)
139
DataSource ds = new DataSource.from_variant (ds_variant,
141
registry.insert (ds.unique_id, ds);
147
public static Variant to_variant (
148
HashTable<string, DataSource> sources)
150
var vb = new VariantBuilder (new VariantType (SIG_DATASOURCES));
152
List<unowned DataSource> data_sources = sources.get_values ();
153
data_sources.sort ((a, b) =>
155
return strcmp (a.unique_id, b.unique_id);
158
foreach (unowned DataSource ds in data_sources)
160
vb.add_value (ds.to_variant ());
167
class DataSourceRegistry: Extension, RemoteRegistry
169
private HashTable<string, DataSource> sources;
170
private HashTable<string, GenericArray<BusName>> running;
171
private uint registration_id;
174
private static const uint DISK_WRITE_TIMEOUT = 5 * 60; // 5 minutes
176
DataSourceRegistry ()
183
running = new HashTable<string, GenericArray<BusName?>>(
184
str_hash, str_equal);
186
Variant? registry = retrieve_config ("registry",
187
DataSources.SIG_DATASOURCES);
188
if (registry != null)
189
sources = DataSources.from_variant (registry, true);
191
sources = new HashTable<string, DataSource> (
192
str_hash, str_equal);
194
// this will be called after bus is acquired, so it shouldn't block
197
var connection = Bus.get_sync (BusType.SESSION, null);
198
registration_id = connection.register_object<RemoteRegistry> (
199
"/org/gnome/zeitgeist/data_source_registry", this);
201
connection.signal_subscribe ("org.freedesktop.DBus",
202
"org.freedesktop.DBus", "NameOwnerChanged",
203
"/org/freedesktop/DBus", null, 0,
208
warning ("%s", err.message);
211
// Changes are saved to the DB every few seconds and at unload.
212
Timeout.add_seconds (DISK_WRITE_TIMEOUT, flush, Priority.LOW);
215
public override void unload ()
219
var connection = Bus.get_sync (BusType.SESSION, null);
220
if (registration_id != 0)
222
connection.unregister_object (registration_id);
228
warning ("%s", err.message);
232
debug ("%s, this.ref_count = %u", Log.METHOD, this.ref_count);
235
public Variant get_data_sources ()
237
return DataSources.to_variant (sources);
240
private bool is_sender_known (BusName sender,
241
GenericArray<BusName> sender_array)
243
for (int i = 0; i < sender_array.length; i++)
245
if (sender == sender_array[i])
251
public bool register_data_source (string unique_id, string name,
252
string description, Variant event_templates, BusName? sender)
254
debug ("%s: %s, %s, %s", Log.METHOD, unique_id, name, description);
257
warning ("%s: sender == null, ignoring request", Log.METHOD);
262
var sender_array = running.lookup (unique_id);
263
if (sender_array == null)
265
running.insert (unique_id, new GenericArray<BusName?>());
266
running.lookup (unique_id).add (sender);
268
else if (is_sender_known (sender, sender_array))
270
running.lookup (unique_id).add (sender);
273
unowned DataSource? ds = sources.lookup (unique_id);
276
var templates = Events.from_variant (event_templates);
278
ds.description = description;
279
ds.event_templates = templates;
280
ds.timestamp = Timestamp.now ();
284
data_source_registered (ds.to_variant ());
290
var templates = Events.from_variant (event_templates);
291
DataSource new_ds = new DataSource.full (unique_id, name,
292
description, templates);
293
new_ds.enabled = true;
294
new_ds.running = true;
295
new_ds.timestamp = Timestamp.now ();
296
sources.insert (unique_id, new_ds);
299
data_source_registered (new_ds.to_variant ());
301
return new_ds.enabled;
306
public void set_data_source_enabled (string unique_id, bool enabled)
308
debug ("%s: %s, %d", Log.METHOD, unique_id, (int) enabled);
309
unowned DataSource? ds = sources.lookup (unique_id);
312
if (ds.enabled != enabled)
314
ds.enabled = enabled;
316
data_source_enabled (unique_id, enabled);
321
warning ("DataSource \"%s\" isn't registered!", unique_id);
325
public Variant get_data_source_from_id (string unique_id) throws Error
327
unowned DataSource? ds = sources.lookup (unique_id);
330
return ds.to_variant ();
333
throw new EngineError.INVALID_KEY (
334
"Datasource with unique ID: %s not found".printf (unique_id));
337
public override void pre_insert_events (GenericArray<Event?> events,
340
foreach (string unique_id in running.get_keys())
342
GenericArray<BusName?> bus_names = running.lookup (unique_id);
343
if (is_sender_known (sender, bus_names))
345
var data_source = sources.lookup (unique_id);
347
data_source.timestamp = Timestamp.now ();
350
if (!data_source.enabled)
352
for (int i = 0; i < events.length; i++)
360
* Cleanup disconnected clients and mark data-sources as not running
361
* when no client remains.
363
private void name_owner_changed (DBusConnection conn, string sender,
364
string path, string interface_name, string signal_name,
367
var name = parameters.get_child_value (0).dup_string ();
368
//var old_owner = parameters.get_child_value (1).dup_string ();
369
var new_owner = parameters.get_child_value (2).dup_string ();
370
if (new_owner != "") return;
372
// Are there data-sources with this bus name?
373
var disconnected_ds = new GenericArray<DataSource> ();
375
var iter = HashTableIter<string, GenericArray<BusName?>> (
378
unowned GenericArray<BusName> name_arr;
379
while (iter.next (out uid, out name_arr))
381
for (int i = 0; i < name_arr.length; i++)
383
if (name_arr[i] == name)
385
disconnected_ds.add (sources.lookup (uid));
386
name_arr.remove_index_fast (i--);
392
if (disconnected_ds.length == 0) return;
394
for (int i = 0; i < disconnected_ds.length; i++)
396
var ds = disconnected_ds[i];
397
unowned string uid = ds.unique_id;
398
debug ("Client disconnected: %s [%s]", ds.name, uid);
400
// FIXME: Update here or change semantics to "last insert"?
401
ds.timestamp = Timestamp.now ();
404
if (running.lookup (uid).length == 0)
406
debug ("No remaining client running: %s [%s]",
408
running.remove (uid);
411
data_source_disconnected (ds.to_variant ());
416
private bool flush ()
420
Variant v = DataSources.to_variant (sources);
421
store_config ("registry", v);
429
#if BUILTIN_EXTENSIONS
430
public static Type data_source_registry_init (TypeModule module)
433
public static Type extension_register (TypeModule module)
436
return typeof (DataSourceRegistry);
440
// vim:expandtab:ts=4:sw=4