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