crafty-4/app/classes/web/tornado_handler.py

193 lines
7.5 KiB
Python
Raw Normal View History

2020-08-12 00:36:09 +00:00
import os
import sys
import json
import asyncio
import logging
logger = logging.getLogger(__name__)
try:
import tornado.web
import tornado.ioloop
import tornado.log
import tornado.template
import tornado.escape
import tornado.locale
import tornado.httpserver
2022-02-27 17:45:32 +00:00
from app.classes.web.file_handler import FileHandler
2020-08-12 00:36:09 +00:00
from app.classes.web.public_handler import PublicHandler
2020-08-13 14:38:36 +00:00
from app.classes.web.panel_handler import PanelHandler
from app.classes.web.default_handler import DefaultHandler
from app.classes.web.server_handler import ServerHandler
from app.classes.web.ajax_handler import AjaxHandler
2020-09-06 04:58:17 +00:00
from app.classes.web.api_handler import ServersStats, NodeStats
from app.classes.web.websocket_handler import SocketHandler
2021-04-17 15:12:23 +00:00
from app.classes.web.static_handler import CustomStaticHandler
2021-08-22 14:17:33 +00:00
from app.classes.web.upload_handler import UploadHandler
from app.classes.web.http_handler import HTTPHandler, HTTPHandlerPage
2021-08-27 01:06:22 +00:00
from app.classes.web.status_handler import StatusHandler
from app.classes.shared.translation import translation
from app.classes.shared.console import console
from app.classes.shared.helpers import helper
2020-08-12 00:36:09 +00:00
except ModuleNotFoundError as e:
logger.critical(f"Import Error: Unable to load {e.name} module", exc_info=True)
console.critical(f"Import Error: Unable to load {e.name} module")
2020-08-12 00:36:09 +00:00
sys.exit(1)
class Webserver:
2020-08-12 00:36:09 +00:00
def __init__(self, controller, tasks_manager):
2020-08-12 00:36:09 +00:00
self.ioloop = None
self.HTTP_Server = None
self.HTTPS_Server = None
self.controller = controller
self.tasks_manager = tasks_manager
2020-08-12 00:36:09 +00:00
self._asyncio_patch()
@staticmethod
def log_function(handler):
info = {
'Status_Code': handler.get_status(),
'Method': handler.request.method,
'URL': handler.request.uri,
'Remote_IP': handler.request.remote_ip,
# pylint: disable=consider-using-f-string
2020-08-12 00:36:09 +00:00
'Elapsed_Time': '%.2fms' % (handler.request.request_time() * 1000)
}
tornado.log.access_log.info(json.dumps(info, indent=4))
@staticmethod
def _asyncio_patch():
"""
As of Python 3.8 (on Windows), the asyncio default event handler has changed to "proactor",
where tornado expects the "selector" handler.
This function checks if the platform is windows and changes the event handler to suit.
(Taken from https://github.com/mkdocs/mkdocs/commit/cf2b136d4257787c0de51eba2d9e30ded5245b31)
"""
logger.debug("Checking if asyncio patch is required")
if sys.platform.startswith("win") and sys.version_info >= (3, 8):
# pylint: disable=reimported,import-outside-toplevel,redefined-outer-name
2020-08-12 00:36:09 +00:00
import asyncio
try:
from asyncio import WindowsSelectorEventLoopPolicy
except ImportError:
logger.debug("asyncio patch isn't required") # Can't assign a policy which doesn't exist.
2020-08-12 00:36:09 +00:00
else:
if not isinstance(asyncio.get_event_loop_policy(), WindowsSelectorEventLoopPolicy):
asyncio.set_event_loop_policy(WindowsSelectorEventLoopPolicy())
logger.debug("Applied asyncio patch")
def run_tornado(self):
# let's verify we have an SSL cert
helper.create_self_signed_cert()
http_port = helper.get_setting('http_port')
https_port = helper.get_setting('https_port')
debug_errors = helper.get_setting('show_errors')
cookie_secret = helper.get_setting('cookie_secret')
2020-08-12 00:36:09 +00:00
if cookie_secret is False:
cookie_secret = helper.random_string_generator(32)
2020-08-12 00:36:09 +00:00
if not http_port:
http_port = 8000
2020-08-12 00:36:09 +00:00
if not https_port:
https_port = 8443
2020-08-12 00:36:09 +00:00
cert_objects = {
'certfile': os.path.join(helper.config_dir, 'web', 'certs', 'commander.cert.pem'),
'keyfile': os.path.join(helper.config_dir, 'web', 'certs', 'commander.key.pem'),
}
logger.info(f"Starting Web Server on ports http:{http_port} https:{https_port}")
2020-08-12 00:36:09 +00:00
asyncio.set_event_loop(asyncio.new_event_loop())
tornado.template.Loader('.')
# TODO: Remove because we don't and won't use
tornado.locale.set_default_locale('en_EN')
2020-08-12 00:36:09 +00:00
handler_args = {"controller": self.controller, "tasks_manager": self.tasks_manager, "translator": translation}
2020-08-12 00:36:09 +00:00
handlers = [
(r'/', DefaultHandler, handler_args),
(r'/public/(.*)', PublicHandler, handler_args),
(r'/panel/(.*)', PanelHandler, handler_args),
(r'/server/(.*)', ServerHandler, handler_args),
(r'/ajax/(.*)', AjaxHandler, handler_args),
(r'/files/(.*)', FileHandler, handler_args),
(r'/api/stats/servers', ServersStats, handler_args),
(r'/api/stats/node', NodeStats, handler_args),
(r'/ws', SocketHandler, handler_args),
2021-09-25 23:02:05 +00:00
(r'/upload', UploadHandler, handler_args),
2021-08-27 01:06:22 +00:00
(r'/status', StatusHandler, handler_args)
2020-08-12 00:36:09 +00:00
]
app = tornado.web.Application(
handlers,
template_path=os.path.join(helper.webroot, 'templates'),
static_path=os.path.join(helper.webroot, 'static'),
debug=debug_errors,
cookie_secret=cookie_secret,
xsrf_cookies=True,
autoreload=False,
log_function=self.log_function,
login_url="/login",
2021-04-17 15:12:23 +00:00
default_handler_class=PublicHandler,
static_handler_class=CustomStaticHandler,
serve_traceback=debug_errors,
2020-08-12 00:36:09 +00:00
)
HTTPhanders = [(r'/', HTTPHandler, handler_args),
(r'/public/(.*)', HTTPHandlerPage, handler_args),
(r'/panel/(.*)', HTTPHandlerPage, handler_args),
(r'/server/(.*)', HTTPHandlerPage, handler_args),
(r'/ajax/(.*)', HTTPHandlerPage, handler_args),
(r'/api/stats/servers', HTTPHandlerPage, handler_args),
(r'/api/stats/node', HTTPHandlerPage, handler_args),
(r'/ws', HTTPHandlerPage, handler_args),
(r'/upload', HTTPHandlerPage, handler_args)]
HTTPapp = tornado.web.Application(
HTTPhanders,
template_path=os.path.join(helper.webroot, 'templates'),
static_path=os.path.join(helper.webroot, 'static'),
debug=debug_errors,
cookie_secret=cookie_secret,
xsrf_cookies=True,
autoreload=False,
log_function=self.log_function,
default_handler_class = HTTPHandler,
login_url="/login",
serve_traceback=debug_errors,
)
2020-08-12 00:36:09 +00:00
self.HTTP_Server = tornado.httpserver.HTTPServer(HTTPapp)
2020-08-12 00:36:09 +00:00
self.HTTP_Server.listen(http_port)
self.HTTPS_Server = tornado.httpserver.HTTPServer(app, ssl_options=cert_objects)
self.HTTPS_Server.listen(https_port)
logger.info(f"https://{helper.get_local_ip()}:{https_port} is up and ready for connections.")
console.info(f"https://{helper.get_local_ip()}:{https_port} is up and ready for connections.")
2020-08-12 00:36:09 +00:00
console.info("Server Init Complete: Listening For Connections:")
self.ioloop = tornado.ioloop.IOLoop.current()
2020-08-12 00:36:09 +00:00
self.ioloop.start()
def stop_web_server(self):
logger.info("Shutting Down Web Server")
console.info("Shutting Down Web Server")
self.ioloop.stop()
self.HTTP_Server.stop()
self.HTTPS_Server.stop()
logger.info("Web Server Stopped")
console.info("Web Server Stopped")