← Back to team overview

zeitgeist team mailing list archive

[Branch ~zeitgeist/zeitgeist/bluebird] Rev 278: Start implementing storage monitor extension.

 

------------------------------------------------------------
revno: 278
committer: Siegfried-Angel Gevatter Pujals <siegfried@xxxxxxxxxxxx>
branch nick: bluebird
timestamp: Thu 2011-09-29 17:30:04 +0200
message:
  Start implementing storage monitor extension.
added:
  extensions/storage-monitor.vala
  src/ext-storage-monitor.vala@
modified:
  .bzrignore
  extensions/Makefile.am
  extensions/blacklist.vala
  src/Makefile.am
  src/extension-collection.vala
  src/extension-store.vala


--
lp:~zeitgeist/zeitgeist/bluebird
https://code.launchpad.net/~zeitgeist/zeitgeist/bluebird

Your team Zeitgeist Framework Team is subscribed to branch lp:~zeitgeist/zeitgeist/bluebird.
To unsubscribe from this branch go to https://code.launchpad.net/~zeitgeist/zeitgeist/bluebird/+edit-subscription
=== modified file '.bzrignore'
--- .bzrignore	2011-09-17 19:38:43 +0000
+++ .bzrignore	2011-09-29 15:30:04 +0000
@@ -46,3 +46,5 @@
 test/direct/marshalling
 test/dbus/__pycache__
 test/direct/table-lookup-test
+src/zeitgeist-engine.vapi
+src/zeitgeist-engine.h

=== modified file 'extensions/Makefile.am'
--- extensions/Makefile.am	2011-09-05 10:27:02 +0000
+++ extensions/Makefile.am	2011-09-29 15:30:04 +0000
@@ -1,7 +1,7 @@
 NULL =
 
 #extensionsdir = $(libdir)/zeitgeist/extensions
-noinst_LTLIBRARIES = ds-registry.la blacklist.la
+noinst_LTLIBRARIES = ds-registry.la blacklist.la storage-monitor.la
 
 AM_CPPFLAGS = \
 	$(BLUEBIRD_CFLAGS) \
@@ -37,3 +37,13 @@
 blacklist_la_LIBADD = \
 	$(BLUEBIRD_LIBS) \
 	$(NULL)
+
+storage_monitor_la_SOURCES = \
+	storage-monitor.la \
+	$(NULL)
+
+storage_monitor_la_LDFLAGS = -module -avoid-version
+
+storage_monitor_la_LIBADD = \
+	$(BLUEBIRD_LIBS) \
+	$(NULL)

=== modified file 'extensions/blacklist.vala'
--- extensions/blacklist.vala	2011-09-28 12:51:08 +0000
+++ extensions/blacklist.vala	2011-09-29 15:30:04 +0000
@@ -145,9 +145,17 @@
         public override void pre_insert_events (GenericArray<Event?> events,
             BusName? sender)
         {
-            for (int i=0; i < events.length; i++)
+            for (int i = 0; i < events.length; i++)
+            {
                 foreach (var tmpl in blacklist.get_values ())
-                    if (events[i].matches_template (tmpl)) events[i] = null;
+                {
+                    if (events[i].matches_template (tmpl))
+                    {
+                        events[i] = null;
+                        break;
+                    }
+                }
+            }
         }
 
         public void add_template (string template_id, Variant event_template)

