From 24136dc57593ae8489cd0ad4e8a928b6f5c9adfd Mon Sep 17 00:00:00 2001 From: qingyun Date: Sat, 4 Aug 2012 18:27:27 +0800 Subject: [PATCH] add CCHttpRequest and related tests to repository --- .../Network/CCHttpRequest/CCHttpRequest.cpp | 576 ++++++++++++++++++ .../Network/CCHttpRequest/CCHttpRequest.h | 185 ++++++ extensions/cocos-ext.h | 2 + .../Classes/ExtensionsTest/ExtensionsTest.cpp | 7 + .../HttpRequestTest/HttpRequestTest.cpp | 155 ++++- .../HttpRequestTest/HttpRequestTest.h | 32 +- .../project.pbxproj.REMOVED.git-id | 2 +- 7 files changed, 940 insertions(+), 19 deletions(-) create mode 100644 extensions/Network/CCHttpRequest/CCHttpRequest.cpp create mode 100644 extensions/Network/CCHttpRequest/CCHttpRequest.h diff --git a/extensions/Network/CCHttpRequest/CCHttpRequest.cpp b/extensions/Network/CCHttpRequest/CCHttpRequest.cpp new file mode 100644 index 0000000000..af2ec811ed --- /dev/null +++ b/extensions/Network/CCHttpRequest/CCHttpRequest.cpp @@ -0,0 +1,576 @@ +/**************************************************************************** + 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 +#include +#include +#include +#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 *s_requestQueue = NULL; +static std::queue *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 *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::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(); + s_responseQueue = new std::queue(); + + 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 &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 &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 *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 + + diff --git a/extensions/Network/CCHttpRequest/CCHttpRequest.h b/extensions/Network/CCHttpRequest/CCHttpRequest.h new file mode 100644 index 0000000000..01d55e6bb3 --- /dev/null +++ b/extensions/Network/CCHttpRequest/CCHttpRequest.h @@ -0,0 +1,185 @@ +/**************************************************************************** + 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 + +//Http request type +typedef enum { + kHttpRequestGet, + kHttpRequestPost, + kHttpRequestDownloadFile, +} HttpRequestType; + +//Request structure +typedef struct { + HttpRequestType reqType; + std::string url; + std::string reqData; + std::vector 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 &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 &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; +}; + +NS_CC_EXT_END + +#endif //__CCHTTPREQUEST_H__ diff --git a/extensions/cocos-ext.h b/extensions/cocos-ext.h index 4b9f2e4e84..6c6db6fd2d 100644 --- a/extensions/cocos-ext.h +++ b/extensions/cocos-ext.h @@ -28,5 +28,7 @@ #include "GUI/CCControlExtension/CCControlExtensions.h" #include "GUI/CCScrollView/CCScrollView.h" +#include "Network/CCHttpRequest/CCHttpRequest.h" + #endif /* __COCOS2D_EXT_H__ */ diff --git a/samples/TestCpp/Classes/ExtensionsTest/ExtensionsTest.cpp b/samples/TestCpp/Classes/ExtensionsTest/ExtensionsTest.cpp index 018fefb1d2..18474386e0 100644 --- a/samples/TestCpp/Classes/ExtensionsTest/ExtensionsTest.cpp +++ b/samples/TestCpp/Classes/ExtensionsTest/ExtensionsTest.cpp @@ -3,6 +3,7 @@ #include "NotificationCenterTest/NotificationCenterTest.h" #include "ControlExtensionTest/CCControlSceneManager.h" #include "CocosBuilderTest/CocosBuilderTest.h" +#include "HttpRequestTest/HttpRequestTest.h" enum { @@ -15,6 +16,7 @@ enum TEST_NOTIFICATIONCENTER = 0, TEST_CCCONTROLBUTTON, TEST_COCOSBUILDER, + TEST_HTTPREQUEST, TEST_MAX_COUNT, }; @@ -23,6 +25,7 @@ static const std::string testsName[TEST_MAX_COUNT] = "NotificationCenterTest", "CCControlButtonTest", "CocosBuilderTest", + "HttpRequestTest", }; //////////////////////////////////////////////////////// @@ -80,6 +83,10 @@ void ExtensionsMainLayer::menuCallback(CCObject* pSender) } } break; + case TEST_HTTPREQUEST: + { + runHttpRequestTest(); + } default: break; } diff --git a/samples/TestCpp/Classes/ExtensionsTest/HttpRequestTest/HttpRequestTest.cpp b/samples/TestCpp/Classes/ExtensionsTest/HttpRequestTest/HttpRequestTest.cpp index 51f0d4c335..a264e387e8 100644 --- a/samples/TestCpp/Classes/ExtensionsTest/HttpRequestTest/HttpRequestTest.cpp +++ b/samples/TestCpp/Classes/ExtensionsTest/HttpRequestTest/HttpRequestTest.cpp @@ -1,9 +1,148 @@ -// -// HttpRequestTest.cpp -// TestCpp -// -// Created by qingyun on 12-8-4. -// Copyright (c) 2012年 __MyCompanyName__. All rights reserved. -// +#include "HttpRequestTest.h" +#include "../ExtensionsTest.h" + +#define GETURL "http://www.google.com" +#define POSTURL "http://www.replacewithyours.com/post.php" +#define DOWNLOADURL "http://www.google.com/index.html" + +USING_NS_CC; +USING_NS_CC_EXT; + +HttpRequestTest::HttpRequestTest() : m_labelStatusCode(NULL) +{ + CCSize winSize = CCDirector::sharedDirector()->getWinSize(); + + CCLabelTTF *label = CCLabelTTF::create("Http Request Test", "Arial", 28); + label->setPosition(ccp(winSize.width / 2, winSize.height - 50)); + addChild(label, 0); + + CCMenu *menuRequest = CCMenu::create(); + menuRequest->setPosition(CCPointZero); + addChild(menuRequest); + + //Get + CCLabelTTF *labelGet = CCLabelTTF::create("Test Get", "Arial", 15); + CCMenuItemLabel *itemGet = CCMenuItemLabel::create(labelGet, this, menu_selector(HttpRequestTest::onLabelGetTestClicked)); + itemGet->setPosition(ccp(winSize.width / 2, winSize.height - 100)); + menuRequest->addChild(itemGet); + + //Post + CCLabelTTF *labelPost = CCLabelTTF::create("Test Post", "Arial", 15); + CCMenuItemLabel *itemPost = CCMenuItemLabel::create(labelPost, this, menu_selector(HttpRequestTest::onLabelPostTestClicked)); + itemPost->setPosition(ccp(winSize.width / 2, winSize.height - 130)); + menuRequest->addChild(itemPost); + + //Post Binary + CCLabelTTF *labelPostBinary = CCLabelTTF::create("Test Post Binary", "Arial", 15); + CCMenuItemLabel *itemPostBinary = CCMenuItemLabel::create(labelPostBinary, this, menu_selector(HttpRequestTest::onLabelPostBinaryTestClicked)); + 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)); + addChild(labelStatus); + setLabelStatusCode(labelStatus); + + //Back Menu + CCMenuItemFont *itemBack = CCMenuItemFont::create("Back", this, menu_selector(HttpRequestTest::toExtensionsMainLayer)); + itemBack->setPosition(ccp(winSize.width - 50, 25)); + CCMenu *menuBack = CCMenu::create(itemBack, NULL); + menuBack->setPosition(CCPointZero); + addChild(menuBack); +} + +void HttpRequestTest::onLabelGetTestClicked(cocos2d::CCObject *sender) +{ + string url = GETURL; + + CCHttpRequest *requestor = CCHttpRequest::sharedHttpRequest(); + requestor->addGetTask(url, this, callfuncND_selector(HttpRequestTest::onHttpRequestCompleted)); +} + +void HttpRequestTest::onLabelPostTestClicked(cocos2d::CCObject *sender) +{ + string url = POSTURL; + string content = "username=hello&password=world"; + + CCHttpRequest *requestor = CCHttpRequest::sharedHttpRequest(); + //You may name the request + requestor->setReqId("login"); + requestor->addPostTask(url, content, this, callfuncND_selector(HttpRequestTest::onHttpRequestCompleted)); +} + +void HttpRequestTest::onLabelPostBinaryTestClicked(cocos2d::CCObject *sender) +{ + string url = POSTURL; + const char *content = "username=hello&password=worl\0d"; + + CCHttpRequest *requestor = CCHttpRequest::sharedHttpRequest(); + requestor->setReqId("postbinary"); + requestor->addPostTask(url, content, strlen(content) + 2, this, callfuncND_selector(HttpRequestTest::onHttpRequestCompleted)); +} + +void HttpRequestTest::onLabelDownloadTestClicked(cocos2d::CCObject *sender) +{ + string url = DOWNLOADURL; + vector 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) { + return; + } + + //If the response is binary, use response->responseData.data() and response->responseData.length() + //To process the response + CCLog("Response Content: %s", response->responseData.c_str()); + + 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) +{ + ExtensionsTestScene *pScene = new ExtensionsTestScene(); + pScene->runThisTest(); + pScene->release(); +} + +void runHttpRequestTest() +{ + CCScene *pScene = CCScene::create(); + HttpRequestTest *pLayer = new HttpRequestTest(); + pScene->addChild(pLayer); + + CCDirector::sharedDirector()->replaceScene(pScene); + pLayer->release(); +} -#include diff --git a/samples/TestCpp/Classes/ExtensionsTest/HttpRequestTest/HttpRequestTest.h b/samples/TestCpp/Classes/ExtensionsTest/HttpRequestTest/HttpRequestTest.h index dd19b4f298..bb1a387354 100644 --- a/samples/TestCpp/Classes/ExtensionsTest/HttpRequestTest/HttpRequestTest.h +++ b/samples/TestCpp/Classes/ExtensionsTest/HttpRequestTest/HttpRequestTest.h @@ -1,14 +1,26 @@ -// -// HttpRequestTest.h -// TestCpp -// -// Created by qingyun on 12-8-4. -// Copyright (c) 2012年 __MyCompanyName__. All rights reserved. -// +#ifndef __HTTPREQUESTHTTP_H +#define __HTTPREQUESTHTTP_H -#ifndef TestCpp_HttpRequestTest_h -#define TestCpp_HttpRequestTest_h +#include "cocos2d.h" +#include "cocos-ext.h" +class HttpRequestTest : public cocos2d::CCLayer +{ + CC_SYNTHESIZE(CCLabelTTF *, m_labelStatusCode, LabelStatusCode); +public: + HttpRequestTest(); + void toExtensionsMainLayer(cocos2d::CCObject *sender); + + //Menu Callbacks + void onLabelGetTestClicked(cocos2d::CCObject *sender); + void onLabelPostTestClicked(cocos2d::CCObject *sender); + void onLabelPostBinaryTestClicked(cocos2d::CCObject *sender); + void onLabelDownloadTestClicked(cocos2d::CCObject *sender); + + //Http Response Callback + void onHttpRequestCompleted(cocos2d::CCObject *sender, void *data); +}; +void runHttpRequestTest(); -#endif +#endif //__HTTPREQUESTHTTP_H diff --git a/samples/TestCpp/proj.ios/TestCpp.xcodeproj/project.pbxproj.REMOVED.git-id b/samples/TestCpp/proj.ios/TestCpp.xcodeproj/project.pbxproj.REMOVED.git-id index d64a5dc114..aafb08ecb8 100644 --- a/samples/TestCpp/proj.ios/TestCpp.xcodeproj/project.pbxproj.REMOVED.git-id +++ b/samples/TestCpp/proj.ios/TestCpp.xcodeproj/project.pbxproj.REMOVED.git-id @@ -1 +1 @@ -7dea09f758e229595c7992fee3cc0a0f0fb49f79 \ No newline at end of file +eae8f176936098bc77ca4472b94f9e018f5c368c \ No newline at end of file