[libgdata] picasaweb: Switch to a stream-based upload API



commit bee6e510abd2cb63341028d30c59f0f2f374b2dd
Author: Philip Withnall <philip tecnocode co uk>
Date:   Fri Dec 10 15:05:46 2010 +0000

    picasaweb: Switch to a stream-based upload API
    
    For similar reasons as the Documents service's switch to a stream-based
    upload and download API, it makes sense to switch the PicasaWeb service to a
    stream-based upload API. This gives us more flexibility as to the source of
    uploaded data.
    
    The test suite has been updated appropriately.
    
    The following API has been changed:
     â?¢ gdata_picasaweb_service_upload_file()
    
    The following API has been removed:
     â?¢ gdata_picasaweb_service_upload_file_async()
     â?¢ gdata_picasaweb_service_upload_file_finish()
    
    The following API has been added:
     â?¢ gdata_picasaweb_service_finish_file_upload()

 docs/reference/gdata-sections.txt                  |    3 +-
 gdata/gdata.symbols                                |    5 +-
 gdata/services/picasaweb/gdata-picasaweb-service.c |  308 +++++---------------
 gdata/services/picasaweb/gdata-picasaweb-service.h |   12 +-
 gdata/tests/picasaweb.c                            |  143 ++++++++--
 5 files changed, 203 insertions(+), 268 deletions(-)
---
diff --git a/docs/reference/gdata-sections.txt b/docs/reference/gdata-sections.txt
index c80da98..071218a 100644
--- a/docs/reference/gdata-sections.txt
+++ b/docs/reference/gdata-sections.txt
@@ -1335,8 +1335,7 @@ gdata_picasaweb_service_query_all_albums_async
 gdata_picasaweb_service_query_files
 gdata_picasaweb_service_query_files_async
 gdata_picasaweb_service_upload_file
-gdata_picasaweb_service_upload_file_async
-gdata_picasaweb_service_upload_file_finish
+gdata_picasaweb_service_finish_file_upload
 gdata_picasaweb_service_insert_album
 gdata_picasaweb_service_insert_album_async
 <SUBSECTION Standard>
diff --git a/gdata/gdata.symbols b/gdata/gdata.symbols
index a4409ec..7d65b16 100644
--- a/gdata/gdata.symbols
+++ b/gdata/gdata.symbols
@@ -587,9 +587,6 @@ gdata_picasaweb_service_get_user
 gdata_picasaweb_service_query_all_albums
 gdata_picasaweb_service_query_all_albums_async
 gdata_picasaweb_service_query_files
-gdata_picasaweb_service_upload_file
-gdata_picasaweb_service_upload_file_async
-gdata_picasaweb_service_upload_file_finish
 gdata_picasaweb_service_insert_album
 gdata_picasaweb_feed_get_type
 gdata_picasaweb_user_get_type
@@ -856,3 +853,5 @@ gdata_documents_service_add_entry_to_folder_async
 gdata_documents_service_add_entry_to_folder_finish
 gdata_documents_service_remove_entry_from_folder_async
 gdata_documents_service_remove_entry_from_folder_finish
+gdata_picasaweb_service_upload_file
+gdata_picasaweb_service_finish_file_upload
diff --git a/gdata/services/picasaweb/gdata-picasaweb-service.c b/gdata/services/picasaweb/gdata-picasaweb-service.c
index 7b911dd..d656150 100644
--- a/gdata/services/picasaweb/gdata-picasaweb-service.c
+++ b/gdata/services/picasaweb/gdata-picasaweb-service.c
@@ -59,22 +59,46 @@
  * 	<title>Uploading a Photo or Video</title>
  * 	<programlisting>
  *	GDataPicasaWebFile *file_entry, *uploaded_file_entry;
+ *	GDataUploadStream *upload_stream;
  *	GFile *file_data;
+ *	GFileInfo *file_info;
+ *	GFileInputStream *file_stream;
  *
  *	/<!-- -->* Specify the GFile image on disk to upload *<!-- -->/
  *	file_data = g_file_new_for_path (path);
  *
+ *	/<!-- -->* Get the file information for the file being uploaded. If another data source was being used for the upload, it would have to
+ *	 * provide an appropriate slug and content type. Note that this is a blocking operation. *<!-- -->/
+ *	file_info = g_file_query_info (file_data, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME "," G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+ *	                               G_FILE_QUERY_INFO_NONE, NULL, NULL);
+ *
  *	/<!-- -->* Create a GDataPicasaWebFile entry for the image, setting a title and caption/summary *<!-- -->/
  *	file_entry = gdata_picasaweb_file_new (NULL);
  *	gdata_entry_set_title (GDATA_ENTRY (file_entry), "Black Cat");
  *	gdata_entry_set_summary (GDATA_ENTRY (file_entry), "Photo of the world's most beautiful cat.");
  *
