ripple-python-common/web/requestsManager.py

97 lines
2.6 KiB
Python

import sys
import traceback
import tornado
import tornado.web
import tornado.gen
from tornado.ioloop import IOLoop
from objects import glob
from common.log import logUtils as log
from raven.contrib.tornado import SentryMixin
class asyncRequestHandler(SentryMixin, 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)
glob.dog.increment(glob.DATADOG_PREFIX + ".incoming_requests")
def checkArguments(arguments, requiredArguments):
"""
Check that every requiredArguments elements are in arguments
:param arguments: full argument list, from tornado
:param requiredArguments: required arguments list
:return: True if all arguments are passed, False if not
"""
for i in requiredArguments:
if i not in arguments:
return False
return True
def printArguments(t):
"""
Print passed arguments, for debug purposes
:param t: tornado object (self)
"""
msg = "ARGS::"
for i in t.request.arguments:
msg += "{}={}\r\n".format(i, t.get_argument(i))
log.debug(msg)