[libgdata] core: Add a “cancellable” property to GDataUploadStream



commit 2338e007e768770627158f5298cc44bd6de80ed8
Author: Philip Withnall <philip tecnocode co uk>
Date:   Fri Dec 17 23:13:53 2010 +0000

    core: Add a â??cancellableâ?? property to GDataUploadStream
    
    Allow the code which creates the GDataUploadStream to specify a GCancellable
    which will cancel the entire upload operation (i.e. permanently cancel all
    I/O on the stream and all network activity).
    
    This breaks the following API:
     â?¢ gdata_upload_stream_new()
    
    The following API has been added:
     â?¢ GDataUploadStream:cancellable
     â?¢ gdata_upload_stream_get_cancellable()
    
    Helps: bgo#637036

 docs/reference/gdata-sections.txt                  |    1 +
 gdata/gdata-upload-stream.c                        |   79 ++++++++++++++++----
 gdata/gdata-upload-stream.h                        |    3 +-
 gdata/gdata.symbols                                |    1 +
 gdata/services/documents/gdata-documents-service.c |    3 +-
 gdata/services/picasaweb/gdata-picasaweb-service.c |    2 +-
 gdata/services/youtube/gdata-youtube-service.c     |    2 +-
 7 files changed, 72 insertions(+), 19 deletions(-)
---
diff --git a/docs/reference/gdata-sections.txt b/docs/reference/gdata-sections.txt
index 34d0235..43ffdc3 100644
--- a/docs/reference/gdata-sections.txt
+++ b/docs/reference/gdata-sections.txt
@@ -1776,6 +1776,7 @@ GDataUploadStreamClass
 gdata_upload_stream_new
 gdata_upload_stream_get_response
 gdata_upload_stream_get_service
+gdata_upload_stream_get_cancellable
 gdata_upload_stream_get_method
 gdata_upload_stream_get_upload_uri
 gdata_upload_stream_get_entry
diff --git a/gdata/gdata-upload-stream.c b/gdata/gdata-upload-stream.c
index f684aee..8ccc240 100644
--- a/gdata/gdata-upload-stream.c
+++ b/gdata/gdata-upload-stream.c
@@ -110,7 +110,8 @@ enum {
 	PROP_ENTRY,
 	PROP_SLUG,
 	PROP_CONTENT_TYPE,
-	PROP_METHOD
+	PROP_METHOD,
+	PROP_CANCELLABLE
 };
 
 G_DEFINE_TYPE (GDataUploadStream, gdata_upload_stream, G_TYPE_OUTPUT_STREAM)
