From 9beaa488c4b5d0f763517db0ce1de5b64dfe78db Mon Sep 17 00:00:00 2001 From: Eitan Isaacson Date: Thu, 31 Mar 2011 13:20:46 -0700 Subject: Introduce rest_proxy_call_upload to provide progress feedback. --- rest/rest-proxy-call-private.h | 1 + rest/rest-proxy-call.c | 129 +++++++++++++++++++++++++++++++++++++++++ rest/rest-proxy-call.h | 13 +++++ 3 files changed, 143 insertions(+) diff --git a/rest/rest-proxy-call-private.h b/rest/rest-proxy-call-private.h index 584a77b..ec7a4be 100644 --- a/rest/rest-proxy-call-private.h +++ b/rest/rest-proxy-call-private.h @@ -31,6 +31,7 @@ G_BEGIN_DECLS typedef struct _RestProxyCallAsyncClosure RestProxyCallAsyncClosure; typedef struct _RestProxyCallContinuousClosure RestProxyCallContinuousClosure; +typedef struct _RestProxyCallUploadClosure RestProxyCallUploadClosure; struct _RestProxyCallPrivate { gchar *method; diff --git a/rest/rest-proxy-call.c b/rest/rest-proxy-call.c index 6ffa56c..d1fe266 100644 --- a/rest/rest-proxy-call.c +++ b/rest/rest-proxy-call.c @@ -50,6 +50,15 @@ struct _RestProxyCallContinuousClosure { SoupMessage *message; }; +struct _RestProxyCallUploadClosure { + RestProxyCall *call; + RestProxyCallUploadCallback callback; + GObject *weak_object; + gpointer userdata; + SoupMessage *message; + gsize uploaded; +}; + enum { PROP_0 = 0, @@ -994,6 +1003,126 @@ error: return FALSE; } +static void +_upload_call_message_completed_cb (SoupSession *session, + SoupMessage *message, + gpointer user_data) +{ + RestProxyCall *call; + RestProxyCallPrivate *priv; + GError *error = NULL; + RestProxyCallUploadClosure *closure; + + closure = (RestProxyCallUploadClosure *) user_data; + call = closure->call; + priv = GET_PRIVATE (call); + + priv->status_code = message->status_code; + priv->status_message = g_strdup (message->reason_phrase); + + _handle_error_from_message (message, &error); + + closure->callback (closure->call, + closure->uploaded, + closure->uploaded, + error, + closure->weak_object, + closure->userdata); + + g_clear_error (&error); + + /* Success. We don't need the weak reference any more */ + if (closure->weak_object) + { + g_object_weak_unref (closure->weak_object, + (GWeakNotify)_call_async_weak_notify_cb, + closure); + } + + priv->cur_call_closure = NULL; + g_object_unref (closure->call); + g_slice_free (RestProxyCallUploadClosure, closure); +} + +static void +_upload_call_message_wrote_data_cb (SoupMessage *msg, + SoupBuffer *chunk, + RestProxyCallUploadClosure *closure) +{ + closure->uploaded = closure->uploaded + chunk->length; + + if (closure->uploaded < msg->request_body->length) + closure->callback (closure->call, + msg->request_body->length, + closure->uploaded, + NULL, + closure->weak_object, + closure->userdata); +} + +gboolean +rest_proxy_call_upload (RestProxyCall *call, + RestProxyCallUploadCallback callback, + GObject *weak_object, + gpointer userdata, + GError **error) +{ + RestProxyCallPrivate *priv; + SoupMessage *message; + RestProxyCallUploadClosure *closure; + + g_return_val_if_fail (REST_IS_PROXY_CALL (call), FALSE); + priv = GET_PRIVATE (call); + g_assert (priv->proxy); + + if (priv->cur_call_closure) + { + /* FIXME: Use GError here */ + g_critical (G_STRLOC ": Call already in progress."); + return FALSE; + } + + message = prepare_message (call, error); + if (message == NULL) + goto error; + + closure = g_slice_new0 (RestProxyCallUploadClosure); + closure->call = g_object_ref (call); + closure->callback = callback; + closure->weak_object = weak_object; + closure->message = message; + closure->userdata = userdata; + closure->uploaded = 0; + + priv->cur_call_closure = (RestProxyCallAsyncClosure *)closure; + + /* Weakly reference this object. We remove our callback if it goes away. */ + if (closure->weak_object) + { + g_object_weak_ref (closure->weak_object, + (GWeakNotify)_call_async_weak_notify_cb, + closure); + } + + g_signal_connect (message, + "wrote-body-data", + (GCallback) _upload_call_message_wrote_data_cb, + closure); + + _rest_proxy_queue_message (priv->proxy, + message, + _upload_call_message_completed_cb, + closure); + g_free (priv->url); + priv->url = NULL; + return TRUE; + +error: + g_free (priv->url); + priv->url = NULL; + return FALSE; +} + /** * rest_proxy_call_cancel: * @call: The #RestProxyCall diff --git a/rest/rest-proxy-call.h b/rest/rest-proxy-call.h index 918b35c..a8085d9 100644 --- a/rest/rest-proxy-call.h +++ b/rest/rest-proxy-call.h @@ -176,6 +176,19 @@ gboolean rest_proxy_call_continuous (RestProxyCall *call, gpointer userdata, GError **error); +typedef void (*RestProxyCallUploadCallback) (RestProxyCall *call, + gsize total, + gsize uploaded, + const GError *error, + GObject *weak_object, + gpointer userdata); + +gboolean rest_proxy_call_upload (RestProxyCall *call, + RestProxyCallUploadCallback cb, + GObject *weak_object, + gpointer userdata, + GError **error); + gboolean rest_proxy_call_cancel (RestProxyCall *call); gboolean rest_proxy_call_sync (RestProxyCall *call, GError **error_out); -- cgit v1.2.3