From 4a4f32aa9a351c616c73e1d068ee8921ba06df09 Mon Sep 17 00:00:00 2001 From: Seif Lotfy Date: Sun, 10 Feb 2013 11:17:54 +0100 Subject: initial directread --- Makefile.am | 2 - configure.ac | 9 +- libzeitgeist/Makefile.am | 6 +- libzeitgeist/client/Makefile.am | 54 +++++ libzeitgeist/client/index.vala | 207 ++++++++++++++++++ libzeitgeist/client/log.vala | 471 ++++++++++++++++++++++++++++++++++++++++ libzeitgeist/index.vala | 207 ------------------ libzeitgeist/log.vala | 471 ---------------------------------------- src/Makefile.am | 1 + 9 files changed, 738 insertions(+), 690 deletions(-) create mode 100644 libzeitgeist/client/Makefile.am create mode 100644 libzeitgeist/client/index.vala create mode 100644 libzeitgeist/client/log.vala delete mode 100644 libzeitgeist/index.vala delete mode 100644 libzeitgeist/log.vala diff --git a/Makefile.am b/Makefile.am index 7b28551c..1fd6c9f3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -6,8 +6,6 @@ SUBDIRS = \ extensions \ data \ python \ - test \ - examples \ po \ doc \ $(NULL) diff --git a/configure.ac b/configure.ac index 0ee830cc..e09d4eca 100644 --- a/configure.ac +++ b/configure.ac @@ -47,20 +47,13 @@ AC_CONFIG_FILES([ src/Makefile libzeitgeist/Makefile libzeitgeist/zeitgeist-2.0.pc + libzeitgeist/client/Makefile extensions/Makefile extensions/fts++/Makefile extensions/fts++/test/Makefile data/Makefile data/ontology/Makefile python/Makefile - test/Makefile - test/dbus/Makefile - test/direct/Makefile - test/c/Makefile - test/data/Makefile - examples/Makefile - examples/c/Makefile - examples/vala/Makefile doc/Makefile doc/libzeitgeist/Makefile po/Makefile.in diff --git a/libzeitgeist/Makefile.am b/libzeitgeist/Makefile.am index 69af9efe..74432004 100644 --- a/libzeitgeist/Makefile.am +++ b/libzeitgeist/Makefile.am @@ -1,5 +1,9 @@ NULL = +SUBDIRS = \ + client \ + $(NULL) + lib_LTLIBRARIES = libzeitgeist-2.0.la ONTOLOGY = \ @@ -33,8 +37,6 @@ libzeitgeist_2_0_la_SOURCES = \ event.vala \ subject.vala \ timerange.vala \ - index.vala \ - log.vala \ timestamp.vala \ monitor.vala \ ontology-uris.vala \ diff --git a/libzeitgeist/client/Makefile.am b/libzeitgeist/client/Makefile.am new file mode 100644 index 00000000..356992c8 --- /dev/null +++ b/libzeitgeist/client/Makefile.am @@ -0,0 +1,54 @@ +NULL = + +lib_LTLIBRARIES = libzeitgeist-client.la + + +AM_CPPFLAGS = \ + $(ZEITGEIST_CFLAGS) \ + -include $(CONFIG_HEADER) \ + -I $(top_srcdir)/libzeitgeist \ + -I $(top_srcdir)/src/ \ + -w \ + $(NULL) + +AM_VALAFLAGS = \ + --target-glib=2.26 \ + --pkg gio-2.0 \ + --pkg gio-unix-2.0 \ + --pkg sqlite3 \ + $(top_srcdir)/libzeitgeist/zeitgeist-2.0.vapi \ + $(top_srcdir)/src/zeitgeist-engine.vapi \ + $(top_srcdir)/config.vapi \ + --vapi zeitgeist-client.vapi \ + -H zeitgeist-client.h \ + -h zeitgeist-client-private.h \ + --library=zeitgeist-client \ + $(NULL) + +libzeitgeist_client_la_SOURCES = \ + log.vala \ + $(NULL) + +libzeitgeist_client_la_LIBADD = \ + $(top_builddir)/libzeitgeist/libzeitgeist-2.0.la \ + $(ZEITGEIST_LIBS) \ + $(NULL)$ +libzeitgeist_client_la_LDFLAGS = -version-info $(LIBZEITGEIST_LT_VERSION) + +libzeitgeist_client_includedir=$(includedir)/zeitgeist-client/ +libzeitgeist_client_include_HEADERS = \ + zeitgeist-client.h \ + $(NULL) + +libzeitgeist_client_vapidir = $(datadir)/vala/vapi/ +libzeitgeist_client_vapi_DATA = \ + zeitgeist-client.vapi \ + $(NULL) + +DISTCLEANFILES = \ + zeitgeist-client.vapi \ + $(NULL) + +CLEANFILES = +MAINTAINERCLEANFILES = + diff --git a/libzeitgeist/client/index.vala b/libzeitgeist/client/index.vala new file mode 100644 index 00000000..6ab3d716 --- /dev/null +++ b/libzeitgeist/client/index.vala @@ -0,0 +1,207 @@ +/* + * Copyright © 2012 Canonical Ltd. + * By Siegfried-A. Gevatter + * + * Based upon a C implementation (© 2010-2012 Canonical Ltd) by: + * Mikkel Kamstrup Erlandsen + * Michal Hruby + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ + +namespace Zeitgeist +{ + +/** + * Query the Zeitgeist Full Text Search Extension + * + * include: zeitgeist.h + */ +public class Index : QueuedProxyWrapper +{ + private RemoteSimpleIndexer proxy; + + /** + * Create a new index that interfaces with the default event index of the + * Zeitgeist daemon. + * + * Create a new {@link Index} instance. The index will start to connect + * to Zeitgeist asynchronously. You can however start calling methods on + * the returned instance immediately, any method calls issued before the + * connection has been established will simply be queued and executed once + * the connection is up. + * + * Returns: A reference to a newly allocated index. Free with g_object_unref(). + */ + public Index () + { + Bus.get_proxy (BusType.SESSION, + Utils.ENGINE_DBUS_NAME, "/org/gnome/zeitgeist/index/activity", 0, + null, (obj, res) => + { + try + { + proxy = Bus.get_proxy.end (res); + proxy_acquired (proxy); + } + catch (IOError err) + { + critical ("Unable to connect to Zeitgeist FTS: %s", + err.message); + proxy_unavailable (err); + } + }); + } + + protected override void on_connection_established () + { + } + + protected override void on_connection_lost () { + } + + /** + * Perform a full text search possibly restricted to a {@link TimeRange} + * and/or set of event templates. + * + * The default boolean operator is %AND. Thus the query + * //foo bar// will be interpreted as //foo AND bar//. To exclude a term + * from the result set prepend it with a minus sign - eg. //foo -bar//. + * Phrase queries can be done by double quoting the string + * //"foo is a bar"//. You can truncate terms by appending a *. + * + * There are a few keys you can prefix to a term or phrase to search within + * a specific set of metadata. They are used like //key:value//. The keys + * //name// and //title// search strictly within the text field of the + * event subjects. The key //app// searches within the application name or + * description that is found in the actor attribute of the events. Lastly, + * you can use the //site// key to search within the domain name of subject + * URIs. + * + * You can also control the results with the boolean operators //AND// and + * //OR// and you may use brackets, ( and ), to control the operator + * precedence. + * + * FIXME: how do we put documentation into _finish? + * The total hit count of the query will be available via the returned + * result set by calling zeitgeist_result_set_estimated_matches(). This will + * often be bigger than the actual number of events held in the result set, + * which is limited by the @num_events parameter passed to + * zeitgeist_index_search(). + * + * @param query The search string to send to Zeitgeist + * @param time_range Restrict matched events to ones within this time + * range. If you are not interested in restricting the timerange pass + * zeitgeist_time_range_new_anytime() as Zeitgeist will detect + * this and optimize the query accordingly + * @param event_templates Restrict matches events to ones matching these + * templates + * @param offset Offset into the result set to read events from + * @param num_events Maximal number of events to retrieve + * @param result_type The {@link ResultType} determining the sort order. + * You may pass {@link ResultType.RELEVANCY} to this + * method to have the results ordered by relevancy calculated + * in relation to @query + * @param cancellable A {@link GLib.Cancellable} used to cancel the + * call or %NULL + */ + public async ResultSet search ( + string query, + TimeRange time_range, + GenericArray event_templates, + uint32 offset, + uint32 num_events, + ResultType result_type, + Cancellable? cancellable=null) throws Error + { + yield wait_for_proxy (); + + Variant result; + uint matches; + + yield proxy.search (query, time_range.to_variant (), + Events.to_variant (event_templates), offset, num_events, + result_type, out result, out matches, cancellable); + + return new SimpleResultSet.with_num_matches ( + Events.from_variant (result), matches); + } + + /** + * Perform a full text search possibly restricted to a {@link TimeRange} + * and/or set of event templates. As opposed to zeitgeist_index_search(), + * this call will also return numeric relevancies of the events + * in the {@link ResultSet}. + * + * See zeitgeist_index_search() for more details on how to create the + * query. + * + * @param query The search string to send to Zeitgeist + * @param time_range Restrict matched events to ones within this time + * range. If you are not interested in restricting the timerange pass + * zeitgeist_time_range_new_anytime() as Zeitgeist will detect + * this and optimize the query accordingly + * @param event_templates Restrict matched events to ones matching these + * templates + * @param storage_state Filter the events by availability of the storage + * medium. + * @param offset Offset into the result set to read events from + * @param num_events Maximal number of events to retrieve + * @param result_type The {@link ResultType} determining the sort order + * You may pass {@link ResultType.RELEVANCY} to this method to + * have the results ordered by relevancy calculated in relation + * to "query" + * @param cancellable a {@link GLib.Cancellable} to cancel the operation or %NULL + */ + public async ResultSet search_with_relevancies ( + string query, + TimeRange time_range, + GenericArray event_templates, + StorageState storage_state, + uint32 offset, + uint32 num_events, + ResultType result_type, + Cancellable? cancellable=null, + out double[] relevancies) throws Error + { + yield wait_for_proxy (); + + Variant result; + Variant relevancies_variant; + uint matches; + + yield proxy.search_with_relevancies (query, time_range.to_variant (), + Events.to_variant (event_templates), storage_state, offset, + num_events, result_type, out relevancies_variant, out result, + out matches, cancellable); + + relevancies = new double[relevancies_variant.n_children ()]; + VariantIter iter = relevancies_variant.iterator (); + for (int i = 0; i < iter.n_children (); ++i) + { + double relevancy; + iter.next ("d", out relevancy); + relevancies[i] = relevancy; + } + + return new SimpleResultSet.with_num_matches ( + Events.from_variant (result), matches); + } + +} + +} + +// vim:expandtab:ts=4:sw=4 diff --git a/libzeitgeist/client/log.vala b/libzeitgeist/client/log.vala new file mode 100644 index 00000000..a0db8712 --- /dev/null +++ b/libzeitgeist/client/log.vala @@ -0,0 +1,471 @@ +/* + * Copyright © 2012 Canonical Ltd. + * By Siegfried-A. Gevatter + * + * Based upon a C implementation (© 2010-2012 Canonical Ltd) by: + * Mikkel Kamstrup Erlandsen + * Michal Hruby + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + */ + +/** + * Zeitgeist is an activity-logging framework to enable the desktop of + * the future. + * + * Its main component is the Zeitgeist engine, a D-Bus service that logs + * any events other applications send to it. An event may be anything like: + * - The user opened/created/modified/closed a file, or visited a website. + * - The user received an e-mail, a phone call or an IM notification. + * - Someone modified a remote (eg. Google Drive) document owned by the user. + * + * This information is then made available to other Zeitgeist-enabled + * applications over a powerful querying and monitoring API, and can be used + * and analyzed to create intelligent or adaptive interfaces. + * + * Zeitgeist also comes with a blacklist extension to make sure the user + * always stays in control of what information is logged. + */ +namespace Zeitgeist +{ + +/** + * Primary access point for talking to the Zeitgeist daemon + * + * {@link Log} encapsulates the low level access to the Zeitgeist daemon. + * You can use it to manage the log by inserting and deleting entries as well + * as do queries on the logged data. + * + * It's important to realize that the #ZeitgeistLog class does not expose + * any API that does synchronous communications with the message bus - + * everything is asynchronous. To ease development some of the methods have + * variants that are "fire and forget" ignoring the normal return value, so + * that callbacks does not have to be set up. + */ +public class Log : QueuedProxyWrapper +{ + private static Log default_instance; + + private RemoteLog proxy; + private Variant? engine_version; + private HashTable monitors; + + public Log () + { + monitors = new HashTable(direct_hash, direct_equal); + Bus.get_proxy (BusType.SESSION, Utils.ENGINE_DBUS_NAME, + Utils.ENGINE_DBUS_PATH, 0, null, (obj, res) => + { + try + { + proxy = Bus.get_proxy.end (res); + proxy_acquired (proxy); + } + catch (IOError err) + { + critical ("Unable to connect to Zeitgeist: %s", + err.message); + proxy_unavailable (err); + } + }); + } + + + /** + * Get a unique instance of #ZeitgeistLog, that you can share in your + * application without caring about memory management. + * + * See zeitgeist_log_new() for more information. + * + * @return ZeitgeistLog. + */ + public static Log get_default () + { + if (default_instance == null) + default_instance = new Log (); + return default_instance; + } + + protected override void on_connection_established () + { + // Reinstate all active monitors + foreach (unowned Monitor monitor in monitors.get_keys ()) + { + reinstall_monitor (monitor); + } + + // Update our cached version property + engine_version = proxy.version; + warn_if_fail (engine_version.get_type_string () == "(iii)"); + } + + protected override void on_connection_lost () { + } + + /** + * Asynchronously send a set of events to the Zeitgeist daemon, requesting they + * be inserted into the log. + * + * @param event A {@link Event} + * @param cancellable a {@link GLib.Cancellable} to cancel the operation or %NULL + */ + public async Array insert_event (Event event, + Cancellable? cancellable=null) throws Error + { + var events = new GenericArray (); + events.add (event); + return yield insert_events (events, cancellable); + } + + + /** + * Asynchronously send a set of events to the Zeitgeist daemon, requesting they + * be inserted into the log. + * + * @param events An {@link GLib.GenericArray} of {@link Event} + * @param cancellable a {@link GLib.Cancellable} to cancel the operation or %NULL + */ + public async Array insert_events (GenericArray events, + Cancellable? cancellable=null) throws Error + { + var events_cp = new GenericArray(); + for (int i = 0; i < events.length; i++) + events_cp.add(events.get(i)); + yield wait_for_proxy (); + uint32[] ids = yield proxy.insert_events (Events.to_variant (events_cp), cancellable); + var result = new Array (); + // Ideally we'd just place "(owned) ids" into the GArray, but .data isn't + // in the Vala bindings... + for (int i = 0; i < ids.length; ++i) + result.append_val (ids[i]); + return result; + } + + /** + * Asynchronously send a set of events to the Zeitgeist daemon, requesting they + * be inserted into the log. + * This method is "fire and forget" and the caller will never know + * whether the events was successfully inserted or not. + * + * This method is exactly equivalent to calling zeitgeist_log_insert_event() + * with NULL set as @cancellable, @callback, and @user_data. + * + * @param event A {@link Event} + */ + public async void insert_event_no_reply (Event event) + throws Error + { + yield insert_event (event); + } + + /** + * Asynchronously send a set of events to the Zeitgeist daemon, requesting they + * be inserted into the log. + * This method is "fire and forget" and the caller will never know + * whether the events was successfully inserted or not. + * + * This method is exactly equivalent to calling zeitgeist_log_insert_event() + * with NULL set as @cancellable, @callback, and @user_data. + * + * @param events An {@link GLib.GenericArray} of {@link Event} + */ + public async void insert_events_no_reply (GenericArray events) + throws Error + { + yield insert_events (events); + } + + /** + * Send a query matching a collection of {@link Event} templates to the {@link Log}. + * The query will match if an event matches any of the templates. If an event + * template has more than one {@link Subject} the query will match if any one + * of the {@link Subject}s templates match. + * + * The query will be done via an asynchronous DBus call and this method will + * return immediately. The return value will be passed to callback as a list + * of {@link Event}s. This list must be the sole argument for the callback. + * + * If you need to do a query yielding a large (or unpredictable) result set + * and you only want to show some of the results at the same time (eg., by + * paging them), consider using {@link find_event_ids}. + * + * In order to use this method there needs to be a mainloop runnning. + * Both Qt and GLib mainloops are supported. + * + * @param time_range {@link TimeRange} A time range in which the events should be considered in + * @param storage_state {@link StorageState} storage state + * @param event_templates An {@link GLib.GenericArray} of {@link Event} + * @param num_events int represteing the number of events that should be returned + * @param result_type {@link ResultType} how the events should be grouped and sorted + * @param cancellable a {@link GLib.Cancellable} to cancel the operation or %NULL + */ + public async ResultSet find_events ( + TimeRange time_range, + GenericArray event_templates, + StorageState storage_state, + uint32 num_events, + ResultType result_type, + Cancellable? cancellable=null) throws Error + { + var event_templates_cp = new GenericArray(); + for (int i = 0; i < event_templates.length; i++) + event_templates_cp.add(event_templates.get(i)); + yield wait_for_proxy (); + var result = yield proxy.find_events (time_range.to_variant (), + Events.to_variant (event_templates_cp), storage_state, + num_events, result_type, cancellable); + return new SimpleResultSet (Events.from_variant (result)); + } + + + /** + * Send a query matching a collection of {@link Event} templates to the {@link Log}. + * The query will match if an event matches any of the templates. If an event + * template has more than one {@link Subject} the query will match if any one + * of the {@link Subject}s templates match. + * + * The query will be done via an asynchronous DBus call and this method will + * return immediately. The return value will be passed to callback as a list + * of intergers represrting {@link Event} id's. + * This list must be the sole argument for the callback. + * + * In order to use this method there needs to be a mainloop runnning. + * Both Qt and GLib mainloops are supported. + * + * @param time_range {@link TimeRange} A time range in which the events should be considered in + * @param storage_state {@link StorageState} storage state + * @param event_templates An {@link GLib.GenericArray} of {@link Event} + * @param num_events int represteing the number of events that should be returned + * @param result_type {@link ResultType} how the events should be grouped and sorted + * @param cancellable a {@link GLib.Cancellable} to cancel the operation or %NULL + */ + public async uint32[] find_event_ids ( + TimeRange time_range, + GenericArray event_templates, + StorageState storage_state, + uint32 num_events, + ResultType result_type, + Cancellable? cancellable=null) throws Error + { + var event_templates_cp = new GenericArray(); + for (int i = 0; i < event_templates.length; i++) + event_templates_cp.add(event_templates.get(i)); + yield wait_for_proxy (); + return yield proxy.find_event_ids (time_range.to_variant (), + Events.to_variant (event_templates_cp), storage_state, + num_events, result_type, cancellable); + } + + /** + * Look up a collection of {@link Event} in the {@link Log} given a collection + * of event ids. This is useful for looking up the event data for events found + * with the find_event_ids_* family of functions. + * + * Each {@link Event} which is not found in the {@link Log} is represented by + * NULL in the resulting collection. The query will be done via an asynchronous + * DBus call and this method will return immediately. The returned events will + * be passed to callback as a list of {@link Event}s, which must be the only + * argument of the function. + * + * In order to use this method there needs to be a mainloop runnning. + * + * @param event_ids a {@link GLib.Array} of {@link Event} ids + * @param cancellable a {@link GLib.Cancellable} to cancel the operation or %NULL + */ + public async ResultSet get_events ( + Array event_ids, + Cancellable? cancellable=null) throws Error + { + uint32[] simple_event_ids = new uint32[event_ids.length]; + for (int i = 0; i < event_ids.length; i++) + simple_event_ids[i] = event_ids.index (i); + yield wait_for_proxy (); + var result = yield proxy.get_events (simple_event_ids, cancellable); + return new SimpleResultSet(Events.from_variant (result)); + } + + /** + * Warning: This API is EXPERIMENTAL and is not fully supported yet. + * + * Get a list of URIs of subjects which frequently occur together with events + * matching event_templates. Possibly restricting to time_range or to URIs + * that occur as subject of events matching result_event_templates. + * + * @param time_range {@link TimeRange} A time range in which the events should be considered in + * @param storage_state {@link StorageState} storage state + * @param event_templates An {@link GLib.GenericArray} of {@link Event} describing the events to relate to + * @param result_event_templates An {@link GLib.GenericArray} of {@link Event} desrcibing the result to be returned + * @param num_events int represteing the number of events that should be returned + * @param result_type {@link ResultType} how the events should be grouped and sorted + * @param cancellable a {@link GLib.Cancellable} to cancel the operation or %NULL + */ + public async string[] find_related_uris ( + TimeRange time_range, + GenericArray event_templates, + GenericArray result_event_templates, + StorageState storage_state, + uint32 num_events, + ResultType result_type, + Cancellable? cancellable=null) throws Error + { + var events_cp = new GenericArray(); + for (int i = 0; i < event_templates.length; i++) + events_cp.add(event_templates.get(i)); + + var results_cp = new GenericArray(); + for (int i = 0; i < result_event_templates.length; i++) + results_cp.add(result_event_templates.get(i)); + + yield wait_for_proxy (); + return yield proxy.find_related_uris (time_range.to_variant (), + Events.to_variant (events_cp), + Events.to_variant (results_cp), + storage_state, num_events, result_type, cancellable); + } + + + /** + * Delete a collection of events from the zeitgeist log given their event ids. + * + * The deletion will be done asynchronously, and this method returns immediately. + * + * @param event_ids Array + * @param cancellable a {@link GLib.Cancellable} to cancel the operation or %NULL + */ + public async TimeRange delete_events (Array event_ids, + Cancellable? cancellable=null) throws Error + { + uint32[] _ids = new uint32 [event_ids.length]; + for (int i=0; i {}); + + // Save the monitor's registration id (0 = not registered) + monitors.insert(monitor, 0); + + if (is_connected) + reinstall_monitor (monitor); + } + + private async void reinstall_monitor (Monitor monitor) + requires (is_connected) + { + if (monitors.lookup (monitor) == 0) + { + try + { + DBusConnection conn = ((DBusProxy) proxy).get_connection (); + + try + { + uint registration_id = conn.register_object ( + monitor.get_path (), monitor); + monitors.insert (monitor, registration_id); + } + catch (GLib.IOError err) + { + warning ("Error installing monitor: %s", err.message); + return; + } + } + catch (IOError err) + { + critical ("Unable to connect to DBus session bus: %s", err.message); + } + } + + proxy.install_monitor ( + monitor.get_path (), + monitor.time_range.to_variant (), + Events.to_variant (monitor.get_templates ())); + } + + /** + * Remove a monitor from Zeitgeist engine that calls back when events matching event_templates are logged. + * + * @param monitor A {@link Monitor} to report back inserts and deletes + */ + public async void remove_monitor (owned Monitor monitor) throws Error + { + yield wait_for_proxy (); + + try + { + yield proxy.remove_monitor (monitor.get_path ()); + } + catch (IOError err) + { + warning ("Failed to remove monitor from Zeitgeist. Retracting" + + "%s from the bus nonetheless: %s", monitor.get_path (), + err.message); + return; + } + + uint registration_id = monitors.lookup (monitor); + if (registration_id != 0) + { + var connection = ((DBusProxy) proxy).get_connection (); + connection.unregister_object (registration_id); + } + } + + /** + * Gets version of currently running Zeitgeist daemon. + * + * This method will return the version of Zeitgeist daemon this instance is + * connected to. If you call this method right after zeitgeist_log_new(), + * only zeros will be returned, a valid version number will only be returned + * once this instance successfully connected to the Zeitgeist daemon - ie. + * the value of the "is-connected" property must be TRUE (you can connect + * to the "notify::is-connected" signal otherwise). + * + * @param major Location for the major version + * @param minor Location for the minor version + * @param micro Location for the micro version + */ + public void get_version (out int major, out int minor, out int micro) { + major = minor = micro = 0; + if (engine_version != null) + engine_version.get ("(iii)", &major, &minor, µ); + } + +} + +} + +// vim:expandtab:ts=4:sw=4 diff --git a/libzeitgeist/index.vala b/libzeitgeist/index.vala deleted file mode 100644 index 6ab3d716..00000000 --- a/libzeitgeist/index.vala +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright © 2012 Canonical Ltd. - * By Siegfried-A. Gevatter - * - * Based upon a C implementation (© 2010-2012 Canonical Ltd) by: - * Mikkel Kamstrup Erlandsen - * Michal Hruby - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - * - */ - -namespace Zeitgeist -{ - -/** - * Query the Zeitgeist Full Text Search Extension - * - * include: zeitgeist.h - */ -public class Index : QueuedProxyWrapper -{ - private RemoteSimpleIndexer proxy; - - /** - * Create a new index that interfaces with the default event index of the - * Zeitgeist daemon. - * - * Create a new {@link Index} instance. The index will start to connect - * to Zeitgeist asynchronously. You can however start calling methods on - * the returned instance immediately, any method calls issued before the - * connection has been established will simply be queued and executed once - * the connection is up. - * - * Returns: A reference to a newly allocated index. Free with g_object_unref(). - */ - public Index () - { - Bus.get_proxy (BusType.SESSION, - Utils.ENGINE_DBUS_NAME, "/org/gnome/zeitgeist/index/activity", 0, - null, (obj, res) => - { - try - { - proxy = Bus.get_proxy.end (res); - proxy_acquired (proxy); - } - catch (IOError err) - { - critical ("Unable to connect to Zeitgeist FTS: %s", - err.message); - proxy_unavailable (err); - } - }); - } - - protected override void on_connection_established () - { - } - - protected override void on_connection_lost () { - } - - /** - * Perform a full text search possibly restricted to a {@link TimeRange} - * and/or set of event templates. - * - * The default boolean operator is %AND. Thus the query - * //foo bar// will be interpreted as //foo AND bar//. To exclude a term - * from the result set prepend it with a minus sign - eg. //foo -bar//. - * Phrase queries can be done by double quoting the string - * //"foo is a bar"//. You can truncate terms by appending a *. - * - * There are a few keys you can prefix to a term or phrase to search within - * a specific set of metadata. They are used like //key:value//. The keys - * //name// and //title// search strictly within the text field of the - * event subjects. The key //app// searches within the application name or - * description that is found in the actor attribute of the events. Lastly, - * you can use the //site// key to search within the domain name of subject - * URIs. - * - * You can also control the results with the boolean operators //AND// and - * //OR// and you may use brackets, ( and ), to control the operator - * precedence. - * - * FIXME: how do we put documentation into _finish? - * The total hit count of the query will be available via the returned - * result set by calling zeitgeist_result_set_estimated_matches(). This will - * often be bigger than the actual number of events held in the result set, - * which is limited by the @num_events parameter passed to - * zeitgeist_index_search(). - * - * @param query The search string to send to Zeitgeist - * @param time_range Restrict matched events to ones within this time - * range. If you are not interested in restricting the timerange pass - * zeitgeist_time_range_new_anytime() as Zeitgeist will detect - * this and optimize the query accordingly - * @param event_templates Restrict matches events to ones matching these - * templates - * @param offset Offset into the result set to read events from - * @param num_events Maximal number of events to retrieve - * @param result_type The {@link ResultType} determining the sort order. - * You may pass {@link ResultType.RELEVANCY} to this - * method to have the results ordered by relevancy calculated - * in relation to @query - * @param cancellable A {@link GLib.Cancellable} used to cancel the - * call or %NULL - */ - public async ResultSet search ( - string query, - TimeRange time_range, - GenericArray event_templates, - uint32 offset, - uint32 num_events, - ResultType result_type, - Cancellable? cancellable=null) throws Error - { - yield wait_for_proxy (); - - Variant result; - uint matches; - - yield proxy.search (query, time_range.to_variant (), - Events.to_variant (event_templates), offset, num_events, - result_type, out result, out matches, cancellable); - - return new SimpleResultSet.with_num_matches ( - Events.from_variant (result), matches); - } - - /** - * Perform a full text search possibly restricted to a {@link TimeRange} - * and/or set of event templates. As opposed to zeitgeist_index_search(), - * this call will also return numeric relevancies of the events - * in the {@link ResultSet}. - * - * See zeitgeist_index_search() for more details on how to create the - * query. - * - * @param query The search string to send to Zeitgeist - * @param time_range Restrict matched events to ones within this time - * range. If you are not interested in restricting the timerange pass - * zeitgeist_time_range_new_anytime() as Zeitgeist will detect - * this and optimize the query accordingly - * @param event_templates Restrict matched events to ones matching these - * templates - * @param storage_state Filter the events by availability of the storage - * medium. - * @param offset Offset into the result set to read events from - * @param num_events Maximal number of events to retrieve - * @param result_type The {@link ResultType} determining the sort order - * You may pass {@link ResultType.RELEVANCY} to this method to - * have the results ordered by relevancy calculated in relation - * to "query" - * @param cancellable a {@link GLib.Cancellable} to cancel the operation or %NULL - */ - public async ResultSet search_with_relevancies ( - string query, - TimeRange time_range, - GenericArray event_templates, - StorageState storage_state, - uint32 offset, - uint32 num_events, - ResultType result_type, - Cancellable? cancellable=null, - out double[] relevancies) throws Error - { - yield wait_for_proxy (); - - Variant result; - Variant relevancies_variant; - uint matches; - - yield proxy.search_with_relevancies (query, time_range.to_variant (), - Events.to_variant (event_templates), storage_state, offset, - num_events, result_type, out relevancies_variant, out result, - out matches, cancellable); - - relevancies = new double[relevancies_variant.n_children ()]; - VariantIter iter = relevancies_variant.iterator (); - for (int i = 0; i < iter.n_children (); ++i) - { - double relevancy; - iter.next ("d", out relevancy); - relevancies[i] = relevancy; - } - - return new SimpleResultSet.with_num_matches ( - Events.from_variant (result), matches); - } - -} - -} - -// vim:expandtab:ts=4:sw=4 diff --git a/libzeitgeist/log.vala b/libzeitgeist/log.vala deleted file mode 100644 index a0db8712..00000000 --- a/libzeitgeist/log.vala +++ /dev/null @@ -1,471 +0,0 @@ -/* - * Copyright © 2012 Canonical Ltd. - * By Siegfried-A. Gevatter - * - * Based upon a C implementation (© 2010-2012 Canonical Ltd) by: - * Mikkel Kamstrup Erlandsen - * Michal Hruby - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - * - */ - -/** - * Zeitgeist is an activity-logging framework to enable the desktop of - * the future. - * - * Its main component is the Zeitgeist engine, a D-Bus service that logs - * any events other applications send to it. An event may be anything like: - * - The user opened/created/modified/closed a file, or visited a website. - * - The user received an e-mail, a phone call or an IM notification. - * - Someone modified a remote (eg. Google Drive) document owned by the user. - * - * This information is then made available to other Zeitgeist-enabled - * applications over a powerful querying and monitoring API, and can be used - * and analyzed to create intelligent or adaptive interfaces. - * - * Zeitgeist also comes with a blacklist extension to make sure the user - * always stays in control of what information is logged. - */ -namespace Zeitgeist -{ - -/** - * Primary access point for talking to the Zeitgeist daemon - * - * {@link Log} encapsulates the low level access to the Zeitgeist daemon. - * You can use it to manage the log by inserting and deleting entries as well - * as do queries on the logged data. - * - * It's important to realize that the #ZeitgeistLog class does not expose - * any API that does synchronous communications with the message bus - - * everything is asynchronous. To ease development some of the methods have - * variants that are "fire and forget" ignoring the normal return value, so - * that callbacks does not have to be set up. - */ -public class Log : QueuedProxyWrapper -{ - private static Log default_instance; - - private RemoteLog proxy; - private Variant? engine_version; - private HashTable monitors; - - public Log () - { - monitors = new HashTable(direct_hash, direct_equal); - Bus.get_proxy (BusType.SESSION, Utils.ENGINE_DBUS_NAME, - Utils.ENGINE_DBUS_PATH, 0, null, (obj, res) => - { - try - { - proxy = Bus.get_proxy.end (res); - proxy_acquired (proxy); - } - catch (IOError err) - { - critical ("Unable to connect to Zeitgeist: %s", - err.message); - proxy_unavailable (err); - } - }); - } - - - /** - * Get a unique instance of #ZeitgeistLog, that you can share in your - * application without caring about memory management. - * - * See zeitgeist_log_new() for more information. - * - * @return ZeitgeistLog. - */ - public static Log get_default () - { - if (default_instance == null) - default_instance = new Log (); - return default_instance; - } - - protected override void on_connection_established () - { - // Reinstate all active monitors - foreach (unowned Monitor monitor in monitors.get_keys ()) - { - reinstall_monitor (monitor); - } - - // Update our cached version property - engine_version = proxy.version; - warn_if_fail (engine_version.get_type_string () == "(iii)"); - } - - protected override void on_connection_lost () { - } - - /** - * Asynchronously send a set of events to the Zeitgeist daemon, requesting they - * be inserted into the log. - * - * @param event A {@link Event} - * @param cancellable a {@link GLib.Cancellable} to cancel the operation or %NULL - */ - public async Array insert_event (Event event, - Cancellable? cancellable=null) throws Error - { - var events = new GenericArray (); - events.add (event); - return yield insert_events (events, cancellable); - } - - - /** - * Asynchronously send a set of events to the Zeitgeist daemon, requesting they - * be inserted into the log. - * - * @param events An {@link GLib.GenericArray} of {@link Event} - * @param cancellable a {@link GLib.Cancellable} to cancel the operation or %NULL - */ - public async Array insert_events (GenericArray events, - Cancellable? cancellable=null) throws Error - { - var events_cp = new GenericArray(); - for (int i = 0; i < events.length; i++) - events_cp.add(events.get(i)); - yield wait_for_proxy (); - uint32[] ids = yield proxy.insert_events (Events.to_variant (events_cp), cancellable); - var result = new Array (); - // Ideally we'd just place "(owned) ids" into the GArray, but .data isn't - // in the Vala bindings... - for (int i = 0; i < ids.length; ++i) - result.append_val (ids[i]); - return result; - } - - /** - * Asynchronously send a set of events to the Zeitgeist daemon, requesting they - * be inserted into the log. - * This method is "fire and forget" and the caller will never know - * whether the events was successfully inserted or not. - * - * This method is exactly equivalent to calling zeitgeist_log_insert_event() - * with NULL set as @cancellable, @callback, and @user_data. - * - * @param event A {@link Event} - */ - public async void insert_event_no_reply (Event event) - throws Error - { - yield insert_event (event); - } - - /** - * Asynchronously send a set of events to the Zeitgeist daemon, requesting they - * be inserted into the log. - * This method is "fire and forget" and the caller will never know - * whether the events was successfully inserted or not. - * - * This method is exactly equivalent to calling zeitgeist_log_insert_event() - * with NULL set as @cancellable, @callback, and @user_data. - * - * @param events An {@link GLib.GenericArray} of {@link Event} - */ - public async void insert_events_no_reply (GenericArray events) - throws Error - { - yield insert_events (events); - } - - /** - * Send a query matching a collection of {@link Event} templates to the {@link Log}. - * The query will match if an event matches any of the templates. If an event - * template has more than one {@link Subject} the query will match if any one - * of the {@link Subject}s templates match. - * - * The query will be done via an asynchronous DBus call and this method will - * return immediately. The return value will be passed to callback as a list - * of {@link Event}s. This list must be the sole argument for the callback. - * - * If you need to do a query yielding a large (or unpredictable) result set - * and you only want to show some of the results at the same time (eg., by - * paging them), consider using {@link find_event_ids}. - * - * In order to use this method there needs to be a mainloop runnning. - * Both Qt and GLib mainloops are supported. - * - * @param time_range {@link TimeRange} A time range in which the events should be considered in - * @param storage_state {@link StorageState} storage state - * @param event_templates An {@link GLib.GenericArray} of {@link Event} - * @param num_events int represteing the number of events that should be returned - * @param result_type {@link ResultType} how the events should be grouped and sorted - * @param cancellable a {@link GLib.Cancellable} to cancel the operation or %NULL - */ - public async ResultSet find_events ( - TimeRange time_range, - GenericArray event_templates, - StorageState storage_state, - uint32 num_events, - ResultType result_type, - Cancellable? cancellable=null) throws Error - { - var event_templates_cp = new GenericArray(); - for (int i = 0; i < event_templates.length; i++) - event_templates_cp.add(event_templates.get(i)); - yield wait_for_proxy (); - var result = yield proxy.find_events (time_range.to_variant (), - Events.to_variant (event_templates_cp), storage_state, - num_events, result_type, cancellable); - return new SimpleResultSet (Events.from_variant (result)); - } - - - /** - * Send a query matching a collection of {@link Event} templates to the {@link Log}. - * The query will match if an event matches any of the templates. If an event - * template has more than one {@link Subject} the query will match if any one - * of the {@link Subject}s templates match. - * - * The query will be done via an asynchronous DBus call and this method will - * return immediately. The return value will be passed to callback as a list - * of intergers represrting {@link Event} id's. - * This list must be the sole argument for the callback. - * - * In order to use this method there needs to be a mainloop runnning. - * Both Qt and GLib mainloops are supported. - * - * @param time_range {@link TimeRange} A time range in which the events should be considered in - * @param storage_state {@link StorageState} storage state - * @param event_templates An {@link GLib.GenericArray} of {@link Event} - * @param num_events int represteing the number of events that should be returned - * @param result_type {@link ResultType} how the events should be grouped and sorted - * @param cancellable a {@link GLib.Cancellable} to cancel the operation or %NULL - */ - public async uint32[] find_event_ids ( - TimeRange time_range, - GenericArray event_templates, - StorageState storage_state, - uint32 num_events, - ResultType result_type, - Cancellable? cancellable=null) throws Error - { - var event_templates_cp = new GenericArray(); - for (int i = 0; i < event_templates.length; i++) - event_templates_cp.add(event_templates.get(i)); - yield wait_for_proxy (); - return yield proxy.find_event_ids (time_range.to_variant (), - Events.to_variant (event_templates_cp), storage_state, - num_events, result_type, cancellable); - } - - /** - * Look up a collection of {@link Event} in the {@link Log} given a collection - * of event ids. This is useful for looking up the event data for events found - * with the find_event_ids_* family of functions. - * - * Each {@link Event} which is not found in the {@link Log} is represented by - * NULL in the resulting collection. The query will be done via an asynchronous - * DBus call and this method will return immediately. The returned events will - * be passed to callback as a list of {@link Event}s, which must be the only - * argument of the function. - * - * In order to use this method there needs to be a mainloop runnning. - * - * @param event_ids a {@link GLib.Array} of {@link Event} ids - * @param cancellable a {@link GLib.Cancellable} to cancel the operation or %NULL - */ - public async ResultSet get_events ( - Array event_ids, - Cancellable? cancellable=null) throws Error - { - uint32[] simple_event_ids = new uint32[event_ids.length]; - for (int i = 0; i < event_ids.length; i++) - simple_event_ids[i] = event_ids.index (i); - yield wait_for_proxy (); - var result = yield proxy.get_events (simple_event_ids, cancellable); - return new SimpleResultSet(Events.from_variant (result)); - } - - /** - * Warning: This API is EXPERIMENTAL and is not fully supported yet. - * - * Get a list of URIs of subjects which frequently occur together with events - * matching event_templates. Possibly restricting to time_range or to URIs - * that occur as subject of events matching result_event_templates. - * - * @param time_range {@link TimeRange} A time range in which the events should be considered in - * @param storage_state {@link StorageState} storage state - * @param event_templates An {@link GLib.GenericArray} of {@link Event} describing the events to relate to - * @param result_event_templates An {@link GLib.GenericArray} of {@link Event} desrcibing the result to be returned - * @param num_events int represteing the number of events that should be returned - * @param result_type {@link ResultType} how the events should be grouped and sorted - * @param cancellable a {@link GLib.Cancellable} to cancel the operation or %NULL - */ - public async string[] find_related_uris ( - TimeRange time_range, - GenericArray event_templates, - GenericArray result_event_templates, - StorageState storage_state, - uint32 num_events, - ResultType result_type, - Cancellable? cancellable=null) throws Error - { - var events_cp = new GenericArray(); - for (int i = 0; i < event_templates.length; i++) - events_cp.add(event_templates.get(i)); - - var results_cp = new GenericArray(); - for (int i = 0; i < result_event_templates.length; i++) - results_cp.add(result_event_templates.get(i)); - - yield wait_for_proxy (); - return yield proxy.find_related_uris (time_range.to_variant (), - Events.to_variant (events_cp), - Events.to_variant (results_cp), - storage_state, num_events, result_type, cancellable); - } - - - /** - * Delete a collection of events from the zeitgeist log given their event ids. - * - * The deletion will be done asynchronously, and this method returns immediately. - * - * @param event_ids Array - * @param cancellable a {@link GLib.Cancellable} to cancel the operation or %NULL - */ - public async TimeRange delete_events (Array event_ids, - Cancellable? cancellable=null) throws Error - { - uint32[] _ids = new uint32 [event_ids.length]; - for (int i=0; i {}); - - // Save the monitor's registration id (0 = not registered) - monitors.insert(monitor, 0); - - if (is_connected) - reinstall_monitor (monitor); - } - - private async void reinstall_monitor (Monitor monitor) - requires (is_connected) - { - if (monitors.lookup (monitor) == 0) - { - try - { - DBusConnection conn = ((DBusProxy) proxy).get_connection (); - - try - { - uint registration_id = conn.register_object ( - monitor.get_path (), monitor); - monitors.insert (monitor, registration_id); - } - catch (GLib.IOError err) - { - warning ("Error installing monitor: %s", err.message); - return; - } - } - catch (IOError err) - { - critical ("Unable to connect to DBus session bus: %s", err.message); - } - } - - proxy.install_monitor ( - monitor.get_path (), - monitor.time_range.to_variant (), - Events.to_variant (monitor.get_templates ())); - } - - /** - * Remove a monitor from Zeitgeist engine that calls back when events matching event_templates are logged. - * - * @param monitor A {@link Monitor} to report back inserts and deletes - */ - public async void remove_monitor (owned Monitor monitor) throws Error - { - yield wait_for_proxy (); - - try - { - yield proxy.remove_monitor (monitor.get_path ()); - } - catch (IOError err) - { - warning ("Failed to remove monitor from Zeitgeist. Retracting" + - "%s from the bus nonetheless: %s", monitor.get_path (), - err.message); - return; - } - - uint registration_id = monitors.lookup (monitor); - if (registration_id != 0) - { - var connection = ((DBusProxy) proxy).get_connection (); - connection.unregister_object (registration_id); - } - } - - /** - * Gets version of currently running Zeitgeist daemon. - * - * This method will return the version of Zeitgeist daemon this instance is - * connected to. If you call this method right after zeitgeist_log_new(), - * only zeros will be returned, a valid version number will only be returned - * once this instance successfully connected to the Zeitgeist daemon - ie. - * the value of the "is-connected" property must be TRUE (you can connect - * to the "notify::is-connected" signal otherwise). - * - * @param major Location for the major version - * @param minor Location for the minor version - * @param micro Location for the micro version - */ - public void get_version (out int major, out int minor, out int micro) { - major = minor = micro = 0; - if (engine_version != null) - engine_version.get ("(iii)", &major, &minor, µ); - } - -} - -} - -// vim:expandtab:ts=4:sw=4 diff --git a/src/Makefile.am b/src/Makefile.am index a686045b..52104b04 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,6 +2,7 @@ NULL = bin_PROGRAMS = zeitgeist-daemon + AM_CPPFLAGS = \ $(ZEITGEIST_CFLAGS) \ -include $(CONFIG_HEADER) \ -- cgit v1.2.1