branch with improvemnts

Fork of M2XStreamClient by AT&T M2X Team

Committer:
citrusbyte
Date:
Fri Jan 03 11:55:17 2014 +0000
Revision:
8:bd39886d72fb
Parent:
6:e6d66d99dd6f
Update mbed library

Who changed what in which revision?

UserRevisionLine numberNew contents of line
citrusbyte 5:ea68c8980ad8 1 #include "M2XStreamClient.h"
citrusbyte 5:ea68c8980ad8 2
citrusbyte 5:ea68c8980ad8 3 #include <jsonlite.h>
citrusbyte 5:ea68c8980ad8 4
citrusbyte 5:ea68c8980ad8 5 #include "StreamParseFunctions.h"
citrusbyte 5:ea68c8980ad8 6 #include "LocationParseFunctions.h"
citrusbyte 5:ea68c8980ad8 7
citrusbyte 5:ea68c8980ad8 8 const char* M2XStreamClient::kDefaultM2XHost = "api-m2x.att.com";
citrusbyte 5:ea68c8980ad8 9
citrusbyte 6:e6d66d99dd6f 10 int print_encoded_string(Print* print, const char* str);
citrusbyte 8:bd39886d72fb 11 int tolower(int ch);
citrusbyte 8:bd39886d72fb 12
citrusbyte 8:bd39886d72fb 13 #if defined(ARDUINO_PLATFORM) || defined(MBED_PLATFORM)
citrusbyte 8:bd39886d72fb 14 int tolower(int ch)
citrusbyte 8:bd39886d72fb 15 {
citrusbyte 8:bd39886d72fb 16 // Arduino and mbed use ASCII table, so we can simplify the implementation
citrusbyte 8:bd39886d72fb 17 if ((ch >= 'A') && (ch <= 'Z')) {
citrusbyte 8:bd39886d72fb 18 return (ch + 32);
citrusbyte 8:bd39886d72fb 19 }
citrusbyte 8:bd39886d72fb 20 return ch;
citrusbyte 8:bd39886d72fb 21 }
citrusbyte 8:bd39886d72fb 22 #else
citrusbyte 8:bd39886d72fb 23 // For other platform, we use libc's tolower by default
citrusbyte 8:bd39886d72fb 24 #include <ctype.h>
citrusbyte 8:bd39886d72fb 25 #endif
citrusbyte 5:ea68c8980ad8 26
citrusbyte 5:ea68c8980ad8 27 M2XStreamClient::M2XStreamClient(Client* client,
citrusbyte 5:ea68c8980ad8 28 const char* key,
citrusbyte 8:bd39886d72fb 29 int case_insensitive,
citrusbyte 5:ea68c8980ad8 30 const char* host,
citrusbyte 5:ea68c8980ad8 31 int port) : _client(client),
citrusbyte 5:ea68c8980ad8 32 _key(key),
citrusbyte 8:bd39886d72fb 33 _case_insensitive(case_insensitive),
citrusbyte 5:ea68c8980ad8 34 _host(host),
citrusbyte 5:ea68c8980ad8 35 _port(port),
citrusbyte 5:ea68c8980ad8 36 _null_print() {
citrusbyte 5:ea68c8980ad8 37 }
citrusbyte 5:ea68c8980ad8 38
citrusbyte 6:e6d66d99dd6f 39 #define WRITE_QUERY_PART(client_, started_, name_, str_) { \
citrusbyte 6:e6d66d99dd6f 40 if (str_) { \
citrusbyte 6:e6d66d99dd6f 41 if (started_) { \
citrusbyte 6:e6d66d99dd6f 42 (client_)->print("&"); \
citrusbyte 6:e6d66d99dd6f 43 } else { \
citrusbyte 6:e6d66d99dd6f 44 (client_)->print("?"); \
citrusbyte 6:e6d66d99dd6f 45 started_ = true; \
citrusbyte 6:e6d66d99dd6f 46 } \
citrusbyte 6:e6d66d99dd6f 47 (client_)->print(name_ "="); \
citrusbyte 6:e6d66d99dd6f 48 (client_)->print(str_); \
citrusbyte 6:e6d66d99dd6f 49 } \
citrusbyte 5:ea68c8980ad8 50 }
citrusbyte 5:ea68c8980ad8 51
citrusbyte 6:e6d66d99dd6f 52 int M2XStreamClient::fetchValues(const char* feedId, const char* streamName,
citrusbyte 6:e6d66d99dd6f 53 stream_value_read_callback callback, void* context,
citrusbyte 6:e6d66d99dd6f 54 const char* startTime, const char* endTime,
citrusbyte 6:e6d66d99dd6f 55 const char* limit) {
citrusbyte 5:ea68c8980ad8 56 if (_client->connect(_host, _port)) {
citrusbyte 6:e6d66d99dd6f 57 bool query_started = false;
citrusbyte 5:ea68c8980ad8 58
citrusbyte 6:e6d66d99dd6f 59 DBGLN("%s", "Connected to M2X server!");
citrusbyte 5:ea68c8980ad8 60 _client->print("GET /v1/feeds/");
citrusbyte 5:ea68c8980ad8 61 print_encoded_string(_client, feedId);
citrusbyte 5:ea68c8980ad8 62 _client->print("/streams/");
citrusbyte 5:ea68c8980ad8 63 print_encoded_string(_client, streamName);
citrusbyte 6:e6d66d99dd6f 64 _client->print("/values");
citrusbyte 5:ea68c8980ad8 65
citrusbyte 6:e6d66d99dd6f 66 WRITE_QUERY_PART(_client, query_started, "start", startTime);
citrusbyte 6:e6d66d99dd6f 67 WRITE_QUERY_PART(_client, query_started, "end", endTime);
citrusbyte 6:e6d66d99dd6f 68 WRITE_QUERY_PART(_client, query_started, "limit", limit);
citrusbyte 6:e6d66d99dd6f 69
citrusbyte 6:e6d66d99dd6f 70 _client->println(" HTTP/1.0");
citrusbyte 5:ea68c8980ad8 71 writeHttpHeader(-1);
citrusbyte 5:ea68c8980ad8 72 } else {
citrusbyte 6:e6d66d99dd6f 73 DBGLN("%s", "ERROR: Cannot connect to M2X server!");
citrusbyte 5:ea68c8980ad8 74 return E_NOCONNECTION;
citrusbyte 5:ea68c8980ad8 75 }
citrusbyte 5:ea68c8980ad8 76 int status = readStatusCode(false);
citrusbyte 5:ea68c8980ad8 77 if (status == 200) {
citrusbyte 5:ea68c8980ad8 78 readStreamValue(callback, context);
citrusbyte 5:ea68c8980ad8 79 }
citrusbyte 5:ea68c8980ad8 80
citrusbyte 5:ea68c8980ad8 81 close();
citrusbyte 5:ea68c8980ad8 82 return status;
citrusbyte 5:ea68c8980ad8 83 }
citrusbyte 5:ea68c8980ad8 84
citrusbyte 5:ea68c8980ad8 85 int M2XStreamClient::readLocation(const char* feedId,
citrusbyte 5:ea68c8980ad8 86 location_read_callback callback,
citrusbyte 5:ea68c8980ad8 87 void* context) {
citrusbyte 5:ea68c8980ad8 88 if (_client->connect(_host, _port)) {
citrusbyte 6:e6d66d99dd6f 89 DBGLN("%s", "Connected to M2X server!");
citrusbyte 5:ea68c8980ad8 90 _client->print("GET /v1/feeds/");
citrusbyte 5:ea68c8980ad8 91 print_encoded_string(_client, feedId);
citrusbyte 5:ea68c8980ad8 92 _client->println("/location HTTP/1.0");
citrusbyte 5:ea68c8980ad8 93
citrusbyte 5:ea68c8980ad8 94 writeHttpHeader(-1);
citrusbyte 5:ea68c8980ad8 95 } else {
citrusbyte 6:e6d66d99dd6f 96 DBGLN("%s", "ERROR: Cannot connect to M2X server!");
citrusbyte 5:ea68c8980ad8 97 return E_NOCONNECTION;
citrusbyte 5:ea68c8980ad8 98 }
citrusbyte 5:ea68c8980ad8 99 int status = readStatusCode(false);
citrusbyte 5:ea68c8980ad8 100 if (status == 200) {
citrusbyte 5:ea68c8980ad8 101 readLocation(callback, context);
citrusbyte 5:ea68c8980ad8 102 }
citrusbyte 5:ea68c8980ad8 103
citrusbyte 5:ea68c8980ad8 104 close();
citrusbyte 5:ea68c8980ad8 105 return status;
citrusbyte 5:ea68c8980ad8 106 }
citrusbyte 5:ea68c8980ad8 107
citrusbyte 5:ea68c8980ad8 108 // Encodes and prints string using Percent-encoding specified
citrusbyte 5:ea68c8980ad8 109 // in RFC 1738, Section 2.2
citrusbyte 6:e6d66d99dd6f 110 int print_encoded_string(Print* print, const char* str) {
citrusbyte 5:ea68c8980ad8 111 int bytes = 0;
citrusbyte 5:ea68c8980ad8 112 for (int i = 0; str[i] != 0; i++) {
citrusbyte 5:ea68c8980ad8 113 if (((str[i] >= 'A') && (str[i] <= 'Z')) ||
citrusbyte 5:ea68c8980ad8 114 ((str[i] >= 'a') && (str[i] <= 'z')) ||
citrusbyte 5:ea68c8980ad8 115 ((str[i] >= '0') && (str[i] <= '9')) ||
citrusbyte 5:ea68c8980ad8 116 (str[i] == '-') || (str[i] == '_') ||
citrusbyte 5:ea68c8980ad8 117 (str[i] == '.') || (str[i] == '~')) {
citrusbyte 5:ea68c8980ad8 118 bytes += print->print(str[i]);
citrusbyte 5:ea68c8980ad8 119 } else {
citrusbyte 5:ea68c8980ad8 120 // Encode all other characters
citrusbyte 5:ea68c8980ad8 121 bytes += print->print('%');
citrusbyte 5:ea68c8980ad8 122 bytes += print->print(HEX(str[i] / 16));
citrusbyte 5:ea68c8980ad8 123 bytes += print->print(HEX(str[i] % 16));
citrusbyte 5:ea68c8980ad8 124 }
citrusbyte 5:ea68c8980ad8 125 }
citrusbyte 5:ea68c8980ad8 126 return bytes;
citrusbyte 5:ea68c8980ad8 127 }
citrusbyte 5:ea68c8980ad8 128
citrusbyte 6:e6d66d99dd6f 129 void M2XStreamClient::writePostHeader(const char* feedId,
citrusbyte 5:ea68c8980ad8 130 const char* streamName,
citrusbyte 5:ea68c8980ad8 131 int contentLength) {
citrusbyte 5:ea68c8980ad8 132 _client->print("PUT /v1/feeds/");
citrusbyte 5:ea68c8980ad8 133 print_encoded_string(_client, feedId);
citrusbyte 5:ea68c8980ad8 134 _client->print("/streams/");
citrusbyte 5:ea68c8980ad8 135 print_encoded_string(_client, streamName);
citrusbyte 5:ea68c8980ad8 136 _client->println(" HTTP/1.0");
citrusbyte 6:e6d66d99dd6f 137
citrusbyte 5:ea68c8980ad8 138 writeHttpHeader(contentLength);
citrusbyte 5:ea68c8980ad8 139 }
citrusbyte 5:ea68c8980ad8 140
citrusbyte 5:ea68c8980ad8 141 void M2XStreamClient::writeHttpHeader(int contentLength) {
citrusbyte 8:bd39886d72fb 142 _client->println(USER_AGENT);
citrusbyte 5:ea68c8980ad8 143 _client->print("X-M2X-KEY: ");
citrusbyte 5:ea68c8980ad8 144 _client->println(_key);
citrusbyte 6:e6d66d99dd6f 145
citrusbyte 5:ea68c8980ad8 146 _client->print("Host: ");
citrusbyte 5:ea68c8980ad8 147 print_encoded_string(_client, _host);
citrusbyte 5:ea68c8980ad8 148 if (_port != kDefaultM2XPort) {
citrusbyte 5:ea68c8980ad8 149 _client->print(":");
citrusbyte 5:ea68c8980ad8 150 // port is an integer, does not need encoding
citrusbyte 5:ea68c8980ad8 151 _client->print(_port);
citrusbyte 5:ea68c8980ad8 152 }
citrusbyte 5:ea68c8980ad8 153 _client->println();
citrusbyte 5:ea68c8980ad8 154
citrusbyte 5:ea68c8980ad8 155 if (contentLength > 0) {
citrusbyte 6:e6d66d99dd6f 156 _client->println("Content-Type: application/json");
citrusbyte 6:e6d66d99dd6f 157 DBG("%s", "Content Length: ");
citrusbyte 6:e6d66d99dd6f 158 DBGLN("%d", contentLength);
citrusbyte 6:e6d66d99dd6f 159
citrusbyte 5:ea68c8980ad8 160 _client->print("Content-Length: ");
citrusbyte 5:ea68c8980ad8 161 _client->println(contentLength);
citrusbyte 5:ea68c8980ad8 162 }
citrusbyte 5:ea68c8980ad8 163 _client->println();
citrusbyte 5:ea68c8980ad8 164 }
citrusbyte 5:ea68c8980ad8 165
citrusbyte 5:ea68c8980ad8 166 int M2XStreamClient::waitForString(const char* str) {
citrusbyte 5:ea68c8980ad8 167 int currentIndex = 0;
citrusbyte 5:ea68c8980ad8 168 if (str[currentIndex] == '\0') return E_OK;
citrusbyte 5:ea68c8980ad8 169
citrusbyte 5:ea68c8980ad8 170 while (true) {
citrusbyte 5:ea68c8980ad8 171 while (_client->available()) {
citrusbyte 5:ea68c8980ad8 172 char c = _client->read();
citrusbyte 6:e6d66d99dd6f 173 DBG("%c", c);
citrusbyte 5:ea68c8980ad8 174
citrusbyte 8:bd39886d72fb 175 int cmp;
citrusbyte 8:bd39886d72fb 176 if (_case_insensitive) {
citrusbyte 8:bd39886d72fb 177 cmp = tolower(c) - tolower(str[currentIndex]);
citrusbyte 8:bd39886d72fb 178 } else {
citrusbyte 8:bd39886d72fb 179 cmp = c - str[currentIndex];
citrusbyte 8:bd39886d72fb 180 }
citrusbyte 8:bd39886d72fb 181
citrusbyte 8:bd39886d72fb 182 if ((str[currentIndex] == '*') || (cmp == 0)) {
citrusbyte 5:ea68c8980ad8 183 currentIndex++;
citrusbyte 5:ea68c8980ad8 184 if (str[currentIndex] == '\0') {
citrusbyte 5:ea68c8980ad8 185 return E_OK;
citrusbyte 5:ea68c8980ad8 186 }
citrusbyte 5:ea68c8980ad8 187 } else {
citrusbyte 5:ea68c8980ad8 188 // start from the beginning
citrusbyte 5:ea68c8980ad8 189 currentIndex = 0;
citrusbyte 5:ea68c8980ad8 190 }
citrusbyte 5:ea68c8980ad8 191 }
citrusbyte 5:ea68c8980ad8 192
citrusbyte 5:ea68c8980ad8 193 if (!_client->connected()) {
citrusbyte 6:e6d66d99dd6f 194 DBGLN("%s", "ERROR: The client is disconnected from the server!");
citrusbyte 6:e6d66d99dd6f 195
citrusbyte 5:ea68c8980ad8 196 close();
citrusbyte 5:ea68c8980ad8 197 return E_DISCONNECTED;
citrusbyte 5:ea68c8980ad8 198 }
citrusbyte 5:ea68c8980ad8 199
citrusbyte 5:ea68c8980ad8 200 delay(1000);
citrusbyte 5:ea68c8980ad8 201 }
citrusbyte 5:ea68c8980ad8 202 // never reached here
citrusbyte 5:ea68c8980ad8 203 return E_NOTREACHABLE;
citrusbyte 5:ea68c8980ad8 204 }
citrusbyte 5:ea68c8980ad8 205
citrusbyte 5:ea68c8980ad8 206 int M2XStreamClient::readStatusCode(bool closeClient) {
citrusbyte 5:ea68c8980ad8 207 int responseCode = 0;
citrusbyte 5:ea68c8980ad8 208 int ret = waitForString("HTTP/*.* ");
citrusbyte 5:ea68c8980ad8 209 if (ret != E_OK) {
citrusbyte 5:ea68c8980ad8 210 if (closeClient) close();
citrusbyte 5:ea68c8980ad8 211 return ret;
citrusbyte 5:ea68c8980ad8 212 }
citrusbyte 5:ea68c8980ad8 213
citrusbyte 5:ea68c8980ad8 214 // ret is not needed from here(since it must be E_OK), so we can use it
citrusbyte 5:ea68c8980ad8 215 // as a regular variable now.
citrusbyte 5:ea68c8980ad8 216 ret = 0;
citrusbyte 5:ea68c8980ad8 217 while (true) {
citrusbyte 5:ea68c8980ad8 218 while (_client->available()) {
citrusbyte 5:ea68c8980ad8 219 char c = _client->read();
citrusbyte 6:e6d66d99dd6f 220 DBG("%c", c);
citrusbyte 6:e6d66d99dd6f 221
citrusbyte 5:ea68c8980ad8 222 responseCode = responseCode * 10 + (c - '0');
citrusbyte 5:ea68c8980ad8 223 ret++;
citrusbyte 5:ea68c8980ad8 224 if (ret == 3) {
citrusbyte 5:ea68c8980ad8 225 if (closeClient) close();
citrusbyte 5:ea68c8980ad8 226 return responseCode;
citrusbyte 5:ea68c8980ad8 227 }
citrusbyte 5:ea68c8980ad8 228 }
citrusbyte 5:ea68c8980ad8 229
citrusbyte 5:ea68c8980ad8 230 if (!_client->connected()) {
citrusbyte 6:e6d66d99dd6f 231 DBGLN("%s", "ERROR: The client is disconnected from the server!");
citrusbyte 6:e6d66d99dd6f 232
citrusbyte 5:ea68c8980ad8 233 if (closeClient) close();
citrusbyte 5:ea68c8980ad8 234 return E_DISCONNECTED;
citrusbyte 5:ea68c8980ad8 235 }
citrusbyte 5:ea68c8980ad8 236
citrusbyte 5:ea68c8980ad8 237 delay(1000);
citrusbyte 5:ea68c8980ad8 238 }
citrusbyte 5:ea68c8980ad8 239
citrusbyte 5:ea68c8980ad8 240 // never reached here
citrusbyte 5:ea68c8980ad8 241 return E_NOTREACHABLE;
citrusbyte 5:ea68c8980ad8 242 }
citrusbyte 5:ea68c8980ad8 243
citrusbyte 5:ea68c8980ad8 244 int M2XStreamClient::readContentLength() {
citrusbyte 5:ea68c8980ad8 245 int ret = waitForString("Content-Length: ");
citrusbyte 5:ea68c8980ad8 246 if (ret != E_OK) {
citrusbyte 5:ea68c8980ad8 247 return ret;
citrusbyte 5:ea68c8980ad8 248 }
citrusbyte 5:ea68c8980ad8 249
citrusbyte 5:ea68c8980ad8 250 // From now on, ret is not needed, we can use it
citrusbyte 5:ea68c8980ad8 251 // to keep the final result
citrusbyte 5:ea68c8980ad8 252 ret = 0;
citrusbyte 5:ea68c8980ad8 253 while (true) {
citrusbyte 5:ea68c8980ad8 254 while (_client->available()) {
citrusbyte 5:ea68c8980ad8 255 char c = _client->read();
citrusbyte 6:e6d66d99dd6f 256 DBG("%c", c);
citrusbyte 6:e6d66d99dd6f 257
citrusbyte 5:ea68c8980ad8 258 if ((c == '\r') || (c == '\n')) {
citrusbyte 5:ea68c8980ad8 259 return (ret == 0) ? (E_INVALID) : (ret);
citrusbyte 5:ea68c8980ad8 260 } else {
citrusbyte 5:ea68c8980ad8 261 ret = ret * 10 + (c - '0');
citrusbyte 5:ea68c8980ad8 262 }
citrusbyte 5:ea68c8980ad8 263 }
citrusbyte 5:ea68c8980ad8 264
citrusbyte 5:ea68c8980ad8 265 if (!_client->connected()) {
citrusbyte 6:e6d66d99dd6f 266 DBGLN("%s", "ERROR: The client is disconnected from the server!");
citrusbyte 6:e6d66d99dd6f 267
citrusbyte 5:ea68c8980ad8 268 return E_DISCONNECTED;
citrusbyte 5:ea68c8980ad8 269 }
citrusbyte 5:ea68c8980ad8 270
citrusbyte 5:ea68c8980ad8 271 delay(1000);
citrusbyte 5:ea68c8980ad8 272 }
citrusbyte 5:ea68c8980ad8 273
citrusbyte 5:ea68c8980ad8 274 // never reached here
citrusbyte 5:ea68c8980ad8 275 return E_NOTREACHABLE;
citrusbyte 5:ea68c8980ad8 276 }
citrusbyte 5:ea68c8980ad8 277
citrusbyte 5:ea68c8980ad8 278 int M2XStreamClient::skipHttpHeader() {
citrusbyte 5:ea68c8980ad8 279 return waitForString("\r\n\r\n");
citrusbyte 5:ea68c8980ad8 280 }
citrusbyte 5:ea68c8980ad8 281
citrusbyte 5:ea68c8980ad8 282 void M2XStreamClient::close() {
citrusbyte 5:ea68c8980ad8 283 // Eats up buffered data before closing
citrusbyte 5:ea68c8980ad8 284 _client->flush();
citrusbyte 5:ea68c8980ad8 285 _client->stop();
citrusbyte 5:ea68c8980ad8 286 }
citrusbyte 5:ea68c8980ad8 287
citrusbyte 5:ea68c8980ad8 288 int M2XStreamClient::readStreamValue(stream_value_read_callback callback,
citrusbyte 5:ea68c8980ad8 289 void* context) {
citrusbyte 5:ea68c8980ad8 290 const int BUF_LEN = 32;
citrusbyte 5:ea68c8980ad8 291 char buf[BUF_LEN];
citrusbyte 5:ea68c8980ad8 292
citrusbyte 5:ea68c8980ad8 293 int length = readContentLength();
citrusbyte 5:ea68c8980ad8 294 if (length < 0) {
citrusbyte 5:ea68c8980ad8 295 close();
citrusbyte 5:ea68c8980ad8 296 return length;
citrusbyte 5:ea68c8980ad8 297 }
citrusbyte 5:ea68c8980ad8 298
citrusbyte 5:ea68c8980ad8 299 int index = skipHttpHeader();
citrusbyte 5:ea68c8980ad8 300 if (index != E_OK) {
citrusbyte 5:ea68c8980ad8 301 close();
citrusbyte 5:ea68c8980ad8 302 return index;
citrusbyte 5:ea68c8980ad8 303 }
citrusbyte 5:ea68c8980ad8 304 index = 0;
citrusbyte 5:ea68c8980ad8 305
citrusbyte 5:ea68c8980ad8 306 stream_parsing_context_state state;
citrusbyte 5:ea68c8980ad8 307 state.state = state.index = 0;
citrusbyte 5:ea68c8980ad8 308 state.callback = callback;
citrusbyte 5:ea68c8980ad8 309 state.context = context;
citrusbyte 5:ea68c8980ad8 310
citrusbyte 5:ea68c8980ad8 311 jsonlite_parser_callbacks cbs = jsonlite_default_callbacks;
citrusbyte 5:ea68c8980ad8 312 cbs.key_found = on_stream_key_found;
citrusbyte 5:ea68c8980ad8 313 cbs.string_found = on_stream_string_found;
citrusbyte 5:ea68c8980ad8 314 cbs.context.client_state = &state;
citrusbyte 5:ea68c8980ad8 315
citrusbyte 5:ea68c8980ad8 316 jsonlite_parser p = jsonlite_parser_init(jsonlite_parser_estimate_size(5));
citrusbyte 5:ea68c8980ad8 317 jsonlite_parser_set_callback(p, &cbs);
citrusbyte 5:ea68c8980ad8 318
citrusbyte 5:ea68c8980ad8 319 jsonlite_result result = jsonlite_result_unknown;
citrusbyte 5:ea68c8980ad8 320 while (index < length) {
citrusbyte 5:ea68c8980ad8 321 int i = 0;
citrusbyte 5:ea68c8980ad8 322
citrusbyte 6:e6d66d99dd6f 323 DBG("%s", "Received Data: ");
citrusbyte 5:ea68c8980ad8 324 while ((i < BUF_LEN) && _client->available()) {
citrusbyte 5:ea68c8980ad8 325 buf[i++] = _client->read();
citrusbyte 6:e6d66d99dd6f 326 DBG("%c", buf[i - 1]);
citrusbyte 5:ea68c8980ad8 327 }
citrusbyte 6:e6d66d99dd6f 328 DBGLNEND;
citrusbyte 5:ea68c8980ad8 329
citrusbyte 5:ea68c8980ad8 330 if ((!_client->connected()) &&
citrusbyte 5:ea68c8980ad8 331 (!_client->available()) &&
citrusbyte 5:ea68c8980ad8 332 ((index + i) < length)) {
citrusbyte 5:ea68c8980ad8 333 jsonlite_parser_release(p);
citrusbyte 5:ea68c8980ad8 334 close();
citrusbyte 5:ea68c8980ad8 335 return E_NOCONNECTION;
citrusbyte 5:ea68c8980ad8 336 }
citrusbyte 5:ea68c8980ad8 337
citrusbyte 5:ea68c8980ad8 338 result = jsonlite_parser_tokenize(p, buf, i);
citrusbyte 5:ea68c8980ad8 339 if ((result != jsonlite_result_ok) &&
citrusbyte 5:ea68c8980ad8 340 (result != jsonlite_result_end_of_stream)) {
citrusbyte 5:ea68c8980ad8 341 jsonlite_parser_release(p);
citrusbyte 5:ea68c8980ad8 342 close();
citrusbyte 5:ea68c8980ad8 343 return E_JSON_INVALID;
citrusbyte 5:ea68c8980ad8 344 }
citrusbyte 5:ea68c8980ad8 345
citrusbyte 5:ea68c8980ad8 346 index += i;
citrusbyte 5:ea68c8980ad8 347 }
citrusbyte 5:ea68c8980ad8 348
citrusbyte 5:ea68c8980ad8 349 jsonlite_parser_release(p);
citrusbyte 5:ea68c8980ad8 350 close();
citrusbyte 5:ea68c8980ad8 351 return (result == jsonlite_result_ok) ? (E_OK) : (E_JSON_INVALID);
citrusbyte 5:ea68c8980ad8 352 }
citrusbyte 5:ea68c8980ad8 353
citrusbyte 5:ea68c8980ad8 354 int M2XStreamClient::readLocation(location_read_callback callback,
citrusbyte 5:ea68c8980ad8 355 void* context) {
citrusbyte 5:ea68c8980ad8 356 const int BUF_LEN = 40;
citrusbyte 5:ea68c8980ad8 357 char buf[BUF_LEN];
citrusbyte 5:ea68c8980ad8 358
citrusbyte 5:ea68c8980ad8 359 int length = readContentLength();
citrusbyte 5:ea68c8980ad8 360 if (length < 0) {
citrusbyte 5:ea68c8980ad8 361 close();
citrusbyte 5:ea68c8980ad8 362 return length;
citrusbyte 5:ea68c8980ad8 363 }
citrusbyte 5:ea68c8980ad8 364
citrusbyte 5:ea68c8980ad8 365 int index = skipHttpHeader();
citrusbyte 5:ea68c8980ad8 366 if (index != E_OK) {
citrusbyte 5:ea68c8980ad8 367 close();
citrusbyte 5:ea68c8980ad8 368 return index;
citrusbyte 5:ea68c8980ad8 369 }
citrusbyte 5:ea68c8980ad8 370 index = 0;
citrusbyte 5:ea68c8980ad8 371
citrusbyte 5:ea68c8980ad8 372 location_parsing_context_state state;
citrusbyte 5:ea68c8980ad8 373 state.state = state.index = 0;
citrusbyte 5:ea68c8980ad8 374 state.callback = callback;
citrusbyte 5:ea68c8980ad8 375 state.context = context;
citrusbyte 5:ea68c8980ad8 376
citrusbyte 5:ea68c8980ad8 377 jsonlite_parser_callbacks cbs = jsonlite_default_callbacks;
citrusbyte 5:ea68c8980ad8 378 cbs.key_found = on_location_key_found;
citrusbyte 5:ea68c8980ad8 379 cbs.string_found = on_location_string_found;
citrusbyte 5:ea68c8980ad8 380 cbs.context.client_state = &state;
citrusbyte 5:ea68c8980ad8 381
citrusbyte 5:ea68c8980ad8 382 jsonlite_parser p = jsonlite_parser_init(jsonlite_parser_estimate_size(5));
citrusbyte 5:ea68c8980ad8 383 jsonlite_parser_set_callback(p, &cbs);
citrusbyte 5:ea68c8980ad8 384
citrusbyte 5:ea68c8980ad8 385 jsonlite_result result = jsonlite_result_unknown;
citrusbyte 5:ea68c8980ad8 386 while (index < length) {
citrusbyte 5:ea68c8980ad8 387 int i = 0;
citrusbyte 5:ea68c8980ad8 388
citrusbyte 6:e6d66d99dd6f 389 DBG("%s", "Received Data: ");
citrusbyte 5:ea68c8980ad8 390 while ((i < BUF_LEN) && _client->available()) {
citrusbyte 5:ea68c8980ad8 391 buf[i++] = _client->read();
citrusbyte 6:e6d66d99dd6f 392 DBG("%c", buf[i - 1]);
citrusbyte 5:ea68c8980ad8 393 }
citrusbyte 6:e6d66d99dd6f 394 DBGLNEND;
citrusbyte 5:ea68c8980ad8 395
citrusbyte 5:ea68c8980ad8 396 if ((!_client->connected()) &&
citrusbyte 5:ea68c8980ad8 397 (!_client->available()) &&
citrusbyte 5:ea68c8980ad8 398 ((index + i) < length)) {
citrusbyte 5:ea68c8980ad8 399 jsonlite_parser_release(p);
citrusbyte 5:ea68c8980ad8 400 close();
citrusbyte 5:ea68c8980ad8 401 return E_NOCONNECTION;
citrusbyte 5:ea68c8980ad8 402 }
citrusbyte 5:ea68c8980ad8 403
citrusbyte 5:ea68c8980ad8 404 result = jsonlite_parser_tokenize(p, buf, i);
citrusbyte 5:ea68c8980ad8 405 if ((result != jsonlite_result_ok) &&
citrusbyte 5:ea68c8980ad8 406 (result != jsonlite_result_end_of_stream)) {
citrusbyte 5:ea68c8980ad8 407 jsonlite_parser_release(p);
citrusbyte 5:ea68c8980ad8 408 close();
citrusbyte 5:ea68c8980ad8 409 return E_JSON_INVALID;
citrusbyte 5:ea68c8980ad8 410 }
citrusbyte 5:ea68c8980ad8 411
citrusbyte 5:ea68c8980ad8 412 index += i;
citrusbyte 5:ea68c8980ad8 413 }
citrusbyte 5:ea68c8980ad8 414
citrusbyte 5:ea68c8980ad8 415 jsonlite_parser_release(p);
citrusbyte 5:ea68c8980ad8 416 close();
citrusbyte 5:ea68c8980ad8 417 return (result == jsonlite_result_ok) ? (E_OK) : (E_JSON_INVALID);
citrusbyte 5:ea68c8980ad8 418 }
citrusbyte 5:ea68c8980ad8 419