/soc/2015/jgeboski/facebook: 853fadf2e250: facebook: queue icon ...

James Geboski jgeboski at gmail.com
Thu Jun 25 20:48:35 EDT 2015


Changeset: 853fadf2e250e048daf9b1de370b875df11dd68e
Author:	 James Geboski <jgeboski at gmail.com>
Date:	 2015-06-25 20:48 -0400
Branch:	 facebook
URL: https://hg.pidgin.im/soc/2015/jgeboski/facebook/rev/853fadf2e250

Description:

facebook: queue icon downloads to prevent lag

diffstat:

 libpurple/protocols/facebook/data.c     |  115 ++++++++++++++++++++++++++++++++
 libpurple/protocols/facebook/data.h     |   22 ++++++
 libpurple/protocols/facebook/facebook.c |   25 +++---
 3 files changed, 149 insertions(+), 13 deletions(-)

diffs (273 lines):

diff --git a/libpurple/protocols/facebook/data.c b/libpurple/protocols/facebook/data.c
--- a/libpurple/protocols/facebook/data.c
+++ b/libpurple/protocols/facebook/data.c
@@ -30,6 +30,8 @@ struct _FbDataPrivate
 	PurpleConnection *gc;
 	PurpleRoomlist *roomlist;
 	gint chatid;
+	GHashTable *icons;
+	GHashTable *icona;
 };
 
 static const gchar *fb_props_strs[] = {
@@ -39,6 +41,9 @@ static const gchar *fb_props_strs[] = {
 	"token"
 };
 
+static void
+fb_data_icon_free(FbDataIcon *icon);
+
 G_DEFINE_TYPE(FbData, fb_data, G_TYPE_OBJECT);
 
 static void
@@ -53,6 +58,9 @@ fb_data_dispose(GObject *obj)
 	if (priv->roomlist != NULL) {
 		g_object_unref(priv->roomlist);
 	}
+
+	g_hash_table_destroy(priv->icons);
+	g_hash_table_destroy(priv->icona);
 }
 
 static void
@@ -71,6 +79,13 @@ fb_data_init(FbData *fata)
 
 	priv = G_TYPE_INSTANCE_GET_PRIVATE(fata, FB_TYPE_DATA, FbDataPrivate);
 	fata->priv = priv;
+
+	priv->icons = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+	                                    (GDestroyNotify) fb_data_icon_free,
+					    NULL);
+	priv->icona = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+	                                    (GDestroyNotify) fb_data_icon_free,
+					    NULL);
 }
 
 FbData *
@@ -243,3 +258,103 @@ fb_data_set_roomlist(FbData *fata, Purpl
 
 	priv->roomlist = list;
 }
+
+FbDataIcon *
+fb_data_icon_add(FbData *fata, PurpleBuddy *buddy, const gchar *url,
+                 PurpleHttpCallback func)
+{
+	FbDataIcon *icon;
+	FbDataPrivate *priv;
+
+	g_return_val_if_fail(FB_IS_DATA(fata), NULL);
+	g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL);
+	g_return_val_if_fail(url != NULL, NULL);
+	priv = fata->priv;
+
+	icon = g_new(FbDataIcon, 1);
+	icon->fata = fata;
+	icon->buddy = buddy;
+	icon->url = g_strdup(url);
+	icon->func = func;
+
+	g_hash_table_replace(priv->icons, icon, icon);
+	return icon;
+}
+
+static void
+fb_data_icon_free(FbDataIcon *icon)
+{
+	g_return_if_fail(icon != NULL);
+
+	g_free(icon->url);
+	g_free(icon);
+}
+
+void
+fb_data_icon_destroy(FbDataIcon *icon)
+{
+	FbDataPrivate *priv;
+
+	g_return_if_fail(icon != NULL);
+	g_return_if_fail(FB_IS_DATA(icon->fata));
+	priv = icon->fata->priv;
+
+	if (!g_hash_table_remove(priv->icons, icon) &&
+	    !g_hash_table_remove(priv->icona, icon))
+	{
+		fb_data_icon_free(icon);
+	}
+}
+
+static void
+fb_data_icon_cb(PurpleHttpConnection *con, PurpleHttpResponse *res,
+                gpointer data)
+{
+	FbDataIcon *icon = data;
+	FbData *fata = icon->fata;
+
+	if (icon->func != NULL) {
+		icon->func(con, res, icon);
+	}
+
+	fb_data_icon_destroy(icon);
+	fb_data_icon_queue(fata);
+}
+
+void
+fb_data_icon_queue(FbData *fata)
+{
+	FbDataIcon *icon;
+	FbDataPrivate *priv;
+	GHashTableIter iter;
+	guint size;
+	PurpleAccount *acct;
+	PurpleConnection *gc;
+
+	g_return_if_fail(FB_IS_DATA(fata));
+	priv = fata->priv;
+	size = g_hash_table_size(priv->icona);
+
+	if (size >= FB_DATA_ICON_MAX) {
+		return;
+	}
+
+	g_hash_table_iter_init(&iter, priv->icons);
+
+	while (g_hash_table_iter_next(&iter, (gpointer*) &icon, NULL)) {
+		acct = purple_buddy_get_account(icon->buddy);
+		gc = purple_account_get_connection(acct);
+
+		if (g_hash_table_lookup_extended(priv->icona, icon, NULL, NULL)) {
+			continue;
+		}
+
+		g_hash_table_iter_steal(&iter);
+		g_hash_table_replace(priv->icona, icon, icon);
+		purple_http_get(gc, fb_data_icon_cb, icon, icon->url);
+
+		if (++size >= FB_DATA_ICON_MAX) {
+			break;
+		}
+	}
+}
diff --git a/libpurple/protocols/facebook/data.h b/libpurple/protocols/facebook/data.h
--- a/libpurple/protocols/facebook/data.h
+++ b/libpurple/protocols/facebook/data.h
@@ -25,6 +25,8 @@
 #include "connection.h"
 #include "glibcompat.h"
 
