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 Alvaro Luis Bustamante

Committer:
alvarolb
Date:
Sat Dec 26 13:18:01 2015 +0000
Revision:
4:de51256455f7
Parent:
1:d54f92accbc3
Adapter pson to properly work in ARM Mbed old compiler

Who changed what in which revision?

UserRevisionLine numberNew contents of line
alvarolb 1:d54f92accbc3 1 // The MIT License (MIT)
alvarolb 1:d54f92accbc3 2 //
alvarolb 1:d54f92accbc3 3 // Copyright (c) 2015 THINGER LTD
alvarolb 1:d54f92accbc3 4 // Author: alvarolb@gmail.com (Alvaro Luis Bustamante)
alvarolb 1:d54f92accbc3 5 //
alvarolb 1:d54f92accbc3 6 // Permission is hereby granted, free of charge, to any person obtaining a copy
alvarolb 1:d54f92accbc3 7 // of this software and associated documentation files (the "Software"), to deal
alvarolb 1:d54f92accbc3 8 // in the Software without restriction, including without limitation the rights
alvarolb 1:d54f92accbc3 9 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
alvarolb 1:d54f92accbc3 10 // copies of the Software, and to permit persons to whom the Software is
alvarolb 1:d54f92accbc3 11 // furnished to do so, subject to the following conditions:
alvarolb 1:d54f92accbc3 12 //
alvarolb 1:d54f92accbc3 13 // The above copyright notice and this permission notice shall be included in
alvarolb 1:d54f92accbc3 14 // all copies or substantial portions of the Software.
alvarolb 1:d54f92accbc3 15 //
alvarolb 1:d54f92accbc3 16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
alvarolb 1:d54f92accbc3 17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
alvarolb 1:d54f92accbc3 18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
alvarolb 1:d54f92accbc3 19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
alvarolb 1:d54f92accbc3 20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
alvarolb 1:d54f92accbc3 21 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
alvarolb 1:d54f92accbc3 22 // THE SOFTWARE.
alvarolb 1:d54f92accbc3 23
alvarolb 1:d54f92accbc3 24 #ifndef THINGER_H
alvarolb 1:d54f92accbc3 25 #define THINGER_H
alvarolb 1:d54f92accbc3 26
alvarolb 1:d54f92accbc3 27 #include "pson.h"
alvarolb 1:d54f92accbc3 28 #include "thinger_map.hpp"
alvarolb 1:d54f92accbc3 29 #include "thinger_resource.hpp"
alvarolb 1:d54f92accbc3 30 #include "thinger_message.hpp"
alvarolb 1:d54f92accbc3 31 #include "thinger_encoder.hpp"
alvarolb 1:d54f92accbc3 32 #include "thinger_decoder.hpp"
alvarolb 1:d54f92accbc3 33 #include "thinger_message.hpp"
alvarolb 1:d54f92accbc3 34 #include "thinger_io.hpp"
alvarolb 1:d54f92accbc3 35
alvarolb 1:d54f92accbc3 36 #define KEEP_ALIVE_MILLIS 60000
alvarolb 1:d54f92accbc3 37
alvarolb 1:d54f92accbc3 38 namespace thinger{
alvarolb 1:d54f92accbc3 39
alvarolb 1:d54f92accbc3 40 using namespace protoson;
alvarolb 1:d54f92accbc3 41
alvarolb 1:d54f92accbc3 42 class thinger : public thinger_io{
alvarolb 1:d54f92accbc3 43 public:
alvarolb 1:d54f92accbc3 44 thinger() :
alvarolb 1:d54f92accbc3 45 encoder(*this),
alvarolb 1:d54f92accbc3 46 decoder(*this),
alvarolb 1:d54f92accbc3 47 last_keep_alive(0),
alvarolb 1:d54f92accbc3 48 keep_alive_response(true)
alvarolb 1:d54f92accbc3 49 {
alvarolb 1:d54f92accbc3 50 }
alvarolb 1:d54f92accbc3 51
alvarolb 1:d54f92accbc3 52 virtual ~thinger(){
alvarolb 1:d54f92accbc3 53 }
alvarolb 1:d54f92accbc3 54
alvarolb 1:d54f92accbc3 55 private:
alvarolb 1:d54f92accbc3 56 thinger_write_encoder encoder;
alvarolb 1:d54f92accbc3 57 thinger_read_decoder decoder;
alvarolb 1:d54f92accbc3 58 unsigned long last_keep_alive;
alvarolb 1:d54f92accbc3 59 bool keep_alive_response;
alvarolb 1:d54f92accbc3 60 thinger_map<thinger_resource> resources_;
alvarolb 1:d54f92accbc3 61
alvarolb 1:d54f92accbc3 62 protected:
alvarolb 1:d54f92accbc3 63 /**
alvarolb 1:d54f92accbc3 64 * Can be override to start reconnection process
alvarolb 1:d54f92accbc3 65 */
alvarolb 1:d54f92accbc3 66 virtual void disconnected(){
alvarolb 1:d54f92accbc3 67 // stop all streaming resources after disconnect
alvarolb 1:d54f92accbc3 68 if(thinger_resource::get_streaming_counter()>0) {
alvarolb 1:d54f92accbc3 69 thinger_map<thinger_resource>::entry* current = resources_.begin();
alvarolb 1:d54f92accbc3 70 while(current!=NULL){
alvarolb 1:d54f92accbc3 71 current->value_.disable_streaming();
alvarolb 1:d54f92accbc3 72 current = current->next_;
alvarolb 1:d54f92accbc3 73 }
alvarolb 1:d54f92accbc3 74 }
alvarolb 1:d54f92accbc3 75 }
alvarolb 1:d54f92accbc3 76
alvarolb 1:d54f92accbc3 77 /**
alvarolb 1:d54f92accbc3 78 * Stream a given resource
alvarolb 1:d54f92accbc3 79 */
alvarolb 1:d54f92accbc3 80 void stream_resource(thinger_resource& resource, thinger_message::signal_flag type){
alvarolb 1:d54f92accbc3 81 thinger_message message;
alvarolb 1:d54f92accbc3 82 message.set_stream_id(resource.get_stream_id());
alvarolb 1:d54f92accbc3 83 message.set_signal_flag(type);
alvarolb 1:d54f92accbc3 84 resource.fill_api_io(message.get_data());
alvarolb 1:d54f92accbc3 85 send_message(message);
alvarolb 1:d54f92accbc3 86 }
alvarolb 1:d54f92accbc3 87
alvarolb 1:d54f92accbc3 88 public:
alvarolb 1:d54f92accbc3 89
alvarolb 1:d54f92accbc3 90 thinger_resource & operator[](const char* res){
alvarolb 1:d54f92accbc3 91 return resources_[res];
alvarolb 1:d54f92accbc3 92 }
alvarolb 1:d54f92accbc3 93
alvarolb 1:d54f92accbc3 94 bool connect(const char* username, const char* device_id, const char* credential)
alvarolb 1:d54f92accbc3 95 {
alvarolb 1:d54f92accbc3 96 // reset keep alive status for each connection
alvarolb 1:d54f92accbc3 97 keep_alive_response = true;
alvarolb 1:d54f92accbc3 98
alvarolb 1:d54f92accbc3 99 thinger_message message;
alvarolb 1:d54f92accbc3 100 message.set_signal_flag(thinger_message::AUTH);
alvarolb 1:d54f92accbc3 101 message.resources().add(username).add(device_id).add(credential);
alvarolb 1:d54f92accbc3 102 if(!send_message(message)) return false;
alvarolb 1:d54f92accbc3 103
alvarolb 1:d54f92accbc3 104 thinger_message response;
alvarolb 1:d54f92accbc3 105 return read_message(response) && response.get_signal_flag() == thinger_message::REQUEST_OK;
alvarolb 1:d54f92accbc3 106 }
alvarolb 1:d54f92accbc3 107
alvarolb 1:d54f92accbc3 108 bool call_endpoint(const char* endpoint_name){
alvarolb 1:d54f92accbc3 109 thinger_message message;
alvarolb 1:d54f92accbc3 110 message.set_signal_flag(thinger_message::CALL_ENDPOINT);
alvarolb 1:d54f92accbc3 111 message.resources().add(endpoint_name);
alvarolb 1:d54f92accbc3 112 return send_message(message);
alvarolb 1:d54f92accbc3 113 }
alvarolb 1:d54f92accbc3 114
alvarolb 1:d54f92accbc3 115 bool call_endpoint(const char* endpoint_name, pson& data){
alvarolb 1:d54f92accbc3 116 thinger_message message;
alvarolb 1:d54f92accbc3 117 message.set_signal_flag(thinger_message::CALL_ENDPOINT);
alvarolb 1:d54f92accbc3 118 message.set_data(data);
alvarolb 1:d54f92accbc3 119 message.resources().add(endpoint_name);
alvarolb 1:d54f92accbc3 120 return send_message(message);
alvarolb 1:d54f92accbc3 121 }
alvarolb 1:d54f92accbc3 122
alvarolb 1:d54f92accbc3 123 bool call_endpoint(const char* endpoint_name, thinger_resource& resource){
alvarolb 1:d54f92accbc3 124 thinger_message message;
alvarolb 1:d54f92accbc3 125 message.set_signal_flag(thinger_message::CALL_ENDPOINT);
alvarolb 1:d54f92accbc3 126 message.resources().add(endpoint_name);
alvarolb 1:d54f92accbc3 127 resource.fill_api_io(message.get_data());
alvarolb 1:d54f92accbc3 128 return send_message(message);
alvarolb 1:d54f92accbc3 129 }
alvarolb 1:d54f92accbc3 130
alvarolb 1:d54f92accbc3 131 /**
alvarolb 1:d54f92accbc3 132 * Stream the given resource. This resource should be previously requested by an external process.
alvarolb 1:d54f92accbc3 133 * Otherwise, the resource will not be streamed as nothing will be listening for it.
alvarolb 1:d54f92accbc3 134 */
alvarolb 1:d54f92accbc3 135 bool stream(thinger_resource& resource){
alvarolb 1:d54f92accbc3 136 if(resource.stream_enabled()){
alvarolb 1:d54f92accbc3 137 stream_resource(resource, thinger_message::STREAM_EVENT);
alvarolb 1:d54f92accbc3 138 return true;
alvarolb 1:d54f92accbc3 139 }
alvarolb 1:d54f92accbc3 140 return false;
alvarolb 1:d54f92accbc3 141 }
alvarolb 1:d54f92accbc3 142
alvarolb 1:d54f92accbc3 143 bool send_message(thinger_message& message)
alvarolb 1:d54f92accbc3 144 {
alvarolb 1:d54f92accbc3 145 thinger_encoder sink;
alvarolb 1:d54f92accbc3 146 sink.encode(message);
alvarolb 1:d54f92accbc3 147 encoder.pb_encode_varint(MESSAGE);
alvarolb 1:d54f92accbc3 148 encoder.pb_encode_varint(sink.bytes_written());
alvarolb 1:d54f92accbc3 149 encoder.encode(message);
alvarolb 1:d54f92accbc3 150 return write(NULL, 0, true);
alvarolb 1:d54f92accbc3 151 }
alvarolb 1:d54f92accbc3 152
alvarolb 1:d54f92accbc3 153 void handle(unsigned long current_time, bool bytes_available)
alvarolb 1:d54f92accbc3 154 {
alvarolb 1:d54f92accbc3 155 // handle input
alvarolb 1:d54f92accbc3 156 if(bytes_available){
alvarolb 1:d54f92accbc3 157 handle_input();
alvarolb 1:d54f92accbc3 158 }
alvarolb 1:d54f92accbc3 159
alvarolb 1:d54f92accbc3 160 // handle keep alive
alvarolb 1:d54f92accbc3 161 if(current_time-last_keep_alive>=KEEP_ALIVE_MILLIS){
alvarolb 1:d54f92accbc3 162 if(keep_alive_response){
alvarolb 1:d54f92accbc3 163 last_keep_alive = current_time;
alvarolb 1:d54f92accbc3 164 keep_alive_response = false;
alvarolb 1:d54f92accbc3 165 encoder.pb_encode_varint(KEEP_ALIVE);
alvarolb 1:d54f92accbc3 166 encoder.pb_encode_varint(0);
alvarolb 1:d54f92accbc3 167 write(NULL, 0, true);
alvarolb 1:d54f92accbc3 168 }else{
alvarolb 1:d54f92accbc3 169 disconnected();
alvarolb 1:d54f92accbc3 170 }
alvarolb 1:d54f92accbc3 171 }
alvarolb 1:d54f92accbc3 172
alvarolb 1:d54f92accbc3 173 // handle streaming resources
alvarolb 1:d54f92accbc3 174 if(thinger_resource::get_streaming_counter()>0){
alvarolb 1:d54f92accbc3 175 thinger_map<thinger_resource>::entry* current = resources_.begin();
alvarolb 1:d54f92accbc3 176 while(current!=NULL){
alvarolb 1:d54f92accbc3 177 if(current->value_.stream_required(current_time)){
alvarolb 1:d54f92accbc3 178 stream_resource(current->value_, thinger_message::STREAM_SAMPLE);
alvarolb 1:d54f92accbc3 179 }
alvarolb 1:d54f92accbc3 180 current = current->next_;
alvarolb 1:d54f92accbc3 181 }
alvarolb 1:d54f92accbc3 182 }
alvarolb 1:d54f92accbc3 183 }
alvarolb 1:d54f92accbc3 184
alvarolb 1:d54f92accbc3 185 bool read_message(thinger_message& message){
alvarolb 1:d54f92accbc3 186 uint8_t type = decoder.pb_decode_varint32();
alvarolb 1:d54f92accbc3 187 switch (type){
alvarolb 1:d54f92accbc3 188 case MESSAGE: {
alvarolb 1:d54f92accbc3 189 size_t size = decoder.pb_decode_varint32();
alvarolb 1:d54f92accbc3 190 decoder.decode(message, size);
alvarolb 1:d54f92accbc3 191 }
alvarolb 1:d54f92accbc3 192 break;
alvarolb 1:d54f92accbc3 193 case KEEP_ALIVE: {
alvarolb 1:d54f92accbc3 194 size_t size = decoder.pb_decode_varint32();
alvarolb 1:d54f92accbc3 195 keep_alive_response = true;
alvarolb 1:d54f92accbc3 196 }
alvarolb 1:d54f92accbc3 197 return false;
alvarolb 1:d54f92accbc3 198 default:
alvarolb 1:d54f92accbc3 199 return false;
alvarolb 1:d54f92accbc3 200 }
alvarolb 1:d54f92accbc3 201 return true;
alvarolb 1:d54f92accbc3 202 }
alvarolb 1:d54f92accbc3 203
alvarolb 1:d54f92accbc3 204 bool handle_input(){
alvarolb 1:d54f92accbc3 205 thinger_message message;
alvarolb 1:d54f92accbc3 206 if(read_message(message)){
alvarolb 1:d54f92accbc3 207 handle_request_received(message);
alvarolb 1:d54f92accbc3 208 }
alvarolb 1:d54f92accbc3 209 return true;
alvarolb 1:d54f92accbc3 210 }
alvarolb 1:d54f92accbc3 211
alvarolb 1:d54f92accbc3 212 private:
alvarolb 1:d54f92accbc3 213
alvarolb 1:d54f92accbc3 214 void handle_request_received(thinger_message& request)
alvarolb 1:d54f92accbc3 215 {
alvarolb 1:d54f92accbc3 216 thinger_message response(request);
alvarolb 1:d54f92accbc3 217 if(!request.has_resource()){
alvarolb 1:d54f92accbc3 218 response.set_signal_flag(thinger_message::REQUEST_ERROR);
alvarolb 1:d54f92accbc3 219 }
alvarolb 1:d54f92accbc3 220 else{
alvarolb 1:d54f92accbc3 221 thinger_resource * thing_resource = NULL;
alvarolb 1:d54f92accbc3 222 for(pson_array::iterator it = request.resources().begin(); it.valid(); it.next()){
alvarolb 1:d54f92accbc3 223 if(!it.item().is_string()){
alvarolb 1:d54f92accbc3 224 response.set_signal_flag(thinger_message::REQUEST_ERROR);
alvarolb 1:d54f92accbc3 225 break;
alvarolb 1:d54f92accbc3 226 }
alvarolb 1:d54f92accbc3 227 const char* resource = it.item();
alvarolb 1:d54f92accbc3 228
alvarolb 1:d54f92accbc3 229 if(it.has_next()){
alvarolb 1:d54f92accbc3 230 thing_resource = thing_resource == NULL ? resources_.find(resource) : thing_resource->find(resource);
alvarolb 1:d54f92accbc3 231 if(thing_resource==NULL) {
alvarolb 1:d54f92accbc3 232 response.set_signal_flag(thinger_message::REQUEST_ERROR);
alvarolb 1:d54f92accbc3 233 break;
alvarolb 1:d54f92accbc3 234 }
alvarolb 1:d54f92accbc3 235 }else{
alvarolb 1:d54f92accbc3 236 if(strcmp("api", resource)==0){
alvarolb 1:d54f92accbc3 237 if(thing_resource==NULL){
alvarolb 1:d54f92accbc3 238 thinger_map<thinger_resource>::entry* current = resources_.begin();
alvarolb 1:d54f92accbc3 239 while(current!=NULL){
alvarolb 1:d54f92accbc3 240 current->value_.fill_api(response.get_data()[current->key_]);
alvarolb 1:d54f92accbc3 241 current = current->next_;
alvarolb 1:d54f92accbc3 242 }
alvarolb 1:d54f92accbc3 243 }else{
alvarolb 1:d54f92accbc3 244 thing_resource->fill_api_io(response.get_data());
alvarolb 1:d54f92accbc3 245 }
alvarolb 1:d54f92accbc3 246 }else{
alvarolb 1:d54f92accbc3 247 thing_resource = thing_resource == NULL ? resources_.find(resource) : thing_resource->find(resource);
alvarolb 1:d54f92accbc3 248 if(thing_resource==NULL){
alvarolb 1:d54f92accbc3 249 response.set_signal_flag(thinger_message::REQUEST_ERROR);
alvarolb 1:d54f92accbc3 250 }else{
alvarolb 1:d54f92accbc3 251 thing_resource->handle_request(request, response);
alvarolb 1:d54f92accbc3 252 }
alvarolb 1:d54f92accbc3 253 }
alvarolb 1:d54f92accbc3 254 }
alvarolb 1:d54f92accbc3 255 }
alvarolb 1:d54f92accbc3 256 }
alvarolb 1:d54f92accbc3 257 send_message(response);
alvarolb 1:d54f92accbc3 258 }
alvarolb 1:d54f92accbc3 259 };
alvarolb 1:d54f92accbc3 260 }
alvarolb 1:d54f92accbc3 261
alvarolb 0:b75d784c7c1a 262 #endif