Api wrapper to communicate with EVRYTHNG's Engine.

Dependencies:   EthernetInterface mbed-rtos

Dependents:   EvrythngApiExample

EvrythngApi.cpp

Committer:
vladounet
Date:
2012-08-30
Revision:
0:d38d192c2f5f

File content as of revision 0:d38d192c2f5f:

/*
 * (c) Copyright 2012 EVRYTHNG Ltd London / Zurich
 * www.evrythng.com
 *
 * --- DISCLAIMER ---
 *
 * EVRYTHNG provides this source code "as is" and without warranty of any kind,
 * and hereby disclaims all express or implied warranties, including without
 * limitation warranties of merchantability, fitness for a particular purpose,
 * performance, accuracy, reliability, and non-infringement.
 *
 * Author: Michel Yerly
 *
 */
#include "EvrythngApi.h"

#include <string>

#include "util.h"
#include "evry_error.h"
#include "JsonParser.h"

//#define DEBUG_EVRYTHNG_API

using namespace std;

const int HTTP_OK = 200;

const char* THNG_PATH = "/thngs/";
const char* THNG_PROP_PATH = "/properties/";

EvrythngApi::EvrythngApi(const string& token, const string& host, int port)
{
    this->token = token;
    this->host = host;
    this->port = port;
}

EvrythngApi::~EvrythngApi()
{
}

int EvrythngApi::getThngPropertyValue(const string& thngId, const string& key, string& value)
{
    string path = THNG_PATH;
    path += thngId;
    path += THNG_PROP_PATH;
    path += key;
    path += "?from=latest";
    string res;
    int err;
    int code;
    if ((err = httpGet(path, res, code)) != 0) return err;
    if (code != HTTP_OK) return EVRY_ERR_UNEXPECTEDHTTPSTATUS;
    JsonParser json;
    json.parse(res.c_str());
    JsonValue* doc = json.getDocument();
    const char* v = doc->getString("0/value");
    if (v) {
        value.assign(v);
        return 0;
    } else {
        return -1;
    }
}

int EvrythngApi::setThngPropertyValue(const std::string& thngId, const std::string& key, const std::string& value, int64_t timestamp)
{
    char strTimestamp[21];
    char* end;
    sprinti64(strTimestamp, timestamp, &end);
    *end = '\0';

    string path = THNG_PATH;
    path += thngId;
    path += THNG_PROP_PATH;
    path += key;

    string json = "[{\"timestamp\":";
    json += strTimestamp;
    json += ",\"value\":\"";
    json += value;
    json += "\"}]";

    string res;
    int err;
    int code;
    if ((err = httpPut(path, json, res, code)) != 0) return err;
    if (code != HTTP_OK) return EVRY_ERR_UNEXPECTEDHTTPSTATUS;

    return 0;
}


int EvrythngApi::httpRequest(HttpMethod method, const string& path, const string& content, string& out, int& codeOut)
{
    int ret;

    const char* strMethod;
    switch (method) {
        case GET:
            strMethod = "GET";
            break;
        case PUT:
            strMethod = "PUT";
            break;
        case POST:
            strMethod = "POST";
            break;
        case DELETE:
            strMethod = "DELETE";
            break;
        default:
            return EVRY_ERR_UNSUPPORTED;
    }

    char contentLength[16];
    snprintf(contentLength, sizeof(contentLength), "%d", content.size());

    string req = strMethod;
    req += " ";
    req += path;
    req += " HTTP/1.0\r\n"
           "Host: ";
    req += host;
    req += "\r\n"
           "Accept: application/json\r\n"
           "Content-Length: ";
    req += contentLength;
    req += "\r\n"
           "Content-Type: application/json\r\n"
           "Connection: close\r\n"
           "Authorization: ";
    req += token;
    req += "\r\n\r\n";

    req += content;

#ifdef DEBUG_EVRYTHNG_API
    dbg.printf("%s\r\n\r\n", req.c_str());
#endif

    TCPSocketConnection socket;

    out.clear();

    string res;

    if (socket.connect(host.c_str(), port) == 0) {

        char* snd = new char[req.size()+1];
        req.copy(snd, req.size());
        snd[req.size()]='\0';
        bool sent = socket.send_all(snd, req.size()) >= 0;
        delete[] snd;

        if (sent) {

            char rcv[256];

            int r;
            while (true) {
                r = socket.receive(rcv, sizeof(rcv));
                if (r <= 0)
                    break;
                res.append(rcv, r);
            }

            ret = EVRY_ERR_OK;

        } else {
            ret = EVRY_ERR_CANTSEND;
        }

        socket.close();

    } else {
        ret = EVRY_ERR_CANTCONNECT;
    }
    
#ifdef DEBUG_EVRYTHNG_API
    dbg.printf("%s", res.c_str());
#endif

    if (res.compare(0,5,"HTTP/") != 0) {
        return EVRY_ERR_UNKNOWN;
    }

    int spPos = res.find(' ', 5);
    if (spPos == string::npos) {
        return EVRY_ERR_UNKNOWN;
    }

    // TODO: check str length
    int code = atoi(res.c_str()+spPos+1);
    if (code < 100 || code > 999) {
        return EVRY_ERR_UNKNOWN;
    }
    codeOut = code;

    int startContent = res.find("\r\n\r\n");
    if (startContent != string::npos) {
        out.append(res.substr(startContent+4,res.size()-startContent-4));
    }

    return ret;
}

int EvrythngApi::httpPut(const string& path, const string& json, string& out, int& codeOut)
{
    return httpRequest(PUT, path, json, out, codeOut);
}

int EvrythngApi::httpGet(const string& path, string& out, int& codeOut)
{
    return httpRequest(GET, path, "", out, codeOut);
}

int EvrythngApi::httpPost(const string& path, const string& json, string& out, int& codeOut)
{
    return httpRequest(POST, path, json, out, codeOut);
}

int EvrythngApi::httpDelete(const string& path, string& out, int& codeOut)
{
    return httpRequest(DELETE, path, "", out, codeOut);
}