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

192 lines
6.6 KiB
Python
Raw Permalink Normal View History

2020-08-12 00:36:09 +00:00
import os
import sys
import json
import asyncio
import logging
import tornado.web
import tornado.ioloop
import tornado.log
import tornado.template
import tornado.escape
import tornado.locale
import tornado.httpserver
from app.classes.models.management import HelpersManagement
from app.classes.shared.console import Console
from app.classes.shared.helpers import Helpers
from app.classes.shared.file_helpers import FileHelpers
from app.classes.shared.main_controller import Controller
2022-03-08 04:40:44 +00:00
from app.classes.web.public_handler import PublicHandler
from app.classes.web.panel_handler import PanelHandler
from app.classes.web.default_handler import DefaultHandler
from app.classes.web.routes.api.api_handlers import api_handlers
2023-09-03 14:04:28 +00:00
from app.classes.web.routes.metrics.metrics_handlers import metrics_handlers
2022-03-08 04:40:44 +00:00
from app.classes.web.server_handler import ServerHandler
2023-09-05 21:16:53 +00:00
from app.classes.web.websocket_handler import WebSocketHandler
2022-03-08 04:40:44 +00:00
from app.classes.web.static_handler import CustomStaticHandler
from app.classes.web.status_handler import StatusHandler
2020-08-12 00:36:09 +00:00
2022-03-08 04:40:44 +00:00
logger = logging.getLogger(__name__)
2020-08-12 00:36:09 +00:00
class Webserver:
controller: Controller
helper: Helpers
2023-09-05 18:27:02 +00:00
def __init__(
2023-09-05 18:37:52 +00:00
self,
helper: Helpers,
controller: Controller,
tasks_manager,
file_helper: FileHelpers,
):
2020-08-12 00:36:09 +00:00
self.ioloop = None
self.https_server = None
self.helper = helper
self.controller = controller
self.tasks_manager = tasks_manager
self.file_helper = file_helper
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
"Elapsed_Time": "%.2fms" % (handler.request.request_time() * 1000),
2020-08-12 00:36:09 +00:00
}
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",
2020-08-12 00:36:09 +00:00
where tornado expects the "selector" handler.
This function checks if the platform is windows and
changes the event handler to suit.
2020-08-12 00:36:09 +00:00
(Taken from
https://github.com/mkdocs/mkdocs/commit/cf2b136d4257787c0de51eba2d9e30ded5245b31)
2020-08-12 00:36:09 +00:00
"""
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
2020-08-12 00:36:09 +00:00
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
):
2020-08-12 00:36:09 +00:00
asyncio.set_event_loop_policy(WindowsSelectorEventLoopPolicy())
logger.debug("Applied asyncio patch")
def run_tornado(self):
# let's verify we have an SSL cert
self.helper.create_self_signed_cert()
2020-08-12 00:36:09 +00:00
https_port = self.helper.get_setting("https_port")
debug_errors = self.helper.get_setting("show_errors")
try:
cookie_secret = HelpersManagement.get_cookie_secret()
except:
cookie_secret = False
if cookie_secret is False or cookie_secret == "":
cookie_secret = self.helper.random_string_generator(32)
HelpersManagement.set_cookie_secret(cookie_secret)
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(
self.helper.config_dir, "web", "certs", "commander.cert.pem"
),
"keyfile": os.path.join(
self.helper.config_dir, "web", "certs", "commander.key.pem"
),
2020-08-12 00:36:09 +00:00
}
2024-03-21 22:10:39 +00:00
logger.info(f"Starting Web Server on ports https:{https_port}")
2020-08-12 00:36:09 +00:00
asyncio.set_event_loop(asyncio.new_event_loop())
tornado.template.Loader(".")
2020-08-12 00:36:09 +00:00
# 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 = {
"helper": self.helper,
"controller": self.controller,
"tasks_manager": self.tasks_manager,
"translator": self.helper.translation,
"file_helper": self.file_helper,
}
2020-08-12 00:36:09 +00:00
handlers = [
(r"/", DefaultHandler, handler_args),
(r"/panel/(.*)", PanelHandler, handler_args),
(r"/server/(.*)", ServerHandler, handler_args),
2023-09-05 21:16:53 +00:00
(r"/ws", WebSocketHandler, handler_args),
(r"/status", StatusHandler, handler_args),
# API Routes V2
*api_handlers(handler_args),
2023-09-03 14:04:28 +00:00
# API Routes OpenMetrics
*metrics_handlers(handler_args),
2023-01-26 21:26:41 +00:00
# Using this one at the end
# to catch all the other requests to Public Handler
(r"/(.*)", PublicHandler, handler_args),
]
2020-08-12 00:36:09 +00:00
app = tornado.web.Application(
handlers,
template_path=os.path.join(self.helper.webroot, "templates"),
static_path=os.path.join(self.helper.webroot, "static"),
2020-08-12 00:36:09 +00:00
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
)
self.https_server = tornado.httpserver.HTTPServer(app, ssl_options=cert_objects)
self.https_server.listen(https_port)
2020-08-12 00:36:09 +00:00
logger.info(
f"https://{Helpers.get_local_ip()}:{https_port} "
f"is up and ready for connections."
)
Console.info(
f"https://{Helpers.get_local_ip()}:{https_port} "
f"is up and ready for connections."
)
Console.info("Server Init Complete: Listening For Connections!")
2020-08-12 00:36:09 +00:00
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")
2020-08-12 00:36:09 +00:00
self.ioloop.stop()
self.https_server.stop()
2020-08-12 00:36:09 +00:00
logger.info("Web Server Stopped")
Console.info("Web Server Stopped")