mbedからGluinサーバへ接続するライブラリです
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; }