Skip to main content
edited tags
Link
200_success
  • 144.2k
  • 22
  • 188
  • 473
edited body
Source Link

I wrote a small aggregator app that aggregates values from a json http post request and outputs the aggregatesaggregated values. Now the aggregator function is somewhat large but the output appears correct.

I wrote a small aggregator app that aggregates values from a json http post request and outputs the aggregates values. Now the aggregator function is somewhat large but the output appears correct.

I wrote a small aggregator app that aggregates values from a json http post request and outputs the aggregated values. Now the aggregator function is somewhat large but the output appears correct.

Source Link

RESTful HTTP Post with falcon

I wrote a small aggregator app that aggregates values from a json http post request and outputs the aggregates values. Now the aggregator function is somewhat large but the output appears correct.

I start it with gunicorn:

$ gunicorn --workers 2 --threads 4 aggregator:api

I test it with curl :

$ curl -X POST -d @aggregator.json http://localhost:8000/aggregate

It outputs the aggregated values.

import falcon
import json
from datetime import datetime
from dateutil import tz
import requests
import time

from_zone = tz.gettz('UTC')
to_zone = tz.gettz('Europe/Stockholm')

class DataService:

    def on_post(self, req, resp):
        data = json.loads(req.stream.read().decode('utf-8'))
        # output the data, we could write it to persistent storage here
        print(data)

class AggregatorService:

    def zero_if_none(self, value):
        if value is not None:
            x = int(value)
        else:
            x = 0
        return x

    # return the start day of consumption e.g. 1 for 2014-12-01
    def get_day_start(self, hours):
        return int(datetime.fromtimestamp(
            int(hours[0][0])
        ).strftime('%d'))

    # return the month number e.g. 2 for February
    def get_month_start(self, hours):
        return int(datetime.fromtimestamp(
            int(hours[0][0])
        ).strftime('%m'))

    # return the day of month number e.g. 5 for 2015-01-05
    def get_day(self, hour):
        return int(datetime.fromtimestamp(
                int(hour[0])
            ).strftime('%d'))

    # return the month number for a timestamp
    def get_month(self, hour):
        return int(datetime.fromtimestamp(
                int(hour[0])
            ).strftime('%m'))

    def on_post(self, req, resp):

        data = json.loads(req.stream.read().decode('utf-8'))
        hours = data['hours']

        day_start = self.get_day_start(hours)
        month_start = self.get_month_start(hours)

        aggr_daily_wh = 0
        aggr_monthly_wh = 0

        aggr_daily_th = 0
        aggr_monthly_th = 0
        jdict = {}

        jdict['user'] = data['user']

        jhours = []
        jdays = []
        jmonths = []

        last_h = 0
        last_day_wh = 0
        last_day_th = 0
        last_month_wh = 0
        last_month_th = 0

        for hour in hours:

            day = self.get_day(hour)
            print("day %d" % day)
            month = self.get_month(hour)
            print("month %d" % month)

            utime = datetime.fromtimestamp(
                int(hour[0])
            ).strftime('%Y-%m-%d %H:%M:%S')

            utc = datetime.strptime(utime, '%Y-%m-%d %H:%M:%S')

            # Tell the datetime object that it's in UTC time zone since
            # datetime objects are 'naive' by default
            utc = utc.replace(tzinfo=from_zone)

            # Convert time zone and change the timestamp
            tstamp = int(time.mktime(utc.astimezone(to_zone).timetuple()))

            # consumption is 0 if there is no value
            wh = self.zero_if_none(hour[1])
            th = self.zero_if_none(hour[2])

            # append hourly comsumption
            jhours.append([tstamp, wh, th])

            if day == day_start:  # aggregate daily comsumption
                aggr_daily_wh += wh
                aggr_daily_th += th
            else:  # new day
                # append daily comsumption
                jdays.append([tstamp, aggr_daily_wh, aggr_daily_th])
                # begin new day
                day_start = day
                aggr_daily_wh = 0
                aggr_daily_th = 0
                aggr_daily_wh += wh
                aggr_daily_th += th

            if month == month_start:  # aggregate monthly consumption
                print("adding from month %d" % month)
                aggr_monthly_wh += wh
                aggr_monthly_th += th
            else:  # new month
                # append monthly comsumption
                jmonths.append([int(tstamp), aggr_monthly_wh, aggr_monthly_th])
                # begin new month
                month_start = month
                aggr_monthly_wh = 0
                aggr_monthly_th = 0
                aggr_monthly_wh += wh
                aggr_monthly_th += th

            # make the values from the last iteration visible outside the loop
            last_h = tstamp
            last_month_wh = aggr_monthly_wh
            last_month_th = aggr_monthly_th
            last_day_wh = aggr_daily_wh
            last_day_th = aggr_daily_th

        # append the last values
        jdays.append([last_h, last_day_wh, last_day_th])
        jmonths.append([last_h, last_month_wh, last_month_th])

        # create the json dictionary
        jdict['hours'] = jhours
        jdict['days'] = jdays
        jdict['months'] = jmonths

        r = requests.post('http://localhost:8000/store', json=jdict)

api = falcon.API()
api.add_route('/aggregate', AggregatorService())
api.add_route('/store', DataService())

aggregator.json

{
  "user": 42,
  "hours": [
    [
      1417392000,
      1,
      null
    ],
    [
      1417395600,
      2,
      3
    ],
    [
      1417647600,
      3,
      2
    ],
    [
      1417651200,
      null,
      6
    ],
    [
      1422835200,
      6,
      2
    ],
    [
      1423094400,
      4,
      3
    ]
  ]
}