facebook: queue icon downloads to prevent lag facebook

Thu, 25 Jun 2015 20:48:26 -0400

author
James Geboski <jgeboski@gmail.com>
date
Thu, 25 Jun 2015 20:48:26 -0400
branch
facebook
changeset 37276
853fadf2e250
parent 37275
9e295f087bf6
child 37277
eb8cefa8897d

facebook: queue icon downloads to prevent lag

libpurple/protocols/facebook/data.c file | annotate | diff | comparison | revisions
libpurple/protocols/facebook/data.h file | annotate | diff | comparison | revisions
libpurple/protocols/facebook/facebook.c file | annotate | diff | comparison | revisions
--- a/libpurple/protocols/facebook/data.c	Wed Jun 24 18:13:18 2015 -0400
+++ b/libpurple/protocols/facebook/data.c	Thu Jun 25 20:48:26 2015 -0400
@@ -30,6 +30,8 @@
 	PurpleConnection *gc;
 	PurpleRoomlist *roomlist;
 	gint chatid;
+	GHashTable *icons;
+	GHashTable *icona;
 };
 
 static const gchar *fb_props_strs[] = {
@@ -39,6 +41,9 @@
 	"token"
 };
 
+static void
+fb_data_icon_free(FbDataIcon *icon);
+
 G_DEFINE_TYPE(FbData, fb_data, G_TYPE_OBJECT);
 
 static void
@@ -53,6 +58,9 @@
 	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 @@
 
 	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 @@
 
 	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;
+		}
+	}
+}
--- a/libpurple/protocols/facebook/data.h	Wed Jun 24 18:13:18 2015 -0400
+++ b/libpurple/protocols/facebook/data.h	Thu Jun 25 20:48:26 2015 -0400
@@ -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 @@
 	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 @@
 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_ */
--- a/libpurple/protocols/facebook/facebook.c	Wed Jun 24 18:13:18 2015 -0400
+++ b/libpurple/protocols/facebook/facebook.c	Thu Jun 25 20:48:26 2015 -0400
@@ -64,30 +64,26 @@
 }
 
 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 @@
 	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 @@
 		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);
 }

mercurial