socket.io-client-cpp icon indicating copy to clipboard operation
socket.io-client-cpp copied to clipboard

example to send a JSON to a Socket.io server

Open domingguss opened this issue 5 years ago • 3 comments

Hi, for anyone looking for an example to read a JSON from a file, and send it over as a sio::message - I have a working setup where JSON is successfully sent over to a Node.js server (through SSL) running Socket.io.

Thought I'd share this. I'm using the awesome nlohmann/json library.

Given the socket is already open and connected,

0. Includes

#include <json.hpp> // using nlohmann's json library
using namespace nlohmann;

1. Converting functions

These functions traverse the json object and recursively convert the whole object into a ready-to-send sio::message::ptr object

sio::message::ptr createObject(json o)
{
    sio::message::ptr object = object_message::create();

    for (json::iterator it = o.begin(); it != o.end(); ++it)
    {
        auto key = it.key();
        auto v = it.value();

        if (v.is_boolean())
        {
            object->get_map()[key] = bool_message::create(v.get<bool>());
        }
        else if (v.is_number_integer())
        {
            object->get_map()[key] = int_message::create(v.get<int>());
        }
        else if (v.is_string())
        {
            object->get_map()[key] = string_message::create(v.get<std::string>());
        }
        else if (v.is_array())
        {
            json childObject = v;
            object->get_map()[key] = createArray(v);
        }
        else if (v.is_object())
        {
            json childObject = v;
            object->get_map()[key] = createObject(childObject);
        }
    }
    return object;
}

sio::message::ptr createArray(json o)
{
    sio::message::ptr array = array_message::create();

    for (json::iterator it = o.begin(); it != o.end(); ++it) {

        auto v = it.value();
        if (v.is_boolean())
        {
            array->get_vector().push_back(bool_message::create(v.get<bool>()));
        }
        else if (v.is_number_integer())
        {
            array->get_vector().push_back(int_message::create(v.get<int>()));
        }
        else if (v.is_string())
        {
            array->get_vector().push_back(string_message::create(v.get<string>()));
        }
        else if (v.is_array())
        {
            array->get_vector().push_back(createArray(v));
        }
        else if (v.is_object())
        {
            array->get_vector().push_back(createObject(v));
        }
    }
    return array;
}

2. JSON reading and emitting code

Now using the converting functions, it's child's play to convert and send the JSON!

    // load json
    std::ifstream ifs("animation.json");
    json animation = json::parse(ifs);

   // do stuff with json
 
   // convert and emit
    sio::message::ptr object = createObject(animation);
    h.socket()->emit("animation", object);

domingguss avatar Jul 31 '20 09:07 domingguss

Thanks a lot!

Just 2 hints for other people wanting to use your solution :

  • make sure to use the latest version of json.hpp (the one from github : https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp) and not the old one that is in the test folder of socket.io-client-cpp)
  • you need to add forward declaration for the second function, as it is used by the first one

EDIT : and if you want to be able to send foating point numbers as well, you should add the following lines in the first function :

        else if (v.is_number_float())
        {
            object->get_map()[key] = double_message::create(v.get<double>());
        }

fnilius avatar Oct 21 '20 14:10 fnilius

Hi ! Thanks a lot for this ! Would you have any example the other way around, converting from sio::message to json ?

gomandr avatar Jun 29 '21 13:06 gomandr

Here is my implementation of the sio::message::ptr -> nlohmann::json function, hope it can help people, I think it makes sense to have alongside the previous functions.

/** @brief Converts an sio::message:ptr object into nlohmann::json
 * 
 * @param sio
 * @return nlohmann::json 
 */
nlohmann::json createJson(sio::message::ptr sio)
{
    // return json
    nlohmann::json json;

    try
    {
        // browse flags, we consider it can only be array/vector or object/map
        if (sio->get_flag() == sio::message::flag_array)
        {
            for (int i = 0; i < int(sio->get_vector().size()); ++i)
            {
                if (sio->get_vector()[i]->get_flag() == sio::message::flag_object ||
                    sio->get_vector()[i]->get_flag() == sio::message::flag_array)
                    json[i] = this->createJson(sio->get_vector()[i]);
                else if (sio->get_vector()[i]->get_flag() == sio::message::flag_integer)
                {
                    json[i] = sio->get_vector()[i]->get_int();
                }
                else if (sio->get_vector()[i]->get_flag() == sio::message::flag_double)
                {
                    json[i] = sio->get_vector()[i]->get_double();
                }
                else if (sio->get_vector()[i]->get_flag() == sio::message::flag_string)
                {
                    json[i] = sio->get_vector()[i]->get_string();
                }
                else if (sio->get_vector()[i]->get_flag() == sio::message::flag_boolean)
                {
                    json[i] = (sio->get_vector()[i]->get_bool() ? "true" : "false");
                }
                else if (sio->get_vector()[i]->get_flag() == sio::message::flag_null)
                {
                    // json[i] = "null"; // do not set json[i] so that it's set to json-null properly
                }
                else
                {
                    std::cout << "Unknown flag in vector: " << sio->get_flag() << ", i is " << i << std::endl;
                }
            }
        }
        else if (sio->get_flag() == sio::message::flag_object)
        {
            for (auto it = sio->get_map().cbegin(); it != sio->get_map().cend(); ++it)
            {
                if (it->second->get_flag() == sio::message::flag_object ||
                    it->second->get_flag() == sio::message::flag_array)
                    json[it->first] = this->createJson(it->second);
                else if (it->second->get_flag() == sio::message::flag_integer)
                {
                    json[it->first] = it->second->get_int();
                }
                else if (it->second->get_flag() == sio::message::flag_double)
                {
                    json[it->first] = it->second->get_double();
                }
                else if (it->second->get_flag() == sio::message::flag_string)
                {
                    json[it->first] = it->second->get_string();
                }
                else if (it->second->get_flag() == sio::message::flag_boolean)
                {
                    json[it->first] = it->second->get_bool();
                }
                else if (it->second->get_flag() == sio::message::flag_null)
                {
                    // json[it->first] = "null"; // do not set json[i] so that it's set to json-null properly
                }
                else
                {
                    std::cout << "Unknown flag in object: " << sio->get_flag() << ", it first is " << it->first << std::endl;
                }
            }
        }
        else
            std::cout << "Unknown flag in createJson function: " << sio->get_flag() << std::endl;
    }
    catch (nlohmann::json::exception &e)
    {
        std::cout << "JSON exception caught in " << __FUNCTION__ << " (message: " << e.what() << ")" << std::endl;
    }

    // return
    return json;
}

Vicidel avatar Apr 01 '22 07:04 Vicidel