mbedからGluinサーバへ接続するライブラリです

Dependents:   Servo_DxDevice

DxClient.cpp

Committer:
komoritan
Date:
2015-02-14
Revision:
0:735163979ecf

File content as of revision 0:735163979ecf:

#include "DxClient.h"
#include "picojson.h"

#if 1
#define DXDBG(x, ...) printf("[DxClient : DBG]"x"\r\n", ##__VA_ARGS__); 
#define DXWARN(x, ...) printf("[DxClient : WARN]"x"\r\n", ##__VA_ARGS__); 
#define DXERR(x, ...) printf("[DxClient : ERR]"x"\r\n", ##__VA_ARGS__); 
#else
#define DXDBG(x, ...) 
#define DXWARN(x, ...)
#define DXERR(x, ...) 
#endif

#define DXINFO(x, ...) printf("[DxClient : INFO]"x"\r\n", ##__VA_ARGS__); 

void generate_randomid( char* out, int len )
{
    int i;
    static char* words = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!#$%&()=<>?-_[]{}";
    for (i=0;i<len-1;i++) {
        out[i] = words[ rand()%strlen(words) ];
    }
    out[len-1] = 0;
}

DxClient::DxClient(char * url, char* deviceid, float seed) 
{
    m_ws.set_server( url );   
    strcpy( m_deviceid, deviceid );
    
    memset( m_user, 0, sizeof(m_user));
    memset( m_pass, 0, sizeof(m_pass));
    memset( m_dev_name, 0, sizeof(m_dev_name));
    memset( m_dev_description, 0, sizeof(m_dev_description));
    
    m_func_get_request = NULL;
    m_func_set_request = NULL;
    
    DXDBG("random seed is %f", seed );
    srand(seed);
}


void DxClient::set_user(char* user, char *pass)
{
    //  set auth user and password
    strncpy( m_user, user, sizeof(m_user) );
    strncpy( m_pass, pass, sizeof(m_pass) );
}

void DxClient::set_device_description(char* desc)
{
    strncpy( m_dev_description, desc, sizeof(m_dev_description) );
}
void DxClient::set_device_name(char* name)
{
    strncpy( m_dev_name, name, sizeof(m_dev_name) );
}


bool DxClient::connect()
{
    bool res;
    res = m_ws.connect();
    if (res) {
        DXDBG("Connected to server by Websocket");
        // send user_auth_request
        res = dx_user_auth_request();
        if (res) {
            DXDBG("...Authorized");
        } else {
            DXDBG("...Login failed");
        }
    } else {
        DXDBG("Failed to server by Websocket");
    }
    return res;
}

bool DxClient::close()
{
    return m_ws.close();
}

// ==============================================
//  Send user_auth_request to server
//  if user is authorized correctly, clinet gets 200 OK response
//  this request must be sent before any other requset
// ==============================================
bool DxClient::dx_user_auth_request()
{
    DXDBG("Call dx_user_auth_request");
    
    int  i, len;
    bool res;
    
    char message[MAX_MESSAGELEN];
    char mesid[MAX_MESSAGEIDLEN];
    generate_randomid( mesid, sizeof(mesid) );
    len = snprintf(message, sizeof(message), "{" \
                    "\"type\":\"user-auth-request\"," \
                    "\"message-id\":\"%s\"," \
                    "\"username\":\"%s\"," \
                    "\"password\":\"%s\"" \
                    "}",
                    mesid,
                    m_user,
                    m_pass
                    );
    if (len >= sizeof(message)-1) {
        DXDBG( "USER_AUTH: message is over MAX LEN");
        return false;
    }
    DXDBG("send: %s", message);

    m_ws.send(message);

    // clear the buffer and wait a sec...
    memset( message, 0, sizeof(message));
    for (i=0, res=false;i<10;i++) {
        wait(0.5f);
        if (m_ws.read(message)) {
            DXDBG("Get Message: %s\n", message);
            picojson::value v;
            std::string err;
            picojson::parse(v, (const char *)message, (const char *)(message + strlen(message)), &err);


            if (err.empty())
            {
                picojson::object& root = v.get<picojson::object>();
                
                // check auth response
                if (root["type"].is<std::string>()) {
                    if (strcmp(root["type"].get<std::string>().c_str(), "user-auth-response")) {
                        DXDBG("USER_AUTH: Not user_auth_response\n");
                        break;
                    }
                } else {
                    DXDBG("USER_AUTH: there is no type\n");
                    break;
                }
                if (root["message-id"].is<std::string>()) {
                    if (strcmp(root["message-id"].get<std::string>().c_str(), mesid)) {
                        DXDBG("USER_AUTH: Not correct response message-id\n");
                        break;
                    }
                } else {
                    DXDBG("USER_AUTH: there is no message-id\n");
                    break;
                }
                if (root["status"].is<std::string>()) {
                    if (strcmp(root["status"].get<std::string>().c_str(), "200 OK")) {
                        DXDBG("USER_AUTH: status error\n");
                        break;
                    }
                } else {
                    DXDBG("USER_AUTH: there is no status\n");
                    break;
                }

                DXDBG("USER_AUTH: user auth is success\n");
                res = true;
            } else {
                DXDBG("USER_AUTH: JSON parse Error\n");
            }
            break;        
        }
    }
    return res;
}

