diff options
Diffstat (limited to 'champlain/champlain-network-tile-source.c')
-rw-r--r-- | champlain/champlain-network-tile-source.c | 305 |
1 files changed, 250 insertions, 55 deletions
diff --git a/champlain/champlain-network-tile-source.c b/champlain/champlain-network-tile-source.c index 281f000..324e2e5 100644 --- a/champlain/champlain-network-tile-source.c +++ b/champlain/champlain-network-tile-source.c @@ -80,17 +80,24 @@ G_DEFINE_TYPE_WITH_PRIVATE (ChamplainNetworkTileSource, champlain_network_tile_s */ #define MAX_CONNS_DEFAULT 2 +#ifndef CHAMPLAIN_LIBSOUP_3 typedef struct { ChamplainMapSource *map_source; SoupMessage *msg; } TileCancelledData; +#endif typedef struct { ChamplainMapSource *map_source; ChamplainTile *tile; +#ifdef CHAMPLAIN_LIBSOUP_3 + SoupMessage *msg; + GCancellable *cancellable; +#else TileCancelledData *cancelled_data; +#endif } TileLoadedData; typedef struct @@ -104,7 +111,7 @@ static void fill_tile (ChamplainMapSource *map_source, ChamplainTile *tile); static void tile_state_notify (ChamplainTile *tile, G_GNUC_UNUSED GParamSpec *pspec, - TileCancelledData *data); + gpointer user_data); static gchar *get_tile_uri (ChamplainNetworkTileSource *source, gint x, @@ -185,11 +192,9 @@ champlain_network_tile_source_dispose (GObject *object) ChamplainNetworkTileSourcePrivate *priv = CHAMPLAIN_NETWORK_TILE_SOURCE (object)->priv; if (priv->soup_session) - { soup_session_abort (priv->soup_session); - g_object_unref (priv->soup_session); - priv->soup_session = NULL; - } + + g_clear_object (&priv->soup_session); G_OBJECT_CLASS (champlain_network_tile_source_parent_class)->dispose (object); } @@ -322,6 +327,13 @@ champlain_network_tile_source_init (ChamplainNetworkTileSource *tile_source) priv->offline = FALSE; priv->max_conns = MAX_CONNS_DEFAULT; +#ifdef CHAMPLAIN_LIBSOUP_3 + priv->soup_session = soup_session_new_with_options ( + "user-agent", "libchamplain/" CHAMPLAIN_VERSION_S, + "max-conns-per-host", MAX_CONNS_DEFAULT, + "max-conns", MAX_CONNS_DEFAULT, + NULL); +#else priv->soup_session = soup_session_new_with_options ( "proxy-uri", NULL, "ssl-strict", FALSE, @@ -336,6 +348,7 @@ champlain_network_tile_source_init (ChamplainNetworkTileSource *tile_source) "max-conns-per-host", MAX_CONNS_DEFAULT, "max-conns", MAX_CONNS_DEFAULT, NULL); +#endif } @@ -474,11 +487,21 @@ champlain_network_tile_source_set_proxy_uri (ChamplainNetworkTileSource *tile_so g_return_if_fail (CHAMPLAIN_IS_NETWORK_TILE_SOURCE (tile_source)); ChamplainNetworkTileSourcePrivate *priv = tile_source->priv; +#ifndef CHAMPLAIN_LIBSOUP_3 SoupURI *uri = NULL; +#endif g_free (priv->proxy_uri); priv->proxy_uri = g_strdup (proxy_uri); +#ifdef CHAMPLAIN_LIBSOUP_3 + if (priv->soup_session) + { + GProxyResolver *resolver = soup_session_get_proxy_resolver (priv->soup_session); + if (!resolver && G_IS_SIMPLE_PROXY_RESOLVER (resolver)) + g_simple_proxy_resolver_set_default_proxy (G_SIMPLE_PROXY_RESOLVER (resolver), priv->proxy_uri); + } +#else if (priv->proxy_uri) uri = soup_uri_new (priv->proxy_uri); @@ -489,6 +512,7 @@ champlain_network_tile_source_set_proxy_uri (ChamplainNetworkTileSource *tile_so if (uri) soup_uri_free (uri); +#endif g_object_notify (G_OBJECT (tile_source), "proxy-uri"); } @@ -660,6 +684,25 @@ get_tile_uri (ChamplainNetworkTileSource *tile_source, return token; } +static void +tile_rendered_data_free (TileRenderedData *data) +{ + g_clear_pointer (&data->etag, g_free); + g_clear_object (&data->map_source); + g_slice_free (TileRenderedData, data); +} + +static void +tile_loaded_data_free (TileLoadedData *data) +{ + g_clear_object (&data->tile); + g_clear_object (&data->map_source); +#ifdef CHAMPLAIN_LIBSOUP_3 + g_clear_object (&data->cancellable); + g_clear_object (&data->msg); +#endif + g_slice_free (TileLoadedData, data); +} static void tile_rendered_cb (ChamplainTile *tile, @@ -668,12 +711,11 @@ tile_rendered_cb (ChamplainTile *tile, gboolean error, TileRenderedData *user_data) { - ChamplainMapSource *map_source = user_data->map_source; + ChamplainMapSource *map_source = g_steal_pointer (&user_data->map_source); ChamplainMapSource *next_source; - gchar *etag = user_data->etag; + gchar *etag = g_steal_pointer (&user_data->etag); g_signal_handlers_disconnect_by_func (tile, tile_rendered_cb, user_data); - g_slice_free (TileRenderedData, user_data); next_source = champlain_map_source_get_next_source (map_source); @@ -697,27 +739,170 @@ tile_rendered_cb (ChamplainTile *tile, g_free (etag); g_object_unref (map_source); - g_object_unref (tile); } +static void +tile_source_loaded (ChamplainMapSource *self, + const guint8 *data, + gsize size, + ChamplainTile *tile) +{ + ChamplainRenderer *renderer = champlain_map_source_get_renderer (self); + champlain_renderer_set_data (renderer, data, size); + champlain_renderer_render (renderer, tile); +} + +static void +on_tile_load_already_cached (ChamplainMapSource *self, + ChamplainTile *tile) +{ + ChamplainTileSource *tile_source = CHAMPLAIN_TILE_SOURCE (self); + ChamplainTileCache *tile_cache = champlain_tile_source_get_cache (tile_source); + + if (tile_cache) + champlain_tile_cache_refresh_tile_time (tile_cache, tile); + + champlain_tile_set_fade_in (tile, TRUE); + champlain_tile_set_state (tile, CHAMPLAIN_STATE_DONE); + champlain_tile_display_content (tile); +} + +static void +on_tile_load_failure (ChamplainMapSource *self, + ChamplainTile *tile) +{ + ChamplainMapSource *next_source = champlain_map_source_get_next_source (self); + + if (next_source) + champlain_map_source_fill_tile (next_source, tile); +} + +static void +connect_to_render_complete (ChamplainMapSource *self, + ChamplainTile *tile, + const char *etag) +{ + TileRenderedData *data; + data = g_slice_new (TileRenderedData); + data->map_source = g_object_ref (self); + data->etag = g_strdup (etag); + + g_signal_connect_data (tile, + "render-complete", + G_CALLBACK (tile_rendered_cb), + data, + (GClosureNotify)tile_rendered_data_free, + 0); +} + +#ifdef CHAMPLAIN_LIBSOUP_3 +static void +tile_bytes_loaded_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GMemoryOutputStream *output_stream = G_MEMORY_OUTPUT_STREAM (source_object); + TileLoadedData *callback_data = user_data; + ChamplainTile *tile = callback_data->tile; + ChamplainMapSource *map_source = callback_data->map_source; + GError *error = NULL; + + if (g_output_stream_splice_finish (G_OUTPUT_STREAM (output_stream), res, &error) != -1) { + gsize size = g_memory_output_stream_get_data_size (output_stream); + gconstpointer data = g_memory_output_stream_get_data (output_stream); + tile_source_loaded (map_source, data, size, tile); + } + + g_clear_error (&error); + tile_loaded_data_free (callback_data); +} static void +tile_loaded_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + TileLoadedData *callback_data = (TileLoadedData *) user_data; + GCancellable *cancellable = callback_data->cancellable; + SoupMessage *msg = callback_data->msg; + ChamplainTile *tile = callback_data->tile; + ChamplainMapSource *map_source = callback_data->map_source; + const gchar *etag; + GInputStream *stream; + GOutputStream *ostream; + GError *error = NULL; + SoupStatus status; + SoupMessageHeaders *response_headers; + + stream = soup_session_send_finish (SOUP_SESSION (source_object), res, &error); + status = soup_message_get_status (msg); + + g_signal_handlers_disconnect_by_func (tile, tile_state_notify, cancellable); + + DEBUG ("Got reply %d", status); + + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + DEBUG ("Download of tile %d, %d got cancelled", + champlain_tile_get_x (tile), champlain_tile_get_y (tile)); + goto cleanup; + } + + if (status == SOUP_STATUS_NOT_MODIFIED) + { + on_tile_load_already_cached (map_source, tile); + goto cleanup; + } + + if (!SOUP_STATUS_IS_SUCCESSFUL (status)) + { + DEBUG ("Unable to download tile %d, %d: %s : %s", + champlain_tile_get_x (tile), + champlain_tile_get_y (tile), + soup_status_get_phrase (status), + soup_message_get_reason_phrase (msg)); + + on_tile_load_failure (map_source, tile); + goto cleanup; + } + + /* Verify if the server sent an etag and save it */ + response_headers = soup_message_get_response_headers (msg); + etag = soup_message_headers_get_one (response_headers, "ETag"); + DEBUG ("Received ETag %s", etag); + + connect_to_render_complete (map_source, tile, etag); + + ostream = g_memory_output_stream_new_resizable (); + g_output_stream_splice_async (ostream, + stream, + G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | + G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, + G_PRIORITY_DEFAULT_IDLE, + cancellable, + tile_bytes_loaded_cb, + callback_data); + g_clear_object (&ostream); + g_clear_object (&stream); + + return; +cleanup: + tile_loaded_data_free (callback_data); + g_clear_error (&error); + g_clear_object (&stream); +} +#else +static void tile_loaded_cb (G_GNUC_UNUSED SoupSession *session, SoupMessage *msg, gpointer user_data) { TileLoadedData *callback_data = (TileLoadedData *) user_data; ChamplainMapSource *map_source = callback_data->map_source; - ChamplainTileSource *tile_source = CHAMPLAIN_TILE_SOURCE (map_source); - ChamplainTileCache *tile_cache = champlain_tile_source_get_cache (tile_source); - ChamplainMapSource *next_source = champlain_map_source_get_next_source (map_source); ChamplainTile *tile = callback_data->tile; const gchar *etag; - TileRenderedData *data; - ChamplainRenderer *renderer; g_signal_handlers_disconnect_by_func (tile, tile_state_notify, callback_data->cancelled_data); - g_slice_free (TileLoadedData, callback_data); DEBUG ("Got reply %d", msg->status_code); @@ -730,9 +915,8 @@ tile_loaded_cb (G_GNUC_UNUSED SoupSession *session, if (msg->status_code == SOUP_STATUS_NOT_MODIFIED) { - if (tile_cache) - champlain_tile_cache_refresh_tile_time (tile_cache, tile); - goto finish; + on_tile_load_already_cached (map_source, tile); + goto cleanup; } if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) @@ -742,44 +926,22 @@ tile_loaded_cb (G_GNUC_UNUSED SoupSession *session, champlain_tile_get_y (tile), soup_status_get_phrase (msg->status_code)); - goto load_next; + on_tile_load_failure (map_source, tile); + goto cleanup; } /* Verify if the server sent an etag and save it */ etag = soup_message_headers_get_one (msg->response_headers, "ETag"); DEBUG ("Received ETag %s", etag); - renderer = champlain_map_source_get_renderer (map_source); - g_return_if_fail (CHAMPLAIN_IS_RENDERER (renderer)); - - data = g_slice_new (TileRenderedData); - data->map_source = map_source; - data->etag = g_strdup (etag); - - g_signal_connect (tile, "render-complete", G_CALLBACK (tile_rendered_cb), data); - - champlain_renderer_set_data (renderer, (guint8*) msg->response_body->data, msg->response_body->length); - champlain_renderer_render (renderer, tile); - - return; - -load_next: - if (next_source) - champlain_map_source_fill_tile (next_source, tile); + connect_to_render_complete (map_source, tile, etag); - goto cleanup; - -finish: - champlain_tile_set_fade_in (tile, TRUE); - champlain_tile_set_state (tile, CHAMPLAIN_STATE_DONE); - champlain_tile_display_content (tile); + tile_source_loaded (map_source, (guint8*) msg->response_body->data, msg->response_body->length, tile); cleanup: - g_object_unref (tile); - g_object_unref (map_source); + tile_loaded_data_free (callback_data); } - static void destroy_cancelled_data (TileCancelledData *data, G_GNUC_UNUSED GClosure *closure) @@ -792,18 +954,31 @@ destroy_cancelled_data (TileCancelledData *data, g_slice_free (TileCancelledData, data); } +#endif static void tile_state_notify (ChamplainTile *tile, G_GNUC_UNUSED GParamSpec *pspec, - TileCancelledData *data) + gpointer user_data) { - if (champlain_tile_get_state (tile) == CHAMPLAIN_STATE_DONE && data->map_source && data->msg) +#ifdef CHAMPLAIN_LIBSOUP_3 + GCancellable *cancellable = user_data; +#else + TileCancelledData *data = user_data; + if (!data->map_source || !data->msg) + return; +#endif + + if (champlain_tile_get_state (tile) == CHAMPLAIN_STATE_DONE) { DEBUG ("Canceling tile download"); +#ifdef CHAMPLAIN_LIBSOUP_3 + g_cancellable_cancel (cancellable); +#else ChamplainNetworkTileSourcePrivate *priv = CHAMPLAIN_NETWORK_TILE_SOURCE (data->map_source)->priv; soup_session_cancel_message (priv->soup_session, data->msg, SOUP_STATUS_CANCELLED); +#endif } } @@ -842,6 +1017,9 @@ fill_tile (ChamplainMapSource *map_source, ChamplainNetworkTileSource *tile_source = CHAMPLAIN_NETWORK_TILE_SOURCE (map_source); ChamplainNetworkTileSourcePrivate *priv = tile_source->priv; +#ifdef CHAMPLAIN_LIBSOUP_3 + GCancellable *cancellable = NULL; +#endif if (champlain_tile_get_state (tile) == CHAMPLAIN_STATE_DONE) return; @@ -865,6 +1043,11 @@ fill_tile (ChamplainMapSource *map_source, const gchar *etag = champlain_tile_get_etag (tile); gchar *date = get_modified_time_string (tile); +#ifdef CHAMPLAIN_LIBSOUP_3 + SoupMessageHeaders *headers = soup_message_get_request_headers (msg); +#else + SoupMessageHeaders *headers = msg->request_headers; +#endif /* If an etag is available, only use it. * OSM servers seems to send now as the modified time for all tiles @@ -873,19 +1056,23 @@ fill_tile (ChamplainMapSource *map_source, if (etag) { DEBUG ("If-None-Match: %s", etag); - soup_message_headers_append (msg->request_headers, + soup_message_headers_append (headers, "If-None-Match", etag); } else if (date) { DEBUG ("If-Modified-Since %s", date); - soup_message_headers_append (msg->request_headers, + soup_message_headers_append (headers, "If-Modified-Since", date); } g_free (date); } +#ifdef CHAMPLAIN_LIBSOUP_3 + cancellable = g_cancellable_new (); + g_signal_connect_data (tile, "notify::state", G_CALLBACK (tile_state_notify), g_object_ref (cancellable), (GClosureNotify) g_object_unref, 0); +#else TileCancelledData *tile_cancelled_data = g_slice_new (TileCancelledData); tile_cancelled_data->map_source = map_source; tile_cancelled_data->msg = msg; @@ -895,18 +1082,26 @@ fill_tile (ChamplainMapSource *map_source, g_signal_connect_data (tile, "notify::state", G_CALLBACK (tile_state_notify), tile_cancelled_data, (GClosureNotify) destroy_cancelled_data, 0); +#endif callback_data = g_slice_new (TileLoadedData); - callback_data->tile = tile; - callback_data->map_source = map_source; + callback_data->tile = g_object_ref (tile); + callback_data->map_source = g_object_ref (map_source); +#ifdef CHAMPLAIN_LIBSOUP_3 + callback_data->cancellable = g_steal_pointer (&cancellable); + callback_data->msg = g_steal_pointer (&msg); + soup_session_send_async (priv->soup_session, + callback_data->msg, + G_PRIORITY_DEFAULT_IDLE, + callback_data->cancellable, + tile_loaded_cb, + callback_data); +#else callback_data->cancelled_data = tile_cancelled_data; - - g_object_ref (map_source); - g_object_ref (tile); - soup_session_queue_message (priv->soup_session, msg, tile_loaded_cb, callback_data); +#endif } else { |