+ *	/<!-- -->* Create an upload stream for the file. This is non-blocking. *<!-- -->/
+ *	upload_stream = gdata_picasaweb_service_upload_file (service, album, file_entry, g_file_info_get_display_name (file_info),
+ *	                                                     g_file_info_get_content_type (file_info), NULL);
+ *	g_object_unref (file_info);
+ *	g_object_unref (file_entry);
+ *
+ *	/<!-- -->* Prepare a file stream for the file to be uploaded. This is a blocking operation. *<!-- -->/
+ *	file_stream = g_file_read (file_data, NULL, NULL);
+ *	g_object_unref (file_data);
+ *
  *	/<!-- -->* Upload the file to the server. Note that this is a blocking operation. *<!-- -->/
- *	uploaded_file_entry = gdata_picasaweb_service_upload_file (service, album, file_entry, file_data, NULL, NULL);
+ *	g_output_stream_splice (G_OUTPUT_STREAM (upload_stream), G_INPUT_STREAM (file_stream),
+ *	                        G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, NULL, NULL);
+ *
+ *	/<!-- -->* Parse the resulting updated entry. This is a non-blocking operation. *<!-- -->/
+ *	uploaded_file_entry = gdata_picasaweb_service_finish_file_upload (service, upload_stream, NULL);
+ *	g_object_unref (file_stream);
+ *	g_object_unref (upload_stream);
+ *
+ *	/<!-- -->* ... *<!-- -->/
  *
- *	g_object_unref (file_entry);
  *	g_object_unref (uploaded_file_entry);
- *	g_object_unref (file_data);
  * 	</programlisting>
  * </example>
  *
@@ -415,87 +439,45 @@ gdata_picasaweb_service_query_files_async (GDataPicasaWebService *self, GDataPic
 	                           progress_user_data, callback, user_data);
 }
 
-static GOutputStream *
-get_file_output_stream (GDataPicasaWebService *self, GDataPicasaWebAlbum *album, GDataPicasaWebFile *file_entry, GFile *file_data, GError **error)
-{
-	GFileInfo *file_info = NULL;
-	const gchar *slug = NULL, *content_type = NULL, *user_id = NULL, *album_id = NULL;
-	GOutputStream *output_stream;
-	gchar *upload_uri;
-
-	/* PicasaWeb allows you to post to a default Dropbox */
-	album_id = (album != NULL) ? gdata_entry_get_id (GDATA_ENTRY (album)) : "default";
-	user_id = gdata_service_get_username (GDATA_SERVICE (self));
-
-	file_info = g_file_query_info (file_data, "standard::display-name,standard::content-type", G_FILE_QUERY_INFO_NONE, NULL, error);
-	if (file_info == NULL)
-		return NULL;
-
-	slug = g_file_info_get_display_name (file_info);
-	content_type = g_file_info_get_content_type (file_info);
-
-	/* 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);
-	output_stream = gdata_upload_stream_new (GDATA_SERVICE (self), SOUP_METHOD_POST, upload_uri, GDATA_ENTRY (file_entry), slug, content_type);
-	g_free (upload_uri);
-	g_object_unref (file_info);
-
-	return output_stream;
-}
-
-static GDataPicasaWebFile *
-parse_spliced_stream (GOutputStream *output_stream, GError **error)
-{
-	const gchar *response_body;
-	gssize response_length;
-	GDataPicasaWebFile *new_entry;
-
-	/* Get the response from the server */
-	response_body = gdata_upload_stream_get_response (GDATA_UPLOAD_STREAM (output_stream), &response_length);
-	g_assert (response_body != NULL && response_length > 0);
-
-	/* Parse the response to produce a GDataPicasaWebFile */
-	new_entry = GDATA_PICASAWEB_FILE (gdata_parsable_new_from_xml (GDATA_TYPE_PICASAWEB_FILE, response_body, (gint) response_length, error));
-
-	return new_entry;
-}
-
 /**
  * gdata_picasaweb_service_upload_file:
  * @self: a #GDataPicasaWebService
  * @album: (allow-none): a #GDataPicasaWebAlbum into which to insert the file, or %NULL
  * @file_entry: a #GDataPicasaWebFile to insert
- * @file_data: the actual file to upload
- * @cancellable: optional #GCancellable object, or %NULL
+ * @slug: the filename to give to the uploaded file
+ * @content_type: the content type of the uploaded data
  * @error: a #GError, or %NULL
  *
- * Uploads a file (photo or video) to the given PicasaWeb @album, using the @actual_file from disk and the metadata from @file. If @album is
- * %NULL, the file will be uploaded to the currently-authenticated user's "Drop Box" album. A user must be authenticated to use this function.
+ * Uploads a file (photo or video) to the given PicasaWeb @album, using the metadata from @file and the file data written to the resulting
+ * #GDataUploadStream. If @album is %NULL, the file will be uploaded to the currently-authenticated user's "Drop Box" album. A user must be
+ * authenticated to use this function.
  *
  * If @file has already been inserted, a %GDATA_SERVICE_ERROR_ENTRY_ALREADY_INSERTED error will be returned. If no user is authenticated
  * with the service, %GDATA_SERVICE_ERROR_AUTHENTICATION_REQUIRED will be returned.
  *
- * If there is a problem reading @file_data, an error from g_output_stream_splice() or g_file_query_info() will be returned. Other errors from
- * #GDataServiceError can be returned for other exceptional conditions, as determined by the server.
+ * The stream returned by this function should be written to using the standard #GOutputStream methods, asychronously or synchronously. Once the stream
+ * is closed (using g_output_stream_close()), gdata_picasaweb_service_finish_file_upload() should be called on it to parse and return the updated
+ * #GDataPicasaWebFile for the uploaded file. This must be done, as @file_entry isn't updated in-place.
  *
- * Return value: (transfer full): the inserted #GDataPicasaWebFile with updated properties from @file_entry; unref with g_object_unref()
+ * Any upload errors will be thrown by the stream methods, and may come from the #GDataServiceError domain.
  *
- * Since: 0.4.0
+ * Return value: (transfer full): a #GDataUploadStream to write the file data to, or %NULL; unref with g_object_unref()
+ *
+ * Since: 0.8.0
  **/
