Dependents: xively-jumpstart-demo
This is Xively C library, the code lives on GitHub.
See our example program and the tutorial, documentation can bee found here.
Diff: src/libxively/http_transport_layer.c
- Revision:
- 0:53753690a8bf
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/libxively/http_transport_layer.c Mon May 13 19:28:22 2013 +0000 @@ -0,0 +1,432 @@ +// Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved. +// This is part of Xively C library, it is under the BSD 3-Clause license. + +/** + * \file http_transport_layer.c + * \author Olgierd Humenczuk + * \brief Implements HTTP _transport layer_ encoders and decoders specific to Xively REST/HTTP API [see http_transport_layer.h] + */ + +#include <string.h> +#include <assert.h> +#include <stdio.h> + +#include "http_transport.h" +#include "http_layer_queries.h" +#include "http_consts.h" +#include "http_layer_parser.h" +#include "xi_macros.h" +#include "xi_helpers.h" +#include "xi_err.h" + +static char XI_HTTP_QUERY_BUFFER[ XI_QUERY_BUFFER_SIZE + XI_CONTENT_BUFFER_SIZE ]; +static char XI_HTTP_QUERY_DATA[ XI_CONTENT_BUFFER_SIZE ]; + + +inline static char* http_encode_concat( char* buffer, size_t buffer_size + , const char* query, const char* content, const char* data ) +{ + int offset = 0; + int size = ( int ) buffer_size; + int s = 0; + + s = snprintf( buffer, size, "%s", query ); + XI_CHECK_S( s, size, offset, XI_HTTP_ENCODE_CREATE_DATASTREAM ); + + if( content != 0 ) + { + s = snprintf( buffer + offset + , XI_MAX( size - offset, 0 ) + , "%s", content ); + XI_CHECK_S( s, size, offset, XI_HTTP_ENCODE_CREATE_DATASTREAM ); + } + + s = snprintf( buffer + offset + , XI_MAX( size - offset, 0 ) + , "%s", XI_HTTP_CRLF ); + XI_CHECK_S( s, size, offset, XI_HTTP_ENCODE_CREATE_DATASTREAM ); + + + if( content != 0 && data != 0 ) + { + s = snprintf( buffer + offset + , XI_MAX( size - offset, 0 ) + , "%s", data ); + XI_CHECK_S( s, size, offset, XI_HTTP_ENCODE_CREATE_DATASTREAM ); + } + + s = snprintf( buffer + offset + , XI_MAX( size - offset, 0 ) + , "%s", XI_HTTP_CRLF ); + + XI_CHECK_S( s, size, offset, XI_HTTP_ENCODE_CREATE_DATASTREAM ); + + return buffer; + +err_handling: + return 0; +} + +const char* http_encode_create_datastream( + const data_layer_t* data_transport + , const char* x_api_key + , int32_t feed_id + , const char *datastream_id + , const xi_datapoint_t* datapoint ) +{ + // prepare parts + const char* data = data_transport->encode_create_datastream( + datastream_id, datapoint ); + + if( data == 0 ) { return 0; } + + const char* query = http_construct_request_datastream( + XI_HTTP_QUERY_POST, &feed_id + , 0, x_api_key + ); + + if( query == 0 ) { return 0; } + + const char* content = http_construct_content( strlen( data ) ); + + return http_encode_concat( XI_HTTP_QUERY_BUFFER, sizeof( XI_HTTP_QUERY_BUFFER ) + , query, content, data ); +} + +const char* http_encode_update_datastream( + const data_layer_t* data_layer + , const char* x_api_key + , int32_t feed_id + , const char *datastream_id + , const xi_datapoint_t* datapoint ) +{ + // prepare parts + const char* data = data_layer->encode_datapoint( datapoint ); + + if( data == 0 ) { return 0; } + + const char* query = http_construct_request_datastream( + XI_HTTP_QUERY_PUT + , &feed_id + , datastream_id + , x_api_key + ); + + if( query == 0 ) { return 0; } + + const char* content = http_construct_content( strlen( data ) ); + + return http_encode_concat( XI_HTTP_QUERY_BUFFER, sizeof( XI_HTTP_QUERY_BUFFER ) + , query, content, data ); +} + +const char* http_encode_get_datastream( + const data_layer_t* data_layer + , const char* x_api_key + , int32_t feed_id + , const char *datastream_id ) +{ + XI_UNUSED( data_layer ); + + // prepare parts + const char* query = http_construct_request_datastream( + XI_HTTP_QUERY_GET + , &feed_id + , datastream_id + , x_api_key ); + + if( query == 0 ) { return 0; } + + return http_encode_concat( XI_HTTP_QUERY_BUFFER, sizeof( XI_HTTP_QUERY_BUFFER ) + , query, 0, 0 ); +} + +const char* http_encode_delete_datastream( + const data_layer_t* data_layer + , const char* x_api_key + , int32_t feed_id + , const char *datastream_id ) +{ + XI_UNUSED( data_layer ); + + // prepare parts + const char* query = http_construct_request_datastream( + XI_HTTP_QUERY_DELETE + , &feed_id + , datastream_id + , x_api_key ); + + if( query == 0 ) { return 0; } + + return http_encode_concat( XI_HTTP_QUERY_BUFFER, sizeof( XI_HTTP_QUERY_BUFFER ) + , query, 0, 0 ); +} + +const char* http_encode_delete_datapoint( + const data_layer_t* data_transport + , const char* x_api_key + , int32_t feed_id + , const char *datastream_id + , const xi_datapoint_t* o ) +{ + XI_UNUSED( data_transport ); + + struct tm* ptm = xi_gmtime( + ( time_t* ) &o->timestamp.timestamp ); + + int s = snprintf( XI_HTTP_QUERY_BUFFER + , sizeof( XI_HTTP_QUERY_BUFFER ) + , "%s/datapoints/%04d-%02d-%02dT%02d:%02d:%02d.%06ldZ" + , datastream_id + , ptm->tm_year + 1900 + , ptm->tm_mon + 1 + , ptm->tm_mday + , ptm->tm_hour + , ptm->tm_min + , ptm->tm_sec + , o->timestamp.micro ); + + XI_CHECK_SIZE( s, ( int ) sizeof( XI_HTTP_QUERY_BUFFER ) + , XI_HTTP_ENCODE_DELETE_DATAPOINT ); + + { + // prepare parts + const char* query = http_construct_request_datastream( + XI_HTTP_QUERY_DELETE + , &feed_id + , XI_HTTP_QUERY_BUFFER + , x_api_key ); + + if( query == 0 ) { return 0; } + + return http_encode_concat( XI_HTTP_QUERY_BUFFER, sizeof( XI_HTTP_QUERY_BUFFER ) + , query, 0, 0 ); + } + +err_handling: + return 0; +} + +const char* http_encode_update_feed( + const data_layer_t* data_layer + , const char* x_api_key + , const xi_feed_t* feed ) +{ + // prepare buffer + XI_CLEAR_STATIC_BUFFER( XI_HTTP_QUERY_DATA ); + + // PRECONDITIONS + assert( data_layer != 0 ); + assert( x_api_key != 0 ); + assert( feed != 0 ); + + // variables initialization + const char* content = 0; + const char* query = 0; + + { // data part preparation + int offset = 0; + int size = sizeof( XI_HTTP_QUERY_DATA ); + int s = 0; + + // for each datastream + // generate the list of datapoints that you want to update + for( size_t i = 0; i < feed->datastream_count; ++i ) + { + const xi_datastream_t* curr_datastream = &feed->datastreams[ i ]; + + // for each datapoint + for( size_t j = 0; j < curr_datastream->datapoint_count; ++j ) + { + const xi_datapoint_t* curr_datapoint + = &curr_datastream->datapoints[ j ]; + + // add the datastream id to the buffer + s = snprintf( + XI_HTTP_QUERY_DATA + offset, XI_MAX( size - offset, 0 ), "%s," + , curr_datastream->datastream_id ); + + XI_CHECK_S( s, size, offset, XI_HTTP_ENCODE_UPDATE_FEED ); + + // add the datapoint data to the buffer + s = data_layer->encode_datapoint_in_place( + XI_HTTP_QUERY_DATA + offset, XI_MAX( size - offset, 0 ) + , curr_datapoint ); + + XI_CHECK_S( s, size, offset, XI_HTTP_ENCODE_UPDATE_FEED ); + } + } + } + + query = http_construct_request_feed( + XI_HTTP_QUERY_PUT + , &feed->feed_id + , x_api_key + , 0 + ); + + if( query == 0 ) { goto err_handling; } + + content = http_construct_content( strlen( XI_HTTP_QUERY_DATA ) ); + + return http_encode_concat( XI_HTTP_QUERY_BUFFER, sizeof( XI_HTTP_QUERY_BUFFER ) + , query, content, XI_HTTP_QUERY_DATA ); + +err_handling: + return 0; +} + +const char* http_encode_get_feed( + const data_layer_t* data_layer + , const char* x_api_key + , const xi_feed_t* feed ) +{ + // prepare buffer + XI_CLEAR_STATIC_BUFFER( XI_HTTP_QUERY_DATA ); + + // PRECONDITIONS + assert( data_layer != 0 ); + assert( x_api_key != 0 ); + assert( feed != 0 ); + + // variables initialization + const char* query = 0; + + { // data part preparation + int offset = 0; + int size = sizeof( XI_HTTP_QUERY_DATA ); + int s = 0; + + // for each datastream + // generate the list of datastreams that you want to get + for( size_t i = 0; i < feed->datastream_count; ++i ) + { + const xi_datastream_t* curr_datastream = &feed->datastreams[ i ]; + + // add the datastream id to the buffer + s = snprintf( + XI_HTTP_QUERY_DATA + offset, XI_MAX( size - offset, 0 ), i == 0 ? "?datastreams=%s" : ",%s" + , curr_datastream->datastream_id ); + + XI_CHECK_S( s, size, offset, XI_HTTP_ENCODE_UPDATE_FEED ); + } + } + + query = http_construct_request_feed( + XI_HTTP_QUERY_GET + , &feed->feed_id + , x_api_key + , XI_HTTP_QUERY_DATA + ); + + if( query == 0 ) { goto err_handling; } + + return http_encode_concat( XI_HTTP_QUERY_BUFFER, sizeof( XI_HTTP_QUERY_BUFFER ) + , query, 0, 0 ); + +err_handling: + return 0; +} + +const char* http_encode_datapoint_delete_range( + const data_layer_t* data_layer + , const char* x_api_key + , int32_t feed_id + , const char* datastream_id + , const xi_timestamp_t* start + , const xi_timestamp_t* end ) +{ + XI_UNUSED( data_layer ); + + struct tm stm; + struct tm etm; + + { + struct tm* tmp = start ? xi_gmtime( + ( time_t* ) &start->timestamp ) : 0; + memcpy( &stm, tmp, sizeof( struct tm ) ); + } + + { + struct tm* tmp = end ? xi_gmtime( + ( time_t* ) &end->timestamp ) : 0; + memcpy( &etm, tmp, sizeof( struct tm ) ); + } + + int s = 0; + + if( start && end ) + { + s = snprintf( XI_HTTP_QUERY_BUFFER + , sizeof( XI_HTTP_QUERY_BUFFER ) + , "%s/datapoints?start=%04d-%02d-%02dT%02d:%02d:%02d.%06ldZ&end=%04d-%02d-%02dT%02d:%02d:%02d.%06ldZ" + , datastream_id + , stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday + , stm.tm_hour, stm.tm_min, stm.tm_sec, start->micro + , etm.tm_year + 1900, etm.tm_mon + 1, etm.tm_mday + , etm.tm_hour, etm.tm_min, etm.tm_sec, end->micro ); + } + else if( start ) + { + s = snprintf( XI_HTTP_QUERY_BUFFER + , sizeof( XI_HTTP_QUERY_BUFFER ) + , "%s/datapoints?start=%04d-%02d-%02dT%02d:%02d:%02d.%06ldZ" + , datastream_id + , stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday + , stm.tm_hour, stm.tm_min, stm.tm_sec, start->micro ); + } + else if( end ) + { + s = snprintf( XI_HTTP_QUERY_BUFFER + , sizeof( XI_HTTP_QUERY_BUFFER ) + , "%s/datapoints?end=%04d-%02d-%02dT%02d:%02d:%02d.%06ldZ" + , datastream_id + , etm.tm_year + 1900, etm.tm_mon + 1, etm.tm_mday + , etm.tm_hour, etm.tm_min, etm.tm_sec, end->micro ); + } + else + { + // just set an error + XI_CHECK_CND( 1 == 0, XI_HTTP_ENCODE_DELETE_RANGE_DATAPOINT ); + } + + XI_CHECK_SIZE( s, ( int ) sizeof( XI_HTTP_QUERY_BUFFER ) + , XI_HTTP_ENCODE_DELETE_RANGE_DATAPOINT ); + + { + // prepare parts + const char* query = http_construct_request_datastream( + XI_HTTP_QUERY_DELETE + , &feed_id + , XI_HTTP_QUERY_BUFFER + , x_api_key ); + + if( query == 0 ) { return 0; } + + return http_encode_concat( XI_HTTP_QUERY_BUFFER, sizeof( XI_HTTP_QUERY_BUFFER ) + , query, 0, 0 ); + } + +err_handling: + return 0; +} + + +const xi_response_t* http_decode_reply( + const data_layer_t* data_layer + , const char* response ) +{ + XI_UNUSED( data_layer ); + + static xi_response_t __tmp; + static http_response_t* __response = &__tmp.http; + + // just pass it further + if( parse_http( __response, response ) == 0 ) + { + return 0; + } + + // pass it to the data_layer + return &__tmp; +}