From cfa937af4cc35c689eeff4d726d650380bb718ac Mon Sep 17 00:00:00 2001 From: Chandni Verma Date: Sat, 14 Sep 2013 13:44:10 +0530 Subject: [PATCH] Make avatar image caching asynchronous Fixes https://bugs.freedesktop.org/show_bug.cgi?id=63402 Based on patch by Luca Versari --- telepathy-glib/contact.c | 148 +++++++++++++++++++++++++++++++++++------------ tests/dbus/contacts.c | 3 + 2 files changed, 114 insertions(+), 37 deletions(-) diff --git a/telepathy-glib/contact.c b/telepathy-glib/contact.c index c505bc8..3caed23 100644 --- a/telepathy-glib/contact.c +++ b/telepathy-glib/contact.c @@ -2755,6 +2755,101 @@ out: static void contact_set_avatar_token (TpContact *self, const gchar *new_token, gboolean request); +typedef struct { + TpContact *self; + TpConnection *connection; + gchar *token; + GArray *data; + gchar *mime_type; +} WriteAvatarData; + +static void +mime_file_written (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GError *error = NULL; + WriteAvatarData *avatar_data = user_data; + GFile *file = G_FILE (source_object); + + if (!g_file_replace_contents_finish (file, res, NULL, &error)) + { + DEBUG ("Failed to store MIME type in cache (%s): %s", + g_file_get_path (file), error->message); + g_clear_error (&error); + } + else + { + DEBUG ("Contact avatar MIME type stored in cache: %s", + g_file_get_path (file)); + } + + if (avatar_data->self != NULL) + { + g_free (avatar_data->self->priv->avatar_mime_type); + avatar_data->self->priv->avatar_mime_type = g_strdup + (avatar_data->mime_type); + + /* Update the avatar token if a newer one is given */ + contact_set_avatar_token (avatar_data->self, avatar_data->token, FALSE); + + /* Notify both property changes together once both files have been + written */ + g_object_notify ((GObject *) avatar_data->self, "avatar-mime-type"); + g_object_notify ((GObject *) avatar_data->self, "avatar-file"); + } + + g_free (avatar_data->mime_type); + g_free (avatar_data->token); + g_slice_free (WriteAvatarData, avatar_data); +} + +static void +avatar_file_written (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GError *error = NULL; + WriteAvatarData *avatar_data = user_data; + GFile *file = G_FILE (source_object); + gchar *mime_filename = NULL; + GFile *mime_file = NULL; + + g_array_unref (avatar_data->data); + if (!g_file_replace_contents_finish (file, res, NULL, &error)) + { + DEBUG ("Failed to store avatar in cache (%s): %s", + g_file_get_path (file), error->message); + g_clear_error (&error); + } + else + { + DEBUG ("Contact avatar stored in cache: %s", + g_file_get_path (file)); + } + + if (avatar_data->self != NULL) + { + tp_clear_object (&avatar_data->self->priv->avatar_file); + avatar_data->self->priv->avatar_file = file; + } + + /* Now write the mime-file. */ + if (!build_avatar_filename (avatar_data->connection, avatar_data->token, + TRUE, NULL, &mime_filename)) + return; + + mime_file = g_file_new_for_path (mime_filename); + + g_file_replace_contents_async (mime_file, avatar_data->mime_type, + strlen (avatar_data->mime_type), NULL, FALSE, + G_FILE_CREATE_PRIVATE|G_FILE_CREATE_REPLACE_DESTINATION, + NULL, &mime_file_written, avatar_data); + + g_free (mime_filename); + g_object_unref (mime_file); +} + static void contact_avatar_retrieved (TpConnection *connection, guint handle, @@ -2765,52 +2860,31 @@ contact_avatar_retrieved (TpConnection *connection, GObject *weak_object G_GNUC_UNUSED) { TpContact *self = _tp_connection_lookup_contact (connection, handle); - gchar *filename; - gchar *mime_filename; - GError *error = NULL; + gchar *filename = NULL; + GFile *avatar_file = NULL; + WriteAvatarData *avatar_data = g_slice_new (WriteAvatarData); - if (!build_avatar_filename (connection, token, TRUE, &filename, - &mime_filename)) + if (!build_avatar_filename (connection, token, TRUE, &filename, NULL)) return; /* Save avatar in cache, even if the contact is unknown, to avoid as much as * possible future avatar requests */ - if (!g_file_set_contents (filename, avatar->data, avatar->len, &error)) - { - DEBUG ("Failed to store avatar in cache (%s): %s", filename, - error ? error->message : "No error message"); - g_clear_error (&error); - goto out; - } - if (!g_file_set_contents (mime_filename, mime_type, -1, &error)) - { - DEBUG ("Failed to store MIME type in cache (%s): %s", mime_filename, - error ? error->message : "No error message"); - g_clear_error (&error); - goto out; - } + avatar_file = g_file_new_for_path (filename); - DEBUG ("Contact#%u avatar stored in cache: %s, %s", handle, filename, - mime_type); - - if (self == NULL) - goto out; + avatar_data->data = g_array_new (FALSE, FALSE, sizeof (gchar)); + g_array_append_vals (avatar_data->data, avatar->data, avatar->len); + avatar_data->self = self; + avatar_data->connection = connection; + avatar_data->token = g_strdup (token); + avatar_data->mime_type = g_strdup (mime_type); - /* Update the avatar token if a newer one is given */ - contact_set_avatar_token (self, token, FALSE); + g_file_replace_contents_async (avatar_file, avatar_data->data->data, + avatar_data->data->len, NULL, FALSE, + G_FILE_CREATE_PRIVATE|G_FILE_CREATE_REPLACE_DESTINATION, NULL, + &avatar_file_written, avatar_data); - tp_clear_object (&self->priv->avatar_file); - self->priv->avatar_file = g_file_new_for_path (filename); - - g_free (self->priv->avatar_mime_type); - self->priv->avatar_mime_type = g_strdup (mime_type); - - g_object_notify ((GObject *) self, "avatar-file"); - g_object_notify ((GObject *) self, "avatar-mime-type"); - -out: g_free (filename); - g_free (mime_filename); + g_object_unref (avatar_file); } static gboolean diff --git a/tests/dbus/contacts.c b/tests/dbus/contacts.c index 9c070a7..7624492 100644 --- a/tests/dbus/contacts.c +++ b/tests/dbus/contacts.c @@ -585,6 +585,9 @@ create_contact_with_fake_avatar (TpTestsContactsConnection *service_conn, g_main_loop_run (result.loop); } + while (g_main_context_pending (NULL)) + g_main_context_iteration (NULL, TRUE); + g_assert_cmpstr (tp_contact_get_avatar_mime_type (contact), ==, avatar_mime_type); -- 1.8.1.2