user3766148
user3766148

Reputation:

c++ rapidjson parse error of CURLOPTS content

I am trying to deserialize a json object that I get from CURLOPTS and I am getting a parse error (wrong data type). How do I get the JSON into a standard c++ object or readable variable?

code:

darknet064tokyo rapidjson # cat testGetprice.cpp
#include "include/rapidjson/document.h"
#include <iostream>
#include <stdio.h>
#include <curl/curl.h>
#include <unistd.h>
#include <unordered_map>

using namespace rapidjson;

size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) {
        size_t written;
        written = fwrite(ptr, size, nmemb, stream);
        return written;
}
//function to get coin data and perform analysis
int getData()
{
        int count = 0;
        //begin non terminating loop
        while(true)
        {
                count++;
                CURL *curl;
                CURLcode res;
                curl = curl_easy_init();
                if(curl) {
                        curl_easy_setopt(curl, CURLOPT_URL, "http://pubapi.cryptsy.com/api.php?method=singlemarketdata&marketid=155");
                        /* Perform the request, res will get the return code */
                        res = curl_easy_perform(curl);
                        /* Check for errors */
                        if(res != CURLE_OK)
                                fprintf(stderr, "curl_easy_perform() failed: %s\n",
                                curl_easy_strerror(res));
                        //begin deserialization
                        Document document;
                        document.Parse(res);
                        assert(document.HasMember("lasttradeprice"));
                        assert(document["hello"].IsString());
                        printf("The Last Traded Price is = %s\n", document["lasttradeprice"].GetString());


                        FILE * pFile;
                        pFile = fopen ("/home/coinz/cryptsy/myfile.txt","a+");
                        if (pFile!=NULL)
                        {
                                curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
                                curl_easy_setopt(curl, CURLOPT_WRITEDATA, pFile);
                                res = curl_easy_perform(curl);
                                //std::cout << pFile << std::endl;
                                fprintf(pFile, "\n");
                                fclose (pFile);
                        }
                        /* always cleanup */
                        curl_easy_cleanup(curl);
                //timer for URL request.  *ADUJST ME AS DESIRED*
                usleep(10000000);
                }
        }
        return 0;
}

//Le Main
int main(void){
        getData();
}

error code output:

darknet064tokyo rapidjson # g++ -g testGetprice.cpp -o testGetprice.o -std=gnu++11
testGetprice.cpp: In function 'int getData()':
testGetprice.cpp:36:22: error: no matching function for call to 'rapidjson::GenericDocument<rapidjson::UTF8<> >::Parse(CURLcode&)'
testGetprice.cpp:36:22: note: candidates are:
In file included from testGetprice.cpp:1:0:
include/rapidjson/document.h:1723:22: note: template<unsigned int parseFlags, class SourceEncoding> rapidjson::GenericDocument& rapidjson::GenericDocument::Parse(const Ch*) [with unsigned int parseFlags = parseFlags; SourceEncoding = SourceEncoding; Encoding = rapidjson::UTF8<>; Allocator = rapidjson::MemoryPoolAllocator<>; StackAllocator = rapidjson::CrtAllocator]
include/rapidjson/document.h:1723:22: note:   template argument deduction/substitution failed:
testGetprice.cpp:36:22: note:   cannot convert 'res' (type 'CURLcode') to type 'const Ch* {aka const char*}'
In file included from testGetprice.cpp:1:0:
include/rapidjson/document.h:1734:22: note: template<unsigned int parseFlags> rapidjson::GenericDocument& rapidjson::GenericDocument::Parse(const Ch*) [with unsigned int parseFlags = parseFlags; Encoding = rapidjson::UTF8<>; Allocator = rapidjson::MemoryPoolAllocator<>; StackAllocator = rapidjson::CrtAllocator]
include/rapidjson/document.h:1734:22: note:   template argument deduction/substitution failed:
testGetprice.cpp:36:22: note:   cannot convert 'res' (type 'CURLcode') to type 'const Ch* {aka const char*}'
In file included from testGetprice.cpp:1:0:
include/rapidjson/document.h:1741:22: note: rapidjson::GenericDocument<Encoding, Allocator, StackAllocator>& rapidjson::GenericDocument<Encoding, Allocator, StackAllocator>::Parse(const Ch*) [with Encoding = rapidjson::UTF8<>; Allocator = rapidjson::MemoryPoolAllocator<>; StackAllocator = rapidjson::CrtAllocator; rapidjson::GenericDocument<Encoding, Allocator, StackAllocator> = rapidjson::GenericDocument<rapidjson::UTF8<> >; rapidjson::GenericDocument<Encoding, Allocator, StackAllocator>::Ch = char]
include/rapidjson/document.h:1741:22: note:   no known conversion for argument 1 from 'CURLcode' to 'const Ch* {aka const char*}'

Upvotes: 0

Views: 1866

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 595320

Pay attention to what you are doing. curl_easy_perform() returns an error code, not the server's response data. You are passing Curl's error code to Document::Parse(), not the actual JSON data. The error messages are telling you exactly that:

error: no matching function for call to 'rapidjson::GenericDocument >::Parse(CURLcode&)'

By default, curl_easy_perform() outputs the received data to stdout. To override that so you can receive the JSON data in your code, you need to use curl_easy_setopt() to assign a custom CURLOPT_WRITEFUNCTION callback that writes the received data to a buffer/string you specify using CURLOPT_WRITEDATA. You are already doing that, but you are writing the data to a file, not to a memory buffer/string.

This type of situation is discussed in the "Handle the Easy libcurl" section of the libCurl tutorial.

Try something more like this:

#include "include/rapidjson/document.h"
#include <iostream>
#include <stdio.h>
#include <curl/curl.h>
#include <unistd.h>
#include <unordered_map>
#include <string>

using namespace rapidjson;

struct myData
{
    std::fstream *file;
    std::string *str;
};

size_t write_data(void *ptr, size_t size, size_t nmemb, myData *data)
{
    size_t numBytes = size * nmemb;

    if (data->file)
        data->file->write((char*)ptr, numBytes);

    if (data->str)
        *(data->str) += std::string((char*)ptr, numBytes);

    return numBytes;
}

//function to get coin data and perform analysis
int getData()
{
    int count = 0;

    //begin non terminating loop
    while(true)
    {
        count++;
        CURL *curl = curl_easy_init();
        if (curl)
        {
            curl_easy_setopt(curl, CURLOPT_URL, "http://pubapi.cryptsy.com/api.php?method=singlemarketdata&marketid=155");

            std::fstream file("/home/coinz/cryptsy/myfile.txt", ios_base::out | ios_base::ate);
            std::string json;

            myData data;
            data.file = &file;
            data.str = &json;

            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_data);
            curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data);

            /* Perform the request, res will get the return code */
            CURLcode res = curl_easy_perform(curl);

            /* Check for errors */
            if (res != CURLE_OK)
            {
                std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
            }
            else
            {
                file << std::endl;

                //begin deserialization
                Document document;
                document.Parse(json.c_str());
                assert(document.HasMember("lasttradeprice"));
                assert(document["hello"].IsString());
                std::cout << "The Last Traded Price is = " << document["lasttradeprice"].GetString() << std::endl;
            }

            /* always cleanup */
            curl_easy_cleanup(curl);
        }

        //timer for URL request.  *ADUJST ME AS DESIRED*
        usleep(10000000);
    }

    return 0;
}

//Le Main
int main(void)
{
    getData();
}

Upvotes: 1

Related Questions