Api wrapper to communicate with EVRYTHNG's Engine.

Dependencies:   EthernetInterface mbed-rtos

Dependents:   EvrythngApiExample

Committer:
vladounet
Date:
Thu Aug 30 13:25:41 2012 +0000
Revision:
1:7162d0e030f5
Parent:
0:d38d192c2f5f
Initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
vladounet 0:d38d192c2f5f 1 /*
vladounet 0:d38d192c2f5f 2 * (c) Copyright 2012 EVRYTHNG Ltd London / Zurich
vladounet 0:d38d192c2f5f 3 * www.evrythng.com
vladounet 0:d38d192c2f5f 4 *
vladounet 0:d38d192c2f5f 5 * --- DISCLAIMER ---
vladounet 0:d38d192c2f5f 6 *
vladounet 0:d38d192c2f5f 7 * EVRYTHNG provides this source code "as is" and without warranty of any kind,
vladounet 0:d38d192c2f5f 8 * and hereby disclaims all express or implied warranties, including without
vladounet 0:d38d192c2f5f 9 * limitation warranties of merchantability, fitness for a particular purpose,
vladounet 0:d38d192c2f5f 10 * performance, accuracy, reliability, and non-infringement.
vladounet 0:d38d192c2f5f 11 *
vladounet 0:d38d192c2f5f 12 * Author: Michel Yerly
vladounet 0:d38d192c2f5f 13 *
vladounet 0:d38d192c2f5f 14 */
vladounet 0:d38d192c2f5f 15 #include "EvrythngApi.h"
vladounet 0:d38d192c2f5f 16
vladounet 0:d38d192c2f5f 17 #include <string>
vladounet 0:d38d192c2f5f 18
vladounet 0:d38d192c2f5f 19 #include "util.h"
vladounet 0:d38d192c2f5f 20 #include "evry_error.h"
vladounet 0:d38d192c2f5f 21 #include "JsonParser.h"
vladounet 0:d38d192c2f5f 22
vladounet 0:d38d192c2f5f 23 //#define DEBUG_EVRYTHNG_API
vladounet 0:d38d192c2f5f 24
vladounet 0:d38d192c2f5f 25 using namespace std;
vladounet 0:d38d192c2f5f 26
vladounet 0:d38d192c2f5f 27 const int HTTP_OK = 200;
vladounet 0:d38d192c2f5f 28
vladounet 0:d38d192c2f5f 29 const char* THNG_PATH = "/thngs/";
vladounet 0:d38d192c2f5f 30 const char* THNG_PROP_PATH = "/properties/";
vladounet 0:d38d192c2f5f 31
vladounet 0:d38d192c2f5f 32 EvrythngApi::EvrythngApi(const string& token, const string& host, int port)
vladounet 0:d38d192c2f5f 33 {
vladounet 0:d38d192c2f5f 34 this->token = token;
vladounet 0:d38d192c2f5f 35 this->host = host;
vladounet 0:d38d192c2f5f 36 this->port = port;
vladounet 0:d38d192c2f5f 37 }
vladounet 0:d38d192c2f5f 38
vladounet 0:d38d192c2f5f 39 EvrythngApi::~EvrythngApi()
vladounet 0:d38d192c2f5f 40 {
vladounet 0:d38d192c2f5f 41 }
vladounet 0:d38d192c2f5f 42
vladounet 0:d38d192c2f5f 43 int EvrythngApi::getThngPropertyValue(const string& thngId, const string& key, string& value)
vladounet 0:d38d192c2f5f 44 {
vladounet 0:d38d192c2f5f 45 string path = THNG_PATH;
vladounet 0:d38d192c2f5f 46 path += thngId;
vladounet 0:d38d192c2f5f 47 path += THNG_PROP_PATH;
vladounet 0:d38d192c2f5f 48 path += key;
vladounet 0:d38d192c2f5f 49 path += "?from=latest";
vladounet 0:d38d192c2f5f 50 string res;
vladounet 0:d38d192c2f5f 51 int err;
vladounet 0:d38d192c2f5f 52 int code;
vladounet 0:d38d192c2f5f 53 if ((err = httpGet(path, res, code)) != 0) return err;
vladounet 0:d38d192c2f5f 54 if (code != HTTP_OK) return EVRY_ERR_UNEXPECTEDHTTPSTATUS;
vladounet 0:d38d192c2f5f 55 JsonParser json;
vladounet 0:d38d192c2f5f 56 json.parse(res.c_str());
vladounet 0:d38d192c2f5f 57 JsonValue* doc = json.getDocument();
vladounet 0:d38d192c2f5f 58 const char* v = doc->getString("0/value");
vladounet 0:d38d192c2f5f 59 if (v) {
vladounet 0:d38d192c2f5f 60 value.assign(v);
vladounet 0:d38d192c2f5f 61 return 0;
vladounet 0:d38d192c2f5f 62 } else {
vladounet 0:d38d192c2f5f 63 return -1;
vladounet 0:d38d192c2f5f 64 }
vladounet 0:d38d192c2f5f 65 }
vladounet 0:d38d192c2f5f 66
vladounet 0:d38d192c2f5f 67 int EvrythngApi::setThngPropertyValue(const std::string& thngId, const std::string& key, const std::string& value, int64_t timestamp)
vladounet 0:d38d192c2f5f 68 {
vladounet 0:d38d192c2f5f 69 char strTimestamp[21];
vladounet 0:d38d192c2f5f 70 char* end;
vladounet 0:d38d192c2f5f 71 sprinti64(strTimestamp, timestamp, &end);
vladounet 0:d38d192c2f5f 72 *end = '\0';
vladounet 0:d38d192c2f5f 73
vladounet 0:d38d192c2f5f 74 string path = THNG_PATH;
vladounet 0:d38d192c2f5f 75 path += thngId;
vladounet 0:d38d192c2f5f 76 path += THNG_PROP_PATH;
vladounet 0:d38d192c2f5f 77 path += key;
vladounet 0:d38d192c2f5f 78
vladounet 0:d38d192c2f5f 79 string json = "[{\"timestamp\":";
vladounet 0:d38d192c2f5f 80 json += strTimestamp;
vladounet 0:d38d192c2f5f 81 json += ",\"value\":\"";
vladounet 0:d38d192c2f5f 82 json += value;
vladounet 0:d38d192c2f5f 83 json += "\"}]";
vladounet 0:d38d192c2f5f 84
vladounet 0:d38d192c2f5f 85 string res;
vladounet 0:d38d192c2f5f 86 int err;
vladounet 0:d38d192c2f5f 87 int code;
vladounet 0:d38d192c2f5f 88 if ((err = httpPut(path, json, res, code)) != 0) return err;
vladounet 0:d38d192c2f5f 89 if (code != HTTP_OK) return EVRY_ERR_UNEXPECTEDHTTPSTATUS;
vladounet 0:d38d192c2f5f 90
vladounet 0:d38d192c2f5f 91 return 0;
vladounet 0:d38d192c2f5f 92 }
vladounet 0:d38d192c2f5f 93
vladounet 0:d38d192c2f5f 94
vladounet 0:d38d192c2f5f 95 int EvrythngApi::httpRequest(HttpMethod method, const string& path, const string& content, string& out, int& codeOut)
vladounet 0:d38d192c2f5f 96 {
vladounet 0:d38d192c2f5f 97 int ret;
vladounet 0:d38d192c2f5f 98
vladounet 0:d38d192c2f5f 99 const char* strMethod;
vladounet 0:d38d192c2f5f 100 switch (method) {
vladounet 0:d38d192c2f5f 101 case GET:
vladounet 0:d38d192c2f5f 102 strMethod = "GET";
vladounet 0:d38d192c2f5f 103 break;
vladounet 0:d38d192c2f5f 104 case PUT:
vladounet 0:d38d192c2f5f 105 strMethod = "PUT";
vladounet 0:d38d192c2f5f 106 break;
vladounet 0:d38d192c2f5f 107 case POST:
vladounet 0:d38d192c2f5f 108 strMethod = "POST";
vladounet 0:d38d192c2f5f 109 break;
vladounet 0:d38d192c2f5f 110 case DELETE:
vladounet 0:d38d192c2f5f 111 strMethod = "DELETE";
vladounet 0:d38d192c2f5f 112 break;
vladounet 0:d38d192c2f5f 113 default:
vladounet 0:d38d192c2f5f 114 return EVRY_ERR_UNSUPPORTED;
vladounet 0:d38d192c2f5f 115 }
vladounet 0:d38d192c2f5f 116
vladounet 0:d38d192c2f5f 117 char contentLength[16];
vladounet 0:d38d192c2f5f 118 snprintf(contentLength, sizeof(contentLength), "%d", content.size());
vladounet 0:d38d192c2f5f 119
vladounet 0:d38d192c2f5f 120 string req = strMethod;
vladounet 0:d38d192c2f5f 121 req += " ";
vladounet 0:d38d192c2f5f 122 req += path;
vladounet 0:d38d192c2f5f 123 req += " HTTP/1.0\r\n"
vladounet 0:d38d192c2f5f 124 "Host: ";
vladounet 0:d38d192c2f5f 125 req += host;
vladounet 0:d38d192c2f5f 126 req += "\r\n"
vladounet 0:d38d192c2f5f 127 "Accept: application/json\r\n"
vladounet 0:d38d192c2f5f 128 "Content-Length: ";
vladounet 0:d38d192c2f5f 129 req += contentLength;
vladounet 0:d38d192c2f5f 130 req += "\r\n"
vladounet 0:d38d192c2f5f 131 "Content-Type: application/json\r\n"
vladounet 0:d38d192c2f5f 132 "Connection: close\r\n"
vladounet 0:d38d192c2f5f 133 "Authorization: ";
vladounet 0:d38d192c2f5f 134 req += token;
vladounet 0:d38d192c2f5f 135 req += "\r\n\r\n";
vladounet 0:d38d192c2f5f 136
vladounet 0:d38d192c2f5f 137 req += content;
vladounet 0:d38d192c2f5f 138
vladounet 0:d38d192c2f5f 139 #ifdef DEBUG_EVRYTHNG_API
vladounet 0:d38d192c2f5f 140 dbg.printf("%s\r\n\r\n", req.c_str());
vladounet 0:d38d192c2f5f 141 #endif
vladounet 0:d38d192c2f5f 142
vladounet 0:d38d192c2f5f 143 TCPSocketConnection socket;
vladounet 0:d38d192c2f5f 144
vladounet 0:d38d192c2f5f 145 out.clear();
vladounet 0:d38d192c2f5f 146
vladounet 0:d38d192c2f5f 147 string res;
vladounet 0:d38d192c2f5f 148
vladounet 0:d38d192c2f5f 149 if (socket.connect(host.c_str(), port) == 0) {
vladounet 0:d38d192c2f5f 150
vladounet 0:d38d192c2f5f 151 char* snd = new char[req.size()+1];
vladounet 0:d38d192c2f5f 152 req.copy(snd, req.size());
vladounet 0:d38d192c2f5f 153 snd[req.size()]='\0';
vladounet 0:d38d192c2f5f 154 bool sent = socket.send_all(snd, req.size()) >= 0;
vladounet 0:d38d192c2f5f 155 delete[] snd;
vladounet 0:d38d192c2f5f 156
vladounet 0:d38d192c2f5f 157 if (sent) {
vladounet 0:d38d192c2f5f 158
vladounet 0:d38d192c2f5f 159 char rcv[256];
vladounet 0:d38d192c2f5f 160
vladounet 0:d38d192c2f5f 161 int r;
vladounet 0:d38d192c2f5f 162 while (true) {
vladounet 0:d38d192c2f5f 163 r = socket.receive(rcv, sizeof(rcv));
vladounet 0:d38d192c2f5f 164 if (r <= 0)
vladounet 0:d38d192c2f5f 165 break;
vladounet 0:d38d192c2f5f 166 res.append(rcv, r);
vladounet 0:d38d192c2f5f 167 }
vladounet 0:d38d192c2f5f 168
vladounet 0:d38d192c2f5f 169 ret = EVRY_ERR_OK;
vladounet 0:d38d192c2f5f 170
vladounet 0:d38d192c2f5f 171 } else {
vladounet 0:d38d192c2f5f 172 ret = EVRY_ERR_CANTSEND;
vladounet 0:d38d192c2f5f 173 }
vladounet 0:d38d192c2f5f 174
vladounet 0:d38d192c2f5f 175 socket.close();
vladounet 0:d38d192c2f5f 176
vladounet 0:d38d192c2f5f 177 } else {
vladounet 0:d38d192c2f5f 178 ret = EVRY_ERR_CANTCONNECT;
vladounet 0:d38d192c2f5f 179 }
vladounet 0:d38d192c2f5f 180
vladounet 0:d38d192c2f5f 181 #ifdef DEBUG_EVRYTHNG_API
vladounet 0:d38d192c2f5f 182 dbg.printf("%s", res.c_str());
vladounet 0:d38d192c2f5f 183 #endif
vladounet 0:d38d192c2f5f 184
vladounet 0:d38d192c2f5f 185 if (res.compare(0,5,"HTTP/") != 0) {
vladounet 0:d38d192c2f5f 186 return EVRY_ERR_UNKNOWN;
vladounet 0:d38d192c2f5f 187 }
vladounet 0:d38d192c2f5f 188
vladounet 0:d38d192c2f5f 189 int spPos = res.find(' ', 5);
vladounet 0:d38d192c2f5f 190 if (spPos == string::npos) {
vladounet 0:d38d192c2f5f 191 return EVRY_ERR_UNKNOWN;
vladounet 0:d38d192c2f5f 192 }
vladounet 0:d38d192c2f5f 193
vladounet 0:d38d192c2f5f 194 // TODO: check str length
vladounet 0:d38d192c2f5f 195 int code = atoi(res.c_str()+spPos+1);
vladounet 0:d38d192c2f5f 196 if (code < 100 || code > 999) {
vladounet 0:d38d192c2f5f 197 return EVRY_ERR_UNKNOWN;
vladounet 0:d38d192c2f5f 198 }
vladounet 0:d38d192c2f5f 199 codeOut = code;
vladounet 0:d38d192c2f5f 200
vladounet 0:d38d192c2f5f 201 int startContent = res.find("\r\n\r\n");
vladounet 0:d38d192c2f5f 202 if (startContent != string::npos) {
vladounet 0:d38d192c2f5f 203 out.append(res.substr(startContent+4,res.size()-startContent-4));
vladounet 0:d38d192c2f5f 204 }
vladounet 0:d38d192c2f5f 205
vladounet 0:d38d192c2f5f 206 return ret;
vladounet 0:d38d192c2f5f 207 }
vladounet 0:d38d192c2f5f 208
vladounet 0:d38d192c2f5f 209 int EvrythngApi::httpPut(const string& path, const string& json, string& out, int& codeOut)
vladounet 0:d38d192c2f5f 210 {
vladounet 0:d38d192c2f5f 211 return httpRequest(PUT, path, json, out, codeOut);
vladounet 0:d38d192c2f5f 212 }
vladounet 0:d38d192c2f5f 213
vladounet 0:d38d192c2f5f 214 int EvrythngApi::httpGet(const string& path, string& out, int& codeOut)
vladounet 0:d38d192c2f5f 215 {
vladounet 0:d38d192c2f5f 216 return httpRequest(GET, path, "", out, codeOut);
vladounet 0:d38d192c2f5f 217 }
vladounet 0:d38d192c2f5f 218
vladounet 0:d38d192c2f5f 219 int EvrythngApi::httpPost(const string& path, const string& json, string& out, int& codeOut)
vladounet 0:d38d192c2f5f 220 {
vladounet 0:d38d192c2f5f 221 return httpRequest(POST, path, json, out, codeOut);
vladounet 0:d38d192c2f5f 222 }
vladounet 0:d38d192c2f5f 223
vladounet 0:d38d192c2f5f 224 int EvrythngApi::httpDelete(const string& path, string& out, int& codeOut)
vladounet 0:d38d192c2f5f 225 {
vladounet 0:d38d192c2f5f 226 return httpRequest(DELETE, path, "", out, codeOut);
vladounet 0:d38d192c2f5f 227 }