[shotwell] faces: Add private DBus communication



commit 2bad02a5d634e1ffe9565d105593e4ced9615227
Author: Jens Georg <mail jensge org>
Date:   Mon Mar 18 15:20:51 2019 +0100

    faces: Add private DBus communication

 meson.build                                        |   5 +
 meson_options.txt                                  |   1 +
 src/AppDirs.vala                                   |   7 +-
 src/faces/FaceDetect.vala                          |  76 +++++++++++---
 src/faces/FacesTool.vala                           |  14 ++-
 subprojects/shotwell-facedetect/meson.build        |   2 +-
 .../shotwell-facedetect/shotwell-facedetect.cpp    | 110 ++++++++++++++++++---
 7 files changed, 187 insertions(+), 28 deletions(-)
---
diff --git a/meson.build b/meson.build
index a940c9ac..fda28500 100644
--- a/meson.build
+++ b/meson.build
@@ -103,6 +103,11 @@ endif
 
 if get_option('face-detection')
   add_global_arguments(['--define=ENABLE_FACES'], language : 'vala')
+
+  if get_option('face_detection_helper_bus') == 'private'
+      add_global_arguments(['--define=FACEDETECT_BUS_PRIVATE'], language : 'vala')
+  endif
+
   if get_option('face-detection-helper')
       subproject('shotwell-facedetect')
   endif
