[geocode-glib] geocode-glib: Accept a hash table for GeocodeBackend.reverse_resolve()



commit 4c27e04be856a81bf09e3697052c514e1e5a5f26
Author: Philip Withnall <philip withnall collabora co uk>
Date:   Thu Oct 13 16:58:23 2016 +0100

    geocode-glib: Accept a hash table for GeocodeBackend.reverse_resolve()
    
    Instead of only accepting a GeocodeLocation, accept a hash table of
    string keys and GValues. Typically, this will contain `lat` and `lon`
    entries which represent the GeocodeLocation. But in future, it could
    contain other keys to look up a GeocodePlace by its backend-specific ID,
    for example; or to limit the search results by place type.
    
    Whether the keys are static or non-static is decided by the caller.
    
    This changes the API in GeocodeBackend (which is not stable yet), but
    not in GeocodeReverse, so it’s not an API break.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=756311

 geocode-glib/geocode-backend.c   |   52 +++++++++++++++---------
 geocode-glib/geocode-backend.h   |    8 ++--
 geocode-glib/geocode-nominatim.c |   80 ++++++++++++++++++-------------------
 geocode-glib/geocode-reverse.c   |   51 +++++++++++++++++++++++-
 4 files changed, 125 insertions(+), 66 deletions(-)