char* dx_type_to_string( dx_prop_type type, char* buf)
{
    char *res = buf;
    switch( type ) {
        case DX_STRING:
            sprintf( res, "string" );
            break;
        case DX_INTEGER:
            sprintf( res, "integer" );
            break;
        case DX_FLOAT:
            sprintf( res, "float" );
            break;
        case DX_BOOLEAN:
            sprintf( res, "boolean" );
            break;
        default:
            sprintf( res, "unknown" );
            break;
    }
    return res;
}
char* dx_direction_to_string( dx_prop_direction dic, char* buf)
{
    char *res = buf;
    switch( dic ) {
        case DX_UPONLY:
            sprintf( res, "uponly" );
            break;
        case DX_DOWNONLY:
            sprintf( res, "downonly" );
            break;
        case DX_UPDOWN:
            sprintf( res, "updown" );
            break;
        default:
            sprintf( res, "unknown" );
            break;
    }
    return res;
}
char* dx_mode_to_string( dx_prop_mode mode, char* buf)
{
    char *res = buf;
    switch( mode ) {
        case DX_READONLY:
            sprintf( res, "readonly" );
            break;
        case DX_WRITEONLY:
            sprintf( res, "writeonly" );
            break;
        case DX_READWRITE:
            sprintf( res, "readwrite" );
            break;
        default:
            sprintf( res, "unknown" );
            break;
    }
    return res;
}