=== added file 'extensions/storage-monitor.vala'
--- extensions/storage-monitor.vala	1970-01-01 00:00:00 +0000
+++ extensions/storage-monitor.vala	2011-09-29 15:30:04 +0000
@@ -0,0 +1,344 @@
+/* ds-registry.vala
+ *
+ * Copyright © 2011 Collabora Ltd.
+ *             By Siegfried-Angel Gevatter Pujals <siegfried@xxxxxxxxxxxx>
+ *
+ * Based upon a Python implementation:
+ *  Copyright © 2009 Mikkel Kamstrup Erlandsen <mikkel.kamstrup@xxxxxxxxx>
+ *  Copyright © 2011 Canonical Ltd.
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+using Zeitgeist;
+
+namespace Zeitgeist
+{
+    [DBus (name = "org.gnome.zeitgeist.StorageMonitor")]
+    public interface RemoteStorageMonitor: Object
+    {
+        [DBus (signature = "a(sa{sv})")]
+        public abstract Variant get_storages () throws Error;
+
+        public signal void storage_available (string storage_id,
+            [DBus (signature = "a{sv}")] Variant storage_description);
+        public signal void storage_unavailable (string storage_id);
+    }
+
+    namespace StorageMedia
+    {
+        private Variant to_variant (string medium_name, bool available,
+            string icon, string display_name)
+        {
+            var vb = new VariantBuilder (new VariantType ("(sa{sv})"));
+
+            vb.add ("s", medium_name);
+            vb.open (new VariantType ("a{sv}"));
+            {
+                vb.open (new VariantType ("{sv}"));
+                vb.add ("s", "available");
+                vb.add ("v", new Variant ("b", available));
+                vb.close ();
+                vb.open (new VariantType ("{sv}"));
+                vb.add ("s", "icon");
+                vb.add ("v", new Variant ("s", icon));
+                vb.close ();
+                vb.open (new VariantType ("{sv}"));
+                vb.add ("s", "display-name");
+                vb.add ("v", new Variant ("s", display_name));
+                vb.close ();
+            }
+            vb.close ();
+
+            return vb.end ();
+        }
+    }
+
+    /*
+     * The Storage Monitor monitors the availability of network interfaces
+     * and storage devices (USB drives, data/audio/video CD/DVDs, etc) and
+     * updates the Zeitgeist database with this information so clients can
+     * efficiently query based on the storage identifier and availability
+     * of the storage medium the event subjects reside on.
+     *
+     * Subject can have the following types of storage identifiers:
+     *  - for local resources, the fixed identifier `local`;
+     *  - for network URIs, the fixed identifier `net`;
+     *  - for resources on storage devices, the UUID of the partition
+     *    they reside in;
+     *  - otherwise, the fixed identifier `unknown`.
+     *
+     * Subjects with storage `local` or `unwknown` are always considered as
+     * available; for network resources, the monitor will use either ConnMan
+     * or NetworkManager (whichever is available).
+     *
+     * For subjects being inserted without a storage id set, this extension
+     * will attempt to determine it and update the subject on the fly.
+     */
+    class StorageMonitor: Extension, RemoteStorageMonitor
+    {
+        private Zeitgeist.SQLite.ZeitgeistDatabase database;
+        private unowned Sqlite.Database db;
+        private uint registration_id;
+
+        private Sqlite.Statement get_storages_stmt;
+        private Sqlite.Statement store_storage_medium_stmt;
+        private Sqlite.Statement insert_unavailable_medium_stmt;
+        private Sqlite.Statement update_medium_state_stmt;
+
+        StorageMonitor ()
+        {
+            Object ();
+        }
+
+        construct
+        {
+            try
+            {
+                prepare_queries ();
+            }
+            catch (EngineError e)
+            {
+                warning ("Storage Monitor couldn't communicate with DB - bye");
+                return;
+            }
+
+            // This will be called after bus is acquired, so it shouldn't block
+            try
+            {
+                var connection = Bus.get_sync (BusType.SESSION, null);
+                registration_id = connection.register_object<RemoteStorageMonitor> (
+                    "/org/gnome/zeitgeist/storagemonitor", this);
+            }
+            catch (Error err)
+            {
+                warning ("%s", err.message);
+            }
+
+            VolumeMonitor monitor = VolumeMonitor.get ();
+            monitor.volume_added.connect (on_volume_added);
+            monitor.volume_removed.connect (on_volume_removed);
+            foreach (Volume volume in monitor.get_volumes ())
+            {
+                add_storage_medium (get_volume_id (volume),
+                    volume.get_icon ().to_string (), volume.get_name ());
+            }
+
+            // FIXME: ConnMan / NetworkManager D-Bus stuff...
+        }
+
+        public override void unload ()
+        {
+            // FIXME: move all this D-Bus stuff to some shared
+            // {request,release}_iface functions
+            try
+            {
+                var connection = Bus.get_sync (BusType.SESSION, null);
+                if (registration_id != 0)
+                {
+                    connection.unregister_object (registration_id);
+                    registration_id = 0;
+                }
+            }
+            catch (Error err)
+            {
+                warning ("%s", err.message);
+            }
+
+            debug ("%s, this.ref_count = %u", Log.METHOD, this.ref_count);
+        }
+
+        private void prepare_queries () throws EngineError
+        {
+            database = engine.database;
+            db = database.database;
+
+            int rc;
+            string sql;
+
+            // Prepare query to retrieve all storage medium information
+            sql = """
+                SELECT value, state, icon, display_name
+                FROM storage
+                """;
+            rc = db.prepare_v2 (sql, -1, out get_storages_stmt);
+            database.assert_query_success (rc, "Storage retrieval query error");
+
+            sql = """
+                INSERT OR REPLACE INTO storage (
+                    value, state, icon, display_name
+                ) VALUES (
+                    ?, ?, ?, ?
+                )""";
+            rc = db.prepare_v2 (sql, -1, out store_storage_medium_stmt);
+            database.assert_query_success (rc, "Storage insertion query error");
+
+            sql = """
+                INSERT INTO storage (
+                    state, value
+                ) VALUES (
+                    ?, ?
+                )""";
+            rc = db.prepare_v2 (sql, -1, out insert_unavailable_medium_stmt);
+            database.assert_query_success (rc,
+                "insert_unavailable_medium_stmt error");
+
+            sql = """
+                UPDATE storage
+                SET state=?
+                WHERE value=?
+                """;
+            rc = db.prepare_v2 (sql, -1, out update_medium_state_stmt);
+            database.assert_query_success (rc,
+                "update_medium_state_stmt error");
+        }
+
+        public override void pre_insert_events (GenericArray<Event?> events,
+            BusName? sender)
+        {
+            for (int i = 0; i < events.length; ++i)
+            {
+                for (int j = 0; j < events[i].subjects.length; ++j)
+                {
+                    Subject subject = events[i].subjects[j];
+                    if (subject.storage == "")
+                        subject.storage = find_storage_for_uri (subject.uri);
+                }
+            }
+        }
+
+        /*
+         * Find the name of the storage medium the given URI resides on.
+         */
+        private string find_storage_for_uri (string uri)
+        {
+            // FIXME
+            return "unknown";
+        }
+
+        private void on_volume_added (VolumeMonitor monitor, Volume volume)
+        {
+            debug ("volume added");
+            Icon icon = volume.get_icon ();
+            string icon_name = "";
+            // FIXME: why volume.get_icon ().to_string () above but not here?
+            if (icon is ThemedIcon && ((ThemedIcon) icon).get_names ().length > 0)
+                icon_name = ((ThemedIcon) icon).get_names ()[0];
+            add_storage_medium (get_volume_id (volume), icon_name,
+                volume.get_name ());
+        }
+
+        private void on_volume_removed (VolumeMonitor monitor, Volume volume)
+        {
+            debug ("Volume removed");
+            remove_storage_medium (get_volume_id (volume));
+        }
+
+        /*
+         * Return a string identifier for a GIO Volume. This id is constructed
+         * as a `best effort` since we can not always uniquely identify
+         * volumes, especially audio- and data CDs are problematic.
+         */
+        private string get_volume_id (Volume volume)
+        {
+            string volume_id;
+
+            volume_id = volume.get_uuid ();
+            if (volume_id != null)
+                return volume_id;
+
+            volume_id = volume.get_identifier ("uuid");
+            if (volume_id != null)
+                return volume_id;
+
+            volume_id = volume.get_identifier ("label");
+            if (volume_id != null)
+                return volume_id;
+
+            return "unknown";
+        }
+
+        public void add_storage_medium (string medium_name, string icon,
+            string display_name)
+        {
+            debug ("VOLUME ADDED: %s".printf(medium_name));
+            store_storage_medium_stmt.reset ();
+            store_storage_medium_stmt.bind_text (1, medium_name);
+            store_storage_medium_stmt.bind_int (2, 1);
+            store_storage_medium_stmt.bind_text (3, icon);
+            store_storage_medium_stmt.bind_text (4, display_name);
+
+            int rc = store_storage_medium_stmt.step ();
+            database.assert_query_success (rc, "add_storage_medium",
+                Sqlite.DONE);
+
+            storage_available (medium_name, StorageMedia.to_variant (
+                medium_name, true, icon, display_name));
+        }
+
+        public void remove_storage_medium (string medium_name)
+        {
+            debug ("VOLUME REMOVED: %s".printf(medium_name));
+            insert_unavailable_medium_stmt.reset ();
+            insert_unavailable_medium_stmt.bind_int (1, 0);
+            insert_unavailable_medium_stmt.bind_text (2, medium_name);
+            if (insert_unavailable_medium_stmt.step () != Sqlite.DONE)
+            {
+                update_medium_state_stmt.reset ();
+                update_medium_state_stmt.bind_int (1, 0);
+                update_medium_state_stmt.bind_text (2, medium_name);
+                int rc = update_medium_state_stmt.step ()
+                database.assert_query_success (rc, "remove_storage_medium",
+                    Sqlite.DONE);
+            }
+            storage_unavailable (medium_name);
+        }
+
+        public Variant get_storages () throws EngineError
+        {
+            var vb = new VariantBuilder (new VariantType ("a(sa{sv})"));
+
+            int rc;
+            get_storages_stmt.reset ();
+            while ((rc = get_storages_stmt.step ()) == Sqlite.ROW)
+            {
+                // name, available?, icon, display name
+                Variant medium = StorageMedia.to_variant (
+                    get_storages_stmt.column_text (0),
+                    get_storages_stmt.column_int (1) == 1,
+                    get_storages_stmt.column_text (2) ?? "",
+                    get_storages_stmt.column_text (3) ?? "");
+                vb.add_value (medium);
+            }
+            database.assert_query_success (rc, "get_storages", Sqlite.DONE);
+
+            return vb.end ();
+        }
+
+    }
+
+    [ModuleInit]
+#if BUILTIN_EXTENSIONS
+    public static Type storage_monitor_init (TypeModule module)
+    {
+#else
+    public static Type extension_register (TypeModule module)
+    {
+#endif
+        return typeof (StorageMonitor);
+    }
+}
+
+// vim:expandtab:ts=4:sw=4