---
diff --git a/geocode-glib/geocode-backend.c b/geocode-glib/geocode-backend.c
index 9fbf524..17f8d1b 100644
--- a/geocode-glib/geocode-backend.c
+++ b/geocode-glib/geocode-backend.c
@@ -145,14 +145,26 @@ geocode_backend_forward_search (GeocodeBackend  *backend,
 /**
  * geocode_backend_reverse_resolve_async:
  * @backend: a #GeocodeBackend.
- * @location: a #GeocodeLocation.
+ * @params: (transfer none) (element-type utf8 GValue): a #GHashTable with string keys, and #GValue values.
  * @cancellable: optional #GCancellable object, %NULL to ignore.
  * @callback: a #GAsyncReadyCallback to call when the request is satisfied.
  * @user_data: the data to pass to callback function.
  *
  * Asynchronously gets the result of a reverse geocoding query using the
- * backend. Use geocode_backend_reverse_resolve() to do the same thing
- * synchronously.
+ * backend.
+ *
+ * Typically, a single result will be returned representing the place at a
+ * given latitude and longitude (the `lat` and `lon` keys to @params); but in
+ * some cases the results will be ambiguous and *multiple* results will be
+ * returned. They will be returned in order of relevance, with the most
+ * relevant result first in the list.
+ *
+ * The @params hash table is in the format used by Telepathy, and documented
+ * in the [Telepathy 
specification](http://telepathy.freedesktop.org/spec/Connection_Interface_Location.html#Mapping:Location).
+ *
+ * See also: [XEP-0080 specification](http://xmpp.org/extensions/xep-0080.html).
+ *
+ * Use geocode_backend_reverse_resolve() to do the same thing synchronously.
  *
  * When the operation is finished, @callback will be called. You can then call
  * geocode_backend_reverse_resolve_finish() to get the result of the operation.
@@ -161,7 +173,7 @@ geocode_backend_forward_search (GeocodeBackend  *backend,
  */
 void
 geocode_backend_reverse_resolve_async (GeocodeBackend      *backend,
-                                       GeocodeLocation     *location,
+                                       GHashTable          *params,
                                        GCancellable        *cancellable,
                                        GAsyncReadyCallback  callback,
                                        gpointer             user_data)
@@ -169,12 +181,12 @@ geocode_backend_reverse_resolve_async (GeocodeBackend      *backend,
        GeocodeBackendInterface *iface;
 
        g_return_if_fail (GEOCODE_IS_BACKEND (backend));
-       g_return_if_fail (GEOCODE_IS_LOCATION (location));
+       g_return_if_fail (params != NULL);
        g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
 
        iface = GEOCODE_BACKEND_GET_IFACE (backend);
 
-       return (* iface->reverse_resolve_async) (backend, location,
+       return (* iface->reverse_resolve_async) (backend, params,
                                                 cancellable, callback, user_data);
 }
 
@@ -212,15 +224,16 @@ geocode_backend_reverse_resolve_finish (GeocodeBackend  *backend,
 /**
  * geocode_backend_reverse_resolve:
  * @backend: a #GeocodeBackend.
- * @location: a #GeocodeLocation.
+ * @params: (transfer none) (element-type utf8 GValue): a #GHashTable with string keys, and #GValue values.
  * @cancellable: optional #GCancellable object, %NULL to ignore.
  * @error: a #GError.
  *
- * Gets the result of a reverse geocoding query using the @backend. Typically, a
- * single result will be returned representing the place at the given location;
- * but in some cases the results will be ambiguous and multiple results will
- * be returned. They will be returned in order of relevance, with the most
- * relevant result first in the list.
+ * Gets the result of a reverse geocoding query using the @backend.
+ *
+ * This is a synchronous function, which means it may block on network requests.
+ * In most situations, the asynchronous version,
+ * geocode_backend_forward_search_async(), is more appropriate. See its
+ * documentation for more information on usage.
  *
  * Returns: (transfer full) (element-type GeocodePlace): A list of
  *    #GeocodePlace instances, or %NULL in case of errors. The list is ordered
@@ -231,14 +244,14 @@ geocode_backend_reverse_resolve_finish (GeocodeBackend  *backend,
  */
 GList *
 geocode_backend_reverse_resolve (GeocodeBackend   *backend,
-                                 GeocodeLocation  *location,
+                                 GHashTable       *params,
                                  GCancellable     *cancellable,
                                  GError          **error)
 {
        GeocodeBackendInterface *iface;
 
        g_return_val_if_fail (GEOCODE_IS_BACKEND (backend), NULL);
-       g_return_val_if_fail (GEOCODE_IS_LOCATION (location), NULL);
+       g_return_val_if_fail (params != NULL, NULL);
        g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
        g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
@@ -254,7 +267,7 @@ geocode_backend_reverse_resolve (GeocodeBackend   *backend,
                return NULL;
        }
 
-       return (* iface->reverse_resolve) (backend, location,
+       return (* iface->reverse_resolve) (backend, params,
                                           cancellable, error);
 }
 
@@ -309,13 +322,13 @@ real_forward_search_finish (GeocodeBackend  *backend,
 static void
 reverse_resolve_async_thread (GTask           *task,
                               GeocodeBackend  *backend,
-                              GeocodeLocation *location,
+                              GHashTable      *params,
                               GCancellable    *cancellable)
 {
        GError *error = NULL;
        GList *places;  /* (element-type GeocodePlace) */
 
-       places = geocode_backend_reverse_resolve (backend, location,
+       places = geocode_backend_reverse_resolve (backend, params,
                                                  cancellable, &error);
        if (error)
                g_task_return_error (task, error);
@@ -326,7 +339,7 @@ reverse_resolve_async_thread (GTask           *task,
 
 static void
 real_reverse_resolve_async (GeocodeBackend      *backend,
-                            GeocodeLocation     *location,
+                            GHashTable          *params,
                             GCancellable        *cancellable,
                             GAsyncReadyCallback  callback,
                             gpointer             user_data)
@@ -334,7 +347,8 @@ real_reverse_resolve_async (GeocodeBackend      *backend,
        GTask *task;
 
        task = g_task_new (backend, cancellable, callback, user_data);
-       g_task_set_task_data (task, g_object_ref (location), g_object_unref);
+       g_task_set_task_data (task, g_hash_table_ref (params),
+                             (GDestroyNotify) g_hash_table_unref);
        g_task_run_in_thread (task, (GTaskThreadFunc) reverse_resolve_async_thread);
        g_object_unref (task);
 }
diff --git a/geocode-glib/geocode-backend.h b/geocode-glib/geocode-backend.h
index a003826..9adfbc5 100644
--- a/geocode-glib/geocode-backend.h
+++ b/geocode-glib/geocode-backend.h
@@ -78,11 +78,11 @@ struct _GeocodeBackendInterface
 
        /* Reverse */
        GList        *(*reverse_resolve)         (GeocodeBackend       *backend,
-                                                 GeocodeLocation      *location,
+                                                 GHashTable           *params,
                                                  GCancellable         *cancellable,
                                                  GError              **error);
        void          (*reverse_resolve_async)   (GeocodeBackend       *backend,
-                                                 GeocodeLocation      *location,
+                                                 GHashTable           *params,
                                                  GCancellable         *cancellable,
                                                  GAsyncReadyCallback   callback,
                                                  gpointer              user_data);
@@ -110,7 +110,7 @@ GList        *geocode_backend_forward_search         (GeocodeBackend      *backe
 
 /* Reverse geocoding operations */
 void          geocode_backend_reverse_resolve_async  (GeocodeBackend       *backend,
-                                                      GeocodeLocation      *location,
+                                                      GHashTable           *params,
                                                       GCancellable         *cancellable,
                                                       GAsyncReadyCallback   callback,
                                                       gpointer              user_data);
@@ -118,7 +118,7 @@ GList        *geocode_backend_reverse_resolve_finish (GeocodeBackend       *back
                                                       GAsyncResult         *result,
                                                       GError              **error);
 GList        *geocode_backend_reverse_resolve        (GeocodeBackend       *backend,
-                                                      GeocodeLocation      *location,
+                                                      GHashTable           *params,
                                                       GCancellable         *cancellable,
                                                       GError              **error);
 
diff --git a/geocode-glib/geocode-nominatim.c b/geocode-glib/geocode-nominatim.c
index b351b30..c4c9601 100644
--- a/geocode-glib/geocode-nominatim.c
+++ b/geocode-glib/geocode-nominatim.c
@@ -783,17 +783,33 @@ _geocode_glib_dup_hash_table (GHashTable *ht)
 }
 
 static gchar *
-get_resolve_uri_for_params (GeocodeNominatim *self,
-                            GHashTable       *orig_ht)
+get_resolve_uri_for_params (GeocodeNominatim  *self,
+                            GHashTable        *orig_ht,
+                            GError           **error)
 {
        GHashTable *ht;
        char *locale;
        char *params, *uri;
        GeocodeNominatimPrivate *priv;
+       const GValue *lat, *lon;
 
        priv = geocode_nominatim_get_instance_private (self);
 
-       ht = _geocode_glib_dup_hash_table (orig_ht);
+       /* Make sure we have both lat and lon. */
+       lat = g_hash_table_lookup (orig_ht, "lat");
+       lon = g_hash_table_lookup (orig_ht, "lon");
+
+       if (lat == NULL || lon == NULL) {
+               g_set_error_literal (error, GEOCODE_ERROR, GEOCODE_ERROR_INVALID_ARGUMENTS,
+                                    "Only following parameters supported: lat, lon");
+
+               return NULL;
+       }
+
+       ht = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
+
+       g_hash_table_insert (ht, (gpointer) "lat", (gpointer) g_value_get_string (lat));
+       g_hash_table_insert (ht, (gpointer) "lon", (gpointer) g_value_get_string (lon));
 
        g_hash_table_insert (ht, (gpointer) "format", (gpointer) "json");
        g_hash_table_insert (ht, (gpointer) "email",
@@ -961,29 +977,6 @@ geocode_nominatim_query (GeocodeNominatim  *self,
 
 /******************************************************************************/
 
-static GHashTable *
-_geocode_location_to_params (GeocodeLocation *location)
-{
-       GHashTable *ht;
-       char coord[G_ASCII_DTOSTR_BUF_SIZE];
-       char *lat;
-       char *lon;
-
-       lat = g_strdup (g_ascii_dtostr (coord,
-                                       G_ASCII_DTOSTR_BUF_SIZE,
-                                       geocode_location_get_latitude (location)));
-
-       lon = g_strdup (g_ascii_dtostr (coord,
-                                       G_ASCII_DTOSTR_BUF_SIZE,
-                                       geocode_location_get_longitude (location)));
-
-       ht = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-       g_hash_table_insert (ht, g_strdup ("lat"), lat);
-       g_hash_table_insert (ht, g_strdup ("lon"), lon);
-
-       return ht;
-}
-
 static GList *
 geocode_nominatim_reverse_resolve_finish (GeocodeBackend  *backend,
                                           GAsyncResult    *res,
@@ -1192,21 +1185,25 @@ on_reverse_query_ready (GeocodeNominatim *self,
 
 static void
 geocode_nominatim_reverse_resolve_async (GeocodeBackend      *self,
-                                         GeocodeLocation     *location,
+                                         GHashTable          *params,
                                          GCancellable        *cancellable,
                                          GAsyncReadyCallback  callback,
                                          gpointer             user_data)
 {
        GTask *task;
-       GHashTable *ht;
        gchar *uri = NULL;
+       GError *error = NULL;
 
        g_return_if_fail (GEOCODE_IS_BACKEND (self));
-       g_return_if_fail (GEOCODE_IS_LOCATION (location));
+       g_return_if_fail (params != NULL);
 
-       ht = _geocode_location_to_params (location);
-       uri = get_resolve_uri_for_params (GEOCODE_NOMINATIM (self), ht);
-       g_hash_table_unref (ht);
+       uri = get_resolve_uri_for_params (GEOCODE_NOMINATIM (self), params,
+                                         &error);
+
+       if (error != NULL) {
+               g_task_report_error (self, callback, user_data, NULL, error);
+               return;
+       }
 
        task = g_task_new (self, cancellable, callback, user_data);
        GEOCODE_NOMINATIM_GET_CLASS (self)->query_async (GEOCODE_NOMINATIM (self),
@@ -1219,23 +1216,24 @@ geocode_nominatim_reverse_resolve_async (GeocodeBackend      *self,
 }
 
 static GList *
-geocode_nominatim_reverse_resolve (GeocodeBackend   *self,
-                                   GeocodeLocation  *location,
-                                   GCancellable     *cancellable,
-                                   GError          **error)
+geocode_nominatim_reverse_resolve (GeocodeBackend  *self,
+                                   GHashTable      *params,
+                                   GCancellable    *cancellable,
+                                   GError         **error)
 {
        char *contents;
-       GHashTable *ht;
        GHashTable *result = NULL;
        g_autoptr (GeocodePlace) place = NULL;
        gchar *uri = NULL;
 
        g_return_val_if_fail (GEOCODE_IS_BACKEND (self), NULL);
-       g_return_val_if_fail (GEOCODE_IS_LOCATION (location), NULL);
+       g_return_val_if_fail (params != NULL, NULL);
 
-       ht = _geocode_location_to_params (location);
-       uri = get_resolve_uri_for_params (GEOCODE_NOMINATIM (self), ht);
-       g_hash_table_unref (ht);
+       uri = get_resolve_uri_for_params (GEOCODE_NOMINATIM (self), params,
+                                         error);
+
+       if (uri == NULL)
+               return NULL;
 
        contents = GEOCODE_NOMINATIM_GET_CLASS (self)->query (GEOCODE_NOMINATIM (self),
                                                              uri,
diff --git a/geocode-glib/geocode-reverse.c b/geocode-glib/geocode-reverse.c
index 43d3b77..eed4029 100644
--- a/geocode-glib/geocode-reverse.c
+++ b/geocode-glib/geocode-reverse.c
@@ -109,6 +109,48 @@ ensure_backend (GeocodeReverse *object)
                object->priv->backend = GEOCODE_BACKEND (geocode_nominatim_get_gnome ());
 }
 
+static GValue *
+str_to_value (const gchar *str)
+{
+       GValue *value;
+
+       value = g_new0 (GValue, 1);
+       g_value_init (value, G_TYPE_STRING);
+       g_value_set_string (value, str);
+
+       return value;
+}
+
+static void
+free_value (GValue *value)
+{
+       g_value_unset (value);
+       g_free (value);
+}
+
+static GHashTable *
+_geocode_location_to_params (GeocodeLocation *location)
+{
+       GHashTable *ht;
+       char lat[G_ASCII_DTOSTR_BUF_SIZE];
+       char lon[G_ASCII_DTOSTR_BUF_SIZE];
+
+       g_ascii_dtostr (lat,
+                       G_ASCII_DTOSTR_BUF_SIZE,
+                       geocode_location_get_latitude (location));
+       g_ascii_dtostr (lon,
+                       G_ASCII_DTOSTR_BUF_SIZE,
+                       geocode_location_get_longitude (location));
+
+       /* Semantics from http://xmpp.org/extensions/xep-0080.html */
+       ht = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
+                                   (GDestroyNotify) free_value);
+       g_hash_table_insert (ht, (gpointer) "lat", str_to_value (lat));
+       g_hash_table_insert (ht, (gpointer) "lon", str_to_value (lon));
+
+       return ht;
+}
+
 static void
 places_list_free (GList *places)
 {
@@ -155,6 +197,7 @@ geocode_reverse_resolve_async (GeocodeReverse     *object,
                                gpointer            user_data)
 {
        GTask *task;
+       g_autoptr (GHashTable) params = NULL;
 
        g_return_if_fail (GEOCODE_IS_REVERSE (object));
        g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
@@ -162,9 +205,11 @@ geocode_reverse_resolve_async (GeocodeReverse     *object,
        ensure_backend (object);
        g_assert (object->priv->backend != NULL);
 
+       params = _geocode_location_to_params (object->priv->location);
+
        task = g_task_new (object, cancellable, callback, user_data);
        geocode_backend_reverse_resolve_async (object->priv->backend,
-                                              object->priv->location,
+                                              params,
                                               cancellable,
                                               (GAsyncReadyCallback) backend_reverse_resolve_ready,
                                               g_object_ref (task));
@@ -211,6 +256,7 @@ geocode_reverse_resolve (GeocodeReverse *object,
 {
        GList *places = NULL;  /* (element-type GeocodePlace) */
        GeocodePlace *place = NULL;
+       g_autoptr (GHashTable) params = NULL;
 
        g_return_val_if_fail (GEOCODE_IS_REVERSE (object), NULL);
        g_return_val_if_fail (error == NULL || *error == NULL, NULL);
@@ -218,8 +264,9 @@ geocode_reverse_resolve (GeocodeReverse *object,
        ensure_backend (object);
        g_assert (object->priv->backend != NULL);
 
+       params = _geocode_location_to_params (object->priv->location);
        places = geocode_backend_reverse_resolve (object->priv->backend,
-                                                 object->priv->location,
+                                                 params,
                                                  NULL,
                                                  error);
 


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