// ==============================================
//
// ==============================================
bool DxClient::register_device( dx_props *props )
{
    DXDBG("Call register_device");
    
    bool res;
    int len;

    char message[MAX_MESSAGELEN];
    char mesid[MAX_MESSAGEIDLEN];
    generate_randomid( mesid, sizeof(mesid) );
    len = snprintf(message, sizeof(message), "{" \
                    "\"type\":\"device-register-request\"," \
                    "\"device-id\":\"%s\"," \
                    "\"message-id\":\"%s\"," \
                    "\"name\":\"%s\"," \
                    "\"description\":\"%s\"," \
                    "\"props\":{",
                    m_deviceid,
                    mesid,
                    m_dev_name,
                    m_dev_description
                    );
    if (len >= sizeof(message)-1) {
        DXDBG( "REGISTER_DEVICE: message is over  MAX LEN");
        return false;
    }
                    
    int i;
    for (i=0;i<props->numofprops;i++) {
        char s_prop[MAX_PROPLEN];
        char s_type[16];
        char s_direction[16];
        char s_mode[16];
        
        char s_val[MAX_PROPSVALLEN];
        switch( props->props[i].type ){
            case DX_STRING:
                sprintf( s_val, "\"%s\"", props->props[i].s_val );
                break;
            case DX_INTEGER:
                sprintf( s_val, "%d", (int)(props->props[i].f_val) );
                break;
            case DX_FLOAT:
                sprintf( s_val, "%f", props->props[i].f_val );
                break;
            case DX_BOOLEAN:
                sprintf( s_val, "%s", props->props[i].b_val?"true":"false" );
                break;
        }
        
        len = snprintf( s_prop, sizeof(s_prop), "\"%s\": {" \
                            "\"value\":%s," \
                            "\"type\":\"%s\"," \
                            "\"direction\":\"%s\"," \
                            "\"mode\":\"%s\"" \
                            "}",
                            props->props[i].name,
                            s_val,
                            dx_type_to_string( props->props[i].type, s_type ),
                            dx_direction_to_string( props->props[i].direction, s_direction ),
                            dx_mode_to_string( props->props[i].mode, s_mode )
                            );
        if (len >= sizeof(s_prop)-1) {
            DXDBG( "REGISTER_DEVICE: prop is over  MAX LEN");
            return false;
        }
        if (len + strlen(message) >= sizeof(message)-1) {
            DXDBG( "REGISTER_DEVICE: message is over  MAX LEN");
            return false;
        }
        strcat( message, s_prop );
        
        if (i+1 < props->numofprops) {
            if (1 + strlen(message) >= sizeof(message)-1) {
                DXDBG( "REGISTER_DEVICE: message is over  MAX LEN");
                return false;
            }
            strncat( message, ",", sizeof(message) );
        }
    }

    if (2 + strlen(message) >= sizeof(message)-1) {
        DXDBG( "REGISTER_DEVICE: message is over  MAX LEN");
        return false;
    }
    strcat( message, "}}" );

    DXDBG("send: %s", message);
    m_ws.send(message);
    
    // clear the buffer and wait a sec...
    memset( message, 0, sizeof(message));
    for (i=0, res=false;i<10;i++) {
        wait(0.5f);
        if (m_ws.read(message)) {
            DXDBG("Get Message(%d): %s", strlen(message), message);
            picojson::value v;
            std::string err;
            picojson::parse(v, (const char *)message, (const char *)(message + strlen(message)), &err);

            if (err.empty())
            {
                picojson::object& root = v.get<picojson::object>();
                // check auth response
                if (root["type"].is<std::string>()) {
                    if (strcmp(root["type"].get<std::string>().c_str(), "device-register-response")) {
                        DXDBG("REGISTER_DEVICE: Not device_register_response");
                        break;
                    }
                } else {
                    DXDBG("REGISTER_DEVICE: there is no type");
                    break;
                }
                if (root["message-id"].is<std::string>()) {
                    if (strcmp(root["message-id"].get<std::string>().c_str(), mesid)) {
                        DXDBG("REGISTER_DEVICE: Not correct response message-id");
                        break;
                    }
                } else {
                    DXDBG("REGISTER_DEVICE: there is no message-id");
                    break;
                }
                if (root["status"].is<std::string>()) {
                    if (strcmp(root["status"].get<std::string>().c_str(), "200 OK")) {
                        DXDBG("REGISTER_DEVICE: status error");
                        break;
                    }
                } else {
                    DXDBG("REGISTER_DEVICE: there is no status");
                    break;
                }
                DXDBG("REGISTER_DEVICE: device register is success");
                res = true;
            } else {
                DXDBG("REGISTER_DEVICE: Parse Error");
            }
            break;
        }
    }

    return res;
}

// ==============================================
//
// ==============================================
bool DxClient::deregister_device()
{
    int len;
    
    char message[MAX_MESSAGELEN];
    char mesid[MAX_MESSAGEIDLEN];

    generate_randomid( mesid, sizeof(mesid) );
    len = snprintf(message, sizeof(message), "{" \
                    "\"type\":\"device-deregister-request\"," \
                    "\"device-id\":\"%s\"," \
                    "\"message-id\":\"%s\"" \
                    "}",
                    m_deviceid,
                    mesid
                    );
    if (len >= sizeof(message)-1) {
        DXDBG( "DEREGISTER_DEVICE: message is over  MAX LEN");
        return false;
    }

    DXDBG("send: %s", message);
    m_ws.send(message);

    // clear the buffer and wait a sec...
    bool res;
    int i;
    memset( message, 0, sizeof(message));
    for (i=0, res=false;i<10;i++) {
        wait(0.5f);
        if (m_ws.read(message)) {
            DXDBG("Get Message(%d): %s", strlen(message), message);
            picojson::value v;
            std::string err;
            picojson::parse(v, (const char *)message, (const char *)(message + strlen(message)), &err);

            if (err.empty())
            {
                picojson::object& root = v.get<picojson::object>();
                // check auth response
                if (root["type"].is<std::string>()) {
                    if (strcmp(root["type"].get<std::string>().c_str(), "device-deregister-response")) {
                        DXDBG("DEREGISTER_DEVICE: Not device_deregister_response");
                        break;
                    }
                } else {
                    DXDBG("DEREGISTER_DEVICE: there is no type");
                    break;
                }
                if (root["message-id"].is<std::string>()) {
                    if (strcmp(root["message-id"].get<std::string>().c_str(), mesid)) {
                        DXDBG("DEREGISTER_DEVICE: Not correct response message-id");
                        break;
                    }
                } else {
                    DXDBG("REGISTER_DEVICE: there is no message-id");
                    break;
                }
                if (root["status"].is<std::string>()) {
                    if (strcmp(root["status"].get<std::string>().c_str(), "200 OK")) {
                        DXDBG("DEREGISTER_DEVICE: status error");
                        break;
                    }
                } else {
                    DXDBG("DEREGISTER_DEVICE: there is no status");
                    break;
                }
                DXDBG("DEREGISTER_DEVICE: device deregister is success");
                res = true;
            } else {
                DXDBG("DEREGISTER_DEVICE: Parse Error");
            }
            break;
        }
    }
                    
    return res;
}