-GDataPicasaWebFile *
-gdata_picasaweb_service_upload_file (GDataPicasaWebService *self, GDataPicasaWebAlbum *album, GDataPicasaWebFile *file_entry, GFile *file_data,
-                                     GCancellable *cancellable, GError **error)
+GDataUploadStream *
+gdata_picasaweb_service_upload_file (GDataPicasaWebService *self, GDataPicasaWebAlbum *album, GDataPicasaWebFile *file_entry, const gchar *slug,
+                                     const gchar *content_type, GError **error)
 {
-	GOutputStream *output_stream;
-	GInputStream *input_stream;
-	GDataPicasaWebFile *new_entry;
-	GError *child_error = NULL;
+	const gchar *user_id = NULL, *album_id = NULL;
+	GDataUploadStream *upload_stream;
+	gchar *upload_uri;
 
 	g_return_val_if_fail (GDATA_IS_PICASAWEB_SERVICE (self), NULL);
 	g_return_val_if_fail (album == NULL || GDATA_IS_PICASAWEB_ALBUM (album), NULL);
 	g_return_val_if_fail (GDATA_IS_PICASAWEB_FILE (file_entry), NULL);
-	g_return_val_if_fail (G_IS_FILE (file_data), NULL);
-	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
+	g_return_val_if_fail (slug != NULL && *slug != '\0', NULL);
+	g_return_val_if_fail (content_type != NULL && *content_type != '\0', NULL);
 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
 	if (gdata_entry_is_inserted (GDATA_ENTRY (file_entry)) == TRUE) {
@@ -510,194 +492,52 @@ gdata_picasaweb_service_upload_file (GDataPicasaWebService *self, GDataPicasaWeb
 		return NULL;
 	}
 
-	output_stream = get_file_output_stream (self, album, file_entry, file_data, error);
-	if (output_stream == NULL)
-		return NULL;
-
-	/* Pipe the input file to the upload stream */
-	input_stream = G_INPUT_STREAM (g_file_read (file_data, cancellable, error));
-	if (input_stream == NULL) {
-		g_object_unref (output_stream);
-		return NULL;
-	}
-
-	g_output_stream_splice (output_stream, input_stream, G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
-	                        cancellable, &child_error);
-
-	g_object_unref (input_stream);
-	if (child_error != NULL) {
-		g_object_unref (output_stream);
-		g_propagate_error (error, child_error);
-		return NULL;
-	}
+	/* PicasaWeb allows you to post to a default Dropbox */
+	album_id = (album != NULL) ? gdata_entry_get_id (GDATA_ENTRY (album)) : "default";
+	user_id = gdata_service_get_username (GDATA_SERVICE (self));
 
-	new_entry = parse_spliced_stream (output_stream, error);
-	g_object_unref (output_stream);
+	/* 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));
+	g_free (upload_uri);
 
-	return new_entry;
+	return upload_stream;
 }
 
 /**
- * gdata_picasaweb_service_upload_file_finish:
+ * gdata_picasaweb_service_finish_file_upload:
  * @self: a #GDataPicasaWebService
- * @result: a #GSimpleAsyncResult
+ * @upload_stream: the #GDataUploadStream from the operation
  * @error: a #GError, or %NULL
  *
- * This should be called to obtain the result of a call to
- * gdata_picasaweb_service_upload_file_async() and to check for
- * errors.
+ * Finish off a file upload operation started by gdata_picasaweb_service_upload_file(), parsing the result and returning the new #GDataPicasaWebFile.
  *
- * If there is a problem reading the subect file's data, an error
- * from g_output_stream_splice() or g_file_query_info() will be
- * returned. Other errors from #GDataServiceError can be returned for
- * other exceptional conditions, as determined by the server.
+ * If an error occurred during the upload operation, it will have been returned during the operation (e.g. by g_output_stream_splice() or one
+ * of the other stream methods). In such a case, %NULL will be returned but @error will remain unset. @error is only set in the case that the server
+ * indicates that the operation was successful, but an error is encountered in parsing the result sent by the server.
  *
- * If the file to upload has already been inserted, a
- * %GDATA_SERVICE_ERROR_ENTRY_ALREADY_INSERTED error will be set. If
- * no user is authenticated with the service when trying to upload it,
- * %GDATA_SERVICE_ERROR_AUTHENTICATION_REQUIRED will be set.
+ * Return value: (transfer full): the new #GDataPicasaWebFile, or %NULL; unref with g_object_unref()
  *
- * Return value: (transfer full): the inserted #GDataPicasaWebFile; unref with
- * g_object_unref()
- *
- * Since: 0.6.0
+ * Since: 0.8.0
  */
 GDataPicasaWebFile *
-gdata_picasaweb_service_upload_file_finish (GDataPicasaWebService *self, GAsyncResult *result, GError **error)
+gdata_picasaweb_service_finish_file_upload (GDataPicasaWebService *self, GDataUploadStream *upload_stream, GError **error)
 {
+	const gchar *response_body;
+	gssize response_length;
+
 	g_return_val_if_fail (GDATA_IS_PICASAWEB_SERVICE (self), NULL);
-	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+	g_return_val_if_fail (GDATA_IS_UPLOAD_STREAM (upload_stream), NULL);
 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
-	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+	/* Get the response from the server */
+	response_body = gdata_upload_stream_get_response (upload_stream, &response_length);
+	if (response_body == NULL || response_length == 0)
 		return NULL;
 
-	g_assert (gdata_picasaweb_service_upload_file_async == g_simple_async_result_get_source_tag (G_SIMPLE_ASYNC_RESULT (result)));
-
-	return GDATA_PICASAWEB_FILE (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result)));
-}
-
-typedef struct {
-	GDataPicasaWebService *service;
-	GAsyncReadyCallback callback;
-	gpointer user_data;
-} UploadFileAsyncData;
-
-static void
-upload_file_async_data_free (UploadFileAsyncData *data)
-{
-	g_object_unref (data->service);
-	g_slice_free (UploadFileAsyncData, data);
-}
-
-static void
-upload_file_async_cb (GOutputStream *output_stream, GAsyncResult *result, UploadFileAsyncData *data)
-{
-	GError *error = NULL;
-	GDataPicasaWebFile *file = NULL;
-	GSimpleAsyncResult *async_result;
-
-	g_output_stream_splice_finish (output_stream, result, &error);
-
-	/* If we're error free, parse the file from the stream */
-	if (error == NULL)
-		file = parse_spliced_stream (output_stream, &error);
-
-	if (error == NULL && file != NULL) {
-		async_result = g_simple_async_result_new (G_OBJECT (data->service), (GAsyncReadyCallback) data->callback,
-		                                          data->user_data, gdata_picasaweb_service_upload_file_async);
-	} else {
-		async_result = g_simple_async_result_new_from_error (G_OBJECT (data->service), (GAsyncReadyCallback) data->callback,
-		                                                     data->user_data, error);
-	}
-
-	g_simple_async_result_set_op_res_gpointer (async_result, file, NULL);
-
-	g_simple_async_result_complete (async_result);
-
-	upload_file_async_data_free (data);
-	g_object_unref (async_result);
-}
-
-/**
- * gdata_picasaweb_service_upload_file_async:
- * @self: a #GDataPicasaWebService
- * @album: (allow-none): a #GDataPicasaWebAlbum into which to insert the file, or %NULL
- * @file_entry: a #GDataPicasaWebFile to insert
- * @file_data: the actual file to upload
- * @cancellable: optional #GCancellable object, or %NULL
- * @callback: a #GAsyncReadyCallback to call when authentication is finished
- * @user_data: (closure): data to pass to the @callback function
- *
- * Uploads a file (photo or video) to the given PicasaWeb @album
- * asynchronously, using the @actual_file from disk and the metadata
- * from @file. If @album is %NULL, the file will be uploaded to the
- * currently-authenticated user's "Drop Box" album. A user must be
- * authenticated to use this function.
- *
- * @callback should call gdata_picasaweb_service_upload_file_finish()
- * to obtain a #GDataPicasaWebFile representing the uploaded file and
- * check for possible errors.
- *
- * Since: 0.6.0
- **/
-void
-gdata_picasaweb_service_upload_file_async (GDataPicasaWebService *self, GDataPicasaWebAlbum *album, GDataPicasaWebFile *file_entry,
-                                           GFile *file_data, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
-{
-	GOutputStream *output_stream;
-	GInputStream *input_stream;
-	UploadFileAsyncData *data;
-	GSimpleAsyncResult *result;
-	GError *error = NULL;
-
-	g_return_if_fail (GDATA_IS_PICASAWEB_SERVICE (self));
-	g_return_if_fail (album == NULL || GDATA_IS_PICASAWEB_ALBUM (album));
-	g_return_if_fail (GDATA_IS_PICASAWEB_FILE (file_entry));
-	g_return_if_fail (G_IS_FILE (file_data));
-	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
-
-	if (gdata_entry_is_inserted (GDATA_ENTRY (file_entry)) == TRUE) {
-		g_set_error_literal (&error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_ENTRY_ALREADY_INSERTED,
-		                     _("The entry has already been inserted."));
-		goto error;
-	}
-
-	if (gdata_service_is_authenticated (GDATA_SERVICE (self)) == FALSE) {
-		g_set_error_literal (&error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_AUTHENTICATION_REQUIRED,
-		                     _("You must be authenticated to upload a file."));
-		goto error;
-	}
-
-	/* Prepare and retrieve a #GDataOutputStream for the file and its data */
-	output_stream = get_file_output_stream (self, album, file_entry, file_data, &error);
-	if (output_stream == NULL)
-		goto error;
-
-	/* Pipe the input file to the upload stream */
-	input_stream = G_INPUT_STREAM (g_file_read (file_data, cancellable, &error));
-	if (input_stream == NULL) {
-		g_object_unref (output_stream);
-		goto error;
-	}
-
-	data = g_slice_new (UploadFileAsyncData);
-	data->service = g_object_ref (self);
-	data->callback = callback;
-	data->user_data = user_data;
-
-	/* Actually transfer the data */
-	g_output_stream_splice_async (output_stream, input_stream, G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
-	                              0, cancellable, (GAsyncReadyCallback) upload_file_async_cb, data);
-
-	g_object_unref (input_stream);
-	g_object_unref (output_stream);
-
-	return;
-
-error:
-	result = g_simple_async_result_new_from_error (G_OBJECT (self), callback, user_data, error);
-	g_simple_async_result_complete (result);
+	/* Parse the response to produce a GDataPicasaWebFile */
+	return GDATA_PICASAWEB_FILE (gdata_parsable_new_from_xml (GDATA_TYPE_PICASAWEB_FILE, response_body, (gint) response_length, error));
 }
 
 /**
diff --git a/gdata/services/picasaweb/gdata-picasaweb-service.h b/gdata/services/picasaweb/gdata-picasaweb-service.h
index cbbd6be..7b3012b 100644
--- a/gdata/services/picasaweb/gdata-picasaweb-service.h
+++ b/gdata/services/picasaweb/gdata-picasaweb-service.h
@@ -25,6 +25,7 @@
 #include <glib-object.h>
 
 #include <gdata/gdata-service.h>
+#include <gdata/gdata-upload-stream.h>
 #include <gdata/services/picasaweb/gdata-picasaweb-album.h>
 #include <gdata/services/picasaweb/gdata-picasaweb-user.h>
 
@@ -85,13 +86,10 @@ void gdata_picasaweb_service_query_files_async (GDataPicasaWebService *self, GDa
 
 #include <gdata/services/picasaweb/gdata-picasaweb-file.h>
 
-GDataPicasaWebFile *gdata_picasaweb_service_upload_file (GDataPicasaWebService *self, GDataPicasaWebAlbum *album, GDataPicasaWebFile *file_entry,
-                                                         GFile *file_data,
-                                                         GCancellable *cancellable, GError **error) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
-
-void gdata_picasaweb_service_upload_file_async (GDataPicasaWebService *self, GDataPicasaWebAlbum *album, GDataPicasaWebFile *file_entry,
-                                                GFile *file_data, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
-GDataPicasaWebFile *gdata_picasaweb_service_upload_file_finish (GDataPicasaWebService *self, GAsyncResult *result,
+GDataUploadStream *gdata_picasaweb_service_upload_file (GDataPicasaWebService *self, GDataPicasaWebAlbum *album, GDataPicasaWebFile *file_entry,
+                                                        const gchar *slug, const gchar *content_type,
+                                                        GError **error) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
+GDataPicasaWebFile *gdata_picasaweb_service_finish_file_upload (GDataPicasaWebService *self, GDataUploadStream *upload_stream,
                                                                 GError **error) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
 
 GDataPicasaWebAlbum *gdata_picasaweb_service_insert_album (GDataPicasaWebService *self, GDataPicasaWebAlbum *album, GCancellable *cancellable,
diff --git a/gdata/tests/picasaweb.c b/gdata/tests/picasaweb.c
index abc5e45..061f21b 100644
--- a/gdata/tests/picasaweb.c
+++ b/gdata/tests/picasaweb.c
@@ -1148,15 +1148,23 @@ test_query_all_albums_async (gconstpointer service)
 }
 
 typedef struct {
+	GDataPicasaWebService *service;
 	GDataPicasaWebFile *photo;
 	GDataPicasaWebFile *updated_photo;
 	GFile *photo_file;
+	gchar *slug;
+	gchar *content_type;
+	GFileInputStream *file_stream;
 } UploadData;
 
 static void
 setup_upload (UploadData *data, gconstpointer service)
 {
+	GFileInfo *file_info;
 	const gchar * const tags[] = { "foo", "bar", ",,baz,baz", NULL };
+	GError *error = NULL;
+
+	data->service = g_object_ref ((gpointer) service);
 
 	/* Build the photo */
 	data->photo = gdata_picasaweb_file_new (NULL);
@@ -1167,6 +1175,22 @@ setup_upload (UploadData *data, gconstpointer service)
 
 	/* File is public domain: http://en.wikipedia.org/wiki/File:German_garden_gnome_cropped.jpg */
 	data->photo_file = g_file_new_for_path (TEST_FILE_DIR "photo.jpg");
+
+	/* Get the file's info */
+	file_info = g_file_query_info (data->photo_file, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME "," G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+	                               G_FILE_QUERY_INFO_NONE, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (G_IS_FILE_INFO (file_info));
+
+	data->slug = g_strdup (g_file_info_get_display_name (file_info));
+	data->content_type = g_strdup (g_file_info_get_content_type (file_info));
+
+	g_object_unref (file_info);
+
+	/* Get an input stream for the file */
+	data->file_stream = g_file_read (data->photo_file, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (G_IS_FILE_INPUT_STREAM (data->file_stream));
 }
 
 static void
@@ -1180,23 +1204,43 @@ teardown_upload (UploadData *data, gconstpointer service)
 
 	g_object_unref (data->photo);
 	g_object_unref (data->photo_file);
+	g_free (data->slug);
+	g_free (data->content_type);
+	g_object_unref (data->file_stream);
+	g_object_unref (data->service);
 }
 
 static void
 test_upload_default_album (UploadData *data, gconstpointer service)
 {
+	GDataUploadStream *upload_stream;
 	const gchar * const *tags, * const *tags2;
+	gssize transfer_size;
 	GError *error = NULL;
 
-	/* Upload the photo */
+	/* Prepare the upload stream */
 	/* TODO right now, it will just go to the default album, we want an uploading one :| */
-	data->updated_photo = gdata_picasaweb_service_upload_file (GDATA_PICASAWEB_SERVICE (service), NULL, data->photo, data->photo_file, NULL,
-	                                                           &error);
+	upload_stream = gdata_picasaweb_service_upload_file (GDATA_PICASAWEB_SERVICE (service), NULL, data->photo, data->slug, data->content_type,
+	                                                     &error);
+	g_assert_no_error (error);
+	g_assert (GDATA_IS_UPLOAD_STREAM (upload_stream));
+
+	/* Upload the photo */
+	transfer_size = g_output_stream_splice (G_OUTPUT_STREAM (upload_stream), G_INPUT_STREAM (data->file_stream),
+	                                        G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, NULL, &error);
+	g_assert_no_error (error);
+	g_assert_cmpint (transfer_size, >, 0);
+
+	/* Finish off the upload */
+	data->updated_photo = gdata_picasaweb_service_finish_file_upload (GDATA_PICASAWEB_SERVICE (service), upload_stream, &error);
 	g_assert_no_error (error);
 	g_assert (GDATA_IS_PICASAWEB_FILE (data->updated_photo));
-	g_clear_error (&error);
 
-	/* TODO: check entries and feed properties */
+	/* Check the photo's properties */
+	g_assert (gdata_entry_is_inserted (GDATA_ENTRY (data->updated_photo)));
+	g_assert_cmpstr (gdata_entry_get_title (GDATA_ENTRY (data->updated_photo)), ==, gdata_entry_get_title (GDATA_ENTRY (data->photo)));
+	g_assert_cmpstr (gdata_picasaweb_file_get_caption (data->updated_photo), ==, gdata_picasaweb_file_get_caption (data->photo));
+
 	tags = gdata_picasaweb_file_get_tags (data->photo);
 	tags2 = gdata_picasaweb_file_get_tags (data->updated_photo);
 	g_assert_cmpuint (g_strv_length ((gchar**) tags2), ==, g_strv_length ((gchar**) tags));
@@ -1225,17 +1269,33 @@ teardown_upload_async (UploadAsyncData *data, gconstpointer service)
 }
 
 static void
-test_upload_default_album_async_cb (GDataPicasaWebService *service, GAsyncResult *result, UploadAsyncData *data)
+test_upload_default_album_async_cb (GOutputStream *stream, GAsyncResult *result, UploadAsyncData *data)
 {
+	const gchar * const *tags, * const *tags2;
+	gssize transfer_size;
 	GError *error = NULL;
 
-	data->data.updated_photo = gdata_picasaweb_service_upload_file_finish (service, result, &error);
+	/* Finish off the transfer */
+	transfer_size = g_output_stream_splice_finish (stream, result, &error);
+	g_assert_no_error (error);
+	g_assert_cmpint (transfer_size, >, 0);
+
+	/* Finish off the upload */
+	data->data.updated_photo = gdata_picasaweb_service_finish_file_upload (data->data.service, GDATA_UPLOAD_STREAM (stream), &error);
 	g_assert_no_error (error);
 	g_assert (GDATA_IS_PICASAWEB_FILE (data->data.updated_photo));
-	g_clear_error (&error);
-	g_assert (gdata_entry_is_inserted (GDATA_ENTRY (data->data.updated_photo)));
 
+	/* Check the photo's properties */
+	g_assert (gdata_entry_is_inserted (GDATA_ENTRY (data->data.updated_photo)));
 	g_assert_cmpstr (gdata_entry_get_title (GDATA_ENTRY (data->data.updated_photo)), ==, gdata_entry_get_title (GDATA_ENTRY (data->data.photo)));
+	g_assert_cmpstr (gdata_picasaweb_file_get_caption (data->data.updated_photo), ==, gdata_picasaweb_file_get_caption (data->data.photo));
+
+	tags = gdata_picasaweb_file_get_tags (data->data.photo);
+	tags2 = gdata_picasaweb_file_get_tags (data->data.updated_photo);
+	g_assert_cmpuint (g_strv_length ((gchar**) tags2), ==, g_strv_length ((gchar**) tags));
+	g_assert_cmpstr (tags2[0], ==, tags[0]);
+	g_assert_cmpstr (tags2[1], ==, tags[1]);
+	g_assert_cmpstr (tags2[2], ==, tags[2]);
 
 	g_main_loop_quit (data->main_loop);
 }
@@ -1243,22 +1303,41 @@ test_upload_default_album_async_cb (GDataPicasaWebService *service, GAsyncResult
 static void
 test_upload_default_album_async (UploadAsyncData *data, gconstpointer service)
 {
-	/* Upload the photo */
-	gdata_picasaweb_service_upload_file_async (GDATA_PICASAWEB_SERVICE (service), NULL, data->data.photo, data->data.photo_file, NULL,
-	                                           (GAsyncReadyCallback) test_upload_default_album_async_cb, data);
+	GDataUploadStream *upload_stream;
+	GError *error = NULL;
+
+	/* Prepare the upload stream */
+	upload_stream = gdata_picasaweb_service_upload_file (GDATA_PICASAWEB_SERVICE (service), NULL, data->data.photo, data->data.slug,
+	                                                     data->data.content_type, &error);
+	g_assert_no_error (error);
+	g_assert (GDATA_IS_UPLOAD_STREAM (upload_stream));
+
+	/* Upload the photo asynchronously */
+	g_output_stream_splice_async (G_OUTPUT_STREAM (upload_stream), G_INPUT_STREAM (data->data.file_stream),
+	                              G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, G_PRIORITY_DEFAULT, NULL,
+	                              (GAsyncReadyCallback) test_upload_default_album_async_cb, data);
 	g_main_loop_run (data->main_loop);
+
+	g_object_unref (upload_stream);
 }
 
 static void
-test_upload_default_album_cancellation_cb (GDataPicasaWebService *service, GAsyncResult *async_result, UploadAsyncData *data)
+test_upload_default_album_cancellation_cb (GOutputStream *stream, GAsyncResult *result, UploadAsyncData *data)
 {
+	gssize transfer_size;
 	GError *error = NULL;
 
-	data->data.updated_photo = gdata_picasaweb_service_upload_file_finish (service, async_result, &error);
+	/* Finish off the transfer */
+	transfer_size = g_output_stream_splice_finish (stream, result, &error);
 	g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
-	g_assert (data->data.updated_photo == NULL);
+	g_assert_cmpint (transfer_size, ==, -1);
 	g_clear_error (&error);
 
+	/* Finish off the upload */
+	data->data.updated_photo = gdata_picasaweb_service_finish_file_upload (data->data.service, GDATA_UPLOAD_STREAM (stream), &error);
+	g_assert_no_error (error);
+	g_assert (data->data.updated_photo == NULL);
+
 	g_main_loop_quit (data->main_loop);
 }
 
@@ -1272,34 +1351,54 @@ test_upload_default_album_cancellation_cancel_cb (GCancellable *cancellable)
 static void
 test_upload_default_album_cancellation (UploadAsyncData *data, gconstpointer service)
 {
+	GDataUploadStream *upload_stream;
 	GCancellable *cancellable;
+	GError *error = NULL;
 
 	/* Create an idle function which will cancel the upload */
 	cancellable = g_cancellable_new ();
 	g_idle_add ((GSourceFunc) test_upload_default_album_cancellation_cancel_cb, cancellable);
 
-	/* Upload the photo */
-	gdata_picasaweb_service_upload_file_async (GDATA_PICASAWEB_SERVICE (service), NULL, data->data.photo, data->data.photo_file, cancellable,
-	                                           (GAsyncReadyCallback) test_upload_default_album_cancellation_cb, data);
+	/* Prepare the upload stream */
+	upload_stream = gdata_picasaweb_service_upload_file (GDATA_PICASAWEB_SERVICE (service), NULL, data->data.photo, data->data.slug,
+	                                                     data->data.content_type, &error);
+	g_assert_no_error (error);
+	g_assert (GDATA_IS_UPLOAD_STREAM (upload_stream));
+
+	/* Upload the photo asynchronously */
+	g_output_stream_splice_async (G_OUTPUT_STREAM (upload_stream), G_INPUT_STREAM (data->data.file_stream),
+	                              G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, G_PRIORITY_DEFAULT, cancellable,
+	                              (GAsyncReadyCallback) test_upload_default_album_cancellation_cb, data);
 	g_main_loop_run (data->main_loop);
 
+	g_object_unref (upload_stream);
 	g_object_unref (cancellable);
 }
 
 static void
 test_upload_default_album_cancellation2 (UploadAsyncData *data, gconstpointer service)
 {
+	GDataUploadStream *upload_stream;
 	GCancellable *cancellable;
+	GError *error = NULL;
 
-	/* Create an idle function which will cancel the upload */
+	/* Create a timeout function which will cancel the upload after 1ms */
 	cancellable = g_cancellable_new ();
 	g_timeout_add (1, (GSourceFunc) test_upload_default_album_cancellation_cancel_cb, cancellable);
 
-	/* Upload the photo */
-	gdata_picasaweb_service_upload_file_async (GDATA_PICASAWEB_SERVICE (service), NULL, data->data.photo, data->data.photo_file, cancellable,
-	                                           (GAsyncReadyCallback) test_upload_default_album_cancellation_cb, data);
+	/* Prepare the upload stream */
+	upload_stream = gdata_picasaweb_service_upload_file (GDATA_PICASAWEB_SERVICE (service), NULL, data->data.photo, data->data.slug,
+	                                                     data->data.content_type, &error);
+	g_assert_no_error (error);
+	g_assert (GDATA_IS_UPLOAD_STREAM (upload_stream));
+
+	/* Upload the photo asynchronously */
+	g_output_stream_splice_async (G_OUTPUT_STREAM (upload_stream), G_INPUT_STREAM (data->data.file_stream),
+	                              G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, G_PRIORITY_DEFAULT, cancellable,
+	                              (GAsyncReadyCallback) test_upload_default_album_cancellation_cb, data);
 	g_main_loop_run (data->main_loop);
 
+	g_object_unref (upload_stream);
 	g_object_unref (cancellable);
 }
 



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