CCNetwork - any suggestions and comments are welcome :)

Recently I am porting an app to cocos2d-x which I made for android, ios, bada, and qnx.

And realized that there is no simple way to get json object asynchronously.

So here, I am posting a class I have made. Please give me a feedback if there are some errors. Thank you.

CCNetwork.h

#include "cocos2d.h"
#include "stdio.h"
#include "stdlib.h"
#include "curl.h"
#include "pthread.h"
#include "cJSON.h"

namespace cocos2d
{
    class CCNetwork : public CCObject
    {
        SEL_CallFunc callback;
        SelectorProtocol *target;
        pthread_t threadInfo;
        char url[260];
        cJSON *cJSONResult;

        CCNetwork()
        {
            cJSONResult = NULL;
        }
    protected:
        static size_t writer( char *data, size_t size, size_t nmemb, string *writerData )
        {
            if(writerData == NULL)
                return 0;

            writerData->append(data, size * nmemb);
            return size * nmemb;
        }
    public:
        virtual ~CCNetwork()
        {
            if( cJSONResult != NULL )
            {
                freeResultJSON();
            }
        }

        static void *run( void *arg )
        {
            CCNetwork *network = (CCNetwork *)arg;
            CURL *curl;
            CURLcode res;
            int result = 1;
            string buffer;

            network->cJSONResult = NULL;

            curl_global_init( CURL_GLOBAL_ALL );

            curl = curl_easy_init();

            if( curl )
            {
                curl_easy_setopt( curl, CURLOPT_URL, network->url );
                curl_easy_setopt( curl, CURLOPT_FOLLOWLOCATION, 1L );
                curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, CCNetwork::writer );
                curl_easy_setopt( curl, CURLOPT_WRITEDATA, &buffer );

                res = curl_easy_perform( curl );

                curl_easy_cleanup( curl );

                if (res == 0)
                {
                    network->cJSONResult = cJSON_Parse( buffer.c_str() );

                    if( network->cJSONResult != NULL )
                        result = 0;
                }
            }

            ((network->target)->*(network->callback))();

            return (void *)result;
        }

        cJSON *getResultJSON()
        {
            int success;

            if( pthread_join( threadInfo, (void **)&success ) == 0 )
                return cJSONResult;
            else
                return NULL;
        }

        void freeResultJSON()
        {
            if( cJSONResult != NULL )
            {
                cJSON_Delete( cJSONResult );
                cJSONResult = NULL;
            }
        }

        static CCNetwork *loadJSON( const char *url, SelectorProtocol *target, SEL_CallFunc callback )
        {
            CCNetwork *network = new CCNetwork();

            if( network != NULL )
            {
                network->target = target;
                network->callback = callback;
                strcpy( network->url, url );

                if( pthread_create( &network->threadInfo, NULL, CCNetwork::run, network ) == 0 )
                {
                    network->autorelease();
                    return network;
                }

                CC_SAFE_DELETE( network );
            }
            return NULL;
        }
    };
}

callback function

void dataArrived() { isThreadRunning = false; }

the part which request url

isThreadRunning = true;
scheduleUpdate();
network = CCNetwork::loadJSON( "http://dodgemissile2.appspot.com/?count=10", this, callfunc_selector( YourNode::dataArrived ) );
network->retain();

update function

void YourNode::update( ccTime dt )
{
    if( !isThreadRunning )
    {
        if( network != NULL )
        {
            cJSON *result = network->getResultJSON();

            // process with result here

            network->release();
        }

        unscheduleUpdate();
    }
}

It will be a very useful class.
My suggestions when reviewing the code.

  1. char url[260]; is danger, especially you dont’ check the length before strcpy( network~~>url, url ), stack will easily overflow. I prefer to use std::string here to make it safe.
  2. You like to use several return points in a function. It’s not good when you would like to write some profile and test the performance. For example:
    <pre>
    static size_t writer
    {
    if
    return 0;
    writerData~~>append(data, size * nmemb);
    return size * nmemb;
    }
The recommended approach is
        static size_t writer( char *data, size_t size, size_t nmemb, string *writerData )
        {
            // profile_start
            size_t retValue = 0;

            if(writerData != NULL)
            {
                  writerData->append(data, size * nmemb);
                  retValue = size * nmemb;
            }

            // profile_end. You have only one return point now
            return retValue;
        }

Very nice recommendations! thank you!

I would like to make it more graceful.

a good class for me.

it’s a very nice class for me,but i have 2 questions of it.
1.why ? fatal error C1083: Cannot open include file: ‘curl/curl.h’: No such file or directory
2.after cocos2d-1.0.1-x-0.11.0 release selector_protocol.h was removed
can’t find SelectorProtocol

Hey Steve, great work, why not post your code on GitHub so we can fork and contribute? :slight_smile:

CCNetwork with an example added to cocos2d-x-extensions.

I will update the code if someone wants to contribute.

http://www.cocos2d-x.org/boards/18/topics/11080

Thank you for your help! I am not familiar with github or other version controllers, so I had a problem to contribute.

CCNetwork has changed a little and now also supports zip file and other file types.

It cheers me up so much that you people are interested in my class :slight_smile:

Anyway, how can I edit the class and upload files? Do I have a permit to do?

I known that git is not easy to understand, but it’s a powerfull tool, so I recomended you to use it.

Check at this links.
http://help.github.com/win-set-up-git/

And use “tortoise-git” as an easy GUI tool for git.

While you are “learning git”, you could upload the files and I will upgrade the repo by myself.

Resume:
~~Install Git && tortoise-git
~~Settup your SSH keys in your github account (upload your public ssh key)
~~fork the cocos2d-x-extension
~~clone your personal “fork”
~~modify your files
~~commit your changes (local)
~~push
~~click on “pull request” and I will accept the changes.

Thank’s all.

Hello!

I tried to use your code, but stumbled with EXC_BAD_ACCESS. I created the separate topic for the issue: http://www.cocos2d-x.org/boards/6/topics/12773.
Could you help if you have any idea?

Thank you!