// ==============================================
//
// ==============================================
bool DxClient::update_device( dx_props *props )
{
    int len;
    
    char message[MAX_MESSAGELEN];
    char mesid[MAX_MESSAGEIDLEN];

    generate_randomid( mesid, sizeof(mesid) );
    len = snprintf(message, sizeof(message), "{" \
                    "\"type\":\"device-update-request\"," \
                    "\"device-id\":\"%s\"," \
                    "\"message-id\":\"%s\"," \
                    "\"props\":{",
                    m_deviceid,
                    mesid
                    );
    if (len >= sizeof(message)-1) {
        DXDBG( "UPDATE_DEVICE: message is over  MAX LEN");
        return false;
    }

    int i;                    
    for (i=0;i<props->numofprops;i++) {
        char s_prop[MAX_PROPLEN];
        char s_val[MAX_PROPSVALLEN];
        switch( props->props[i].type ){
            case DX_STRING:
                sprintf( s_val, "\"%s\"", props->props[i].s_val );
                break;
            case DX_INTEGER:
                sprintf( s_val, "%d", (int)(props->props[i].f_val) );
                break;
            case DX_FLOAT:
                sprintf( s_val, "%f", props->props[i].f_val );
                break;
            case DX_BOOLEAN:
                sprintf( s_val, "%s", props->props[i].b_val?"true":"false" );
                break;
        }
        
        len = snprintf( s_prop, sizeof(s_prop), "\"%s\": {" \
                            "\"value\":%s" \
                            "}",
                            props->props[i].name,
                            s_val
                            );
        if (len >= sizeof(s_prop)-1) {
            DXDBG( "UPDATE_DEVICE: prop is over  MAX LEN");
            return false;
        }
        if (len + strlen(message) >= sizeof(message)-1) {
            DXDBG( "UPDATE_DEVICE: message is over  MAX LEN");
            return false;
        }
        strcat( message, s_prop );
        
        if (i+1 < props->numofprops) {
            if (1 + strlen(message) >= sizeof(message)-1) {
                DXDBG( "UPDATE_DEVICE: message is over  MAX LEN");
                return false;
            }
            strncat( message, ",", sizeof(message) );
        }
    }

    if (2 + strlen(message) >= sizeof(message)-1) {
        DXDBG( "UPDATE_DEVICE: message is over  MAX LEN");
        return false;
    }
    strcat( message, "}}" );

    DXDBG("send: %s", message);
    m_ws.send(message);

    bool res=true;
/*    
    // clear the buffer and wait a sec...
    memset( message, 0, sizeof(message));
    for (i=0, res=false;i<10;i++) {
        wait(0.5f);
        if (m_ws.read(message)) {
            DXDBG("Get Message(%d): %s", strlen(message), message);
            picojson::value v;
            std::string err;
            picojson::parse(v, (const char *)message, (const char *)(message + strlen(message)), &err);

            if (err.empty())
            {
                picojson::object& root = v.get<picojson::object>();
                // check auth response
                if (root["type"].is<std::string>()) {
                    if (strcmp(root["type"].get<std::string>().c_str(), "device-update-response")) {
                        DXDBG("UPDATE_DEVICE: Not device_update_response");
                        break;
                    }
                } else {
                    DXDBG("UPDATE_DEVICE: there is no type");
                    break;
                }
                if (root["message-id"].is<std::string>()) {
                    if (strcmp(root["message-id"].get<std::string>().c_str(), mesid)) {
                        DXDBG("UPDATE_DEVICE: Not correct response message-id");
                        break;
                    }
                } else {
                    DXDBG("UPDATE_DEVICE: there is no message-id");
                    break;
                }
                if (root["status"].is<std::string>()) {
                    if (strcmp(root["status"].get<std::string>().c_str(), "200 OK")) {
                        DXDBG("UPDATE_DEVICE: status error");
                        break;
                    }
                } else {
                    DXDBG("UPDATE_DEVICE: there is no status");
                    break;
                }
                DXDBG("UPDATE_DEVICE: device update is success");
                res = true;
            } else {
                DXDBG("UPDATE_DEVICE: Parse Error");
            }
            break;
        }
    }

*/
    return res;
}


