/soc/2015/jgeboski/facebook: 213498a7ab94: facebook: fetch conta...
James Geboski
jgeboski at gmail.com
Sat Jul 18 09:43:11 EDT 2015
Changeset: 213498a7ab9453d1a9ae1ae6e8a91770299780b5
Author: James Geboski <jgeboski at gmail.com>
Date: 2015-07-18 09:42 -0400
Branch: facebook
URL: https://hg.pidgin.im/soc/2015/jgeboski/facebook/rev/213498a7ab94
Description:
facebook: fetch contacts in incremental chunks
When a user has several thousand contacts, the HTTP request can fail on
Facebook's side due to the large amount of data. The data for each user
is quite large, and when trying to fetch over one thousand users in a
single request, Facebook will likely error.
In order to resolve the issue, the contacts are fetched in incremental
chunks of 200. This is an arbitrary number, but seems safe enough not
to cause any issues, while also not sending an excessive amount of HTTP
requests.
This fixes the HTTP 500 error many people were receiving when opening a
Facebook connection, and having a significant number of friends.
diffstat:
libpurple/protocols/facebook/api.c | 98 ++++++++++++++++++++++++++--
libpurple/protocols/facebook/api.h | 5 +-
libpurple/protocols/facebook/facebook.c | 11 ++-
libpurple/protocols/facebook/marshaller.list | 1 +
4 files changed, 104 insertions(+), 11 deletions(-)
diffs (247 lines):
diff --git a/libpurple/protocols/facebook/api.c b/libpurple/protocols/facebook/api.c
--- a/libpurple/protocols/facebook/api.c
+++ b/libpurple/protocols/facebook/api.c
@@ -58,6 +58,9 @@ struct _FbApiPrivate
};
+static void
+fb_api_contacts_after(FbApi *api, const gchar *writeid);
+
G_DEFINE_TYPE(FbApi, fb_api, G_TYPE_OBJECT);
static void
@@ -217,9 +220,9 @@ fb_api_class_init(FbApiClass *klass)
G_SIGNAL_ACTION,
0,
NULL, NULL,
- fb_marshal_VOID__POINTER,
+ fb_marshal_VOID__POINTER_BOOLEAN,
G_TYPE_NONE,
- 1, G_TYPE_POINTER);
+ 2, G_TYPE_POINTER, G_TYPE_BOOLEAN);
g_signal_new("error",
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_ACTION,
@@ -321,7 +324,9 @@ fb_api_json_chk(FbApi *api, gconstpointe
root = fb_json_node_new(data, size, &err);
FB_API_ERROR_CHK(api, err, return FALSE);
- if (fb_json_node_chk_str(root, "$.failedSend.errorMessage", &msg)) {
+ if (fb_json_node_chk_str(root, "$.error.summary", &msg) ||
+ fb_json_node_chk_str(root, "$.failedSend.errorMessage", &msg))
+ {
fb_api_error(api, FB_API_ERROR_GENERAL, "%s", msg);
} else if (fb_json_node_chk_int(root, "$.error_code", &code)) {
if (!fb_json_node_chk_str(root, "$.error_msg", &msg)) {
@@ -1007,6 +1012,7 @@ fb_api_cb_contacts(PurpleHttpConnection
FbApiUser user;
FbHttpParams *params;
gchar *str;
+ gchar *writeid = NULL;
GError *err = NULL;
GList *elms = NULL;
GList *l;
@@ -1031,6 +1037,11 @@ fb_api_cb_contacts(PurpleHttpConnection
node = l->data;
fb_api_user_reset(&user, FALSE);
+ g_free(writeid);
+ writeid = fb_json_node_get_str(node, "$.graph_api_write_id",
+ &err);
+ FB_API_ERROR_CHK(api, err, goto finish);
+
str = fb_json_node_get_str(node, "$.represented_profile.id",
NULL);
@@ -1045,7 +1056,7 @@ fb_api_cb_contacts(PurpleHttpConnection
"$.structured_name.text",
NULL);
user.icon = fb_json_node_get_str(node,
- "$.huge_picture_url.uri",
+ "$.hugePictureUrl.uri",
NULL);
params = fb_http_params_new_parse(user.icon, TRUE);
@@ -1057,13 +1068,18 @@ fb_api_cb_contacts(PurpleHttpConnection
users = g_slist_prepend(users, mptr);
}
- g_signal_emit_by_name(api, "contacts", users);
+ g_signal_emit_by_name(api, "contacts", users, writeid == NULL);
+
+ if (writeid != NULL) {
+ fb_api_contacts_after(api, writeid);
+ }
finish:
if (G_LIKELY(arr != NULL)) {
json_array_unref(arr);
}
+ g_free(writeid);
g_list_free(elms);
g_slist_free_full(users, (GDestroyNotify) fb_api_user_free);
json_node_free(root);
@@ -1073,18 +1089,86 @@ void
fb_api_contacts(FbApi *api)
{
FbHttpParams *prms;
+ gchar *json;
+ JsonBuilder *bldr;
static const FbApiHttpInfo info = {
fb_api_cb_contacts,
- "com.facebook.contacts.service.d",
+ "com.facebook.contacts.service.c",
"FetchContactsFullQuery",
"get"
};
+ /* Object key mapping:
+ * 0 = profile_types
+ * 1 = limit
+ * 2 = small_img_size
+ * 3 = big_img_size
+ * 4 = huge_img_size
+ * 5 = low_res_cover_size
+ * 6 = media_type
+ * 7 = high_res_cover_size
+ */
+
+ bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
+ fb_json_bldr_arr_begin(bldr, "0");
+ fb_json_bldr_add_str(bldr, NULL, "user");
+ fb_json_bldr_arr_end(bldr);
+
+ fb_json_bldr_add_str(bldr, "1", FB_API_CONTACTS_COUNT);
+
+ json = fb_json_bldr_close(bldr, JSON_NODE_OBJECT, NULL);
prms = fb_http_params_new();
fb_http_params_set_str(prms, "query_id", FB_API_QRYID_CONTACTS);
- fb_http_params_set_str(prms, "query_params", "{}");
+ fb_http_params_set_str(prms, "query_params", json);
fb_api_http_req(api, &info, prms, FB_API_URL_GQL);
+ g_free(json);
+}
+
+static void
+fb_api_contacts_after(FbApi *api, const gchar *writeid)
+{
+ FbHttpParams *prms;
+ gchar *json;
+ JsonBuilder *bldr;
+
+ static const FbApiHttpInfo info = {
+ fb_api_cb_contacts,
+ "com.facebook.contacts.service.c",
+ "FetchContactsFullWithAfterQuery",
+ "get"
+ };
+
+ /* Object key mapping:
+ * 0 = profile_types
+ * 1 = after
+ * 2 = limit
+ * 3 = small_img_size
+ * 4 = big_img_size
+ * 5 = huge_img_size
+ * 6 = low_res_cover_size
+ * 7 = media_type
+ * 8 = high_res_cover_size
+ */
+
+ if (g_str_has_prefix(writeid, "contact_")) {
+ writeid += 8;
+ }
+
+ bldr = fb_json_bldr_new(JSON_NODE_OBJECT);
+ fb_json_bldr_arr_begin(bldr, "0");
+ fb_json_bldr_add_str(bldr, NULL, "user");
+ fb_json_bldr_arr_end(bldr);
+
+ fb_json_bldr_add_str(bldr, "1", writeid);
+ fb_json_bldr_add_str(bldr, "2", FB_API_CONTACTS_COUNT);
+
+ json = fb_json_bldr_close(bldr, JSON_NODE_OBJECT, NULL);
+ prms = fb_http_params_new();
+ fb_http_params_set_str(prms, "query_id", FB_API_QRYID_CONTACTS_AFTER);
+ fb_http_params_set_str(prms, "query_params", json);
+ fb_api_http_req(api, &info, prms, FB_API_URL_GQL);
+ g_free(json);
}
void
diff --git a/libpurple/protocols/facebook/api.h b/libpurple/protocols/facebook/api.h
--- a/libpurple/protocols/facebook/api.h
+++ b/libpurple/protocols/facebook/api.h
@@ -36,6 +36,8 @@
#define FB_API_KEY "256002347743983"
#define FB_API_SECRET "374e60f8b9bb6b8cbb30f78030438895"
+#define FB_API_CONTACTS_COUNT "200"
+
#define FB_API_URL_AUTH FB_API_BHOST "/method/auth.login"
#define FB_API_URL_FQL FB_API_GHOST "/fql"
#define FB_API_URL_GQL FB_API_GHOST "/graphql"
@@ -43,7 +45,8 @@
#define FB_API_URL_THRDS FB_API_GHOST "/me/threads"
#define FB_API_URL_TOPIC FB_API_HOST "/method/messaging.setthreadname"
-#define FB_API_QRYID_CONTACTS "10153122424521729"
+#define FB_API_QRYID_CONTACTS "10153746900696729"
+#define FB_API_QRYID_CONTACTS_AFTER "10153746900731729"
#define FB_TYPE_API (fb_api_get_type())
#define FB_API(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), FB_TYPE_API, FbApi))
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
@@ -100,7 +100,7 @@ fb_cb_data_icon(PurpleHttpConnection *co
}
static void
-fb_cb_api_contacts(FbApi *api, GSList *users, gpointer data)
+fb_cb_api_contacts(FbApi *api, GSList *users, gboolean complete, gpointer data)
{
const gchar *alias;
const gchar *csum;
@@ -113,12 +113,14 @@ fb_cb_api_contacts(FbApi *api, GSList *u
PurpleAccount *acct;
PurpleBuddy *bdy;
PurpleConnection *gc;
+ PurpleConnectionState state;
PurpleGroup *grp;
gc = fb_data_get_connection(fata);
acct = purple_connection_get_account(gc);
grp = purple_blist_get_default_group();
alias = purple_account_get_private_alias(acct);
+ state = purple_connection_get_state(gc);
g_value_init(&val, FB_TYPE_ID);
g_object_get_property(G_OBJECT(api), "uid", &val);
@@ -157,8 +159,11 @@ fb_cb_api_contacts(FbApi *api, GSList *u
}
fb_data_icon_queue(fata);
- purple_connection_update_progress(gc, _("Connecting"), 3, 4);
- fb_api_connect(api);
+
+ if (complete && (state != PURPLE_CONNECTION_CONNECTED)) {
+ purple_connection_update_progress(gc, _("Connecting"), 3, 4);
+ fb_api_connect(api);
+ }
}
static void
diff --git a/libpurple/protocols/facebook/marshaller.list b/libpurple/protocols/facebook/marshaller.list
--- a/libpurple/protocols/facebook/marshaller.list
+++ b/libpurple/protocols/facebook/marshaller.list
@@ -1,5 +1,6 @@
VOID:INT64
VOID:OBJECT
VOID:POINTER
+VOID:POINTER,BOOLEAN
VOID:STRING,BOXED
VOID:VOID
More information about the Commits
mailing list