+#define FB_DATA_ICON_MAX 4
+
 #define FB_TYPE_DATA             (fb_data_get_type())
 #define FB_DATA(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), FB_TYPE_DATA, FbData))
 #define FB_DATA(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), FB_TYPE_DATA, FbData))
@@ -36,6 +38,7 @@
 typedef struct _FbData FbData;
 typedef struct _FbDataClass FbDataClass;
 typedef struct _FbDataPrivate FbDataPrivate;
+typedef struct _FbDataIcon FbDataIcon;
 
 struct _FbData
 {
@@ -48,6 +51,15 @@ struct _FbDataClass
 	GObjectClass parent_class;
 };
 
+struct _FbDataIcon
+{
+	FbData *fata;
+	PurpleBuddy *buddy;
+	gchar *url;
+	gchar *csum;
+	PurpleHttpCallback func;
+};
+
 
 GType
 fb_data_get_type(void);
@@ -76,4 +88,14 @@ fb_data_get_roomlist(FbData *fata);
 void
 fb_data_set_roomlist(FbData *fata, PurpleRoomlist *list);
 
+FbDataIcon *
+fb_data_icon_add(FbData *fata, PurpleBuddy *buddy, const gchar *url,
+                 PurpleHttpCallback func);
+
+void
+fb_data_icon_destroy(FbDataIcon *icon);
+
+void
+fb_data_icon_queue(FbData *fata);
+
 #endif /* _FACEBOOK_DATA_H_ */
diff --git a/libpurple/protocols/facebook/facebook.c b/libpurple/protocols/facebook/facebook.c
--- a/libpurple/protocols/facebook/facebook.c
+++ b/libpurple/protocols/facebook/facebook.c
@@ -64,30 +64,26 @@ fb_cb_api_connect(FbApi *api, gpointer d
 }
 
 static void
-fb_cb_icon_fetch(PurpleHttpConnection *con, PurpleHttpResponse *res,
-                 gpointer data)
+fb_cb_data_icon(PurpleHttpConnection *con, PurpleHttpResponse *res,
+                gpointer data)
 {
 	const gchar *csum;
 	const gchar *name;
 	const gchar *str;
 	FbApi *api;
-	FbData *fata;
+	FbDataIcon *icon = data;
 	FbHttpParams *params;
 	GError *err = NULL;
 	gsize size;
 	guchar *idata;
 	PurpleAccount *acct;
-	PurpleBuddy *bdy = data;
-	PurpleConnection *gc;
 	PurpleHttpRequest *req;
 
-	acct = purple_buddy_get_account(bdy);
-	gc = purple_account_get_connection(acct);
-	fata = purple_connection_get_protocol_data(gc);
-	api = fb_data_get_api(fata);
+	acct = purple_buddy_get_account(icon->buddy);
+	api = fb_data_get_api(icon->fata);
 
 	if (!fb_http_error_chk(res, &err)) {
-		fb_cb_api_error(api, err, fata);
+		fb_cb_api_error(api, err, icon->fata);
 		g_error_free(err);
 		return;
 	}
@@ -97,7 +93,7 @@ fb_cb_icon_fetch(PurpleHttpConnection *c
 	params = fb_http_params_new_parse(str, TRUE);
 	csum = fb_http_params_get_str(params, "oh", &err);
 
-	name = purple_buddy_get_name(bdy);
+	name = purple_buddy_get_name(icon->buddy);
 	str = purple_http_response_get_data(res, &size);
 	idata = g_memdup(str, size);
 
@@ -149,17 +145,20 @@ fb_cb_api_contacts(FbApi *api, GSList *u
 		if (bdy == NULL) {
 			bdy = purple_buddy_new(acct, uid, user->name);
 			purple_blist_add_buddy(bdy, NULL, grp, NULL);
-			purple_http_get(gc, fb_cb_icon_fetch, bdy, user->icon);
+			fb_data_icon_add(fata, bdy, user->icon,
+			                 fb_cb_data_icon);
 			continue;
 		}
 
 		csum = purple_buddy_icons_get_checksum_for_user(bdy);
 
 		if (!purple_strequal(csum, user->csum)) {
-			purple_http_get(gc, fb_cb_icon_fetch, bdy, user->icon);
+			fb_data_icon_add(fata, bdy, user->icon,
+			                 fb_cb_data_icon);
 		}
 	}
 
+	fb_data_icon_queue(fata);
 	purple_connection_update_progress(gc, _("Connecting"), 3, 4);
 	fb_api_connect(api);
 }



More information about the Commits mailing list