diff --git a/meson_options.txt b/meson_options.txt
index 72fbe5d2..fe15ee75 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -8,4 +8,5 @@ option('udev', type: 'boolean', value : 'true', description: 'Enable or disable
 option('install-apport-hook', type : 'boolean', value : 'true', description: 'Enable Ubuntu apport hook')
 option('face-detection', type:'boolean', value:false, description: 'Enable face detection and recognition 
features')
 option('face-detection-helper', type : 'boolean', value : 'true', description : 'If face-detection is 
enabled, build the external helper tool')
+option('face_detection_helper_bus', type:'combo', choices: ['private', 'session'], value : 'session', 
description: 'Which DBus bus to use for external helper tool')
 option('fatal_warnings', type:'boolean', value:false)
diff --git a/src/AppDirs.vala b/src/AppDirs.vala
index 66b1c938..4c4b8c58 100644
--- a/src/AppDirs.vala
+++ b/src/AppDirs.vala
@@ -263,7 +263,7 @@ class AppDirs {
         File? install_dir = get_install_dir();
         
         return (install_dir != null) ? install_dir.get_child("share").get_child("shotwell")
-            : get_exec_dir();
+            : get_lib_dir();
     }
 #endif
     
@@ -332,7 +332,7 @@ class AppDirs {
 #if ENABLE_FACES
     public static File get_facedetect_bin() {
         const string filename = "shotwell-facedetect";
-        File f = AppDirs.get_libexec_dir().get_parent().get_child("facedetect").get_child (filename);
+        File f = 
AppDirs.get_libexec_dir().get_parent().get_child("subprojects").get_child(filename).get_child (filename);
         if (!f.query_exists()) {
             f = AppDirs.get_libexec_dir().get_child("shotwell").get_child(filename);
         }
@@ -340,7 +340,8 @@ class AppDirs {
     }
 
     public static File get_haarcascade_file() {
-        File f = 
File.new_for_path(AppDirs.get_exec_dir().get_parent().get_parent().get_child("facedetect").get_child("facedetect-haarcascade.xml").get_path());
+        const string filename = "facedetect-haarcascade.xml";
+        var f = 
AppDirs.get_resources_dir().get_parent().get_child("subprojects").get_child("shotwell-facedetect").get_child 
(filename);
         if (f.query_exists()) {//testing meson builddir
             return f;
         }
diff --git a/src/faces/FaceDetect.vala b/src/faces/FaceDetect.vala
index 618d3a54..4bf6e6af 100644
--- a/src/faces/FaceDetect.vala
+++ b/src/faces/FaceDetect.vala
@@ -33,7 +33,7 @@ public struct FaceRect {
 }
 
 [DBus (name = "org.gnome.Shotwell.Faces1")]
-public interface FaceDetectInterface : Object {
+public interface FaceDetectInterface : DBusProxy {
     public abstract FaceRect[] detect_faces(string inputName, string cascadeName, double scale, bool infer)
         throws IOError, DBusError;
     public abstract bool load_net(string netFile)
@@ -53,6 +53,11 @@ public class FaceDetect {
     
     public static FaceDetectInterface interface;
 
+#if FACEDETECT_BUS_PRIVATE
+    private static GLib.DBusServer dbus_server;
+    private static Subprocess process;
+#endif
+
     public static void create_interface(DBusConnection connection, string bus_name, string owner) {
         if (bus_name == DBUS_NAME) {
             message("Dbus name %s available", bus_name);
@@ -63,9 +68,67 @@ public class FaceDetect {
         message("Dbus name %s gone", bus_name);
         connected = false;
     }
+
+    private static bool on_new_connection(DBusServer server, DBusConnection connection) {
+        try {
+            interface = connection.get_proxy_sync(null, DBUS_PATH,
+                                                  DBusProxyFlags.DO_NOT_LOAD_PROPERTIES
+                                                  | DBusProxyFlags.DO_NOT_CONNECT_SIGNALS,
+                                                  null);
+            Idle.add(() => {
+                try {
+                    if (interface.load_net(net_file))
+                        connected = true;
+                    else {
+                        AppWindow.error_message(ERROR_MESSAGE);
+                    }
+                } catch (Error error) {
+                    critical("Failed to call load_net: %s", error.message);
+                    AppWindow.error_message(ERROR_MESSAGE);
+                }
+                return false;
+            });
+
+            return true;
+        } catch (Error error) {
+            critical("Failed to create interface for face detect: %s", error.message);
+            AppWindow.error_message(ERROR_MESSAGE);
+
+            return false;
+        }
+    }
     
     public static void init(string net_file) {
         FaceDetect.net_file = net_file;
+#if FACEDETECT_BUS_PRIVATE
+        var address = "unix:tmpdir=%s".printf(Environment.get_tmp_dir());
+        var observer = new DBusAuthObserver();
+        observer.authorize_authenticated_peer.connect((stream, credentials) => {
+            debug("Observer trying to authorize for %s", credentials.to_string());
+            if (credentials == null)
+                return false;
+
+            try {
+                if (!credentials.is_same_user(new Credentials()))
+                    return false;
+                return true;
+            } catch (Error error) {
+                return false;
+            }
+        });
+
+        try {
+            dbus_server = new GLib.DBusServer.sync(address, DBusServerFlags.NONE, DBus.generate_guid(), 
observer, null);
+            dbus_server.new_connection.connect(on_new_connection);
+            dbus_server.start();
+            process = new Subprocess(SubprocessFlags.NONE, AppDirs.get_facedetect_bin().get_path(),
+            "--address=" + dbus_server.get_client_address());
+
+        } catch (Error error) {
+            warning("Failed to create private DBus server: %s", error.message);
+            AppWindow.error_message(ERROR_MESSAGE);
+        }
+#else
         Bus.watch_name(BusType.SESSION, DBUS_NAME, BusNameWatcherFlags.NONE,
                        create_interface, interface_gone);
         try {
@@ -78,16 +141,7 @@ public class FaceDetect {
             AppWindow.error_message(ERROR_MESSAGE);
         }
         connected = true;
+#endif
     }
 
-    public static double dot_product(double[] vec1, double[] vec2) {
-        if (vec1.length != vec2.length) {
-            return 0;
-        }
-        double ret = 0;
-        for (var i = 0; i < vec1.length; i++) {
-            ret += vec1[i] * vec2[i];
-        }
-        return ret;
-    }
 }
diff --git a/src/faces/FacesTool.vala b/src/faces/FacesTool.vala
index 1d1db106..866f0317 100644
--- a/src/faces/FacesTool.vala
+++ b/src/faces/FacesTool.vala
@@ -900,6 +900,18 @@ public class FacesTool : EditingTools.EditingTool {
         }
     }
 
+    private double dot_product(double[] vec1, double[] vec2) {
+        if (vec1.length != vec2.length) {
+            return 0;
+        }
+
+        double ret = 0;
+        for (var i = 0; i < vec1.length; i++) {
+            ret += vec1[i] * vec2[i];
+        }
+        return ret;
+    }
+
     private Face? get_face_match(FaceShape face_shape, double threshold) {
         Gee.List<FaceLocationRow?> face_vecs;
         try {
@@ -915,7 +927,7 @@ public class FacesTool : EditingTools.EditingTool {
             string[] vec_str = row.vec.split(",");
             double[] vec = {};
             foreach (var d in vec_str) vec += double.parse(d);
-            double product = FaceDetect.dot_product(face_shape.get_face_vec(), vec[0:128]);
+            double product = dot_product(face_shape.get_face_vec(), vec[0:128]);
             if (product > max_product) {
                 max_product = product;
                 guess_id = row.face_id;
diff --git a/subprojects/shotwell-facedetect/meson.build b/subprojects/shotwell-facedetect/meson.build
index 4ece7d15..493bc04b 100644
--- a/subprojects/shotwell-facedetect/meson.build
+++ b/subprojects/shotwell-facedetect/meson.build
@@ -1,4 +1,4 @@
-project('shotwell-facedetect', ['c', 'cpp'])
+project('shotwell-facedetect', ['c', 'cpp'], default_options : ['cpp_std=c++14'])
 gnome = import('gnome')
 facedetect_dep = dependency('opencv', version : ['>= 2.3.0'], required : true)
 cpp = meson.get_compiler('cpp')
diff --git a/subprojects/shotwell-facedetect/shotwell-facedetect.cpp 
b/subprojects/shotwell-facedetect/shotwell-facedetect.cpp
index 7a6aca95..9031dfc3 100644
--- a/subprojects/shotwell-facedetect/shotwell-facedetect.cpp
+++ b/subprojects/shotwell-facedetect/shotwell-facedetect.cpp
@@ -11,6 +11,9 @@
 #include "shotwell-facedetect.hpp"
 #include "dbus-interface.h"
 
+const char* FACEDETECT_INTERFACE_NAME = "org.gnome.Shotwell.Faces1";
+const char* FACEDETECT_PATH = "/org/gnome/shotwell/faces";
+
 // DBus binding functions
 static gboolean on_handle_detect_faces(ShotwellFaces1 *object,
                                        GDBusMethodInvocation *invocation,
@@ -84,21 +87,25 @@ static gboolean on_handle_terminate(ShotwellFaces1 *object,
 
 static void on_name_acquired(GDBusConnection *connection,
                              const gchar *name, gpointer user_data) {
-    ShotwellFaces1 *interface;
-    GError *error;
-    interface = shotwell_faces1_skeleton_new();
     g_debug("Got name %s", name);
-    g_signal_connect(interface, "handle-detect-faces", G_CALLBACK (on_handle_detect_faces), NULL);
+
+    ShotwellFaces1 *interface = shotwell_faces1_skeleton_new();
+    g_signal_connect(interface, "handle-detect-faces", G_CALLBACK (on_handle_detect_faces), nullptr);
     g_signal_connect(interface, "handle-terminate", G_CALLBACK (on_handle_terminate), user_data);
-    g_signal_connect(interface, "handle-load-net", G_CALLBACK (on_handle_load_net), NULL);
-    g_signal_connect(interface, "handle-face-to-vec", G_CALLBACK (on_handle_face_to_vec), NULL);
-    error = NULL;
-    g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(interface), connection, 
"/org/gnome/shotwell/faces", &error);
+    g_signal_connect(interface, "handle-load-net", G_CALLBACK (on_handle_load_net), nullptr);
+    g_signal_connect(interface, "handle-face-to-vec", G_CALLBACK (on_handle_face_to_vec), nullptr);
+
+    GError *error = nullptr;
+    g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(interface), connection, FACEDETECT_PATH, 
&error);
+    if (error != nullptr) {
+        g_print("Failed to export interface: %s", error->message);
+        g_clear_error(&error);
+    }
 }
 
 static void on_name_lost(GDBusConnection *connection,
                          const gchar *name, gpointer user_data) {
-    if (connection == NULL) {
+    if (connection == nullptr) {
         g_debug("Unable to establish connection for name %s", name);
     } else {
         g_debug("Connection for name %s disconnected", name);
@@ -106,11 +113,90 @@ static void on_name_lost(GDBusConnection *connection,
     g_main_loop_quit((GMainLoop *)user_data);
 }
 
+static char* address = nullptr;
+
+static GOptionEntry entries[] = {
+    { "address", 'a', 0, G_OPTION_ARG_STRING, &address, "Use private DBus ADDRESS instead of session", 
"ADDRESS" },
+    { nullptr }
+};
+
+static gboolean
+on_authorize_authenticated_peer (GIOStream *iostream,
+                                 GCredentials *credentials,
+                                 gpointer user_data)
+{
+    GCredentials *own_credentials = nullptr;
+    gboolean ret_val = FALSE;
+
+    g_debug("Authorizing peer with credentials %s\n", g_credentials_to_string (credentials));
+
+    if (credentials == nullptr)
+        goto out;
+
+    own_credentials = g_credentials_new ();
+
+    {
+        GError* error = nullptr;
+
+        if (!g_credentials_is_same_user (credentials, own_credentials, &error))
+        {
+            g_warning ("Unable to authorize peer: %s", error->message);
+            g_clear_error (&error);
+
+            goto out;
+        }
+    }
+
+    ret_val = TRUE;
+
+out:
+    g_clear_object (&own_credentials);
+
+    return ret_val;
+}
+
 int main(int argc, char **argv) {
     GMainLoop *loop;
-    loop = g_main_loop_new (NULL, FALSE);
-       g_bus_own_name(G_BUS_TYPE_SESSION, "org.gnome.Shotwell.Faces1", G_BUS_NAME_OWNER_FLAGS_NONE, NULL,
-                   on_name_acquired, on_name_lost, loop, NULL);
+    GError *error = nullptr;
+    GOptionContext *context;
+
+    context = g_option_context_new ("- Shotwell face detection helper service");
+    g_option_context_add_main_entries (context, entries, "shotwell");
+    if (!g_option_context_parse (context, &argc, &argv, &error)) {
+        g_print ("Failed to parse options: %s\n", error->message);
+        exit(1);
+    }
+
+    loop = g_main_loop_new (nullptr, FALSE);
+
+
+    // We are running on the sesion bus
+    if (address == nullptr) {
+        g_debug("Starting %s on G_BUS_TYPE_SESSION", argv[0]);
+        g_bus_own_name(G_BUS_TYPE_SESSION, FACEDETECT_INTERFACE_NAME, G_BUS_NAME_OWNER_FLAGS_NONE,
+                nullptr, on_name_acquired, on_name_lost, loop, nullptr);
+
+    } else {
+        g_debug("Starting %s on %s", argv[0], address);
+        GDBusAuthObserver *observer = g_dbus_auth_observer_new ();
+        g_signal_connect (G_OBJECT (observer), "authorize-authenticated-peer",
+                G_CALLBACK (on_authorize_authenticated_peer), nullptr);
+
+        GDBusConnection *connection = g_dbus_connection_new_for_address_sync (address,
+                                                             G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
+                                                             observer,
+                                                             nullptr,
+                                                             &error);
+        if (connection != nullptr)
+            on_name_acquired(connection, FACEDETECT_INTERFACE_NAME, loop);
+    }
+
+    if (error != nullptr) {
+        g_error("Failed to get connection on %s bus: %s",
+                address == nullptr ? "session" : "private",
+                error->message);
+    }
+
     g_main_loop_run (loop);
     return 0;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]