app/server/server_management.py
import logging
import tornado.httpserver
import tornado.ioloop
import tornado.web
from application_settings.logging_settings import LoggingSettings
from application_settings.server_settings import ServerSettings
from server.apis.auth.auth_api_management import AuthApiManagement
from server.apis.docs.doc_redirects_management import DocumentationRedirectsManagement
from server.apis.rest.rest_api_management import RestApiManagement
from server.apis.websocket.websocket_api_management import WebsocketApiManagement
from server.apis.websocket.websocket_handler import WebsocketHandler
from server.static_hosting.static_hosting_management import StaticHostingManagement
log = logging.getLogger("opserv." + __name__)
class ServerManagement:
__tornado_loop = None
@classmethod
def start_server(cls):
port = cls.__get_port()
log.debug("Starting server on port {0}".format(port))
tls_options = cls.__get_tls_options()
log.debug("All connections will{0}be encrypted".format(
" NOT " if tls_options is None else " "
))
tornado_server = tornado.httpserver.HTTPServer(
cls.__get_tornado_application(),
ssl_options=tls_options
)
tornado_server.listen(port)
cls.__tornado_loop = tornado.ioloop.IOLoop.current()
cls.__tornado_loop.start()
@classmethod
def stop_server(cls):
if cls.__tornado_loop is not None:
cls.__tornado_loop.stop()
else:
log.error("Tried to stop non-existing server")
@classmethod
def __get_port(cls):
port = ServerSettings.get_setting(ServerSettings.KEY_PORT)
if port is None:
port = 8888
return port
@classmethod
def __get_tls_options(cls):
if False: # TODO Read certificate based on runtime argument
return {
"certfile": "/var/pyTest/keys/ca.csr",
"keyfile": "/var/pyTest/keys/ca.key"
}
return None
@classmethod
def __get_tornado_application(cls):
settings = {
"compress_response": True,
"debug": LoggingSettings.get_setting(LoggingSettings.KEY_CONSOLE_LOG) in (logging.DEBUG, logging.NOTSET)
}
return tornado.web.Application(
cls.__get_request_handlers(),
**settings
)
@classmethod
def __get_request_handlers(cls):
request_handlers = [
("/apis/*", None) # TODO Add handler that lists /rest, /websocket, /auth
]
request_handlers.extend(AuthApiManagement.get_handlers())
request_handlers.extend(WebsocketApiManagement.get_handlers())
request_handlers.extend(RestApiManagement.get_handlers())
request_handlers.extend(DocumentationRedirectsManagement.get_handlers())
request_handlers.extend(StaticHostingManagement.get_handlers())
return request_handlers
@classmethod
def broadcast_new_measurement(cls, component_type: str, component_arg: str, metric: str, timestamp: int,
value: str):
if cls.__tornado_loop is not None:
cls.__tornado_loop.add_callback(
WebsocketHandler.broadcast_new_measurement,
component_type, component_arg, metric, timestamp, value
)
else:
log.error("Tried to broadcast a new measurement but the server does not exist (yet)")