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): filter_pass = [] for k, v in arguments_filter.items(): if v == argumentTypes.optional: filter_pass.append( arg_filter_and(arguments, k) ) elif v == argumentTypes.required: filter_pass.append( arg_filter_require_all(arguments, k) ) elif v == argumentTypes.one_required: filter_pass.append( arg_filter_first(arguments, k, False) ) elif v == argumentTypes.only_one: filter_pass.append( arg_filter_only_one(arguments, k) ) return filter_pass 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): for i in filter: if i in arguments: return i return optional