@@ -23,12 +23,35 @@ class NilmApp(object):
def __init__(self, db):
self.db = db
# Set this to False to get better tracebacks from some requests
# (/stream/extract, /stream/intervals)
use_chunked_http_response = False
version = "1.1"
# Decorators
def chunked_response(func):
"""Decorator to enable chunked responses"""
# Set this to False to get better tracebacks from some requests
# (/stream/extract, /stream/intervals).
func._cp_config = { 'response.stream': False }
return func
def workaround_cp_bug_1200(func):
"""Decorator to work around CherryPy bug #1200 in a response
generator"""
# Even if chunked responses are disabled, you may still miss miss
# LookupError, or UnicodeError exceptions due to CherryPy bug
# #1200. This throws them as generic Exceptions insteads.
import functools
import traceback
@functools.wraps(func)
def wrapper(*args, **kwargs):
try:
for val in func(*args, **kwargs):
yield val
except (LookupError, UnicodeError) as e:
raise Exception("bug workaround; real exception is:\n" +
traceback.format_exc())
return wrapper
# CherryPy apps
class Root(NilmApp):
"""Root application for NILM database"""
@@ -217,6 +240,7 @@ class Stream(NilmApp):
# /stream/intervals?path=/newton/prep
# /stream/intervals?path=/newton/prep&start=1234567890.0&end=1234567899.0
@cherrypy.expose
@chunked_response
def intervals(self, path, start = None, end = None):
"""
Get intervals from backend database. Streams the resulting
@@ -238,9 +262,9 @@ class Stream(NilmApp):
if len(streams) != 1:
raise cherrypy.HTTPError("404 Not Found", "No such stream")
@workaround_cp_bug_1200
def content(start, end):
# Note: disable response.stream below to get better debug info
# from tracebacks in this subfunction.
# Note: disable chunked responses to see tracebacks from here.
while True:
(intervals, restart) = self.db.stream_intervals(path,start,end)
response = ''.join([ json.dumps(i) + "\n" for i in intervals ])
@@ -249,10 +273,10 @@ class Stream(NilmApp):
break
start = restart
return content(start, end)
intervals._cp_config = { 'response.stream': use_chunked_http_response }
# /stream/extract?path=/newton/prep&start=1234567890.0&end=1234567899.0
@cherrypy.expose
@chunked_response
def extract(self, path, start = None, end = None, count = False):
"""
Extract data from backend database. Streams the resulting
@@ -282,9 +306,9 @@ class Stream(NilmApp):
# Get formatter
formatter = nilmdb.layout.Formatter(layout)
@workaround_cp_bug_1200
def content(start, end, count):
# Note: disable response.stream below to get better debug info
# from tracebacks in this subfunction.
# Note: disable chunked responses to see tracebacks from here.
if count:
matched = self.db.stream_extract(path, start, end, count)
yield sprintf("%d\n", matched)
@@ -300,8 +324,6 @@ class Stream(NilmApp):
return
start = restart
return content(start, end, count)
extract._cp_config = { 'response.stream': use_chunked_http_response }
class Exiter(object):
"""App that exits the server, for testing"""