// ==============================================
//
// ==============================================
bool DxClient::keepalive_device()
{
    DXDBG("Call keepalive_device");
    
    int  len;
    
    char message[MAX_MESSAGELEN];
    char mesid[MAX_MESSAGEIDLEN];
    generate_randomid( mesid, sizeof(mesid) );
    len = snprintf(message, sizeof(message), "{" \
                    "\"type\":\"keep-alive-request\"," \
                    "\"device-id\":\"%s\"," \
                    "\"message-id\":\"%s\"" \
                    "}",
                    m_deviceid,
                    mesid
                    );
    if (len >= sizeof(message)-1) {
        DXDBG( "KEEPALIVE_DEVICE: message is over MAX LEN");
        return false;
    }
    DXDBG("send: %s", message);

    m_ws.send(message);

    bool res=true;
/*
    int i;
    // clear the buffer and wait a sec...
    memset( message, 0, sizeof(message));
    for (i=0, res=true;i<10;i++) {
        wait(0.5f);
        if (m_ws.read(message)) {
            DXDBG("Get Message: %s\n", message);
            picojson::value v;
            std::string err;
            picojson::parse(v, (const char *)message, (const char *)(message + strlen(message)), &err);


            if (err.empty())
            {
                picojson::object& root = v.get<picojson::object>();
                
                // check auth response
                if (root["type"].is<std::string>()) {
                    if (strcmp(root["type"].get<std::string>().c_str(), "keep-alive-response")) {
                        DXDBG("KEEPALIVE_DEVICE: Not keep-alive-response\n");
                        break;
                    }
                } else {
                    DXDBG("KEEPALIVE_DEVICE: there is no type\n");
                    break;
                }
                if (root["message-id"].is<std::string>()) {
                    if (strcmp(root["message-id"].get<std::string>().c_str(), mesid)) {
                        DXDBG("KEEPALIVE_DEVICE: Not correct response message-id\n");
                        break;
                    }
                } else {
                    DXDBG("KEEPALIVE_DEVICE: there is no message-id\n");
                    break;
                }
                if (root["status"].is<std::string>()) {
                    if (strcmp(root["status"].get<std::string>().c_str(), "200 OK")) {
                        DXDBG("KEEPALIVE_DEVICE: status error\n");
                        break;
                    }
                } else {
                    DXDBG("KEEPALIVE_DEVICE: there is no status\n");
                    break;
                }

                DXDBG("KEEPALIVE_DEVICE: keep alive is success\n");
                res = true;
            } else {
                DXDBG("KEEPALIVE_DEVICE: JSON parse Error\n");
            }
            break;        
        }
    }
*/
    return res;
}


