|
@@ -1,9 +1,11 @@
|
|
|
-import os
|
|
|
import logging.config
|
|
|
+import typing as T
|
|
|
|
|
|
from glob import glob
|
|
|
+from pathlib import Path
|
|
|
|
|
|
import eventlet
|
|
|
+import munch
|
|
|
import socketio
|
|
|
|
|
|
from flask import send_from_directory
|
|
@@ -59,50 +61,28 @@ class WebServer:
|
|
|
wrapper class for flask and socket.io which initializes most networking
|
|
|
"""
|
|
|
|
|
|
- def __init__(self, app, settings: dict, discovery: bool = True):
|
|
|
+ index: Path = Path.cwd() / 'webui' / 'index.html'
|
|
|
+
|
|
|
+ def __init__(self, app, settings: munch.Munch, discovery: bool = True):
|
|
|
|
|
|
logging.config.dictConfig(settings.logging)
|
|
|
- is_production = os.path.exists('webui/index.html')
|
|
|
+ self.app = app
|
|
|
+ # set json encoder so database objects are serialized correctly
|
|
|
+ self.app.json_encoder = JSONEncoder
|
|
|
|
|
|
# initialize web server
|
|
|
- if is_production:
|
|
|
+ if self.is_production:
|
|
|
app.logger.info('production build')
|
|
|
|
|
|
- # find static files and folders
|
|
|
- static_files = {}
|
|
|
-
|
|
|
- for file_path in glob('webui/*'):
|
|
|
- file_path = file_path.replace('\\', '/')
|
|
|
- static_files[file_path[5:]] = file_path
|
|
|
-
|
|
|
- # separately add svg files and set their correct mime type
|
|
|
- for svg_path in glob('webui/img/*.svg'):
|
|
|
- svg_path = svg_path.replace('\\', '/')
|
|
|
- static_files[svg_path[5:]] = {'content_type': 'image/svg+xml', 'filename': svg_path}
|
|
|
-
|
|
|
- # create service objects
|
|
|
- if len(settings['allowedOrigins']) > 0:
|
|
|
- origins = settings['allowedOrigins']
|
|
|
- self.__sio = socketio.Server(cors_allowed_origins=origins, async_mode='eventlet')
|
|
|
- else:
|
|
|
- self.__sio = socketio.Server(async_mode='eventlet')
|
|
|
-
|
|
|
- self.wsgi_app = socketio.WSGIApp(self.__sio, app, static_files=static_files)
|
|
|
-
|
|
|
# overwrite root path to serve index.html
|
|
|
- @app.route('/', methods=['GET'])
|
|
|
+ @self.app.route('/', methods=['GET'])
|
|
|
def index():
|
|
|
# pylint: disable=unused-variable
|
|
|
- return send_from_directory(os.path.join(os.getcwd(), 'webui'), 'index.html')
|
|
|
+ return send_from_directory(str(self.index.parent), self.index.name)
|
|
|
|
|
|
else:
|
|
|
app.logger.info('development build')
|
|
|
|
|
|
- # create service objects
|
|
|
- self.__sio = socketio.Server(cors_allowed_origins='*', async_mode='eventlet')
|
|
|
- self.app = app
|
|
|
- self.wsgi_app = socketio.WSGIApp(self.__sio, app)
|
|
|
-
|
|
|
# set access control header to allow requests from Vue.js development server
|
|
|
@self.app.after_request
|
|
|
def after_request(response):
|
|
@@ -110,8 +90,9 @@ class WebServer:
|
|
|
response.headers['Access-Control-Allow-Origin'] = '*'
|
|
|
return response
|
|
|
|
|
|
- # set json encoder so database objects are serialized correctly
|
|
|
- self.app.json_encoder = JSONEncoder
|
|
|
+ # create service objects
|
|
|
+ self.sio = socketio.Server(**self.sio_kwargs(settings.allowedOrigins))
|
|
|
+ self.wsgi_app = socketio.WSGIApp(self.sio, app, static_files=self.static_files)
|
|
|
|
|
|
self.host = settings.host
|
|
|
self.port = settings.port
|
|
@@ -119,7 +100,7 @@ class WebServer:
|
|
|
# create notification manager
|
|
|
self.jobs = JobRunner()
|
|
|
self.pipelines = PipelineCache(self.jobs, settings.get("pipeline_cache_time"))
|
|
|
- self.notifications = NotificationManager(self.__sio)
|
|
|
+ self.notifications = NotificationManager(self.sio)
|
|
|
|
|
|
self.jobs.on_create(self.notifications.create_job)
|
|
|
self.jobs.on_start(self.notifications.edit_job)
|
|
@@ -133,6 +114,45 @@ class WebServer:
|
|
|
Model.discover("models/")
|
|
|
LabelProvider.discover("labels/")
|
|
|
|
|
|
+ def sio_kwargs(self, allowed_origins) -> T.Dict[str, T.Union[str, list]]:
|
|
|
+ """keyword arguments for the socketio.Server depending on the mode"""
|
|
|
+ kwargs: T.Dict[str, T.Union[str, list]] = dict(async_mode="eventlet")
|
|
|
+
|
|
|
+ if self.is_production:
|
|
|
+ if isinstance(allowed_origins, list) and len(allowed_origins) > 0:
|
|
|
+ kwargs["cors_allowed_origins"] = allowed_origins
|
|
|
+ else:
|
|
|
+ kwargs["cors_allowed_origins"] = "*"
|
|
|
+
|
|
|
+ return kwargs
|
|
|
+
|
|
|
+ @property
|
|
|
+ def is_production(self) -> bool:
|
|
|
+ """property checking, whether the UI is built (production mode)
|
|
|
+ or served by npm serve (development mode)"""
|
|
|
+ return self.index.exists()
|
|
|
+
|
|
|
+ @property
|
|
|
+ def static_files(self) -> T.Optional[T.Dict[str, T.Union[str, dict]]]:
|
|
|
+ """returns a dictionary of static files (production mode)
|
|
|
+ or None (development mode)"""
|
|
|
+
|
|
|
+ if not self.is_production:
|
|
|
+ return None
|
|
|
+
|
|
|
+ # find static files and folders
|
|
|
+ static_files: T.Dict[str, T.Union[str, dict]] = {}
|
|
|
+
|
|
|
+ for file_path in glob('webui/*'):
|
|
|
+ file_path = file_path.replace('\\', '/')
|
|
|
+ static_files[file_path[5:]] = file_path
|
|
|
+
|
|
|
+ # separately add svg files and set their correct mime type
|
|
|
+ for svg_path in glob('webui/img/*.svg'):
|
|
|
+ svg_path = svg_path.replace('\\', '/')
|
|
|
+ static_files[svg_path[5:]] = {'content_type': 'image/svg+xml', 'filename': svg_path}
|
|
|
+
|
|
|
+ return static_files
|
|
|
|
|
|
def define_routes(self):
|
|
|
""" defines app routes """
|