[geocode-glib] lib: Return a location from geocode_ipclient_search()



commit d589297a653588beb5112a614d3e6aaad05cbfd3
Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
Date:   Fri Mar 22 02:28:18 2013 +0200

    lib: Return a location from geocode_ipclient_search()
    
    This API is a lot more useful if we provide a parsed GeocodeLocation
    object to the caller rather than just the raw JSON string we get as
    response from server.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=696526

 geocode-glib/geocode-glib-private.h |    3 +
 geocode-glib/geocode-glib.symbols   |    1 +
 geocode-glib/geocode-ipclient.c     |  116 ++++++++++++++++++++++++++++++++---
 geocode-glib/geocode-ipclient.h     |   11 ++--
 geocode-glib/test-geoip.c           |   64 ++++++++++++--------
 5 files changed, 155 insertions(+), 40 deletions(-)
---
diff --git a/geocode-glib/geocode-glib-private.h b/geocode-glib/geocode-glib-private.h
index d6b8610..2393c9e 100644
--- a/geocode-glib/geocode-glib-private.h
+++ b/geocode-glib/geocode-glib-private.h
@@ -24,6 +24,7 @@
 #define GEOCODE_GLIB_PRIVATE_H
 
 #include <glib.h>
+#include "geocode-location.h"
 
 G_BEGIN_DECLS
 
@@ -41,6 +42,8 @@ GList      *_geocode_parse_search_json  (const char *contents,
                                         GError    **error);
 GFile      *_get_resolve_query_for_params (GHashTable  *orig_ht,
                                           gboolean     reverse);
+GeocodeLocation *_geocode_ip_json_to_location (const char  *json,
+                                              GError     **error);
 
 char       *_geocode_object_get_lang (void);
 
diff --git a/geocode-glib/geocode-glib.symbols b/geocode-glib/geocode-glib.symbols
index 5245bf9..e8d8e2d 100644
--- a/geocode-glib/geocode-glib.symbols
+++ b/geocode-glib/geocode-glib.symbols
@@ -19,6 +19,7 @@ geocode_reverse_resolve
 geocode_error_quark
 _geocode_parse_search_json
 _geocode_parse_resolve_json
+_geocode_ip_json_to_location
 geocode_ipclient_get_type
 geocode_ipclient_new
 geocode_ipclient_new_for_ip
diff --git a/geocode-glib/geocode-ipclient.c b/geocode-glib/geocode-ipclient.c
index 47e5194..34c34c8 100644
--- a/geocode-glib/geocode-ipclient.c
+++ b/geocode-glib/geocode-ipclient.c
@@ -23,7 +23,11 @@
 #include <stdlib.h>
 #include <glib.h>
 #include <libsoup/soup.h>
+#include <json-glib/json-glib.h>
+#include "geocode-glib-private.h"
 #include "geocode-ipclient.h"
+#include "geocode-error.h"
+#include "geocode-ip-server/geoip-server.h"
 
 /**
  * SECTION:geocode-ipclient
@@ -280,6 +284,92 @@ geocode_ipclient_search_async (GeocodeIpclient           *ipclient,
         g_object_unref (query);
 }
 
+static gboolean
+parse_server_error (JsonObject *object, GError **error)
+{
+        GeoipServerError server_error_code;
+        int error_code;
+        const char *error_message;
+
+        if (!json_object_has_member (object, "error_code"))
+            return FALSE;
+
+        server_error_code = json_object_get_int_member (object, "error_code");
+        switch (server_error_code) {
+                case INVALID_IP_ADDRESS_ERR:
+                        error_code = GEOCODE_ERROR_INVALID_ARGUMENTS;
+                        break;
+                case INVALID_ENTRY_ERR:
+                        error_code = GEOCODE_ERROR_NO_MATCHES;
+                        break;
+                case DATABASE_ERR:
+                        error_code = GEOCODE_ERROR_INTERNAL_SERVER;
+                        break;
+        }
+
+        error_message = json_object_get_string_member (object, "error_message");
+
+        g_set_error_literal (error,
+                             GEOCODE_ERROR,
+                             error_code,
+                             error_message);
+
+        return TRUE;
+}
+
+GeocodeLocation *
+_geocode_ip_json_to_location (const char  *json,
+                             GError     **error)
+{
+        JsonParser *parser;
+        JsonNode *node;
+        JsonObject *object;
+        GeocodeLocation *location;
+        char *desc = NULL;
+
+        parser = json_parser_new ();
+
+        if (!json_parser_load_from_data (parser, json, -1, error))
+                return NULL;
+
+        node = json_parser_get_root (parser);
+        object = json_node_get_object (node);
+
+        if (parse_server_error (object, error))
+                return NULL;
+
+        location = geocode_location_new (0, 0);
+        location->latitude = json_object_get_double_member (object, "latitude");
+        location->longitude = json_object_get_double_member (object, "longitude");
+
+        if (json_object_has_member (object, "country_name")) {
+                if (json_object_has_member (object, "region_name")) {
+                        if (json_object_has_member (object, "city")) {
+                                desc = g_strdup_printf ("%s, %s, %s",
+                                                        json_object_get_string_member (object, "city"),
+                                                        json_object_get_string_member (object, 
"region_name"),
+                                                        json_object_get_string_member (object, 
"country_name"));
+                        } else {
+                                desc = g_strdup_printf ("%s, %s",
+                                                        json_object_get_string_member (object, 
"region_name"),
+                                                        json_object_get_string_member (object, 
"country_name"));
+                        }
+                } else {
+                        desc = g_strdup_printf ("%s",
+                                                json_object_get_string_member (object, "country_name"));
+                }
+        }
+
+        if (desc != NULL) {
+                geocode_location_set_description (location, desc);
+                g_free (desc);
+        }
+
+        g_object_unref (parser);
+
+        return location;
+}
+
 /**
  * geocode_ipclient_search_finish:
  * @ipclient: a #GeocodeIpclient representing a query
@@ -288,17 +378,17 @@ geocode_ipclient_search_async (GeocodeIpclient           *ipclient,
  *
  * Finishes a geolocation search operation. See geocode_ipclient_search_async().
  *
- * Returns: a string containing the result of the query in JSON format
- * or %NULL in case of errors.
- * Free the returned string with g_free() when done.
+ * Returns: (transfer full): A #GeocodeLocation object or %NULL in case of
+ * errors. Free the returned object with g_object_unref() when done.
  **/
