mirror of https://github.com/axmolengine/axmol.git
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:
parent
c3a0205652
commit
62d20a9825
|
@ -885,6 +885,8 @@ HttpClient::HttpClient()
|
||||||
, _threadCount(0)
|
, _threadCount(0)
|
||||||
, _cookie(nullptr)
|
, _cookie(nullptr)
|
||||||
, _requestSentinel(new HttpRequest())
|
, _requestSentinel(new HttpRequest())
|
||||||
|
, _clearRequestPredicate(nullptr)
|
||||||
|
, _clearResponsePredicate(nullptr)
|
||||||
{
|
{
|
||||||
CCLOG("In the constructor of HttpClient!");
|
CCLOG("In the constructor of HttpClient!");
|
||||||
increaseThreadCount();
|
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()
|
void HttpClient::increaseThreadCount()
|
||||||
{
|
{
|
||||||
_threadCountMutex.lock();
|
_threadCountMutex.lock();
|
||||||
|
|
|
@ -371,6 +371,8 @@ HttpClient::HttpClient()
|
||||||
, _threadCount(0)
|
, _threadCount(0)
|
||||||
, _cookie(nullptr)
|
, _cookie(nullptr)
|
||||||
, _requestSentinel(new HttpRequest())
|
, _requestSentinel(new HttpRequest())
|
||||||
|
, _clearRequestPredicate(nullptr)
|
||||||
|
, _clearResponsePredicate(nullptr)
|
||||||
{
|
{
|
||||||
CCLOG("In the constructor of HttpClient!");
|
CCLOG("In the constructor of HttpClient!");
|
||||||
memset(_responseMessage, 0, sizeof(char) * RESPONSE_BUFFER_SIZE);
|
memset(_responseMessage, 0, sizeof(char) * RESPONSE_BUFFER_SIZE);
|
||||||
|
@ -534,7 +536,39 @@ void HttpClient::processResponse(HttpResponse* response, char* responseMessage)
|
||||||
response->setErrorBuffer(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()
|
void HttpClient::increaseThreadCount()
|
||||||
{
|
{
|
||||||
|
|
|
@ -403,6 +403,8 @@ HttpClient::HttpClient()
|
||||||
, _threadCount(0)
|
, _threadCount(0)
|
||||||
, _cookie(nullptr)
|
, _cookie(nullptr)
|
||||||
, _requestSentinel(new HttpRequest())
|
, _requestSentinel(new HttpRequest())
|
||||||
|
, _clearRequestPredicate(nullptr)
|
||||||
|
, _clearResponsePredicate(nullptr)
|
||||||
{
|
{
|
||||||
CCLOG("In the constructor of HttpClient!");
|
CCLOG("In the constructor of HttpClient!");
|
||||||
memset(_responseMessage, 0, RESPONSE_BUFFER_SIZE * sizeof(char));
|
memset(_responseMessage, 0, RESPONSE_BUFFER_SIZE * sizeof(char));
|
||||||
|
@ -575,6 +577,39 @@ void HttpClient::processResponse(HttpResponse* response, char* responseMessage)
|
||||||
response->setSucceed(true);
|
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()
|
void HttpClient::increaseThreadCount()
|
||||||
{
|
{
|
||||||
|
|
|
@ -150,6 +150,34 @@ public:
|
||||||
std::mutex& getCookieFileMutex() {return _cookieFileMutex;}
|
std::mutex& getCookieFileMutex() {return _cookieFileMutex;}
|
||||||
|
|
||||||
std::mutex& getSSLCaFileMutex() {return _sslCaFileMutex;}
|
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:
|
private:
|
||||||
HttpClient();
|
HttpClient();
|
||||||
virtual ~HttpClient();
|
virtual ~HttpClient();
|
||||||
|
@ -203,6 +231,9 @@ private:
|
||||||
char _responseMessage[RESPONSE_BUFFER_SIZE];
|
char _responseMessage[RESPONSE_BUFFER_SIZE];
|
||||||
|
|
||||||
HttpRequest* _requestSentinel;
|
HttpRequest* _requestSentinel;
|
||||||
|
|
||||||
|
ClearRequestPredicate _clearRequestPredicate;
|
||||||
|
ClearResponsePredicate _clearResponsePredicate;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace network
|
} // namespace network
|
||||||
|
|
|
@ -33,6 +33,7 @@ using namespace cocos2d::network;
|
||||||
HttpClientTests::HttpClientTests()
|
HttpClientTests::HttpClientTests()
|
||||||
{
|
{
|
||||||
ADD_TEST_CASE(HttpClientTest);
|
ADD_TEST_CASE(HttpClientTest);
|
||||||
|
ADD_TEST_CASE(HttpClientClearRequestsTest);
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpClientTest::HttpClientTest()
|
HttpClientTest::HttpClientTest()
|
||||||
|
@ -398,3 +399,149 @@ void HttpClientTest::onHttpRequestCompleted(HttpClient *sender, HttpResponse *re
|
||||||
log("request ref count not 2, is %d", response->getHttpRequest()->getReferenceCount());
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -56,4 +56,28 @@ private:
|
||||||
cocos2d::Label* _labelStatusCode;
|
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
|
#endif //__HTTPREQUESTHTTP_H
|
||||||
|
|
Loading…
Reference in New Issue