osu-wayback/web/asyncTornado.py
2019-03-11 13:25:39 +01:00

110 lines
3.1 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(arguments, arguments_filter):
for k, v in arguments_filter.items():
if v == argumentTypes.optional:
return arg_filter_and(arguments, k)
elif v == argumentTypes.required:
return arg_filter_require_all(arguments, k)
elif v == argumentTypes.one_required:
return arg_filter_first(arguments, k, False)
elif v == argumentTypes.only_one:
return arg_filter_only_one(arguments, k)
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