Add clear request and responses method to httpclient (#19598)

* Added functionality to clear pending responses and requests in the http client

* Responses and Requests now are processed in similar way

* Fix for clearing the http requests

* Added tests for HttpClient::clearResponseAndRequestQueue
This commit is contained in:
minggo 2019-04-10 18:33:55 -07:00 committed by GitHub
parent c3a0205652
commit 62d20a9825
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 307 additions and 1 deletions

View File

@ -885,6 +885,8 @@ HttpClient::HttpClient()
, _threadCount(0)
, _cookie(nullptr)
, _requestSentinel(new HttpRequest())
, _clearRequestPredicate(nullptr)
, _clearResponsePredicate(nullptr)
{
CCLOG("In the constructor of HttpClient!");
increaseThreadCount();
@ -991,6 +993,39 @@ void HttpClient::dispatchResponseCallbacks()
}
}
void HttpClient::clearResponseAndRequestQueue()
{
_requestQueueMutex.lock();
if (_requestQueue.size())
{
for (auto it = _requestQueue.begin(); it != _requestQueue.end();)
{
if(!_clearRequestPredicate ||
_clearRequestPredicate((*it)))
{
(*it)->release();
it =_requestQueue.erase(it);
}
else
{
it++;
}
}
}
_requestQueueMutex.unlock();
_responseQueueMutex.lock();
if (_clearResponsePredicate)
{
_responseQueue.erase(std::remove_if(_responseQueue.begin(), _responseQueue.end(), _clearResponsePredicate), _responseQueue.end());
}
else
{
_responseQueue.clear();
}
_responseQueueMutex.unlock();
}
void HttpClient::increaseThreadCount()
{
_threadCountMutex.lock();

View File

@ -371,6 +371,8 @@ HttpClient::HttpClient()
, _threadCount(0)
, _cookie(nullptr)
, _requestSentinel(new HttpRequest())
, _clearRequestPredicate(nullptr)
, _clearResponsePredicate(nullptr)
{
CCLOG("In the constructor of HttpClient!");
memset(_responseMessage, 0, sizeof(char) * RESPONSE_BUFFER_SIZE);
@ -534,7 +536,39 @@ void HttpClient::processResponse(HttpResponse* response, char* responseMessage)
response->setErrorBuffer(responseMessage);
}
}
void HttpClient::clearResponseAndRequestQueue()
{
_requestQueueMutex.lock();
if (_requestQueue.size())
{
for (auto it = _requestQueue.begin(); it != _requestQueue.end();)
{
if(!_clearRequestPredicate ||
_clearRequestPredicate((*it)))
{
(*it)->release();
it =_requestQueue.erase(it);
}
else
{
it++;
}
}
}
_requestQueueMutex.unlock();
_responseQueueMutex.lock();
if (_clearResponsePredicate)
{
_responseQueue.erase(std::remove_if(_responseQueue.begin(), _responseQueue.end(), _clearResponsePredicate), _responseQueue.end());
}
else
{
_responseQueue.clear();
}
_responseQueueMutex.unlock();
}
void HttpClient::increaseThreadCount()
{

View File

@ -403,6 +403,8 @@ HttpClient::HttpClient()
, _threadCount(0)
, _cookie(nullptr)
, _requestSentinel(new HttpRequest())
, _clearRequestPredicate(nullptr)
, _clearResponsePredicate(nullptr)
{
CCLOG("In the constructor of HttpClient!");
memset(_responseMessage, 0, RESPONSE_BUFFER_SIZE * sizeof(char));
@ -575,6 +577,39 @@ void HttpClient::processResponse(HttpResponse* response, char* responseMessage)
response->setSucceed(true);
}
}
void HttpClient::clearResponseAndRequestQueue()
{
_requestQueueMutex.lock();
if (_requestQueue.size())
{
for (auto it = _requestQueue.begin(); it != _requestQueue.end();)
{
if(!_clearRequestPredicate ||
_clearRequestPredicate((*it)))
{
(*it)->release();
it =_requestQueue.erase(it);
}
else
{
it++;
}
}
}
_requestQueueMutex.unlock();
_responseQueueMutex.lock();
if (_clearResponsePredicate)
{
_responseQueue.erase(std::remove_if(_responseQueue.begin(), _responseQueue.end(), _clearResponsePredicate), _responseQueue.end());
}
else
{
_responseQueue.clear();
}
_responseQueueMutex.unlock();
}
void HttpClient::increaseThreadCount()
{

View File

@ -150,6 +150,34 @@ public:
std::mutex& getCookieFileMutex() {return _cookieFileMutex;}
std::mutex& getSSLCaFileMutex() {return _sslCaFileMutex;}
typedef std::function<bool(HttpRequest*)> ClearRequestPredicate;
typedef std::function<bool(HttpResponse*)> ClearResponsePredicate;
/**
* Clears the pending http responses and http requests
* If defined, the method uses the ClearRequestPredicate and ClearResponsePredicate
* to check for each request/response which to delete
*/
void clearResponseAndRequestQueue();
/**
* Sets a predicate function that is going to be called to determine if we proceed
* each of the pending requests
*
* @param predicate function that will be called
*/
void setClearRequestPredicate(ClearRequestPredicate predicate) { _clearRequestPredicate = predicate; }
/**
Sets a predicate function that is going to be called to determine if we proceed
* each of the pending requests
*
* @param cb predicate function that will be called
*/
void setClearResponsePredicate(ClearResponsePredicate predicate) { _clearResponsePredicate = predicate; }
private:
HttpClient();
virtual ~HttpClient();
@ -203,6 +231,9 @@ private:
char _responseMessage[RESPONSE_BUFFER_SIZE];
HttpRequest* _requestSentinel;
ClearRequestPredicate _clearRequestPredicate;
ClearResponsePredicate _clearResponsePredicate;
};
} // namespace network

