How to download multiple facebook avatars with fast speed?

Hi all,

Now, I have a leaderboards with 30 users !

When users login to my game , I want to download 30 user avatars from facebook !

And display it on the Leaderboard Layer !

I used cocos2d::network::HttpRequest to request this link :
https://graph.facebook.com/[FBID]/picture?type=square

Here is my code :

 for (size_t i = 0; i < leaderboardUsers.size(); i++)
	{
		const std::string k_fbID = leaderboardUsers.at(i).m_fbAvUrl;

		if (!k_fbID.empty())
		{
			std::string avatarPath = FileUtils::getInstance()->getWritablePath() + "/avatars/" + k_fbID + ".png";

			if (!FileUtils::getInstance()->isFileExist(avatarPath))
			{
				std::string url = "https://graph.facebook.com/" + k_fbID + "/picture?type=square";

				try
				{
					cocos2d::network::HttpRequest *request = new cocos2d::network::HttpRequest();
					request->setUrl(url);
					request->setRequestType(cocos2d::network::HttpRequest::Type::GET);
					request->setResponseCallback([=](cocos2d::network::HttpClient * sender, cocos2d::network::HttpResponse * response) {

						if (!response || (!response->isSucceed()))
						{
							return;
						}
					
						std::vector<char>*buffer = response->getResponseData();
						std::string data = std::string(buffer->begin(), buffer->end());

						Image img;

						if (img.initWithImageData((const unsigned char*)data.c_str(), data.size()))
						{
							img.saveToFile(avatarPath.c_str());
						}

					});
					cocos2d::network::HttpClient::getInstance()->send(request);
					request->release();
				}
				catch (...)
				{
				}
			}
		}
	}

I tested on some android devices , It is really slow !

To get all avatars of leaderboards , takes nearly 4-6 minutes !

How can I speed up my requests ?

Thanks all !

2 Tips:

  1. Try to download avatar one by one instead of for loop at once.
    Once 1 avatar is downloaded, fire another HttpRequest for next avatar.
  2. Better specify width & height for avatar instead of square type
    picture?width=50&height=50
1 Like

hi ! Thanks for your support ! I tested your solution ! It cannot help me ! It works same as my code above ! It is really slow ! :sob: :sob:

I am using that way only and working fine for us.

Let me x2 check again ! And I will show me my code !

This is a common issue on latency when sending several requests (and rate limiting). I have similar issues with my own backend, and it is a symptom of moving towards micro service oriented smaller requests. A common solution is to batch the requests into 1 request. It seems Facebook graph API has this setup for you to use already:

Note you might need to add a little additional logic client side to get around rate limiter.

I assume you are hitting a rate limit which will put your IP on a cool down before allowing new requests. This is likely what is causing your long response time. You will need to experiment with a good request/batch sending to stay within Facebookā€™s limits and minimize latency as well.

Also** cache is your friend. Look into setting up a cache client side, or if you put a server in the middle of these requests you can use redis etc

More information on FB rate limiting:

When the limit has been reached stop making API calls. 
Continuing to make calls will continue to increase your call count which 
will increase the time before calls will be successful again.

Hi,

Iā€™ve a similar problem.
My game is in production and since some months, iā€™m having problems for GET facebook photos of ā€œmy friendsā€. Iā€™ve more than one friend, and when I try to get all photos, i can get only one. When I request the second photo of my second friend, i receive this response " The request timed out. ". It worked until a few months ago. Since weeks, it doesnā€™t work anymore. Itā€™s very strange.

My code:

for(....) //my friend list
{
  HttpRequest* requestFacebookPhoto = new HttpRequest();
  requestFacebookPhoto->setUrl(friendPhotoUrl); //I tested all URLs in Chrome and it works. The url is ok.
  requestFacebookPhoto->setRequestType(HttpRequest::Type::GET);
  requestFacebookPhoto->setResponseCallback([](HttpClient* client, HttpResponse* response) {

    if (!response or response->getResponseCode() != 200) {

        //response code is -1, so, when i debug it, it enters to this if

        return;
    }

    //more code below..

  }); 

  HttpClient::getInstance()->send(requestFacebookPhoto);
  requestFacebookPhoto->release();
}

