/soc/2015/jgeboski/facebook: 213498a7ab94: facebook: fetch conta...
James Geboski <[email protected]>
| Newsgroups | gmane.comp.gnome.gaim.cvs |
|---|---|
| Message-ID | <[email protected]> |
Changeset: 213498a7ab9453d1a9ae1ae6e8a91770299780b5 Author: James Geboski <[email protected]> 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 _______________________________________________ Commits mailing list [email protected] https://pidgin.im/cgi-bin/mailman/listinfo/commits