128 lines
3.5 KiB
Python
128 lines
3.5 KiB
Python
import tornado
|
|
import tornado.web
|
|
import tornado.gen
|
|
from tornado.ioloop import IOLoop
|
|
|
|
from constants import argumentTypes
|
|
from objects import glob
|
|
|
|
# Copied from https://zxq.co/ripple/ripple-python-common/src/branch/master/web/requestsManager.py
|
|
class asyncRequestHandler(tornado.web.RequestHandler):
|
|
"""
|
|
Tornado asynchronous request handler
|
|
create a class that extends this one (requestHelper.asyncRequestHandler)
|
|
use asyncGet() and asyncPost() instead of get() and post().
|
|
Done. I'm not kidding.
|
|
"""
|
|
@tornado.web.asynchronous
|
|
@tornado.gen.engine
|
|
def get(self, *args, **kwargs):
|
|
try:
|
|
yield tornado.gen.Task(runBackground, (self.asyncGet, tuple(args), dict(kwargs)))
|
|
finally:
|
|
if not self._finished:
|
|
self.finish()
|
|
|
|
@tornado.web.asynchronous
|
|
@tornado.gen.engine
|
|
def post(self, *args, **kwargs):
|
|
try:
|
|
yield tornado.gen.Task(runBackground, (self.asyncPost, tuple(args), dict(kwargs)))
|
|
finally:
|
|
if not self._finished:
|
|
self.finish()
|
|
|
|
def asyncGet(self, *args, **kwargs):
|
|
self.send_error(405)
|
|
|
|
def asyncPost(self, *args, **kwargs):
|
|
self.send_error(405)
|
|
|
|
def getRequestIP(self):
|
|
"""
|
|
Return CF-Connecting-IP (request IP when under cloudflare, you have to configure nginx to enable that)
|
|
If that fails, return X-Forwarded-For (request IP when not under Cloudflare)
|
|
if everything else fails, return remote IP
|
|
|
|
:return: Client IP address
|
|
"""
|
|
if "CF-Connecting-IP" in self.request.headers:
|
|
return self.request.headers.get("CF-Connecting-IP")
|
|
elif "X-Forwarded-For" in self.request.headers:
|
|
return self.request.headers.get("X-Forwarded-For")
|
|
else:
|
|
return self.request.remote_ip
|
|
|
|
|
|
def runBackground(data, callback):
|
|
"""
|
|
Run a function in the background.
|
|
Used to handle multiple requests at the same time
|
|
|
|
:param data: (func, args, kwargs)
|
|
:param callback: function to call when `func` (data[0]) returns
|
|
:return:
|
|
"""
|
|
func, args, kwargs = data
|
|
def _callback(result):
|
|
IOLoop.instance().add_callback(lambda: callback(result))
|
|
glob.pool.apply_async(func, args, kwargs, _callback)
|
|
|
|
def check_arguments(tornado_inst):
|
|
arguments = tornado_inst.request.arguments
|
|
arguments_filter = tornado_inst.ARGS
|
|
arguments_validator = tornado_inst.ARGS_VALIDATION
|
|
|
|
args = None
|
|
|
|
for k, v in arguments_filter.items():
|
|
if v == argumentTypes.optional:
|
|
args = arg_filter_and(arguments, k)
|
|
elif v == argumentTypes.required:
|
|
args = arg_filter_require_all(arguments, k)
|
|
elif v == argumentTypes.one_required:
|
|
args = arg_filter_first(arguments, k, False)
|
|
elif v == argumentTypes.only_one:
|
|
args = arg_filter_only_one(arguments, k)
|
|
|
|
if args:
|
|
for k, v in arguments_validator.items():
|
|
for i in range( len(v) ):
|
|
if v[i] in args:
|
|
if not k( tornado_inst.get_argument(v[i]) ):
|
|
raise Exception("%s is not type of %s" % (v[i], k.__name__ ))
|
|
|
|
#for arg in args:
|
|
# if tornado_inst.get_argument(arg) is not
|
|
|
|
return args
|
|
|
|
def arg_filter_and(arguments, filter, can_false = False):
|
|
arg_filter = []
|
|
for i in filter:
|
|
if i in arguments:
|
|
arg_filter.append(i)
|
|
if can_false:
|
|
return arg_filter if len(arg_filter) else False
|
|
return arg_filter
|
|
|
|
def arg_filter_require_all(arguments, required):
|
|
for i in required:
|
|
if i not in arguments:
|
|
return False
|
|
return required
|
|
|
|
def arg_filter_only_one(arguments, required):
|
|
arg_filter = []
|
|
for i in required:
|
|
if i in arguments:
|
|
arg_filter.append(i)
|
|
return True if len(arg_filter) == 1 else False
|
|
|
|
def arg_filter_first(arguments, filter, optional = True):
|
|
arg_filter = []
|
|
for i in filter:
|
|
if i in arguments:
|
|
arg_filter.append(i)
|
|
return arg_filter if len(arg_filter) else optional
|