I tried to make a delay between each request, but it doesnā€™t work either.
The question is, whatā€™s the solution? because, far as I know, I canā€™t request all photos in only one request. And if I could, iā€™m sure that it has a limit too. What about if Iā€™ve 1000 friends? haha.

Did you find the solution?

I put a detailed response about batching requests / trying to get around rate limiting. Did you give that a try?

Also, if you have 1000 friends, that is where a server side cache would be beneficial. Users would have their avatar cached at account creation, and there could be a expiration on the cache to make sure there is a current photo, or it can check each time the given user logs on etc. 1000 avatars cached properly could result in a sub 50ms response time.

If I understand this correctly, batching wonā€™t help with the rate limiting either, besides reducing the network traffic. This is the specific part Iā€™m referring to on that page:

What do we consider an API call?
....
You can also use the Batch API to batch your requests, but note that each sub-request
is its own API call, or even multiple API calls in the case of specifying many ids.

Caching is would be best method to use here.

If a user of an app has 1000 friends, there should never be a need to retrieve all at once. How about you only retrieve what is visible to the user. Imagine itā€™s a list view, and as the user is scrolling through it, you grab the next set of images (only as many as the user can see). You can cache them on the client very easily. For example, in a SQLite table, save the id of each user you received an image for, and the path to that image (do not store the image data in the database). So, in future, you check your SQLite database first to see if the image exists, and if it does, grab that instead of sending off a request to the Facebook API.

You then have a choice to update photos every X period of time, or if your app allows the user to click on one of their friends, then that would be a perfect time to refresh the photo (itā€™s unlikely your user is going to click all 1000 friendsā€¦)

2 Likes

This is what we do, may be thats why we dont face this issueā€¦?!!

1 Like

For sure, I was just throwing some ideas around. I donā€™t use Facebook API or retrieve FB avatars in any of my projects. Just what I came up with from some 2minute searches in the actual documentations. I like to batch my requests to my API where possible for network reasons like you mentioned, but since the rate limiter is integrated into the FB batch endpoint, it might not help the rate limit side. And yes, when in doubt ā€¦ cache!

Also good point on the ā€˜only pull what is necessaryā€™. Imagine if Instagram pulled their entire list every time you pulled up a profile :smiley: ā€¦ lazy loading

1 Like

i used cocos2d Downloader component and didnā€™t take that much time

For me:

I downloaded all avatars in SingleTone Class with priority stack !

If the game is downloading avatars and you have a new request with high priority ?
-> You need to push it to the top of the stack !

Nobody has the problem of timed out that I mentioned in my last post? I donā€™t know how to fix that :sweat:

Did you read @tdebock reply?
Here

Try to implement this at server side. This is what we do and never had any problem.

I think avatars cached isnā€™t the solution. The problem that Iā€™ve is that the server give me a ā€œtime-outā€ response when I request the second avatar. I could cached the avatars but when I try to request these again, I will have the same problem.

Also, I donā€™t like to store images or personal information in my own database. Maybe iā€™m violating some privacy term. I store only his/her facebook id in my own db.

when you say time outā€¦ is this a time out on your own request, or from FB side? If your request has a 10ms time out, it might not give FB enough time to respond etc. But if FB is timing out, you should reach out to FB dev community not cocos.

The time out is in the response callback.

for(....) //my friend list
{
  HttpRequest* requestFacebookPhoto = new HttpRequest();
  requestFacebookPhoto->setUrl(friendPhotoUrl); //I tested all URLs in Chrome and it works. The url is ok.
  requestFacebookPhoto->setRequestType(HttpRequest::Type::GET);
  requestFacebookPhoto->setResponseCallback([](HttpClient* client, HttpResponse* response) {

    if (!response or response->getResponseCode() != 200) {

        //response code is -1, so, when i debug it, it enters to this if

        return;
    }

    //more code below..

  }); 

  HttpClient::getInstance()->send(requestFacebookPhoto);
  requestFacebookPhoto->release();
}

It seem to be a FB problem, not mine. But I asked in the community and nobody gives me a solution. Maybe there are some limitation in the API or whateverā€¦ itā€™s strange.

Can you provide the full error message from response?