@@ -211,6 +212,27 @@ gdata_upload_stream_class_init (GDataUploadStreamClass *klass)
 	                                                      "Content type", "The content type of the file being uploaded.",
 	                                                      NULL,
 	                                                      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+	/**
+	 * GDataUploadStream:cancellable:
+	 *
+	 * An optional cancellable used to cancel the entire upload operation. If a #GCancellable instance isn't provided for this property at
+	 * construction time (i.e. to gdata_upload_stream_new()), one will be created internally and can be retrieved using
+	 * gdata_upload_stream_get_cancellable() and used to cancel the upload operation with g_cancellable_cancel() just as if it was passed to
+	 * gdata_upload_stream_new().
+	 *
+	 * If the upload operation is cancelled using this #GCancellable, any ongoing network activity will be stopped, and any pending or future calls
+	 * to #GOutputStream API on the #GDataUploadStream will return %G_IO_ERROR_CANCELLED. Note that the #GCancellable objects which can be passed
+	 * to individual #GOutputStream operations will not cancel the upload operation proper if cancelled â?? they will merely cancel that API call.
+	 * The only way to cancel the upload operation completely is using #GDataUploadStream:cancellable.
+	 *
+	 * Since: 0.8.0
+	 **/
+	g_object_class_install_property (gobject_class, PROP_CANCELLABLE,
+	                                 g_param_spec_object ("cancellable",
+	                                                      "Cancellable", "An optional cancellable used to cancel the entire upload operation.",
+	                                                      G_TYPE_CANCELLABLE,
+	                                                      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 }
 
 static void
@@ -235,6 +257,10 @@ gdata_upload_stream_constructor (GType type, guint n_construct_params, GObjectCo
 	object = G_OBJECT_CLASS (gdata_upload_stream_parent_class)->constructor (type, n_construct_params, construct_params);
 	priv = GDATA_UPLOAD_STREAM (object)->priv;
 
+	/* Create a #GCancellable for the entire upload operation if one wasn't specified for #GDataUploadStream:cancellable during construction */
+	if (priv->cancellable == NULL)
+		priv->cancellable = g_cancellable_new ();
+
 	/* Build the message */
 	priv->message = soup_message_new (priv->method, priv->upload_uri);
 
@@ -339,6 +365,9 @@ gdata_upload_stream_get_property (GObject *object, guint property_id, GValue *va
 		case PROP_CONTENT_TYPE:
 			g_value_set_string (value, priv->content_type);
 			break;
+		case PROP_CANCELLABLE:
+			g_value_set_object (value, priv->cancellable);
+			break;
 		default:
 			/* We don't have any other property... */
 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -371,6 +400,10 @@ gdata_upload_stream_set_property (GObject *object, guint property_id, const GVal
 		case PROP_CONTENT_TYPE:
 			priv->content_type = g_value_dup_string (value);
 			break;
+		case PROP_CANCELLABLE:
+			/* Construction only */
+			priv->cancellable = g_value_dup_object (value);
+			break;
 		default:
 			/* We don't have any other property... */
 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -715,19 +748,9 @@ static void
 create_network_thread (GDataUploadStream *self, GError **error)
 {
 	GDataUploadStreamPrivate *priv = self->priv;
-	GError *child_error = NULL;
 
-	g_assert (priv->cancellable == NULL);
 	g_assert (priv->network_thread == NULL);
-
-	priv->cancellable = g_cancellable_new ();
-	priv->network_thread = g_thread_create ((GThreadFunc) upload_thread, self, TRUE, &child_error);
-
-	if (child_error != NULL) {
-		g_object_unref (priv->cancellable);
-		priv->cancellable = NULL;
-		g_propagate_error (error, child_error);
-	}
+	priv->network_thread = g_thread_create ((GThreadFunc) upload_thread, self, TRUE, error);
 }
 
 /**
@@ -738,6 +761,7 @@ create_network_thread (GDataUploadStream *self, GError **error)
  * @entry: (allow-none): the entry to upload as metadata, or %NULL
  * @slug: the file's slug (filename)
  * @content_type: the content type of the file being uploaded
+ * @cancellable: (allow-none): a #GCancellable for the entire upload stream, or %NULL
  *
  * Creates a new #GDataUploadStream, allowing a file to be uploaded from a GData service using standard #GOutputStream API.
  *
@@ -754,15 +778,21 @@ create_network_thread (GDataUploadStream *self, GError **error)
  * As well as the standard GIO errors, calls to the #GOutputStream API on a #GDataUploadStream can also return any relevant specific error from
  * #GDataServiceError, or %GDATA_SERVICE_ERROR_PROTOCOL_ERROR in the general case.
  *
+ * If a #GCancellable is provided in @cancellable, the upload operation may be cancelled at any time from another thread using g_cancellable_cancel().
+ * In this case, any ongoing network activity will be stopped, and any pending or future calls to #GOutputStream API on the #GDataUploadStream will
+ * return %G_IO_ERROR_CANCELLED. Note that the #GCancellable objects which can be passed to individual #GOutputStream operations will not cancel the
+ * upload operation proper if cancelled â?? they will merely cancel that API call. The only way to cancel the upload operation completely is using this
+ * @cancellable.
+ *
  * Note that network communication won't begin until the first call to g_output_stream_write() on the #GDataUploadStream.
  *
  * Return value: a new #GOutputStream, or %NULL; unref with g_object_unref()
  *
- * Since: 0.5.0
+ * Since: 0.8.0
  **/
 GOutputStream *
 gdata_upload_stream_new (GDataService *service, const gchar *method, const gchar *upload_uri, GDataEntry *entry,
-			 const gchar *slug, const gchar *content_type)
+                         const gchar *slug, const gchar *content_type, GCancellable *cancellable)
 {
 	g_return_val_if_fail (GDATA_IS_SERVICE (service), NULL);
 	g_return_val_if_fail (method != NULL, NULL);
@@ -770,10 +800,11 @@ gdata_upload_stream_new (GDataService *service, const gchar *method, const gchar
 	g_return_val_if_fail (entry == NULL || GDATA_IS_ENTRY (entry), NULL);
 	g_return_val_if_fail (slug != NULL, NULL);
 	g_return_val_if_fail (content_type != NULL, NULL);
+	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
 
 	/* Create the upload stream */
 	return G_OUTPUT_STREAM (g_object_new (GDATA_TYPE_UPLOAD_STREAM, "method", method, "upload-uri", upload_uri, "service", service,
-	                                      "entry", entry, "slug", slug, "content-type", content_type, NULL));
+	                                      "entry", entry, "slug", slug, "content-type", content_type, "cancellable", cancellable, NULL));
 }
 
 /**
@@ -926,3 +957,21 @@ gdata_upload_stream_get_content_type (GDataUploadStream *self)
 	g_return_val_if_fail (GDATA_IS_UPLOAD_STREAM (self), NULL);
 	return self->priv->content_type;
 }
+
+/**
+ * gdata_upload_stream_get_cancellable:
+ * @self: a #GDataUploadStream
+ *
+ * Gets the #GCancellable for the entire upload operation, #GDataUploadStream:cancellable.
+ *
+ * Return value: (transfer none): the #GCancellable for the entire upload operation
+ *
+ * Since: 0.8.0
+ **/
+GCancellable *
+gdata_upload_stream_get_cancellable (GDataUploadStream *self)
+{
+	g_return_val_if_fail (GDATA_IS_UPLOAD_STREAM (self), NULL);
+	g_assert (self->priv->cancellable != NULL);
+	return self->priv->cancellable;
+}
diff --git a/gdata/gdata-upload-stream.h b/gdata/gdata-upload-stream.h
index 9413ba5..133b6f4 100644
--- a/gdata/gdata-upload-stream.h
+++ b/gdata/gdata-upload-stream.h
@@ -65,7 +65,7 @@ typedef struct {
 GType gdata_upload_stream_get_type (void) G_GNUC_CONST;
 
 GOutputStream *gdata_upload_stream_new (GDataService *service, const gchar *method, const gchar *upload_uri, GDataEntry *entry,
-                                        const gchar *slug, const gchar *content_type) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
+                                        const gchar *slug, const gchar *content_type, GCancellable *cancellable) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
 
 const gchar *gdata_upload_stream_get_response (GDataUploadStream *self, gssize *length);
 
@@ -75,6 +75,7 @@ const gchar *gdata_upload_stream_get_upload_uri (GDataUploadStream *self) G_GNUC
 GDataEntry *gdata_upload_stream_get_entry (GDataUploadStream *self) G_GNUC_PURE;
 const gchar *gdata_upload_stream_get_slug (GDataUploadStream *self) G_GNUC_PURE;
 const gchar *gdata_upload_stream_get_content_type (GDataUploadStream *self) G_GNUC_PURE;
+GCancellable *gdata_upload_stream_get_cancellable (GDataUploadStream *self) G_GNUC_PURE;
 
 G_END_DECLS
 
diff --git a/gdata/gdata.symbols b/gdata/gdata.symbols
index 1d05b77..ec777a6 100644
--- a/gdata/gdata.symbols
+++ b/gdata/gdata.symbols
@@ -862,3 +862,4 @@ gdata_contacts_contact_set_photo_async
 gdata_contacts_contact_set_photo_finish
 gdata_youtube_video_get_coordinates
 gdata_youtube_video_set_coordinates
+gdata_upload_stream_get_cancellable
diff --git a/gdata/services/documents/gdata-documents-service.c b/gdata/services/documents/gdata-documents-service.c
index 4ec5b01..0e3c260 100644
--- a/gdata/services/documents/gdata-documents-service.c
+++ b/gdata/services/documents/gdata-documents-service.c
@@ -302,7 +302,8 @@ upload_update_document (GDataDocumentsService *self, GDataDocumentsDocument *doc
 		content_type = "application/x-vnd.oasis.opendocument.spreadsheet";
 
 	/* We need streaming file I/O: GDataUploadStream */
-	return GDATA_UPLOAD_STREAM (gdata_upload_stream_new (GDATA_SERVICE (self), method, upload_uri, GDATA_ENTRY (document), slug, content_type));
+	return GDATA_UPLOAD_STREAM (gdata_upload_stream_new (GDATA_SERVICE (self), method, upload_uri, GDATA_ENTRY (document), slug, content_type,
+	                                                     NULL));
 }
 
 /**
diff --git a/gdata/services/picasaweb/gdata-picasaweb-service.c b/gdata/services/picasaweb/gdata-picasaweb-service.c
index d656150..b19e384 100644
--- a/gdata/services/picasaweb/gdata-picasaweb-service.c
+++ b/gdata/services/picasaweb/gdata-picasaweb-service.c
@@ -499,7 +499,7 @@ gdata_picasaweb_service_upload_file (GDataPicasaWebService *self, GDataPicasaWeb
 	/* Build the upload URI and upload stream */
 	upload_uri = _gdata_service_build_uri (TRUE, "http://picasaweb.google.com/data/feed/api/user/%s/albumid/%s";, user_id, album_id);
 	upload_stream = GDATA_UPLOAD_STREAM (gdata_upload_stream_new (GDATA_SERVICE (self), SOUP_METHOD_POST, upload_uri, GDATA_ENTRY (file_entry),
-	                                                              slug, content_type));
+	                                                              slug, content_type, NULL));
 	g_free (upload_uri);
 
 	return upload_stream;
diff --git a/gdata/services/youtube/gdata-youtube-service.c b/gdata/services/youtube/gdata-youtube-service.c
index bd75b23..de5fa55 100644
--- a/gdata/services/youtube/gdata-youtube-service.c
+++ b/gdata/services/youtube/gdata-youtube-service.c
@@ -643,7 +643,7 @@ gdata_youtube_service_upload_video (GDataYouTubeService *self, GDataYouTubeVideo
 	/* Streaming upload support using GDataUploadStream; automatically handles the XML and multipart stuff for us */
 	return GDATA_UPLOAD_STREAM (gdata_upload_stream_new (GDATA_SERVICE (self), SOUP_METHOD_POST,
 	                                                     "http://uploads.gdata.youtube.com/feeds/api/users/default/uploads";,
-	                                                      GDATA_ENTRY (video), slug, content_type));
+	                                                      GDATA_ENTRY (video), slug, content_type, NULL));
 }
 
 /**



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