ems/src/API.py

254 lines
7.4 KiB
Python
Raw Normal View History

'''
Created on 24.10.2013
@author: Philipp Rauch
@version: 0.6
'''
from sys import stderr
import datetime
from flask import Flask, jsonify, abort, make_response, request
from socket import gethostname
from config import Config
import ems
### LOAD CONFIG ###
c = Config()
conf = c.readConf()
api_host = gethostname() if conf['flask_server'] == '0.0.0.0' else conf['flask_server']
api_url = 'http://%s:%s' % (api_host, conf['flask_port'])
#### BUFFER ####
class Buffer(object):
error = {
'db_error' : {
'id' : 1,
'content' : None }
}
system = {
'00_config' : conf,
2014-01-23 16:32:18 +01:00
'0_request' : [],
'0_done' : [],
'device' : {},
2014-01-23 16:32:18 +01:00
'error' : error
}
_instance = None
_id = 0
def __new__(cls, *args, **kwargs):
# http://stackoverflow.com/questions/42558/python-and-the-singleton-pattern
if not cls._instance:
cls._instance = super(Buffer, cls).__new__(
cls, *args, **kwargs)
return cls._instance
def gen_start_url(self, l):
'''
generate a URL form a list
@param l: list of aspacts of the URL
@return: URL
'''
url = api_url
for i in l:
url = '%s/%s' % (url, i)
return url
def get_level(self, l):
'''
iterating over a dictionary on a given path
@param l: items witch tell the path to the value
@return: dictionary with the key and value of the last item in the list
'''
level = l.pop(0)
for i in l:
if isinstance(level, dict) and i in level:
level = level.get(i)
else:
abort(404)
self.set_href(level, self.gen_start_url(l)) #set all links above
return {l[-1] : level}
def generate_links(self, dic, url, postfix):
'''
generats a link to dic if dic is a dictionary
@param dic: variable that is being tested on a dictionary
@param url: previous url
@param postfix: appendix to the given url
'''
if isinstance(dic, dict):
if '00_config' in url.split('/'):
return
url = '%s/%s' % (url, postfix)
self.set_href(dic, url)
else:
return
def set_href(self, dic, url):
'''
set the ref link if dic is a dictionary
@param dic: variable that is being tested on a dictionary
@param url: url to the first dictionary
'''
if isinstance(dic, dict):
for i in dic.keys():
self.generate_links(dic.get(i), url, i)
dic.update({'000_href': url})
dic.update({'000_timestamp' : str(datetime.datetime.now())})
def foo(self, l, args):
'''
@param l: list
@param args: arguments from the reqest
@return: Dictionary
'''
del l[-1]
dic = self.get_level(l).get(l[-1])
if isinstance(dic, dict) and 'dyn' in dic:
message = 'generating view for %s' % (l[-1])
else:
abort(404)
return { l[-1] : message, 'args' : args.to_dict(flat=False)}
def update_buffer(self, push):
'''
Method to update the Buffer on the given path
@param push: message to push in the buffer
construction: key is the path
value is the dict
'''
## Test of valid push message ##
if not isinstance(push, dict):
stderr.write('error wrong parameter: Type is %s expect dict' %
push.__class__.__name__)
return
if len(push.keys()) not in [1]:
stderr.write('error wrong number of arguments: %s expect 1' %
len(push.keys()))
return
if not isinstance(push.get(push.keys()[0]) ,dict):
stderr.write('error value is not dict')
return
key = push.keys()[0]
value = push[key]
path = key.split('/')
if path[0] == '':
path.remove('')
sys = self.system
for key in path:
try:
sys = sys[key]
except KeyError:
stderr.write('error wrong path: %s' % key)
return
sys.update(value)
2014-01-23 16:32:18 +01:00
return key
def init_buffer(self):
self.system['reqest'].append('init')
2013-11-29 15:04:02 +01:00
pass
class Request(object):
def __init__(self, path, time, id):
self.content = path
self.time = time
self.id = id
class API(object):
def __init__(self):
self.app = Flask(__name__)
### Start EMS thread ###
self.EMS = ems.ems(buf)
self.emsthread = self.EMS.start()
if conf['config_debug']:
print 'EMS-Thread:\t', self.EMS
print '\tAPI-BUFFER:\t', buf
### ADD URL RULES ###
self.app.error_handler_spec[None][400] = bad_reqest
self.app.error_handler_spec[None][404] = not_found
self.app.error_handler_spec[None][405] = not_allowed
self.app.error_handler_spec[None][500] = server_error
self.app.add_url_rule('/', 'get_root', get_root, methods = ['GET'])
self.app.add_url_rule('/<path:path>', 'get_catch_all',
get_catch_all, methods = ['GET'])
buf = Buffer()
########## ERROR Handler ##########
def not_allowed(error):
return make_response(jsonify( { 'error': '405 Not Allowed' } ), 405)
def not_found(error):
return make_response(jsonify( { 'error': '404 Not Found' } ), 404)
def bad_reqest(error):
return make_response(jsonify( { 'error': '400 Bad Reqest' } ), 400)
def server_error(error):
return make_response(jsonify( { 'error': '500 Internal Server Error' } ), 500)
########## GET Handler ##########
def get_root():
buf.set_href(Buffer.system, api_url)
return jsonify( { 'system' : Buffer.system } )
def get_catch_all(path):
l = path.split('/')
l.insert(0, Buffer.system)
if '' == l[-1]: # if last element of list is empty
del l[-1] # remove it
out = buf.get_level(l)
elif 'dyn' == l[-1]:
args = request.args # returns a dictionary with a list of values for each key
# each value and each key is represented as a string
# to convert it to a dictionary use to_dict(flat=False)
# to_dict(flat=True) returns the key and the first item of the value list.
out = buf.foo(l, args)
else:
#req = add_reqest(path)
#while req not in Buffer.system['done']:
# pass
#Buffer.system['done'].remove(req)
out = buf.get_level(l)
return jsonify( out )
def add_reqest(path):
notinlist = False
time = datetime.datetime.now()
id = Buffer._id
tmp = Request(path, time, id)
try:
Buffer.system['request'].index(tmp)
except ValueError:
notinlist = True
if notinlist:
Buffer.system['request'].insert(0, tmp)
return id
else:
return False
def API_start():
api = API()
api.app.run(host = conf['flask_server'],
port = int(conf['flask_port']))
#debug = conf['flask_debug']
API_start()