// ==============================================
//
// ==============================================
bool DxClient::handle_messages()
{
    bool res = true;
    
    char message[MAX_MESSAGELEN];

    
    // clear the buffer and wait a sec...
    while(1) {
        memset( message, 0, sizeof(message));
        if (m_ws.read(message)) {
            DXDBG("Get Message(%d): %s", strlen(message), message);
            picojson::value v;
            std::string err;
            picojson::parse(v, (const char *)message, (const char *)(message + strlen(message)), &err);

            if (err.empty())
            {
                picojson::object& root = v.get<picojson::object>();
                // check auth response
                if (root["message-id"].is<std::string>()) {
                    // no check message-d
                } else {
                    DXDBG("HANDLE_MESSAGE: there is no message-id");
                    continue;
                }
                if (root["device-id"].is<std::string>()) {
                    if (strcmp(root["device-id"].get<std::string>().c_str(), m_deviceid)) {
                        DXDBG("HANDLE_MESSAGE: different device-id");
                        continue;
                    }
                } else {
                    DXDBG("HANDLE_MESSAGE: there is no device-id");
                    continue;
                }
                
                if (root["type"].is<std::string>()) {
                    if (!strcmp(root["type"].get<std::string>().c_str(), "device-get-request")
                        || !strcmp(root["type"].get<std::string>().c_str(), "device-set-request")) {
                        DXDBG("HANDLE_MESSAGE: recv %s", root["type"].get<std::string>().c_str());

//                        if ( 1) {
                        if(root["props"].is<picojson::object>() ){
//                            picojson::object& props_root = root;
                            picojson::object& props_root = root["props"].get<picojson::object>();

                            dx_props ps;
                            ps.numofprops = props_root.size();
                            DXDBG("HANDLE_MESSAGE: prop size: %d", ps.numofprops);

                            ps.props = (dx_prop*)malloc( sizeof(dx_prop) * ps.numofprops );
                            if (ps.props == NULL) {
                                DXDBG("HANDLE_MESSAGE: No memory");
                                continue;
                            }
                            memset( ps.props, 0, sizeof(dx_prop) * ps.numofprops );

                            dx_prop *pr = ps.props;
                            for (picojson::object::const_iterator it = props_root.begin(); it != props_root.end(); it++,pr++) {
                                if (props_root[it->first].is<picojson::object>()) {
                                    picojson::object& prop = props_root[it->first].get<picojson::object>();
                                    
                                    if (prop["value"].is<std::string>()) { // test only
                                        snprintf( pr->s_val, sizeof(pr->s_val), "%s", prop["value"].get<std::string>().c_str() );
                                    }
                                    else if (prop["value"].is<double>()) { // integer or float
                                        pr->f_val = prop["value"].get<double>();
                                        if ( (int)(pr->f_val) ) {
                                            pr->b_val = true;
                                        } else {
                                            pr->b_val = false;
                                        }
                                    }
                                    else if (prop["value"].is<bool>()) { // integer or float
                                        pr->b_val = prop["value"].get<bool>();
                                        if(pr->b_val){
                                            pr->f_val = 1;
                                        } else {
                                            pr->f_val = 0;
                                        }
                                    }
                                }
                                snprintf( pr->name, sizeof(pr->name), "%s", it->first.c_str() );
                                DXDBG("HANDLE_MESSAGE: prop name: %s", pr->name);
                            }
                            
                            if (m_func_get_request && !strcmp(root["type"].get<std::string>().c_str(), "device-get-request")) {
                                if((*m_func_get_request)( &ps )) {
                                    dx_device_get_response(&ps, root["message-id"].get<std::string>().c_str());
                                } else {
                                    dx_error_response(root["message-id"].get<std::string>().c_str());
                                }
                            }
                            if (m_func_set_request && !strcmp(root["type"].get<std::string>().c_str(), "device-set-request")) {
                                if((*m_func_set_request)( &ps )) {
                                    dx_device_set_response(&ps, root["message-id"].get<std::string>().c_str());
                                } else {
                                    dx_error_response(root["message-id"].get<std::string>().c_str());
                                }
                            }
                            free(ps.props);
                            continue;
                        } else {
                            DXDBG("HANDLE_MESSAGE: no props in request");
                        }
                        // send error message
                        dx_error_response(root["message-id"].get<std::string>().c_str());
                    }
                    else if (!strcmp(root["type"].get<std::string>().c_str(), "device-update-response")) {
                        DXDBG("HANDLE_MESSAGE: recv device-update-response");
                    }
                    else if (!strcmp(root["type"].get<std::string>().c_str(), "keep-alive-response")) {
                        DXDBG("HANDLE_MESSAGE: recv keep-alive-response");

                    }
                    else {
                        DXDBG("HANDLE_MESSAGE: Unknown message type");
                    }
                } else {
                    DXDBG("HANDLE_MESSAGE: there is no type");
                }
            } else {
                DXDBG("HANDLE_MESSAGE: Parse Error");
            }
        } else {
            break; // no more message
        }
    }

    return res;
}


