mirror of https://github.com/axmolengine/axmol.git
issue #1424, http-get works ok. Tomorrow I will focus on post.
This commit is contained in:
parent
39e45da8d9
commit
b094f70ab3
|
@ -1,576 +0,0 @@
|
|||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2012 greathqy
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "CCHttpRequest.h"
|
||||
#include <queue>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <errno.h>
|
||||
#include "platform/CCThread.h"
|
||||
#include "curl/curl.h"
|
||||
|
||||
NS_CC_EXT_BEGIN
|
||||
|
||||
static pthread_t s_requestThread;
|
||||
static pthread_mutex_t s_requestQueueMutex;
|
||||
static pthread_mutex_t s_responseQueueMutex;
|
||||
static sem_t * s_pSem = NULL;
|
||||
static unsigned long s_asyncRequestCount = 0;
|
||||
|
||||
#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS
|
||||
#define CC_ASYNC_HTTPREQUEST_USE_NAMED_SEMAPHORE 1
|
||||
#else
|
||||
#define CC_ASYNC_HTTPREQUEST_USE_NAMED_SEMAPHORE 0
|
||||
#endif
|
||||
|
||||
#if CC_ASYNC_HTTPREQUEST_USE_NAMED_SEMAPHORE
|
||||
#define CC_ASYNC_HTTPREQUEST_SEMAPHORE "ccHttpAsync"
|
||||
#else
|
||||
static sem_t s_sem;
|
||||
#endif
|
||||
|
||||
static bool need_quit = false;
|
||||
|
||||
static std::queue<HttpRequestPacket *> *s_requestQueue = NULL;
|
||||
static std::queue<HttpResponsePacket *> *s_responseQueue = NULL;
|
||||
|
||||
static CCHttpRequest *_g_singleton_httprequest = NULL;
|
||||
|
||||
static char errorBuffer[CURL_ERROR_SIZE];
|
||||
typedef size_t (*write_callback)(void *ptr, size_t size, size_t nmemb, void *stream);
|
||||
|
||||
//Callback function used by libcurl for save file
|
||||
size_t writeFile(void *ptr, size_t size, size_t nmemb, void *stream)
|
||||
{
|
||||
int written = fwrite(ptr, size, nmemb, (FILE *)stream);
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
//Callback function used by libcurl for collect response data
|
||||
size_t writeData(void *ptr, size_t size, size_t nmemb, void *stream)
|
||||
{
|
||||
std::string *str = (std::string *)stream;
|
||||
|
||||
size_t sizes = size * nmemb;
|
||||
str->append((char *)ptr, sizes);
|
||||
|
||||
return sizes;
|
||||
}
|
||||
|
||||
//Prototypes
|
||||
void releaseRequestQueue();
|
||||
bool configureCURL(CURL *handle);
|
||||
int processGetTask(HttpRequestPacket *task, write_callback callback, void *stream, int32_t *responseCode);
|
||||
int processPostTask(HttpRequestPacket *task, write_callback callback, void *stream, int32_t *responseCode);
|
||||
int processDownloadTask(HttpRequestPacket *task, write_callback callback, void *stream, int32_t *responseCode);
|
||||
|
||||
void CCHttpRequest::purgeSharedHttpRequest()
|
||||
{
|
||||
CC_SAFE_RELEASE_NULL(_g_singleton_httprequest);
|
||||
}
|
||||
|
||||
CCHttpRequest *CCHttpRequest::sharedHttpRequest()
|
||||
{
|
||||
if (_g_singleton_httprequest == NULL) {
|
||||
_g_singleton_httprequest = new CCHttpRequest();
|
||||
}
|
||||
|
||||
return _g_singleton_httprequest;
|
||||
}
|
||||
|
||||
//Worker thread
|
||||
static void *requestThread(void *data)
|
||||
{
|
||||
CCThread thread;
|
||||
thread.createAutoreleasePool();
|
||||
|
||||
HttpRequestPacket *req = NULL;
|
||||
|
||||
while (true) {
|
||||
//Wait for http request tasks from main thread
|
||||
int semWaitRet = sem_wait(s_pSem);
|
||||
if (semWaitRet < 0) {
|
||||
CCLog("HttpRequest async thread semaphore error: %s\n", strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
std::queue<HttpRequestPacket *> *pQueue = s_requestQueue;
|
||||
pthread_mutex_lock(&s_requestQueueMutex); //Get request task from queue
|
||||
if (pQueue->empty()) {
|
||||
pthread_mutex_unlock(&s_requestQueueMutex);
|
||||
|
||||
if (need_quit) {
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (need_quit) {
|
||||
pthread_mutex_unlock(&s_requestQueueMutex);
|
||||
break;
|
||||
}
|
||||
|
||||
req = pQueue->front();
|
||||
pQueue->pop();
|
||||
pthread_mutex_unlock(&s_requestQueueMutex);
|
||||
}
|
||||
|
||||
//Create a response packet and assume it will successed
|
||||
HttpResponsePacket *responsePacket = new HttpResponsePacket();
|
||||
responsePacket->request = req;
|
||||
responsePacket->succeed = true;
|
||||
|
||||
//Process the request
|
||||
if (req->reqType == kHttpRequestGet) { //Get Request
|
||||
int32_t ret = processGetTask(req, writeData, &responsePacket->responseData, &responsePacket->responseCode);
|
||||
if (ret != 0) {
|
||||
responsePacket->succeed = false;
|
||||
responsePacket->responseData = errorBuffer;
|
||||
}
|
||||
} else if (req->reqType == kHttpRequestPost) { //Post Request
|
||||
int32_t ret = processPostTask(req, writeData, &responsePacket->responseData, &responsePacket->responseCode);
|
||||
if (ret != 0) {
|
||||
responsePacket->succeed = false;
|
||||
responsePacket->responseData = errorBuffer;
|
||||
}
|
||||
} else if (req->reqType == kHttpRequestDownloadFile) { //Download File Request
|
||||
bool fullyDownloaded = true;
|
||||
std::vector<std::string>::iterator iter;
|
||||
std::string saveFileName;
|
||||
std::string needDownload;
|
||||
|
||||
for (iter = req->files.begin(); iter != req->files.end(); ++iter) {
|
||||
needDownload = *iter;
|
||||
std::string::size_type pos = needDownload.rfind("/");
|
||||
|
||||
if (pos != std::string::npos) {
|
||||
saveFileName = needDownload.substr(pos + 1);
|
||||
} else {
|
||||
saveFileName = needDownload;
|
||||
}
|
||||
|
||||
//If the download url is http://www.xxx.com/yyy.html
|
||||
//The saved file name must be yyy.html
|
||||
saveFileName = CCFileUtils::sharedFileUtils()->getWriteablePath() + saveFileName;
|
||||
FILE *handle = fopen(saveFileName.c_str(), "w+");
|
||||
if (!handle) {
|
||||
fullyDownloaded = false;
|
||||
break;
|
||||
}
|
||||
req->url = needDownload;
|
||||
int32_t ret = processDownloadTask(req, writeFile, handle, &responsePacket->responseCode);
|
||||
if (handle) {
|
||||
fclose(handle);
|
||||
}
|
||||
if (ret != 0) {
|
||||
fullyDownloaded = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Only consider download task successfully when all the files downloaded
|
||||
if (!fullyDownloaded) {
|
||||
responsePacket->succeed = false;
|
||||
responsePacket->responseData = errorBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&s_responseQueueMutex);
|
||||
s_responseQueue->push(responsePacket);
|
||||
pthread_mutex_unlock(&s_responseQueueMutex);
|
||||
}
|
||||
|
||||
//If worker thread received quit signal, clean up un-completed request queue
|
||||
releaseRequestQueue();
|
||||
|
||||
if (s_pSem != NULL) {
|
||||
#if CC_ASYNC_HTTPREQUEST_USE_NAMED_SEMAPHORE
|
||||
sem_unlink(CC_ASYNC_HTTPREQUEST_SEMAPHORE);
|
||||
sem_close(s_pSem);
|
||||
#else
|
||||
sem_destroy(s_pSem);
|
||||
#endif
|
||||
|
||||
s_pSem = NULL;
|
||||
|
||||
pthread_mutex_destroy(&s_requestQueueMutex);
|
||||
pthread_mutex_destroy(&s_responseQueueMutex);
|
||||
|
||||
delete s_requestQueue;
|
||||
delete s_responseQueue;
|
||||
}
|
||||
|
||||
pthread_exit(NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Release Http request task queue
|
||||
void releaseRequestQueue()
|
||||
{
|
||||
pthread_mutex_lock(&s_requestQueueMutex);
|
||||
|
||||
int32_t requestQueueSize = s_requestQueue->size();
|
||||
if (requestQueueSize > 0) {
|
||||
for (int32_t i = 0; i < requestQueueSize; ++i) {
|
||||
HttpRequestPacket *packet = s_requestQueue->front();
|
||||
s_requestQueue->pop();
|
||||
|
||||
delete packet;
|
||||
}
|
||||
|
||||
s_asyncRequestCount -= requestQueueSize;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&s_requestQueueMutex);
|
||||
}
|
||||
|
||||
//Configure curl's timeout property
|
||||
bool configureCURL(CURL *handle)
|
||||
{
|
||||
if (!handle) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t code;
|
||||
code = curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, errorBuffer);
|
||||
if (code != CURLE_OK) {
|
||||
return false;
|
||||
}
|
||||
code = curl_easy_setopt(handle, CURLOPT_TIMEOUT, CCHttpRequest::sharedHttpRequest()->getDownloadTimeout());
|
||||
if (code != CURLE_OK) {
|
||||
return false;
|
||||
}
|
||||
code = curl_easy_setopt(handle, CURLOPT_CONNECTTIMEOUT, CCHttpRequest::sharedHttpRequest()->getConnectTimeout());
|
||||
if (code != CURLE_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//Process Get Request
|
||||
int processGetTask(HttpRequestPacket *task, write_callback callback, void *stream, int32_t *responseCode)
|
||||
{
|
||||
CURLcode code = CURL_LAST;
|
||||
CURL *curl = curl_easy_init();
|
||||
|
||||
do {
|
||||
if (!configureCURL(curl)) {
|
||||
break;
|
||||
}
|
||||
|
||||
code = curl_easy_setopt(curl, CURLOPT_URL, task->url.c_str());
|
||||
if (code != CURLE_OK) {
|
||||
break;
|
||||
}
|
||||
code = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback);
|
||||
if (code != CURLE_OK) {
|
||||
break;
|
||||
}
|
||||
code = curl_easy_setopt(curl, CURLOPT_WRITEDATA, stream);
|
||||
if (code != CURLE_OK) {
|
||||
break;
|
||||
}
|
||||
code = curl_easy_perform(curl);
|
||||
if (code != CURLE_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
code = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, responseCode);
|
||||
if (code != CURLE_OK || *responseCode / 100 != 2) {
|
||||
code = CURLE_HTTP_RETURNED_ERROR;
|
||||
}
|
||||
} while (0);
|
||||
if (curl) {
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
return (code == CURLE_OK ? 0 : 1);
|
||||
}
|
||||
|
||||
//Process POST Request
|
||||
int processPostTask(HttpRequestPacket *task, write_callback callback, void *stream, int32_t *responseCode)
|
||||
{
|
||||
CURLcode code = CURL_LAST;
|
||||
CURL *curl = curl_easy_init();
|
||||
|
||||
do {
|
||||
if (!configureCURL(curl)) {
|
||||
break;
|
||||
}
|
||||
|
||||
code = curl_easy_setopt(curl, CURLOPT_URL, task->url.c_str());
|
||||
if (code != CURLE_OK) {
|
||||
break;
|
||||
}
|
||||
code = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback);
|
||||
if (code != CURLE_OK) {
|
||||
break;
|
||||
}
|
||||
code = curl_easy_setopt(curl, CURLOPT_WRITEDATA, stream);
|
||||
if (code != CURLE_OK) {
|
||||
break;
|
||||
}
|
||||
code = curl_easy_setopt(curl, CURLOPT_POST, 1);
|
||||
if (code != CURLE_OK) {
|
||||
break;
|
||||
}
|
||||
code = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, task->reqData.data());
|
||||
if (code != CURLE_OK) {
|
||||
break;
|
||||
}
|
||||
code = curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, task->reqData.size());
|
||||
if (code != CURLE_OK) {
|
||||
break;
|
||||
}
|
||||
code = curl_easy_perform(curl);
|
||||
if (code != CURLE_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
code = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, responseCode);
|
||||
if (code != CURLE_OK || *responseCode / 100 != 2) {
|
||||
code = CURLE_HTTP_RETURNED_ERROR;
|
||||
}
|
||||
} while (0);
|
||||
if (curl) {
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
return (code == CURLE_OK ? 0 : 1);
|
||||
}
|
||||
|
||||
//Process Download Request
|
||||
int processDownloadTask(HttpRequestPacket *task, write_callback callback, void *stream, int32_t *responseCode)
|
||||
{
|
||||
return processGetTask(task, callback, stream, responseCode);
|
||||
}
|
||||
|
||||
CCHttpRequest::CCHttpRequest()
|
||||
{
|
||||
m_timeout = 60;
|
||||
m_connectTimeout = 10;
|
||||
}
|
||||
|
||||
CCHttpRequest::~CCHttpRequest()
|
||||
{
|
||||
need_quit = true;
|
||||
|
||||
if (s_pSem != NULL) {
|
||||
sem_post(s_pSem);
|
||||
}
|
||||
}
|
||||
|
||||
//Lazy create semaphore & mutex & thread
|
||||
bool CCHttpRequest::lazyInitThreadSemphore()
|
||||
{
|
||||
if (s_pSem != NULL) {
|
||||
return true;
|
||||
} else {
|
||||
#if CC_ASYNC_HTTPREQUEST_USE_NAMED_SEMAPHORE
|
||||
s_pSem = sem_open(CC_ASYNC_HTTPREQUEST_SEMAPHORE, O_CREAT, 0644, 0);
|
||||
if (s_pSem == SEM_FAILED) {
|
||||
CCLog("Open HttpRequest Semaphore failed");
|
||||
s_pSem = NULL;
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
int semRet = sem_init(&s_sem, 0, 0);
|
||||
if (semRet < 0) {
|
||||
CCLog("Init HttpRequest Semaphore failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_pSem = &s_sem;
|
||||
#endif
|
||||
|
||||
s_requestQueue = new std::queue<HttpRequestPacket *>();
|
||||
s_responseQueue = new std::queue<HttpResponsePacket *>();
|
||||
|
||||
pthread_mutex_init(&s_requestQueueMutex, NULL);
|
||||
pthread_mutex_init(&s_responseQueueMutex, NULL);
|
||||
|
||||
pthread_create(&s_requestThread, NULL, requestThread, NULL);
|
||||
pthread_detach(s_requestThread);
|
||||
|
||||
need_quit = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//Add a get task to queue
|
||||
void CCHttpRequest::addGetTask(std::string url, cocos2d::CCObject *pTarget, SEL_CallFuncND pSelector)
|
||||
{
|
||||
bool inited = lazyInitThreadSemphore();
|
||||
if (!inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (0 == s_asyncRequestCount) {
|
||||
CCDirector::sharedDirector()->getScheduler()->scheduleSelector(schedule_selector(CCHttpRequest::dispatchResponseCallbacks), this, 0, false);
|
||||
}
|
||||
|
||||
++s_asyncRequestCount;
|
||||
if (pTarget) {
|
||||
pTarget->retain();
|
||||
}
|
||||
|
||||
HttpRequestPacket *packet = new HttpRequestPacket();
|
||||
packet->reqType = kHttpRequestGet;
|
||||
packet->reqId = this->reqId;
|
||||
packet->url = url;
|
||||
packet->pTarget = pTarget;
|
||||
packet->pSelector = pSelector;
|
||||
|
||||
this->reqId.clear();
|
||||
|
||||
pthread_mutex_lock(&s_requestQueueMutex);
|
||||
s_requestQueue->push(packet);
|
||||
pthread_mutex_unlock(&s_requestQueueMutex);
|
||||
|
||||
//Notify thread start to work
|
||||
sem_post(s_pSem);
|
||||
}
|
||||
|
||||
//Add a post task to queue
|
||||
void CCHttpRequest::addPostTask(std::string &url, std::string &postData, CCObject *pTarget, SEL_CallFuncND pSelector)
|
||||
{
|
||||
bool inited = lazyInitThreadSemphore();
|
||||
if (!inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (0 == s_asyncRequestCount) {
|
||||
CCDirector::sharedDirector()->getScheduler()->scheduleSelector(schedule_selector(CCHttpRequest::dispatchResponseCallbacks), this, 0, false);
|
||||
}
|
||||
|
||||
++s_asyncRequestCount;
|
||||
if (pTarget) {
|
||||
pTarget->retain();
|
||||
}
|
||||
|
||||
HttpRequestPacket *packet = new HttpRequestPacket();
|
||||
packet->reqType = kHttpRequestPost;
|
||||
packet->reqId = this->reqId;
|
||||
packet->url = url;
|
||||
packet->reqData = postData;
|
||||
packet->pTarget = pTarget;
|
||||
packet->pSelector = pSelector;
|
||||
|
||||
this->reqId.clear();
|
||||
|
||||
pthread_mutex_lock(&s_requestQueueMutex);
|
||||
s_requestQueue->push(packet);
|
||||
pthread_mutex_unlock(&s_requestQueueMutex);
|
||||
|
||||
//Notify thread start to work
|
||||
sem_post(s_pSem);
|
||||
}
|
||||
|
||||
//Add post task to queue, data binary safe
|
||||
void CCHttpRequest::addPostTask(std::string &url, std::vector<char> &buffer, cocos2d::CCObject *pTarget, SEL_CallFuncND pSelector)
|
||||
{
|
||||
std::string postData = std::string((const char *)&buffer.front(), buffer.size());
|
||||
addPostTask(url, postData, pTarget, pSelector);
|
||||
}
|
||||
|
||||
//Convert const char* to string and call the matched addPostTask method
|
||||
void CCHttpRequest::addPostTask(std::string &url, const char *buffer, int32_t bufferLen, cocos2d::CCObject *pTarget, SEL_CallFuncND pSelector)
|
||||
{
|
||||
std::string postData = std::string(buffer, bufferLen);
|
||||
addPostTask(url, postData, pTarget, pSelector);
|
||||
}
|
||||
|
||||
//Add a download task to queue
|
||||
void CCHttpRequest::addDownloadTask(std::vector<std::string> &urls, CCObject *pTarget, SEL_CallFuncND pSelector)
|
||||
{
|
||||
bool init = lazyInitThreadSemphore();
|
||||
if (!init) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (0 == s_asyncRequestCount) {
|
||||
CCDirector::sharedDirector()->getScheduler()->scheduleSelector(schedule_selector(CCHttpRequest::dispatchResponseCallbacks), this, 0, false);
|
||||
}
|
||||
|
||||
++s_asyncRequestCount;
|
||||
if (pTarget) {
|
||||
pTarget->retain();
|
||||
}
|
||||
|
||||
HttpRequestPacket *packet = new HttpRequestPacket();
|
||||
packet->reqType = kHttpRequestDownloadFile;
|
||||
packet->reqId = this->reqId;
|
||||
packet->files = urls;
|
||||
packet->pTarget = pTarget;
|
||||
packet->pSelector = pSelector;
|
||||
|
||||
pthread_mutex_lock(&s_requestQueueMutex);
|
||||
s_requestQueue->push(packet);
|
||||
pthread_mutex_unlock(&s_requestQueueMutex);
|
||||
|
||||
sem_post(s_pSem);
|
||||
}
|
||||
|
||||
//Poll and notify main thread if responses exists in queue
|
||||
void CCHttpRequest::dispatchResponseCallbacks(float delta)
|
||||
{
|
||||
std::queue<HttpResponsePacket *> *pQueue = s_responseQueue;
|
||||
|
||||
pthread_mutex_lock(&s_responseQueueMutex);
|
||||
if (pQueue->empty()) {
|
||||
pthread_mutex_unlock(&s_responseQueueMutex);
|
||||
} else {
|
||||
HttpResponsePacket *packet = pQueue->front();
|
||||
pQueue->pop();
|
||||
|
||||
pthread_mutex_unlock(&s_responseQueueMutex);
|
||||
|
||||
--s_asyncRequestCount;
|
||||
if (0 == s_asyncRequestCount) {
|
||||
CCDirector::sharedDirector()->getScheduler()->unscheduleSelector(schedule_selector(CCHttpRequest::dispatchResponseCallbacks), this);
|
||||
}
|
||||
|
||||
HttpRequestPacket *orgRequest = packet->request;
|
||||
CCObject *pTarget = orgRequest->pTarget;
|
||||
SEL_CallFuncND pSelector = orgRequest->pSelector;
|
||||
|
||||
if (pTarget && pSelector) {
|
||||
(pTarget->*pSelector)((CCNode *)this, packet);
|
||||
|
||||
pTarget->release();
|
||||
}
|
||||
|
||||
delete orgRequest;
|
||||
delete packet;
|
||||
}
|
||||
}
|
||||
|
||||
NS_CC_EXT_END
|
||||
|
||||
|
|
@ -1,193 +0,0 @@
|
|||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2012 greathqy
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __CCHTTPREQUEST_H__
|
||||
#define __CCHTTPREQUEST_H__
|
||||
|
||||
#include "cocos2d.h"
|
||||
#include "ExtensionMacros.h"
|
||||
|
||||
NS_CC_EXT_BEGIN
|
||||
|
||||
/**
|
||||
* @addtogroup Network
|
||||
* @{
|
||||
*/
|
||||
|
||||
//Http request type
|
||||
typedef enum {
|
||||
kHttpRequestGet,
|
||||
kHttpRequestPost,
|
||||
kHttpRequestDownloadFile,
|
||||
} HttpRequestType;
|
||||
|
||||
//Request structure
|
||||
typedef struct {
|
||||
HttpRequestType reqType;
|
||||
std::string url;
|
||||
std::string reqData;
|
||||
std::vector<std::string> files;
|
||||
std::string reqId;
|
||||
cocos2d::CCObject *pTarget;
|
||||
cocos2d::SEL_CallFuncND pSelector;
|
||||
} HttpRequestPacket;
|
||||
|
||||
//Response structure
|
||||
typedef struct {
|
||||
HttpRequestPacket *request;
|
||||
std::string responseData;
|
||||
int32_t responseCode;
|
||||
bool succeed;
|
||||
} HttpResponsePacket;
|
||||
|
||||
/** @brief Singleton that handles asynchrounous http requests
|
||||
* Once the request completed, a callback will issued in main thread when it provided during make request
|
||||
*/
|
||||
class CC_DLL CCHttpRequest : public cocos2d::CCObject
|
||||
{
|
||||
public:
|
||||
/** Return the shared instance **/
|
||||
static CCHttpRequest *sharedHttpRequest();
|
||||
|
||||
/** Relase the shared instance **/
|
||||
static void purgeSharedHttpRequest();
|
||||
|
||||
CCHttpRequest();
|
||||
virtual ~CCHttpRequest();
|
||||
|
||||
/**
|
||||
* Add a get request to task queue
|
||||
* @param url url want to get
|
||||
* @param pTarget callback target
|
||||
* @param pSelector callback selector
|
||||
* @return NULL
|
||||
*/
|
||||
void addGetTask(std::string url, cocos2d::CCObject *pTarget, cocos2d::SEL_CallFuncND pSelector);
|
||||
|
||||
/**
|
||||
* Add a post request to task queue
|
||||
* @param url the post destination url
|
||||
* @param postData data want to post
|
||||
* @param pTarget callback target
|
||||
* @param pSelector callback selector
|
||||
* @return NULL
|
||||
*/
|
||||
void addPostTask(std::string &url, std::string &postData, cocos2d::CCObject *pTarget, cocos2d::SEL_CallFuncND pSelector);
|
||||
|
||||
/**
|
||||
* Add a post request to task queue, binary data supported
|
||||
* @param url the post destination url
|
||||
* @param buffer the data want to post
|
||||
* @param pTarget callback target
|
||||
* @param pSelector callback selector
|
||||
* @return NULL
|
||||
*/
|
||||
void addPostTask(std::string &url, std::vector<char> &buffer, cocos2d::CCObject *pTarget, cocos2d::SEL_CallFuncND pSelector);
|
||||
|
||||
/**
|
||||
* Add a post request to task queue, binary data supported
|
||||
* @param url the post destination url
|
||||
* @param buffer the data want to post
|
||||
* @param buffer the data's length
|
||||
* @param pTarget callback target
|
||||
* @param pSelector callback selector
|
||||
* @return NULL
|
||||
*/
|
||||
void addPostTask(std::string &url, const char *buffer, int32_t bufferLen, cocos2d::CCObject *pTarget, cocos2d::SEL_CallFuncND pSelector);
|
||||
|
||||
/**
|
||||
* Add a download request to task queue
|
||||
* @param url urls want to download
|
||||
* @param pTarget callback target
|
||||
* @param pSelector callback selector
|
||||
* @return NULL
|
||||
*/
|
||||
void addDownloadTask(std::vector<std::string> &urls, cocos2d::CCObject *pTarget, cocos2d::SEL_CallFuncND pSelector);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Change the connect timeout
|
||||
* @param timeout
|
||||
* @return NULL
|
||||
*/
|
||||
inline void setConnectTimeout(int32_t timeout) {m_connectTimeout = timeout;};
|
||||
|
||||
/**
|
||||
* Get connect timeout
|
||||
* @return int
|
||||
*/
|
||||
inline int32_t getConnectTimeout() {return m_connectTimeout;}
|
||||
|
||||
|
||||
/**
|
||||
* Change the download timeout
|
||||
* @param timeout
|
||||
* @return NULL
|
||||
*/
|
||||
inline void setDownloadTimeout(int32_t timeout) {m_timeout = timeout;};
|
||||
|
||||
|
||||
/**
|
||||
* Get download timeout
|
||||
* @return int
|
||||
*/
|
||||
inline int32_t getDownloadTimeout() {return m_timeout;}
|
||||
|
||||
/**
|
||||
* Set request Id
|
||||
* Used to distinguish multple requests if you don't want to provide different callbacks for each request
|
||||
* @param reqId request identifier
|
||||
* @return NULL
|
||||
*/
|
||||
inline void setReqId(const std::string reqId) {this->reqId = reqId;}
|
||||
|
||||
/**
|
||||
* Get request id
|
||||
* @return NULL
|
||||
*/
|
||||
inline const std::string& getReqId() {return this->reqId;};
|
||||
|
||||
private:
|
||||
/**
|
||||
* Init pthread mutex, semaphore, and create new thread for http requests
|
||||
* @return bool
|
||||
*/
|
||||
bool lazyInitThreadSemphore();
|
||||
/** Poll function called from main thread to dispatch callbacks when http requests finished **/
|
||||
void dispatchResponseCallbacks(float delta);
|
||||
|
||||
private:
|
||||
int32_t m_connectTimeout;
|
||||
int32_t m_timeout;
|
||||
|
||||
std::string reqId;
|
||||
};
|
||||
|
||||
// end of Network group
|
||||
/// @}
|
||||
|
||||
NS_CC_EXT_END
|
||||
|
||||
#endif //__CCHTTPREQUEST_H__
|
|
@ -0,0 +1,480 @@
|
|||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2012 greathqy
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "HttpClient.h"
|
||||
// #include "platform/CCThread.h"
|
||||
|
||||
#include <queue>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "curl/curl.h"
|
||||
|
||||
NS_CC_EXT_BEGIN
|
||||
|
||||
static pthread_t s_networkThread;
|
||||
static pthread_mutex_t s_requestQueueMutex;
|
||||
static pthread_mutex_t s_responseQueueMutex;
|
||||
static sem_t * s_pSem = NULL;
|
||||
static unsigned long s_asyncRequestCount = 0;
|
||||
|
||||
#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS
|
||||
#define CC_ASYNC_HTTPREQUEST_USE_NAMED_SEMAPHORE 1
|
||||
#else
|
||||
#define CC_ASYNC_HTTPREQUEST_USE_NAMED_SEMAPHORE 0
|
||||
#endif
|
||||
|
||||
#if CC_ASYNC_HTTPREQUEST_USE_NAMED_SEMAPHORE
|
||||
#define CC_ASYNC_HTTPREQUEST_SEMAPHORE "ccHttpAsync"
|
||||
#else
|
||||
static sem_t s_sem;
|
||||
#endif
|
||||
|
||||
static bool need_quit = false;
|
||||
|
||||
static CCArray* s_requestQueue = NULL;
|
||||
static CCArray* s_responseQueue = NULL;
|
||||
|
||||
static CCHttpClient *s_pHttpClient = NULL; // pointer to singleton
|
||||
|
||||
static char s_errorBuffer[CURL_ERROR_SIZE];
|
||||
|
||||
typedef size_t (*write_callback)(void *ptr, size_t size, size_t nmemb, void *stream);
|
||||
|
||||
|
||||
// Callback function used by libcurl for collect response data
|
||||
size_t writeData(void *ptr, size_t size, size_t nmemb, void *stream)
|
||||
{
|
||||
std::vector<char> *recvBuffer = (std::vector<char>*)stream;
|
||||
size_t sizes = size * nmemb;
|
||||
|
||||
recvBuffer->clear();
|
||||
recvBuffer->assign((char*)ptr, (char*)ptr + sizes);
|
||||
|
||||
return sizes;
|
||||
}
|
||||
|
||||
// Prototypes
|
||||
bool configureCURL(CURL *handle);
|
||||
int processGetTask(HttpRequest *task, write_callback callback, void *stream, int32_t *errorCode);
|
||||
int processPostTask(HttpRequest *task, write_callback callback, void *stream, int32_t *errorCode);
|
||||
// int processDownloadTask(HttpRequest *task, write_callback callback, void *stream, int32_t *errorCode);
|
||||
|
||||
|
||||
//Worker thread
|
||||
static void* networkThread(void *data)
|
||||
{
|
||||
HttpRequest *request = NULL;
|
||||
|
||||
while (true)
|
||||
{
|
||||
// Wait for http request tasks from main thread
|
||||
int semWaitRet = sem_wait(s_pSem);
|
||||
if (semWaitRet < 0) {
|
||||
CCLog("HttpRequest async thread semaphore error: %s\n", strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
if (need_quit)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// step 1: send http request if the requestQueue isn't empty
|
||||
request = NULL;
|
||||
|
||||
pthread_mutex_lock(&s_requestQueueMutex); //Get request task from queue
|
||||
if (0 != s_requestQueue->count())
|
||||
{
|
||||
request = dynamic_cast<HttpRequest*>(s_requestQueue->objectAtIndex(0));
|
||||
s_requestQueue->removeObjectAtIndex(0);
|
||||
}
|
||||
pthread_mutex_unlock(&s_requestQueueMutex);
|
||||
|
||||
if (NULL == request)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// step 2: libcurl sync access
|
||||
|
||||
// Create a HttpResponse object, the default setting is http access failed
|
||||
HttpResponse *response = new HttpResponse(request);
|
||||
|
||||
int responseCode = CURL_LAST;
|
||||
int retValue = 0;
|
||||
|
||||
// Process the request -> get response packet
|
||||
switch (request->getRequestType())
|
||||
{
|
||||
case HttpRequest::kHttpGet: // HTTP GET
|
||||
retValue = processGetTask(request,
|
||||
writeData,
|
||||
response->getResponseData(),
|
||||
&responseCode);
|
||||
break;
|
||||
|
||||
case HttpRequest::kHttpPost: // HTTP POST
|
||||
retValue = processPostTask(request,
|
||||
writeData,
|
||||
response->getResponseData(),
|
||||
&responseCode);
|
||||
break;
|
||||
|
||||
default:
|
||||
CCAssert(true, "CCHttpClient: unkown request type, only GET and POSt are supported");
|
||||
break;
|
||||
}
|
||||
|
||||
response->setResponseCode(responseCode);
|
||||
|
||||
if (retValue != 0)
|
||||
{
|
||||
response->setSucceed(false);
|
||||
response->setErrorBuffer(s_errorBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
response->setSucceed(true);
|
||||
}
|
||||
|
||||
// add response packet into queue
|
||||
pthread_mutex_lock(&s_responseQueueMutex);
|
||||
s_responseQueue->addObject(response);
|
||||
pthread_mutex_unlock(&s_responseQueueMutex);
|
||||
|
||||
// resume dispatcher selector
|
||||
CCDirector::sharedDirector()->getScheduler()->resumeTarget(CCHttpClient::getInstance());
|
||||
}
|
||||
|
||||
// cleanup: if worker thread received quit signal, clean up un-completed request queue
|
||||
pthread_mutex_lock(&s_requestQueueMutex);
|
||||
|
||||
CCObject* pObj = NULL;
|
||||
CCARRAY_FOREACH(s_requestQueue, pObj)
|
||||
{
|
||||
HttpRequest* request = dynamic_cast<HttpRequest*>(pObj);
|
||||
request->getTarget()->release();
|
||||
s_asyncRequestCount--;
|
||||
}
|
||||
s_requestQueue->removeAllObjects();
|
||||
|
||||
pthread_mutex_unlock(&s_requestQueueMutex);
|
||||
|
||||
|
||||
if (s_pSem != NULL) {
|
||||
#if CC_ASYNC_HTTPREQUEST_USE_NAMED_SEMAPHORE
|
||||
sem_unlink(CC_ASYNC_HTTPREQUEST_SEMAPHORE);
|
||||
sem_close(s_pSem);
|
||||
#else
|
||||
sem_destroy(s_pSem);
|
||||
#endif
|
||||
|
||||
s_pSem = NULL;
|
||||
|
||||
pthread_mutex_destroy(&s_requestQueueMutex);
|
||||
pthread_mutex_destroy(&s_responseQueueMutex);
|
||||
|
||||
s_requestQueue->release();
|
||||
s_responseQueue->release();
|
||||
}
|
||||
|
||||
pthread_exit(NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Configure curl's timeout property
|
||||
bool configureCURL(CURL *handle)
|
||||
{
|
||||
if (!handle) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t code;
|
||||
code = curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, s_errorBuffer);
|
||||
if (code != CURLE_OK) {
|
||||
return false;
|
||||
}
|
||||
code = curl_easy_setopt(handle, CURLOPT_TIMEOUT, CCHttpClient::getInstance()->getTimeoutForRead());
|
||||
if (code != CURLE_OK) {
|
||||
return false;
|
||||
}
|
||||
code = curl_easy_setopt(handle, CURLOPT_CONNECTTIMEOUT, CCHttpClient::getInstance()->getTimeoutForConnect());
|
||||
if (code != CURLE_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//Process Get Request
|
||||
int processGetTask(HttpRequest *request, write_callback callback, void *stream, int *responseCode)
|
||||
{
|
||||
CURLcode code = CURL_LAST;
|
||||
CURL *curl = curl_easy_init();
|
||||
|
||||
do {
|
||||
if (!configureCURL(curl))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
code = curl_easy_setopt(curl, CURLOPT_URL, request->getUrl());
|
||||
if (code != CURLE_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
code = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback);
|
||||
if (code != CURLE_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
code = curl_easy_setopt(curl, CURLOPT_WRITEDATA, stream);
|
||||
if (code != CURLE_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
code = curl_easy_perform(curl);
|
||||
if (code != CURLE_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
code = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, responseCode);
|
||||
if (code != CURLE_OK || *responseCode != 200)
|
||||
{
|
||||
code = CURLE_HTTP_RETURNED_ERROR;
|
||||
}
|
||||
} while (0);
|
||||
|
||||
if (curl) {
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
return (code == CURLE_OK ? 0 : 1);
|
||||
}
|
||||
|
||||
//Process POST Request
|
||||
int processPostTask(HttpRequest *request, write_callback callback, void *stream, int32_t *responseCode)
|
||||
{
|
||||
CURLcode code = CURL_LAST;
|
||||
CURL *curl = curl_easy_init();
|
||||
|
||||
do {
|
||||
if (!configureCURL(curl)) {
|
||||
break;
|
||||
}
|
||||
|
||||
code = curl_easy_setopt(curl, CURLOPT_URL, request->getUrl());
|
||||
if (code != CURLE_OK) {
|
||||
break;
|
||||
}
|
||||
code = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback);
|
||||
if (code != CURLE_OK) {
|
||||
break;
|
||||
}
|
||||
code = curl_easy_setopt(curl, CURLOPT_WRITEDATA, stream);
|
||||
if (code != CURLE_OK) {
|
||||
break;
|
||||
}
|
||||
code = curl_easy_setopt(curl, CURLOPT_POST, 1);
|
||||
if (code != CURLE_OK) {
|
||||
break;
|
||||
}
|
||||
code = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request->getRequestData());
|
||||
if (code != CURLE_OK) {
|
||||
break;
|
||||
}
|
||||
code = curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, request->getRequestDataSize());
|
||||
if (code != CURLE_OK) {
|
||||
break;
|
||||
}
|
||||
code = curl_easy_perform(curl);
|
||||
if (code != CURLE_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
code = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, responseCode);
|
||||
if (code != CURLE_OK || *responseCode != 200) {
|
||||
code = CURLE_HTTP_RETURNED_ERROR;
|
||||
}
|
||||
} while (0);
|
||||
if (curl) {
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
return (code == CURLE_OK ? 0 : 1);
|
||||
}
|
||||
|
||||
// HttpClient implementation
|
||||
CCHttpClient* CCHttpClient::getInstance()
|
||||
{
|
||||
if (s_pHttpClient == NULL) {
|
||||
s_pHttpClient = new CCHttpClient();
|
||||
}
|
||||
|
||||
return s_pHttpClient;
|
||||
}
|
||||
|
||||
void CCHttpClient::destroyInstance()
|
||||
{
|
||||
CC_SAFE_RELEASE_NULL(s_pHttpClient);
|
||||
}
|
||||
|
||||
CCHttpClient::CCHttpClient()
|
||||
:_timeoutForRead(60)
|
||||
,_timeoutForConnect(30)
|
||||
{
|
||||
CCDirector::sharedDirector()->getScheduler()->scheduleSelector(
|
||||
schedule_selector(CCHttpClient::dispatchResponseCallbacks), this, 0, false);
|
||||
CCDirector::sharedDirector()->getScheduler()->pauseTarget(this);
|
||||
}
|
||||
|
||||
CCHttpClient::~CCHttpClient()
|
||||
{
|
||||
need_quit = true;
|
||||
|
||||
if (s_pSem != NULL) {
|
||||
sem_post(s_pSem);
|
||||
}
|
||||
|
||||
CCDirector::sharedDirector()->getScheduler()->unscheduleSelector(schedule_selector(CCHttpClient::dispatchResponseCallbacks), this);
|
||||
}
|
||||
|
||||
//Lazy create semaphore & mutex & thread
|
||||
bool CCHttpClient::lazyInitThreadSemphore()
|
||||
{
|
||||
if (s_pSem != NULL) {
|
||||
return true;
|
||||
} else {
|
||||
#if CC_ASYNC_HTTPREQUEST_USE_NAMED_SEMAPHORE
|
||||
s_pSem = sem_open(CC_ASYNC_HTTPREQUEST_SEMAPHORE, O_CREAT, 0644, 0);
|
||||
if (s_pSem == SEM_FAILED) {
|
||||
CCLog("Open HttpRequest Semaphore failed");
|
||||
s_pSem = NULL;
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
int semRet = sem_init(&s_sem, 0, 0);
|
||||
if (semRet < 0) {
|
||||
CCLog("Init HttpRequest Semaphore failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_pSem = &s_sem;
|
||||
#endif
|
||||
|
||||
s_requestQueue = new CCArray();
|
||||
s_requestQueue->init();
|
||||
|
||||
s_responseQueue = new CCArray();
|
||||
s_responseQueue->init();
|
||||
|
||||
pthread_mutex_init(&s_requestQueueMutex, NULL);
|
||||
pthread_mutex_init(&s_responseQueueMutex, NULL);
|
||||
|
||||
pthread_create(&s_networkThread, NULL, networkThread, NULL);
|
||||
pthread_detach(s_networkThread);
|
||||
|
||||
need_quit = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//Add a get task to queue
|
||||
void CCHttpClient::send(HttpRequest* request)
|
||||
{
|
||||
if (false == lazyInitThreadSemphore())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!request)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
++s_asyncRequestCount;
|
||||
|
||||
request->retain();
|
||||
if (request->getTarget())
|
||||
{
|
||||
request->getTarget()->retain();
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&s_requestQueueMutex);
|
||||
s_requestQueue->addObject(request);
|
||||
pthread_mutex_unlock(&s_requestQueueMutex);
|
||||
|
||||
// Notify thread start to work
|
||||
sem_post(s_pSem);
|
||||
}
|
||||
|
||||
// Poll and notify main thread if responses exists in queue
|
||||
void CCHttpClient::dispatchResponseCallbacks(float delta)
|
||||
{
|
||||
CCLog("CCHttpClient::dispatchResponseCallbacks is running");
|
||||
HttpResponse* response = NULL;
|
||||
|
||||
pthread_mutex_lock(&s_responseQueueMutex);
|
||||
if (s_responseQueue->count())
|
||||
{
|
||||
response = dynamic_cast<HttpResponse*>(s_responseQueue->objectAtIndex(0));
|
||||
s_responseQueue->removeObjectAtIndex(0);
|
||||
}
|
||||
pthread_mutex_unlock(&s_responseQueueMutex);
|
||||
|
||||
if (response)
|
||||
{
|
||||
--s_asyncRequestCount;
|
||||
|
||||
HttpRequest *request = response->getHttpRequest();
|
||||
CCObject *pTarget = request->getTarget();
|
||||
SEL_CallFuncND pSelector = request->getSelector();
|
||||
|
||||
if (pTarget && pSelector)
|
||||
{
|
||||
(pTarget->*pSelector)((CCNode *)this, response);
|
||||
}
|
||||
|
||||
response->release();
|
||||
}
|
||||
|
||||
if (0 == s_asyncRequestCount)
|
||||
{
|
||||
CCDirector::sharedDirector()->getScheduler()->pauseTarget(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
NS_CC_EXT_END
|
||||
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2012 greathqy
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __CCHTTPREQUEST_H__
|
||||
#define __CCHTTPREQUEST_H__
|
||||
|
||||
#include "cocos2d.h"
|
||||
#include "ExtensionMacros.h"
|
||||
|
||||
#include "HttpRequest.h"
|
||||
#include "HttpResponse.h"
|
||||
|
||||
NS_CC_EXT_BEGIN
|
||||
|
||||
/**
|
||||
* @addtogroup Network
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
/** @brief Singleton that handles asynchrounous http requests
|
||||
* Once the request completed, a callback will issued in main thread when it provided during make request
|
||||
*/
|
||||
class CC_DLL CCHttpClient : public cocos2d::CCObject
|
||||
{
|
||||
public:
|
||||
/** Return the shared instance **/
|
||||
static CCHttpClient *getInstance();
|
||||
|
||||
/** Relase the shared instance **/
|
||||
static void destroyInstance();
|
||||
|
||||
/**
|
||||
* Add a get request to task queue
|
||||
* @param request a HttpRequest object, which includes url, response callback etc.
|
||||
* @return NULL
|
||||
*/
|
||||
void send(HttpRequest* request);
|
||||
|
||||
|
||||
/**
|
||||
* Add a download request to task queue
|
||||
* @param url urls want to download
|
||||
* @param pTarget callback target
|
||||
* @param pSelector callback selector
|
||||
* @return NULL
|
||||
|
||||
void addDownloadTask(std::vector<std::string> &urls, cocos2d::CCObject *pTarget, cocos2d::SEL_CallFuncND pSelector);
|
||||
*/
|
||||
|
||||
/**
|
||||
* Change the connect timeout
|
||||
* @param timeout
|
||||
* @return NULL
|
||||
*/
|
||||
inline void setTimeoutForConnect(int value) {_timeoutForConnect = value;};
|
||||
|
||||
/**
|
||||
* Get connect timeout
|
||||
* @return int
|
||||
*
|
||||
*/
|
||||
inline int getTimeoutForConnect() {return _timeoutForConnect;}
|
||||
|
||||
|
||||
/**
|
||||
* Change the download timeout
|
||||
* @param timeout
|
||||
* @return NULL
|
||||
*/
|
||||
inline void setTimeoutForRead(int value) {_timeoutForRead = value;};
|
||||
|
||||
|
||||
/**
|
||||
* Get download timeout
|
||||
* @return int
|
||||
*/
|
||||
inline int getTimeoutForRead() {return _timeoutForRead;};
|
||||
|
||||
private:
|
||||
CCHttpClient();
|
||||
virtual ~CCHttpClient();
|
||||
bool init(void);
|
||||
|
||||
/**
|
||||
* Init pthread mutex, semaphore, and create new thread for http requests
|
||||
* @return bool
|
||||
*/
|
||||
bool lazyInitThreadSemphore();
|
||||
/** Poll function called from main thread to dispatch callbacks when http requests finished **/
|
||||
void dispatchResponseCallbacks(float delta);
|
||||
|
||||
private:
|
||||
int _timeoutForConnect;
|
||||
int _timeoutForRead;
|
||||
|
||||
// std::string reqId;
|
||||
};
|
||||
|
||||
// end of Network group
|
||||
/// @}
|
||||
|
||||
NS_CC_EXT_END
|
||||
|
||||
#endif //__CCHTTPREQUEST_H__
|
|
@ -0,0 +1,175 @@
|
|||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
//Http request type
|
||||
typedef enum {
|
||||
kHttpRequestGet,
|
||||
kHttpRequestPost,
|
||||
// kHttpRequestDownloadFile,
|
||||
} HttpRequestType;
|
||||
|
||||
/// Http Request structure
|
||||
typedef struct {
|
||||
HttpRequestType requestType; /// kHttpRequestGet, kHttpRequestPost or other enums
|
||||
std::string url; /// target url that this request is sent to
|
||||
std::vector<char> requestData; /// used for POST
|
||||
std::string tag; /// user defined tag, to identify different requests in response callback
|
||||
cocos2d::CCObject* pTarget; /// callback target of pSelector function
|
||||
cocos2d::SEL_CallFuncND pSelector; /// callback function, e.g. MyLayer::onHttpResponse(CCObject *sender, void *data)
|
||||
void* pUserData; /// You can add your customed data here
|
||||
} HttpRequestPacket;
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __HTTP_REQUEST_H__
|
||||
#define __HTTP_REQUEST_H__
|
||||
|
||||
#include "cocos2d.h"
|
||||
#include "ExtensionMacros.h"
|
||||
|
||||
NS_CC_EXT_BEGIN
|
||||
|
||||
class HttpRequest : public cocos2d::CCObject
|
||||
{
|
||||
public:
|
||||
/** Use this enum type as param in setReqeustType(param) */
|
||||
typedef enum
|
||||
{
|
||||
kHttpGet,
|
||||
kHttpPost,
|
||||
kHttpUnkown,
|
||||
} HttpRequestType;
|
||||
|
||||
HttpRequest()
|
||||
{
|
||||
_requestType = kHttpUnkown;
|
||||
_url.clear();
|
||||
_requestData.clear();
|
||||
_tag.clear();
|
||||
_pTarget = NULL;
|
||||
_pSelector = NULL;
|
||||
_pUserData = NULL;
|
||||
};
|
||||
|
||||
virtual ~HttpRequest()
|
||||
{
|
||||
if (_pTarget)
|
||||
{
|
||||
_pTarget->release();
|
||||
}
|
||||
};
|
||||
|
||||
/** override autorelease method to avoid developers to call it */
|
||||
CCObject* autorelease(void)
|
||||
{
|
||||
CCAssert(true, "HttpResponse is used between network thread and ui thread \
|
||||
therefore, autorelease is forbidden here");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// setter/getters for properties
|
||||
|
||||
inline void setRequestType(HttpRequestType type)
|
||||
{
|
||||
_requestType = type;
|
||||
};
|
||||
inline HttpRequestType getRequestType()
|
||||
{
|
||||
return _requestType;
|
||||
};
|
||||
|
||||
inline void setUrl(const char* url)
|
||||
{
|
||||
_url = url;
|
||||
};
|
||||
inline const char* getUrl()
|
||||
{
|
||||
return _url.c_str();
|
||||
};
|
||||
|
||||
inline void setRequestData(const char* buffer, unsigned int len)
|
||||
{
|
||||
_requestData.assign(buffer, buffer + len);
|
||||
};
|
||||
inline char* getRequestData()
|
||||
{
|
||||
return &(_requestData.front());
|
||||
}
|
||||
inline int getRequestDataSize()
|
||||
{
|
||||
return _requestData.size();
|
||||
}
|
||||
|
||||
inline void setTag(const char* tag)
|
||||
{
|
||||
_tag = tag;
|
||||
};
|
||||
inline const char* getTag()
|
||||
{
|
||||
return _tag.c_str();
|
||||
};
|
||||
|
||||
inline void setUserData(void* pUserData)
|
||||
{
|
||||
_pUserData = pUserData;
|
||||
};
|
||||
inline void* getUserData()
|
||||
{
|
||||
return _pUserData;
|
||||
};
|
||||
|
||||
inline void setResponseCallback(cocos2d::CCObject* pTarget, cocos2d::SEL_CallFuncND pSelector)
|
||||
{
|
||||
_pTarget = pTarget;
|
||||
_pSelector = pSelector;
|
||||
|
||||
if (_pTarget)
|
||||
{
|
||||
_pTarget->retain();
|
||||
}
|
||||
}
|
||||
inline CCObject* getTarget()
|
||||
{
|
||||
return _pTarget;
|
||||
}
|
||||
inline cocos2d::SEL_CallFuncND getSelector()
|
||||
{
|
||||
return _pSelector;
|
||||
}
|
||||
|
||||
protected:
|
||||
// properties
|
||||
HttpRequestType _requestType; /// kHttpRequestGet, kHttpRequestPost or other enums
|
||||
std::string _url; /// target url that this request is sent to
|
||||
std::vector<char> _requestData; /// used for POST
|
||||
std::string _tag; /// user defined tag, to identify different requests in response callback
|
||||
cocos2d::CCObject* _pTarget; /// callback target of pSelector function
|
||||
cocos2d::SEL_CallFuncND _pSelector; /// callback function, e.g. MyLayer::onHttpResponse(CCObject *sender, void *data)
|
||||
void* _pUserData; /// You can add your customed data here
|
||||
};
|
||||
|
||||
NS_CC_EXT_END
|
||||
|
||||
#endif //__HTTP_REQUEST_H__
|
|
@ -0,0 +1,121 @@
|
|||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __HTTP_RESPONSE__
|
||||
#define __HTTP_RESPONSE__
|
||||
|
||||
#include "cocos2d.h"
|
||||
#include "ExtensionMacros.h"
|
||||
#include "HttpRequest.h"
|
||||
|
||||
NS_CC_EXT_BEGIN
|
||||
|
||||
class HttpResponse : public cocos2d::CCObject
|
||||
{
|
||||
public:
|
||||
HttpResponse(HttpRequest* request)
|
||||
{
|
||||
_pHttpRequest = request;
|
||||
if (_pHttpRequest)
|
||||
{
|
||||
_pHttpRequest->retain();
|
||||
}
|
||||
|
||||
_succeed = false;
|
||||
_responseData.clear();
|
||||
_errorBuffer.clear();
|
||||
}
|
||||
virtual ~HttpResponse()
|
||||
{
|
||||
if (_pHttpRequest)
|
||||
{
|
||||
_pHttpRequest->release();
|
||||
}
|
||||
}
|
||||
|
||||
/** override autorelease method to prevent developers from calling it */
|
||||
CCObject* autorelease(void)
|
||||
{
|
||||
CCAssert(true, "HttpResponse is used between network thread and ui thread \
|
||||
therefore, autorelease is forbidden here");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// setters,getters for properties
|
||||
inline HttpRequest* getHttpRequest()
|
||||
{
|
||||
return _pHttpRequest;
|
||||
}
|
||||
|
||||
inline void setSucceed(bool value)
|
||||
{
|
||||
_succeed = value;
|
||||
};
|
||||
inline bool isSucceed()
|
||||
{
|
||||
return _succeed;
|
||||
};
|
||||
|
||||
inline void setResponseData(std::vector<char>* data)
|
||||
{
|
||||
_responseData = *data;
|
||||
}
|
||||
inline std::vector<char>* getResponseData()
|
||||
{
|
||||
return &_responseData;
|
||||
}
|
||||
|
||||
inline void setResponseCode(int value)
|
||||
{
|
||||
_responseCode = value;
|
||||
}
|
||||
inline int getResponseCode()
|
||||
{
|
||||
return _responseCode;
|
||||
}
|
||||
|
||||
inline void setErrorBuffer(const char* value)
|
||||
{
|
||||
_errorBuffer.clear();
|
||||
_errorBuffer.assign(value);
|
||||
};
|
||||
inline const char* getErrorBuffer()
|
||||
{
|
||||
return _errorBuffer.c_str();
|
||||
}
|
||||
|
||||
protected:
|
||||
bool initWithRequest(HttpRequest* request);
|
||||
|
||||
// properties
|
||||
HttpRequest* _pHttpRequest; /// the corresponding HttpRequest pointer who leads to this response
|
||||
bool _succeed;
|
||||
std::vector<char> _responseData;
|
||||
int _responseCode; /// the CURLcode returned from libcurl
|
||||
std::string _errorBuffer; /// if _responseCode != 200, please read _errorBuffer to find the reason
|
||||
};
|
||||
|
||||
NS_CC_EXT_END
|
||||
|
||||
#endif //__HTTP_RESPONSE_H__
|
|
@ -28,7 +28,9 @@
|
|||
#include "GUI/CCControlExtension/CCControlExtensions.h"
|
||||
#include "GUI/CCScrollView/CCScrollView.h"
|
||||
|
||||
#include "Network/CCHttpRequest/CCHttpRequest.h"
|
||||
#include "network/HttpRequest.h"
|
||||
#include "network/HttpResponse.h"
|
||||
#include "network/HttpClient.h"
|
||||
|
||||
#endif /* __COCOS2D_EXT_H__ */
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "NotificationCenterTest/NotificationCenterTest.h"
|
||||
#include "ControlExtensionTest/CCControlSceneManager.h"
|
||||
#include "CocosBuilderTest/CocosBuilderTest.h"
|
||||
#include "HttpRequestTest/HttpRequestTest.h"
|
||||
#include "NetworkTest/HttpRequestTest.h"
|
||||
|
||||
enum
|
||||
{
|
||||
|
|
|
@ -38,12 +38,6 @@ HttpRequestTest::HttpRequestTest() : m_labelStatusCode(NULL)
|
|||
itemPostBinary->setPosition(ccp(winSize.width / 2, winSize.height - 160));
|
||||
menuRequest->addChild(itemPostBinary);
|
||||
|
||||
//Download File
|
||||
CCLabelTTF *labelDownload = CCLabelTTF::create("Test Download", "Arial", 15);
|
||||
CCMenuItemLabel *itemDownload = CCMenuItemLabel::create(labelDownload, this, menu_selector(HttpRequestTest::onLabelDownloadTestClicked));
|
||||
itemDownload->setPosition(ccp(winSize.width / 2, winSize.height - 190));
|
||||
menuRequest->addChild(itemDownload);
|
||||
|
||||
//Response Code Label
|
||||
CCLabelTTF *labelStatus = CCLabelTTF::create("Notice: Replace Post Url With Your Own", "Marker Felt", 20);
|
||||
labelStatus->setPosition(ccp(winSize.width / 2, winSize.height - 250));
|
||||
|
@ -59,26 +53,65 @@ HttpRequestTest::HttpRequestTest() : m_labelStatusCode(NULL)
|
|||
}
|
||||
|
||||
void HttpRequestTest::onLabelGetTestClicked(cocos2d::CCObject *sender)
|
||||
{
|
||||
string url = GETURL;
|
||||
{
|
||||
/*****
|
||||
test 1
|
||||
******/
|
||||
|
||||
CCHttpRequest *requestor = CCHttpRequest::sharedHttpRequest();
|
||||
requestor->addGetTask(url, this, callfuncND_selector(HttpRequestTest::onHttpRequestCompleted));
|
||||
HttpRequest* request1 = new HttpRequest();
|
||||
// required fields
|
||||
request1->setUrl("http://www.google.com");
|
||||
request1->setRequestType(HttpRequest::kHttpGet);
|
||||
request1->setResponseCallback(this, callfuncND_selector(HttpRequestTest::onHttpRequestCompleted));
|
||||
// optional fields
|
||||
request1->setTag("HttpTest: GET");
|
||||
|
||||
CCHttpClient::getInstance()->send(request1);
|
||||
|
||||
// don't forget to release it, pair to new
|
||||
request1->release();
|
||||
|
||||
/*****
|
||||
test 2
|
||||
******/
|
||||
HttpRequest* request2 = new HttpRequest();
|
||||
request2->setUrl("http://www.baidu.com");
|
||||
request2->setRequestType(HttpRequest::kHttpGet);
|
||||
request2->setResponseCallback(this, callfuncND_selector(HttpRequestTest::onHttpRequestCompleted));
|
||||
CCHttpClient::getInstance()->send(request2);
|
||||
request2->release();
|
||||
|
||||
/*****
|
||||
test 3
|
||||
******/
|
||||
HttpRequest* request3 = new HttpRequest();
|
||||
request3->setUrl("http://just-make-this-request-failed.com");
|
||||
request3->setRequestType(HttpRequest::kHttpGet);
|
||||
request3->setResponseCallback(this, callfuncND_selector(HttpRequestTest::onHttpRequestCompleted));
|
||||
CCHttpClient::getInstance()->send(request3);
|
||||
request3->release();
|
||||
|
||||
}
|
||||
|
||||
void HttpRequestTest::onLabelPostTestClicked(cocos2d::CCObject *sender)
|
||||
{
|
||||
string url = POSTURL;
|
||||
string content = "username=hello&password=world";
|
||||
const char* content = "username=a\0b";
|
||||
|
||||
CCHttpRequest *requestor = CCHttpRequest::sharedHttpRequest();
|
||||
//You may name the request
|
||||
requestor->setReqId("login");
|
||||
requestor->addPostTask(url, content, this, callfuncND_selector(HttpRequestTest::onHttpRequestCompleted));
|
||||
HttpRequest* request = new HttpRequest();
|
||||
request->autorelease();
|
||||
|
||||
request->setUrl(POSTURL);
|
||||
request->setRequestData(content, strlen(content) + 2);
|
||||
request->setResponseCallback(this, callfuncND_selector(HttpRequestTest::onHttpRequestCompleted));
|
||||
|
||||
request->setTag("HttpTest: POST");
|
||||
|
||||
CCHttpClient::getInstance()->send(request);
|
||||
}
|
||||
|
||||
void HttpRequestTest::onLabelPostBinaryTestClicked(cocos2d::CCObject *sender)
|
||||
{
|
||||
/*
|
||||
string url = POSTURL;
|
||||
const char *content = "username=a\0b";
|
||||
|
||||
|
@ -91,45 +124,56 @@ void HttpRequestTest::onLabelPostBinaryTestClicked(cocos2d::CCObject *sender)
|
|||
vec.insert(vec.end(), content, content + strlen(content) + 2);
|
||||
requestor->setReqId("postbinary");
|
||||
requestor->addPostTask(url, vec, this, callfuncND_selector(HttpRequestTest::onHttpRequestCompleted));
|
||||
}
|
||||
|
||||
void HttpRequestTest::onLabelDownloadTestClicked(cocos2d::CCObject *sender)
|
||||
{
|
||||
string url = DOWNLOADURL;
|
||||
vector<string> files;
|
||||
|
||||
files.push_back(url);
|
||||
|
||||
CCHttpRequest *requestor = CCHttpRequest::sharedHttpRequest();
|
||||
requestor->setReqId("download");
|
||||
requestor->addDownloadTask(files, this, callfuncND_selector(HttpRequestTest::onHttpRequestCompleted));
|
||||
*/
|
||||
}
|
||||
|
||||
void HttpRequestTest::onHttpRequestCompleted(cocos2d::CCObject *sender, void *data)
|
||||
{
|
||||
HttpResponsePacket *response = (HttpResponsePacket *)data;
|
||||
|
||||
//You can get original request type from: response->request->reqType
|
||||
|
||||
if (response->request->reqId != "") {
|
||||
CCLog("%s completed", response->request->reqId.c_str());
|
||||
}
|
||||
|
||||
char buffer[128];
|
||||
sprintf(buffer, "Response code: %d", response->responseCode);
|
||||
getLabelStatusCode()->setString(buffer);
|
||||
|
||||
if (!response->succeed) {
|
||||
HttpResponse *response = (HttpResponse*)data;
|
||||
|
||||
if (!response)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// You can get original request type from: response->request->reqType
|
||||
if (0 != strlen(response->getHttpRequest()->getTag()))
|
||||
{
|
||||
CCLog("%s completed", response->getHttpRequest()->getTag());
|
||||
}
|
||||
|
||||
CCLog("response code: %d", response->getResponseCode());
|
||||
|
||||
if (!response->isSucceed())
|
||||
{
|
||||
CCLog("response failed");
|
||||
CCLog("error buffer: %s", response->getErrorBuffer());
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<char> *buffer = response->getResponseData();
|
||||
printf("Http Test, dump data: ");
|
||||
for (int i = 0; i < buffer->size(); i++)
|
||||
{
|
||||
printf("%c", (*buffer)[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// dump response data
|
||||
|
||||
|
||||
//If the response is binary, use response->responseData.data() and response->responseData.length()
|
||||
//To process the response
|
||||
|
||||
/*
|
||||
if (response->responseData.length() >= kMaxLogLen) {
|
||||
response->responseData = response->responseData.substr(0, kMaxLogLen / 2);
|
||||
}
|
||||
CCLog("Response Content: %s", response->responseData.c_str());
|
||||
*/
|
||||
|
||||
// CCLog("Response Content: %s", response->responseData.begin());
|
||||
|
||||
/*
|
||||
if (response->request->reqId == "postbinary") {
|
||||
int32_t length = response->responseData.length();
|
||||
const char *data = response->responseData.data();
|
||||
|
@ -138,13 +182,8 @@ void HttpRequestTest::onHttpRequestCompleted(cocos2d::CCObject *sender, void *da
|
|||
CCLog("%c", data[i]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if (response->request->reqId == "download") {
|
||||
string downloaded = response->request->files[0];
|
||||
string saved = downloaded.substr(downloaded.rfind("/") + 1);
|
||||
|
||||
CCLog("%s downloaded, and saved as %s in your application's writeable directory", downloaded.c_str(), saved.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void HttpRequestTest::toExtensionsMainLayer(cocos2d::CCObject *sender)
|
|
@ -1 +1 @@
|
|||
eae8f176936098bc77ca4472b94f9e018f5c368c
|
||||
afa666f94104aca6725fb837f7c037ba586c0fbd
|
Loading…
Reference in New Issue