from glob import glob from os import path, getcwd from os.path import exists import eventlet import socketio from flask import Flask, send_from_directory from pycs.database.Database import Database from pycs.frontend.endpoints.ListJobs import ListJobs from pycs.frontend.endpoints.ListLabelProviders import ListLabelProviders from pycs.frontend.endpoints.ListModels import ListModels from pycs.frontend.endpoints.ListProjects import ListProjects from pycs.frontend.endpoints.additional.FolderInformation import FolderInformation from pycs.frontend.endpoints.data.GetCroppedFile import GetCroppedFile from pycs.frontend.endpoints.data.GetFile import GetFile from pycs.frontend.endpoints.data.GetPreviousAndNextFile import GetPreviousAndNextFile from pycs.frontend.endpoints.data.GetResizedFile import GetResizedFile from pycs.frontend.endpoints.data.RemoveFile import RemoveFile from pycs.frontend.endpoints.data.UploadFile import UploadFile from pycs.frontend.endpoints.jobs.RemoveJob import RemoveJob from pycs.frontend.endpoints.labels.CreateLabel import CreateLabel from pycs.frontend.endpoints.labels.EditLabelName import EditLabelName from pycs.frontend.endpoints.labels.EditLabelParent import EditLabelParent from pycs.frontend.endpoints.labels.ListLabelTree import ListLabelTree from pycs.frontend.endpoints.labels.ListLabels import ListLabels from pycs.frontend.endpoints.labels.RemoveLabel import RemoveLabel from pycs.frontend.endpoints.pipelines.FitModel import FitModel from pycs.frontend.endpoints.pipelines.PredictFile import PredictFile from pycs.frontend.endpoints.pipelines.PredictModel import PredictModel from pycs.frontend.endpoints.projects.CreateProject import CreateProject from pycs.frontend.endpoints.projects.EditProjectDescription import EditProjectDescription from pycs.frontend.endpoints.projects.EditProjectName import EditProjectName from pycs.frontend.endpoints.projects.ExecuteExternalStorage import ExecuteExternalStorage from pycs.frontend.endpoints.projects.ExecuteLabelProvider import ExecuteLabelProvider from pycs.frontend.endpoints.projects.GetProjectModel import GetProjectModel from pycs.frontend.endpoints.projects.ListCollections import ListCollections from pycs.frontend.endpoints.projects.ListFiles import ListFiles from pycs.frontend.endpoints.projects.RemoveProject import RemoveProject from pycs.frontend.endpoints.results.ConfirmResult import ConfirmResult from pycs.frontend.endpoints.results.CreateResult import CreateResult from pycs.frontend.endpoints.results.EditResultData import EditResultData from pycs.frontend.endpoints.results.EditResultLabel import EditResultLabel from pycs.frontend.endpoints.results.GetProjectResults import GetProjectResults from pycs.frontend.endpoints.results.GetResults import GetResults from pycs.frontend.endpoints.results.RemoveResult import RemoveResult from pycs.frontend.endpoints.results.ResetResults import ResetResults from pycs.frontend.notifications.NotificationManager import NotificationManager from pycs.frontend.util.JSONEncoder import JSONEncoder from pycs.jobs.JobRunner import JobRunner from pycs.util.PipelineCache import PipelineCache class WebServer: """ wrapper class for flask and socket.io which initializes most networking """ # pylint: disable=line-too-long # pylint: disable=too-many-statements def __init__(self, settings: dict, database: Database, jobs: JobRunner, pipelines: PipelineCache): # initialize web server if exists('webui/index.html'): print('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.__flask = Flask(__name__) self.__app = socketio.WSGIApp(self.__sio, self.__flask, static_files=static_files) # overwrite root path to serve index.html @self.__flask.route('/', methods=['GET']) def index(): # pylint: disable=unused-variable return send_from_directory(path.join(getcwd(), 'webui'), 'index.html') else: print('development build') # create service objects self.__sio = socketio.Server(cors_allowed_origins='*', async_mode='eventlet') self.__flask = Flask(__name__) self.__app = socketio.WSGIApp(self.__sio, self.__flask) # set access control header to allow requests from Vue.js development server @self.__flask.after_request def after_request(response): # pylint: disable=unused-variable response.headers['Access-Control-Allow-Origin'] = '*' return response # set json encoder so database objects are serialized correctly self.__flask.json_encoder = JSONEncoder # create notification manager notifications = NotificationManager(self.__sio) jobs.on_create(notifications.create_job) jobs.on_start(notifications.edit_job) jobs.on_progress(notifications.edit_job) jobs.on_finish(notifications.edit_job) jobs.on_remove(notifications.remove_job) # additional self.__flask.add_url_rule( '/folder', view_func=FolderInformation.as_view('folder_information') ) # jobs self.__flask.add_url_rule( '/jobs', view_func=ListJobs.as_view('list_jobs', jobs) ) self.__flask.add_url_rule( '/jobs//remove', view_func=RemoveJob.as_view('remove_job', jobs) ) # models self.__flask.add_url_rule( '/models', view_func=ListModels.as_view('list_models', database) ) self.__flask.add_url_rule( '/projects//model', view_func=GetProjectModel.as_view('get_project_model', database) ) # labels self.__flask.add_url_rule( '/label_providers', view_func=ListLabelProviders.as_view('label_providers', database) ) self.__flask.add_url_rule( '/projects//labels', view_func=ListLabels.as_view('list_labels', database) ) self.__flask.add_url_rule( '/projects//labels/tree', view_func=ListLabelTree.as_view('list_label_tree', database) ) self.__flask.add_url_rule( '/projects//labels', view_func=CreateLabel.as_view('create_label', database, notifications) ) self.__flask.add_url_rule( '/projects//labels//remove', view_func=RemoveLabel.as_view('remove_label', database, notifications) ) self.__flask.add_url_rule( '/projects//labels//name', view_func=EditLabelName.as_view('edit_label_name', database, notifications) ) self.__flask.add_url_rule( '/projects//labels//parent', view_func=EditLabelParent.as_view('edit_label_parent', database, notifications) ) # collections self.__flask.add_url_rule( '/projects//collections', view_func=ListCollections.as_view('list_collections', database) ) self.__flask.add_url_rule( '/projects//data///', view_func=ListFiles.as_view('list_collection_files', database) ) # data self.__flask.add_url_rule( '/projects//data', view_func=UploadFile.as_view('upload_file', database, notifications) ) self.__flask.add_url_rule( '/projects//data//', view_func=ListFiles.as_view('list_files', database) ) self.__flask.add_url_rule( '/data//remove', view_func=RemoveFile.as_view('remove_file', database, notifications) ) self.__flask.add_url_rule( '/data/', view_func=GetFile.as_view('get_file', database) ) self.__flask.add_url_rule( '/data//', view_func=GetResizedFile.as_view('get_resized_file', database) ) self.__flask.add_url_rule( '/data///', view_func=GetCroppedFile.as_view('crop_result', database) ) self.__flask.add_url_rule( '/data//previous_next', view_func=GetPreviousAndNextFile.as_view('get_previous_and_next_file', database) ) # results self.__flask.add_url_rule( '/projects//results', view_func=GetProjectResults.as_view('get_project_results', database) ) self.__flask.add_url_rule( '/data//results', view_func=GetResults.as_view('get_results', database) ) self.__flask.add_url_rule( '/data//results', view_func=CreateResult.as_view('create_result', database, notifications) ) self.__flask.add_url_rule( '/data//reset', view_func=ResetResults.as_view('reset_results', database, notifications) ) self.__flask.add_url_rule( '/results//remove', view_func=RemoveResult.as_view('remove_result', database, notifications) ) self.__flask.add_url_rule( '/results//confirm', view_func=ConfirmResult.as_view('confirm_result', database, notifications) ) self.__flask.add_url_rule( '/results//label', view_func=EditResultLabel.as_view('edit_result_label', database, notifications) ) self.__flask.add_url_rule( '/results//data', view_func=EditResultData.as_view('edit_result_data', database, notifications) ) # projects self.__flask.add_url_rule( '/projects', view_func=ListProjects.as_view('list_projects', database) ) self.__flask.add_url_rule( '/projects', view_func=CreateProject.as_view('create_project', database, notifications, jobs) ) self.__flask.add_url_rule( '/projects//label_provider', view_func=ExecuteLabelProvider.as_view('execute_label_provider', database, notifications, jobs) ) self.__flask.add_url_rule( '/projects//external_storage', view_func=ExecuteExternalStorage.as_view('execute_external_storage', database, notifications, jobs) ) self.__flask.add_url_rule( '/projects//remove', view_func=RemoveProject.as_view('remove_project', database, notifications) ) self.__flask.add_url_rule( '/projects//name', view_func=EditProjectName.as_view('edit_project_name', database, notifications) ) self.__flask.add_url_rule( '/projects//description', view_func=EditProjectDescription.as_view('edit_project_description', database, notifications) ) # pipelines self.__flask.add_url_rule( '/projects//pipelines/fit', view_func=FitModel.as_view('fit_model', database, jobs, pipelines) ) self.__flask.add_url_rule( '/projects//pipelines/predict', view_func=PredictModel.as_view('predict_model', database, notifications, jobs, pipelines) ) self.__flask.add_url_rule( '/data//predict', view_func=PredictFile.as_view('predict_file', database, notifications, jobs, pipelines) ) # finally start web server eventlet.wsgi.server(eventlet.listen((settings['host'], settings['port'])), self.__app)