bool DxClient::dx_error_response( const char* mesid)
{
    DXDBG("Call dx_error_response");
    
    int  len;
    char message[MAX_MESSAGELEN];
    len = snprintf(message, sizeof(message), "{" \
                    "\"device-id\":\"%s\"," \
                    "\"message-id\":\"%s\"," \
                    "\"status\":\"400 Bad Request\"" \
                    "}",
                    m_deviceid,
                    mesid
                    );
    if (len >= sizeof(message)-1) {
        DXDBG( "ERROR_RESPONSE: message is over MAX LEN");
        return false;
    }
    DXDBG("send: %s", message);
    m_ws.send(message);
    
    return true;
}


void DxClient::set_get_requset_handler(REQUEST_HANDLER handler)
{
    m_func_get_request = handler;
}
void DxClient::set_set_requset_handler(REQUEST_HANDLER handler)
{
    m_func_set_request = handler;
}


// ==============================================
//
// ==============================================
bool DxClient::dx_device_get_response( dx_props *props, const char* mesid )
{
    DXDBG("Call dx_device_get_response");

    int len;
    char message[MAX_MESSAGELEN];

    len = snprintf(message, sizeof(message), "{" \
                    "\"type\":\"device-get-response\"," \
                    "\"device-id\":\"%s\"," \
                    "\"message-id\":\"%s\"," \
                    "\"props\":{",
                    m_deviceid,
                    mesid
                    );
    if (len >= sizeof(message)-1) {
        DXDBG( "DEVICE_GET: message is over  MAX LEN");
        return false;
    }

    int i;                    
    for (i=0;i<props->numofprops;i++) {
        char s_prop[MAX_PROPLEN];
        char s_val[MAX_PROPSVALLEN];
        switch( props->props[i].type ){
            case DX_STRING:
                sprintf( s_val, "\"%s\"", props->props[i].s_val );
                break;
            case DX_INTEGER:
                sprintf( s_val, "%d", (int)(props->props[i].f_val) );
                break;
            case DX_FLOAT:
                sprintf( s_val, "%f", props->props[i].f_val );
                break;
            case DX_BOOLEAN:
                sprintf( s_val, "%s", props->props[i].b_val?"true":"false" );
                break;
        }
        
        len = snprintf( s_prop, sizeof(s_prop), "\"%s\": {" \
                            "\"value\":%s" \
                            "}",
                            props->props[i].name,
                            s_val
                            );
        if (len >= sizeof(s_prop)-1) {
            DXDBG( "DEVICE_GET: prop is over  MAX LEN");
            return false;
        }
        if (len + strlen(message) >= sizeof(message)-1) {
            DXDBG( "DEVICE_GET: message is over  MAX LEN");
            return false;
        }
        strcat( message, s_prop );
        
        if (i+1 < props->numofprops) {
            if (1 + strlen(message) >= sizeof(message)-1) {
                DXDBG( "DEVICE_GET: message is over  MAX LEN");
                return false;
            }
            strncat( message, ",", sizeof(message) );
        }
    }

    if (2 + strlen(message) >= sizeof(message)-1) {
        DXDBG( "DEVICE_GET: message is over  MAX LEN");
        return false;
    }
    strcat( message, "}}" );

    DXDBG("send: %s", message);
    m_ws.send(message);
    
    return true;
}

bool DxClient::dx_device_set_response( dx_props *props, const char* mesid )
{
    DXDBG("Call dx_device_set_response");
    
    int  len;
    char message[MAX_MESSAGELEN];
    len = snprintf(message, sizeof(message), "{" \
                    "\"type\":\"device-set-response\"," \
                    "\"device-id\":\"%s\"," \
                    "\"message-id\":\"%s\"," \
                    "\"status\":\"200 OK\"" \
                    "}",
                    m_deviceid,
                    mesid
                    );
    if (len >= sizeof(message)-1) {
        DXDBG( "ERROR_RESPONSE: message is over MAX LEN");
        return false;
    }
    DXDBG("send: %s", message);
    m_ws.send(message);
    
    return true;
}