Thinger.io Client Library for ARM mbed platform. This is a generic library that provides a base class that can be used to other develop hardware specific libraries.
Fork of ThingerClient by
Revision 1:d54f92accbc3, committed 2015-12-25
- Comitter:
- alvarolb
- Date:
- Fri Dec 25 17:20:21 2015 +0000
- Parent:
- 0:b75d784c7c1a
- Child:
- 2:8c6f158b95c3
- Commit message:
- Small changes
Changed in this revision
thinger/thinger.h | Show annotated file Show diff for this revision Revisions of this file |
--- a/thinger/thinger.h Thu Dec 24 13:18:08 2015 +0000 +++ b/thinger/thinger.h Fri Dec 25 17:20:21 2015 +0000 @@ -1,262 +1,262 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 THINGER LTD -// Author: alvarolb@gmail.com (Alvaro Luis Bustamante) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef THINGER_H -#define THINGER_H - -#include "pson.h" -#include "thinger_map.hpp" -#include "thinger_resource.hpp" -#include "thinger_message.hpp" -#include "thinger_encoder.hpp" -#include "thinger_decoder.hpp" -#include "thinger_message.hpp" -#include "thinger_io.hpp" - -#define KEEP_ALIVE_MILLIS 60000 - -namespace thinger{ - - using namespace protoson; - - class thinger : public thinger_io{ - public: - thinger() : - encoder(*this), - decoder(*this), - last_keep_alive(0), - keep_alive_response(true) - { - } - - virtual ~thinger(){ - } - - private: - thinger_write_encoder encoder; - thinger_read_decoder decoder; - unsigned long last_keep_alive; - bool keep_alive_response; - thinger_map<thinger_resource> resources_; - - protected: - /** - * Can be override to start reconnection process - */ - virtual void disconnected(){ - // stop all streaming resources after disconnect - if(thinger_resource::get_streaming_counter()>0) { - thinger_map<thinger_resource>::entry* current = resources_.begin(); - while(current!=NULL){ - current->value_.disable_streaming(); - current = current->next_; - } - } - } - - /** - * Stream a given resource - */ - void stream_resource(thinger_resource& resource, thinger_message::signal_flag type){ - thinger_message message; - message.set_stream_id(resource.get_stream_id()); - message.set_signal_flag(type); - resource.fill_api_io(message.get_data()); - send_message(message); - } - - public: - - thinger_resource & operator[](const char* res){ - return resources_[res]; - } - - bool connect(const char* username, const char* device_id, const char* credential) - { - // reset keep alive status for each connection - keep_alive_response = true; - - thinger_message message; - message.set_signal_flag(thinger_message::AUTH); - message.resources().add(username).add(device_id).add(credential); - if(!send_message(message)) return false; - - thinger_message response; - return read_message(response) && response.get_signal_flag() == thinger_message::REQUEST_OK; - } - - bool call_endpoint(const char* endpoint_name){ - thinger_message message; - message.set_signal_flag(thinger_message::CALL_ENDPOINT); - message.resources().add(endpoint_name); - return send_message(message); - } - - bool call_endpoint(const char* endpoint_name, pson& data){ - thinger_message message; - message.set_signal_flag(thinger_message::CALL_ENDPOINT); - message.set_data(data); - message.resources().add(endpoint_name); - return send_message(message); - } - - bool call_endpoint(const char* endpoint_name, thinger_resource& resource){ - thinger_message message; - message.set_signal_flag(thinger_message::CALL_ENDPOINT); - message.resources().add(endpoint_name); - resource.fill_api_io(message.get_data()); - return send_message(message); - } - - /** - * Stream the given resource. This resource should be previously requested by an external process. - * Otherwise, the resource will not be streamed as nothing will be listening for it. - */ - bool stream(thinger_resource& resource){ - if(resource.stream_enabled()){ - stream_resource(resource, thinger_message::STREAM_EVENT); - return true; - } - return false; - } - - bool send_message(thinger_message& message) - { - thinger_encoder sink; - sink.encode(message); - encoder.pb_encode_varint(MESSAGE); - encoder.pb_encode_varint(sink.bytes_written()); - encoder.encode(message); - return write(NULL, 0, true); - } - - void handle(unsigned long current_time, bool bytes_available) - { - // handle input - if(bytes_available){ - handle_input(); - } - - // handle keep alive - if(current_time-last_keep_alive>KEEP_ALIVE_MILLIS){ - if(keep_alive_response){ - last_keep_alive = current_time; - keep_alive_response = false; - encoder.pb_encode_varint(KEEP_ALIVE); - encoder.pb_encode_varint(0); - write(NULL, 0, true); - }else{ - disconnected(); - } - } - - // handle streaming resources - if(thinger_resource::get_streaming_counter()>0){ - thinger_map<thinger_resource>::entry* current = resources_.begin(); - while(current!=NULL){ - if(current->value_.stream_required(current_time)){ - stream_resource(current->value_, thinger_message::STREAM_SAMPLE); - } - current = current->next_; - } - } - } - - bool read_message(thinger_message& message){ - uint8_t type = decoder.pb_decode_varint32(); - switch (type){ - case MESSAGE: { - size_t size = decoder.pb_decode_varint32(); - decoder.decode(message, size); - } - break; - case KEEP_ALIVE: { - size_t size = decoder.pb_decode_varint32(); - keep_alive_response = true; - } - return false; - default: - return false; - } - return true; - } - - bool handle_input(){ - thinger_message message; - if(read_message(message)){ - handle_request_received(message); - } - return true; - } - - private: - - void handle_request_received(thinger_message& request) - { - thinger_message response(request); - if(!request.has_resource()){ - response.set_signal_flag(thinger_message::REQUEST_ERROR); - } - else{ - thinger_resource * thing_resource = NULL; - for(pson_array::iterator it = request.resources().begin(); it.valid(); it.next()){ - if(!it.item().is_string()){ - response.set_signal_flag(thinger_message::REQUEST_ERROR); - break; - } - const char* resource = it.item(); - - if(it.has_next()){ - thing_resource = thing_resource == NULL ? resources_.find(resource) : thing_resource->find(resource); - if(thing_resource==NULL) { - response.set_signal_flag(thinger_message::REQUEST_ERROR); - break; - } - }else{ - if(strcmp("api", resource)==0){ - if(thing_resource==NULL){ - thinger_map<thinger_resource>::entry* current = resources_.begin(); - while(current!=NULL){ - current->value_.fill_api(response.get_data()[current->key_]); - current = current->next_; - } - }else{ - thing_resource->fill_api_io(response.get_data()); - } - }else{ - thing_resource = thing_resource == NULL ? resources_.find(resource) : thing_resource->find(resource); - if(thing_resource==NULL){ - response.set_signal_flag(thinger_message::REQUEST_ERROR); - }else{ - thing_resource->handle_request(request, response); - } - } - } - } - } - send_message(response); - } - }; -} - +// The MIT License (MIT) +// +// Copyright (c) 2015 THINGER LTD +// Author: alvarolb@gmail.com (Alvaro Luis Bustamante) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef THINGER_H +#define THINGER_H + +#include "pson.h" +#include "thinger_map.hpp" +#include "thinger_resource.hpp" +#include "thinger_message.hpp" +#include "thinger_encoder.hpp" +#include "thinger_decoder.hpp" +#include "thinger_message.hpp" +#include "thinger_io.hpp" + +#define KEEP_ALIVE_MILLIS 60000 + +namespace thinger{ + + using namespace protoson; + + class thinger : public thinger_io{ + public: + thinger() : + encoder(*this), + decoder(*this), + last_keep_alive(0), + keep_alive_response(true) + { + } + + virtual ~thinger(){ + } + + private: + thinger_write_encoder encoder; + thinger_read_decoder decoder; + unsigned long last_keep_alive; + bool keep_alive_response; + thinger_map<thinger_resource> resources_; + + protected: + /** + * Can be override to start reconnection process + */ + virtual void disconnected(){ + // stop all streaming resources after disconnect + if(thinger_resource::get_streaming_counter()>0) { + thinger_map<thinger_resource>::entry* current = resources_.begin(); + while(current!=NULL){ + current->value_.disable_streaming(); + current = current->next_; + } + } + } + + /** + * Stream a given resource + */ + void stream_resource(thinger_resource& resource, thinger_message::signal_flag type){ + thinger_message message; + message.set_stream_id(resource.get_stream_id()); + message.set_signal_flag(type); + resource.fill_api_io(message.get_data()); + send_message(message); + } + + public: + + thinger_resource & operator[](const char* res){ + return resources_[res]; + } + + bool connect(const char* username, const char* device_id, const char* credential) + { + // reset keep alive status for each connection + keep_alive_response = true; + + thinger_message message; + message.set_signal_flag(thinger_message::AUTH); + message.resources().add(username).add(device_id).add(credential); + if(!send_message(message)) return false; + + thinger_message response; + return read_message(response) && response.get_signal_flag() == thinger_message::REQUEST_OK; + } + + bool call_endpoint(const char* endpoint_name){ + thinger_message message; + message.set_signal_flag(thinger_message::CALL_ENDPOINT); + message.resources().add(endpoint_name); + return send_message(message); + } + + bool call_endpoint(const char* endpoint_name, pson& data){ + thinger_message message; + message.set_signal_flag(thinger_message::CALL_ENDPOINT); + message.set_data(data); + message.resources().add(endpoint_name); + return send_message(message); + } + + bool call_endpoint(const char* endpoint_name, thinger_resource& resource){ + thinger_message message; + message.set_signal_flag(thinger_message::CALL_ENDPOINT); + message.resources().add(endpoint_name); + resource.fill_api_io(message.get_data()); + return send_message(message); + } + + /** + * Stream the given resource. This resource should be previously requested by an external process. + * Otherwise, the resource will not be streamed as nothing will be listening for it. + */ + bool stream(thinger_resource& resource){ + if(resource.stream_enabled()){ + stream_resource(resource, thinger_message::STREAM_EVENT); + return true; + } + return false; + } + + bool send_message(thinger_message& message) + { + thinger_encoder sink; + sink.encode(message); + encoder.pb_encode_varint(MESSAGE); + encoder.pb_encode_varint(sink.bytes_written()); + encoder.encode(message); + return write(NULL, 0, true); + } + + void handle(unsigned long current_time, bool bytes_available) + { + // handle input + if(bytes_available){ + handle_input(); + } + + // handle keep alive + if(current_time-last_keep_alive>=KEEP_ALIVE_MILLIS){ + if(keep_alive_response){ + last_keep_alive = current_time; + keep_alive_response = false; + encoder.pb_encode_varint(KEEP_ALIVE); + encoder.pb_encode_varint(0); + write(NULL, 0, true); + }else{ + disconnected(); + } + } + + // handle streaming resources + if(thinger_resource::get_streaming_counter()>0){ + thinger_map<thinger_resource>::entry* current = resources_.begin(); + while(current!=NULL){ + if(current->value_.stream_required(current_time)){ + stream_resource(current->value_, thinger_message::STREAM_SAMPLE); + } + current = current->next_; + } + } + } + + bool read_message(thinger_message& message){ + uint8_t type = decoder.pb_decode_varint32(); + switch (type){ + case MESSAGE: { + size_t size = decoder.pb_decode_varint32(); + decoder.decode(message, size); + } + break; + case KEEP_ALIVE: { + size_t size = decoder.pb_decode_varint32(); + keep_alive_response = true; + } + return false; + default: + return false; + } + return true; + } + + bool handle_input(){ + thinger_message message; + if(read_message(message)){ + handle_request_received(message); + } + return true; + } + + private: + + void handle_request_received(thinger_message& request) + { + thinger_message response(request); + if(!request.has_resource()){ + response.set_signal_flag(thinger_message::REQUEST_ERROR); + } + else{ + thinger_resource * thing_resource = NULL; + for(pson_array::iterator it = request.resources().begin(); it.valid(); it.next()){ + if(!it.item().is_string()){ + response.set_signal_flag(thinger_message::REQUEST_ERROR); + break; + } + const char* resource = it.item(); + + if(it.has_next()){ + thing_resource = thing_resource == NULL ? resources_.find(resource) : thing_resource->find(resource); + if(thing_resource==NULL) { + response.set_signal_flag(thinger_message::REQUEST_ERROR); + break; + } + }else{ + if(strcmp("api", resource)==0){ + if(thing_resource==NULL){ + thinger_map<thinger_resource>::entry* current = resources_.begin(); + while(current!=NULL){ + current->value_.fill_api(response.get_data()[current->key_]); + current = current->next_; + } + }else{ + thing_resource->fill_api_io(response.get_data()); + } + }else{ + thing_resource = thing_resource == NULL ? resources_.find(resource) : thing_resource->find(resource); + if(thing_resource==NULL){ + response.set_signal_flag(thinger_message::REQUEST_ERROR); + }else{ + thing_resource->handle_request(request, response); + } + } + } + } + } + send_message(response); + } + }; +} + #endif