-char *
+GeocodeLocation *
 geocode_ipclient_search_finish (GeocodeIpclient *ipclient,
                                 GAsyncResult    *res,
                                 GError          **error)
 {
         GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
         char *contents = NULL;
+        GeocodeLocation *location;
 
         g_return_val_if_fail (GEOCODE_IS_IPCLIENT (ipclient), NULL);
 
@@ -308,7 +398,10 @@ geocode_ipclient_search_finish (GeocodeIpclient *ipclient,
                 return NULL;
 
         contents = g_simple_async_result_get_op_res_gpointer (simple);
-        return contents;
+        location = _geocode_ip_json_to_location (contents, error);
+        g_free (contents);
+
+        return location;
 }
 
 /**
@@ -318,16 +411,16 @@ geocode_ipclient_search_finish (GeocodeIpclient *ipclient,
  *
  * Gets the geolocation data for an IP address from the server.
  *
- * Returns: a string containing the result of the query in JSON format
- * or %NULL in case of errors.
- * Free the returned string with g_free() when done.
+ * Returns: (transfer full): A #GeocodeLocation object or %NULL in case of
+ * errors. Free the returned object with g_object_unref() when done.
  **/
-char *
+GeocodeLocation *
 geocode_ipclient_search (GeocodeIpclient        *ipclient,
                          GError                 **error)
 {
         char *contents;
         GFile *query;
+        GeocodeLocation *location;
 
         g_return_val_if_fail (GEOCODE_IS_IPCLIENT (ipclient), NULL);
         g_return_val_if_fail (ipclient->priv->server != NULL, NULL);
@@ -347,5 +440,8 @@ geocode_ipclient_search (GeocodeIpclient        *ipclient,
         }
         g_object_unref (query);
 
-        return contents;
+        location = _geocode_ip_json_to_location (contents, error);
+        g_free (contents);
+
+        return location;
 }
diff --git a/geocode-glib/geocode-ipclient.h b/geocode-glib/geocode-ipclient.h
index ab9e7d9..7bd26da 100644
--- a/geocode-glib/geocode-ipclient.h
+++ b/geocode-glib/geocode-ipclient.h
@@ -25,6 +25,7 @@
 
 #include <glib.h>
 #include <gio/gio.h>
+#include "geocode-location.h"
 
 G_BEGIN_DECLS
 
@@ -71,12 +72,12 @@ void geocode_ipclient_search_async  (GeocodeIpclient       *ipclient,
                                      GAsyncReadyCallback    callback,
                                      gpointer               user_data);
 
-char *geocode_ipclient_search_finish (GeocodeIpclient   *ipclient,
-                                      GAsyncResult      *res,
-                                      GError            **error);
+GeocodeLocation *geocode_ipclient_search_finish (GeocodeIpclient   *ipclient,
+                                                 GAsyncResult      *res,
+                                                 GError            **error);
 
-char *geocode_ipclient_search (GeocodeIpclient *ipclient,
-                               GError          **error);
+GeocodeLocation *geocode_ipclient_search (GeocodeIpclient *ipclient,
+                                          GError          **error);
 
 G_END_DECLS
 
diff --git a/geocode-glib/test-geoip.c b/geocode-glib/test-geoip.c
index 4b1881f..895e643 100644
--- a/geocode-glib/test-geoip.c
+++ b/geocode-glib/test-geoip.c
@@ -9,30 +9,39 @@
 
 static GMainLoop *loop = NULL;
 
+typedef struct {
+        const char *ip;
+
+        double expected_latitude;
+        double expected_longitude;
+        const char *expected_description;
+} TestData;
+
 static void
 test_search (gconstpointer data)
 {
         GeocodeIpclient *ipclient;
         GError *error = NULL;
-        char *contents;
-        const char *ip;
+        GeocodeLocation *location;
+        TestData *test_data = (TestData *) data;
 
-        ip = (const char *) data;
-        if (ip)
-                ipclient = geocode_ipclient_new_for_ip (ip);
-        else
+        if (test_data->ip)
+                ipclient = geocode_ipclient_new_for_ip (test_data->ip);
+        else {
                 ipclient = geocode_ipclient_new ();
-
-        contents = geocode_ipclient_search (ipclient, &error);
-        if (!contents) {
+        }
+        location = geocode_ipclient_search (ipclient, &error);
+        if (!location) {
                 g_warning ("Failed at getting the geolocation information: %s", error->message);
                 g_error_free (error);
         }
-        g_assert (contents != NULL);
-        g_assert (strstr (contents, "\"ERROR\"") == NULL);
+        g_assert (location != NULL);
+        g_assert (location->latitude == test_data->expected_latitude);
+        g_assert (location->longitude == test_data->expected_longitude);
+        g_assert (location->description != NULL &&
+                  strcmp(location->description, test_data->expected_description) == 0);
+        geocode_location_free (location);
         g_object_unref (ipclient);
-        g_print ("%s\n", contents);
-        g_free (contents);
 }
 
 static void
@@ -42,31 +51,30 @@ print_geolocation_info_cb (GObject          *source_object,
 {
         GeocodeIpclient *object = (GeocodeIpclient *) source_object;
         GError *error = NULL;
-        char *results;
+        GeocodeLocation *location;
 
-        results = geocode_ipclient_search_finish (object, res, &error);
-        if (results == NULL) {
+        location = geocode_ipclient_search_finish (object, res, &error);
+        if (location == NULL) {
                 g_message ("Failed to search the geolocation info: %s", error->message);
                 g_error_free (error);
                 exit (1);
         }
-        g_print ("%s\n", results);
-        g_free (results);
+        g_print ("Location: %s (%f,%f)\n", location->description, location->latitude,  location->longitude);
 
+        geocode_location_free (location);
         g_object_unref (object);
         exit (0);
 }
 
-
 int main (int argc, char **argv)
 {
         GError *error = NULL;
         GOptionContext *context;
         GeocodeIpclient *ipclient;
-        char *ip = NULL;
+        TestData data = { NULL, 0.0f, 0.0f, NULL };
         gboolean regr = FALSE;
         const GOptionEntry entries[] = {
-                { "ip", 0, 0, G_OPTION_ARG_STRING, &ip, "The ip address for which to search the geolocation 
data", NULL },
+                { "ip", 0, 0, G_OPTION_ARG_STRING, &data.ip, "The ip address for which to search the 
geolocation data", NULL },
                 { "regr", 0, 0, G_OPTION_ARG_NONE, &regr, "Run the default testcases", NULL },
                 { NULL }
         };
@@ -86,13 +94,19 @@ int main (int argc, char **argv)
         }
 
         if (regr == TRUE) {
-                g_test_add_data_func ("/geoip/search_with_ip", "24.24.24.24", test_search);
-                g_test_add_data_func ("/geocode/search", NULL, test_search);
+                data.expected_latitude = 43.089199f;
+                data.expected_longitude = -76.025002f;
+                data.expected_description = "East Syracuse, New York, United States";
+
+                g_test_add_data_func ("/geocode/search", &data, test_search);
+
+                data.ip = "24.24.24.24";
+                g_test_add_data_func ("/geoip/search_with_ip", &data, test_search);
                 return g_test_run ();
         }
 
-        if (ip)
-                ipclient = geocode_ipclient_new_for_ip (ip);
+        if (data.ip)
+                ipclient = geocode_ipclient_new_for_ip (data.ip);
         else
                 ipclient = geocode_ipclient_new ();
         geocode_ipclient_search_async (ipclient, NULL, print_geolocation_info_cb, NULL);


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