summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEitan Isaacson <eitan@monotonous.org>2011-03-31 13:20:46 -0700
committerEitan Isaacson <eitan@monotonous.org>2011-04-13 09:56:49 -0700
commit9beaa488c4b5d0f763517db0ce1de5b64dfe78db (patch)
tree968aff2fa379bd93beb89f4f9df307757d0af226
parentd7393d28345d98e39ec5497926a334f5a9b187ac (diff)
downloadlibrest-9beaa488c4b5d0f763517db0ce1de5b64dfe78db.tar.gz
Introduce rest_proxy_call_upload to provide progress feedback.
-rw-r--r--rest/rest-proxy-call-private.h1
-rw-r--r--rest/rest-proxy-call.c129
-rw-r--r--rest/rest-proxy-call.h13
3 files changed, 143 insertions, 0 deletions
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);