branch with improvemnts

Fork of M2XStreamClient by AT&T M2X Team

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