97 lines
2.6 KiB
Python
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)
|