[librest: 1/4] Introduce rest_proxy_call_upload to provide progress feedback.



commit 9beaa488c4b5d0f763517db0ce1de5b64dfe78db
Author: Eitan Isaacson <eitan monotonous org>
Date:   Thu Mar 31 13:20:46 2011 -0700

    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(+), 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);



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