=== modified file 'src/Makefile.am'
--- src/Makefile.am	2011-09-25 13:45:59 +0000
+++ src/Makefile.am	2011-09-29 15:30:04 +0000
@@ -23,6 +23,7 @@
 	ext-data-source-registry.vala \
 	ext-blacklist.vala \
 	ext-histogram.vala \
+	ext-storage-monitor.vala \
 	$(NULL)
 
 bluebird_VALASOURCES = \

=== added symlink 'src/ext-storage-monitor.vala'
=== target is u'../extensions/storage-monitor.vala'
=== modified file 'src/extension-collection.vala'
--- src/extension-collection.vala	2011-09-16 23:45:36 +0000
+++ src/extension-collection.vala	2011-09-29 15:30:04 +0000
@@ -46,7 +46,8 @@
             {
                 data_source_registry_init,
                 blacklist_init,
-                histogram_init
+                histogram_init,
+                storage_monitor_init
             };
 
             foreach (var func in builtins)
@@ -168,6 +169,7 @@
     private extern static Type data_source_registry_init (TypeModule mod);
     private extern static Type blacklist_init (TypeModule mod);
     private extern static Type histogram_init (TypeModule mod);
+    private extern static Type storage_monitor_init (TypeModule mod);
 #endif
 
 }

=== modified file 'src/extension-store.vala'
--- src/extension-store.vala	2011-09-25 13:45:59 +0000
+++ src/extension-store.vala	2011-09-29 15:30:04 +0000
@@ -36,8 +36,7 @@
             prepare_queries ();
         }
 
-        private void prepare_queries ()
-            throws EngineError
+        private void prepare_queries () throws EngineError
         {
             int rc;
             string sql;