View File

@ -33,6 +33,7 @@ using namespace cocos2d::network;
HttpClientTests::HttpClientTests()
{
ADD_TEST_CASE(HttpClientTest);
ADD_TEST_CASE(HttpClientClearRequestsTest);
}
HttpClientTest::HttpClientTest()
@ -398,3 +399,149 @@ void HttpClientTest::onHttpRequestCompleted(HttpClient *sender, HttpResponse *re
log("request ref count not 2, is %d", response->getHttpRequest()->getReferenceCount());
}
}
HttpClientClearRequestsTest::HttpClientClearRequestsTest()
: _labelStatusCode(nullptr)
{
auto winSize = Director::getInstance()->getWinSize();
const int MARGIN = 40;
const int SPACE = 35;
const int CENTER = winSize.width / 2;
auto menuRequest = Menu::create();
menuRequest->setPosition(Vec2::ZERO);
addChild(menuRequest);
// Get
auto labelGet = Label::createWithTTF("Test Clear all Get", "fonts/arial.ttf", 22);
auto itemGet = MenuItemLabel::create(labelGet, CC_CALLBACK_1(HttpClientClearRequestsTest::onMenuCancelAllClicked, this));
itemGet->setPosition(CENTER, winSize.height - MARGIN - SPACE);
menuRequest->addChild(itemGet);
// Post
auto labelPost = Label::createWithTTF("Test Clear but only with the tag DELETE", "fonts/arial.ttf", 22);
auto itemPost = MenuItemLabel::create(labelPost, CC_CALLBACK_1(HttpClientClearRequestsTest::onMenuCancelSomeClicked, this));
itemPost->setPosition(CENTER, winSize.height - MARGIN - 2 * SPACE);
menuRequest->addChild(itemPost);
// Response Code Label
_labelStatusCode = Label::createWithTTF("HTTP Status Code", "fonts/arial.ttf", 18);
_labelStatusCode->setPosition(winSize.width / 2, winSize.height - MARGIN - 6 * SPACE);
addChild(_labelStatusCode);
// Tracking Data Label
_labelTrakingData = Label::createWithTTF("Got 0 of 0 expected http requests", "fonts/arial.ttf", 16);
_labelTrakingData->setPosition(CENTER, winSize.height - MARGIN - 5 * SPACE);
addChild(_labelTrakingData);
_totalExpectedRequests = 0;
_totalProcessedRequests = 0;
}
HttpClientClearRequestsTest::~HttpClientClearRequestsTest()
{
HttpClient::destroyInstance();
}
void HttpClientClearRequestsTest::onMenuCancelAllClicked(cocos2d::Ref *sender)
{
for (int i=0; i < 10; i++)
{
HttpRequest* request = new (std::nothrow) HttpRequest();
std::stringstream url;
url << "http://cocos2d-x.org/images/logo.png?id=" << std::to_string(i);
request->setUrl(url.str());
request->setRequestType(HttpRequest::Type::GET);
request->setResponseCallback(CC_CALLBACK_2(HttpClientClearRequestsTest::onHttpRequestCompleted, this));
url.str("");
url << "TEST_" << std::to_string(i);
request->setTag(url.str());
HttpClient::getInstance()->send(request);
request->release();
}
_totalProcessedRequests = 0;
_totalExpectedRequests = 1;
HttpClient::getInstance()->setClearRequestPredicate(nullptr);
HttpClient::getInstance()->setClearResponsePredicate(nullptr);
HttpClient::getInstance()->clearResponseAndRequestQueue();
// waiting
_labelStatusCode->setString("waiting...");
}
void HttpClientClearRequestsTest::onMenuCancelSomeClicked(cocos2d::Ref *sender)
{
// test 1
for (int i=0; i < 10; i++)
{
HttpRequest* request = new (std::nothrow) HttpRequest();
std::stringstream url;
url << "http://cocos2d-x.org/images/logo.png?id=" << std::to_string(i);
request->setUrl(url.str());
request->setRequestType(HttpRequest::Type::GET);
request->setResponseCallback(CC_CALLBACK_2(HttpClientClearRequestsTest::onHttpRequestCompleted, this));
url.str("");
if (i < 5) {
url << "TEST_" << std::to_string(i);
_totalExpectedRequests++;
}
else {
url << "DELETE_" << std::to_string(i);
}
request->setTag(url.str());
HttpClient::getInstance()->send(request);
request->release();
}
HttpClient::getInstance()->setClearRequestPredicate([&](HttpRequest* req)
{
auto r = !!strstr(req->getTag(), "DELETE_");
return r;
});
HttpClient::getInstance()->setClearResponsePredicate(nullptr);
HttpClient::getInstance()->clearResponseAndRequestQueue();
// waiting
_labelStatusCode->setString("waiting...");
}
void HttpClientClearRequestsTest::onHttpRequestCompleted(HttpClient *sender, HttpResponse *response)
{
if (!response)
{
return;
}
// You can get original request type from: response->request->reqType
if (0 != strlen(response->getHttpRequest()->getTag()))
{
log("%s completed", response->getHttpRequest()->getTag());
}
long statusCode = response->getResponseCode();
char statusString[64] = {};
sprintf(statusString, "HTTP Status Code: %ld, tag = %s", statusCode, response->getHttpRequest()->getTag());
_labelStatusCode->setString(statusString);
log("response code: %ld", statusCode);
_totalProcessedRequests++;
sprintf(statusString, "Got %d of %d expected http requests", _totalProcessedRequests, _totalExpectedRequests);
_labelTrakingData->setString(statusString);
if (!response->isSucceed())
{
log("response failed");
log("error buffer: %s", response->getErrorBuffer());
}
}

View File

@ -56,4 +56,28 @@ private:
cocos2d::Label* _labelStatusCode;
};
class HttpClientClearRequestsTest : public TestCase
{
public:
CREATE_FUNC(HttpClientClearRequestsTest);
HttpClientClearRequestsTest();
virtual ~HttpClientClearRequestsTest();
//Menu Callbacks
void onMenuCancelAllClicked(cocos2d::Ref *sender);
void onMenuCancelSomeClicked(cocos2d::Ref *sender);
//Http Response Callback
void onHttpRequestCompleted(cocos2d::network::HttpClient *sender, cocos2d::network::HttpResponse *response);
virtual std::string title() const override { return "Http Request Test"; }
private:
int _totalExpectedRequests;
int _totalProcessedRequests;
cocos2d::Label* _labelTrakingData;
cocos2d::Label* _labelStatusCode;
};
#endif //__HTTPREQUESTHTTP_H