1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
"""All webserver logic lives here, including routes"""
from flask import Flask, Response
from flask import request, jsonify
import sys, os, re
import cherrypy
from paste.translogger import TransLogger
import simplejson as json
sys.path.append("./lib")
from pb import *
from db import Db
from param import BadParamError
from config import SERVER_HOST, SERVER_PORT
#FIXME add remote_addr and this jsonp thing
class InvalidUsage(Exception):
"""error class for InvalidUsage"""
status_code = 400
def __init__(self, message, status_code=None, payload=None):
Exception.__init__(self)
self.message = message
if status_code is not None:
self.status_code = status_code
self.payload = payload
def to_dict(self):
rv = dict(self.payload or ())
rv['message'] = self.message
return rv
class Server(object):
"""Main server class"""
def __init__(self):
self.app = Flask(__name__)
self._wsgi_server = None
@self.app.route('/test', methods=['GET'])
def test():
return "HELLO WORLD!"
@self.app.route('/im/api/<pb_classname>', methods=['POST'])
def pb(pb_classname):
x_forwarded_headers = request.headers.getlist("X-Forwarded-For")
if x_forwarded_headers:
host = x_forwarded_headers[0]
regex = re.compile(r'[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+')
forwarded_ip = regex.search(host).group()
else:
forwarded_ip = None
return self._response_post(
pb_classname,
request.form.to_dict(),
remote_addr=forwarded_ip
)
@self.app.errorhandler(InvalidUsage)
def handle_invalid_usage(error):
response = jsonify(error.to_dict())
response.status_code = error.status_code
return response
self._classname_aliases = {
'generate' : 'PbGenerate',
'imgrid' : 'PbGrid',
'imbreak' : 'PbBreaker',
'impattern' : 'PbPattern',
'imgradient' : 'PbGradient',
'landscape' : 'PbLandscape',
}
@self.app.route('/im/data', methods=['GET'])
def get_data():
args_dict = request.args.to_dict()
query_dict = {}
for elem in ["newfile", "time"]:
if args_dict.get(elem):
query_dict[elem] = args_dict.get(elem)
if args_dict:
try:
db = Db()
return Response(
#flask prevents from returning arrays, so we need the json module
json.dumps(db.search(**query_dict)),
mimetype='application/json'
)
except Exception as e:
return str(e)
else:
raise InvalidUsage('Improper Usage', status_code=410)
def _find_class_by_name(self, pb_classname):
pb_classname = self._classname_aliases.get(pb_classname, None) or pb_classname
try:
return filter(lambda c: c.__name__ == pb_classname, Pb.__subclasses__())[0]
except IndexError:
raise InvalidUsage('No such api', status_code=410)
def _response_post(self, pb_classname, request_form, remote_addr=None):
pb_class = self._find_class_by_name(pb_classname)
classnames = map(lambda c: c.__name__, Pb.__subclasses__())
try:
pb = pb_class(**request_form)
pb.create()
pb.file_s3move()
pb.db_send(remote_addr=remote_addr)
json_data = jsonify(pb.file_dict())
if pb.params.callback: #accounts for jsonp
return "%s(%s)" % (pb.params.callback, json_data)
return json_data
except BadParamError:
for i in request_form.keys():
sys.stderr.write('\'%s\':\'%s\'\n' % (i, request_form[i] or None))
return jsonify({'error' : 'Bad Params'})
except PbProcessError:
sys.stderr.write(dict(request_form))
return jsonify({'error' : 'Problem with server-side processing' })
def run(self, host=SERVER_HOST, port=SERVER_PORT):
self.app.run(host=host, port=port)
def run_wsgi(self, server_port=SERVER_PORT, host=SERVER_HOST):
#http://fgimian.github.io/blog/2012/12/08/setting-up-a-rock-solid-python-development-web-server/
# Enable WSGI access logging via Paste
app_logged = TransLogger(self.app)
# Mount the WSGI callable object (app) on the root directory
cherrypy.tree.graft(app_logged, '/')
# Set the configuration of the web server
cherrypy.config.update({
'engine.autoreload_on': True,
'log.screen': True,
'server.socket_port': server_port,
'server.socket_host': host
})
cherrypy.engine.start()
cherrypy.engine.block()
|