WebServer.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. from glob import glob
  2. from os import path, getcwd
  3. from os.path import exists
  4. import eventlet
  5. import socketio
  6. from flask import Flask, send_from_directory
  7. from pycs.database.Database import Database
  8. from pycs.frontend.endpoints.ListJobs import ListJobs
  9. from pycs.frontend.endpoints.ListLabelProviders import ListLabelProviders
  10. from pycs.frontend.endpoints.ListModels import ListModels
  11. from pycs.frontend.endpoints.ListProjects import ListProjects
  12. from pycs.frontend.endpoints.additional.FolderInformation import FolderInformation
  13. from pycs.frontend.endpoints.data.GetFile import GetFile
  14. from pycs.frontend.endpoints.data.GetPreviousAndNextFile import GetPreviousAndNextFile
  15. from pycs.frontend.endpoints.data.GetResizedFile import GetResizedFile
  16. from pycs.frontend.endpoints.data.RemoveFile import RemoveFile
  17. from pycs.frontend.endpoints.data.UploadFile import UploadFile
  18. from pycs.frontend.endpoints.jobs.RemoveJob import RemoveJob
  19. from pycs.frontend.endpoints.labels.CreateLabel import CreateLabel
  20. from pycs.frontend.endpoints.labels.EditLabelName import EditLabelName
  21. from pycs.frontend.endpoints.labels.EditLabelParent import EditLabelParent
  22. from pycs.frontend.endpoints.labels.ListLabels import ListLabels
  23. from pycs.frontend.endpoints.labels.RemoveLabel import RemoveLabel
  24. from pycs.frontend.endpoints.pipelines.FitModel import FitModel
  25. from pycs.frontend.endpoints.pipelines.PredictFile import PredictFile
  26. from pycs.frontend.endpoints.pipelines.PredictModel import PredictModel
  27. from pycs.frontend.endpoints.projects.CreateProject import CreateProject
  28. from pycs.frontend.endpoints.projects.EditProjectDescription import EditProjectDescription
  29. from pycs.frontend.endpoints.projects.EditProjectName import EditProjectName
  30. from pycs.frontend.endpoints.projects.ExecuteExternalStorage import ExecuteExternalStorage
  31. from pycs.frontend.endpoints.projects.ExecuteLabelProvider import ExecuteLabelProvider
  32. from pycs.frontend.endpoints.projects.GetProjectModel import GetProjectModel
  33. from pycs.frontend.endpoints.projects.ListCollections import ListCollections
  34. from pycs.frontend.endpoints.projects.ListFiles import ListFiles
  35. from pycs.frontend.endpoints.projects.RemoveProject import RemoveProject
  36. from pycs.frontend.endpoints.results.ConfirmResult import ConfirmResult
  37. from pycs.frontend.endpoints.results.CreateResult import CreateResult
  38. from pycs.frontend.endpoints.results.EditResultData import EditResultData
  39. from pycs.frontend.endpoints.results.EditResultLabel import EditResultLabel
  40. from pycs.frontend.endpoints.results.GetProjectResults import GetProjectResults
  41. from pycs.frontend.endpoints.results.GetResults import GetResults
  42. from pycs.frontend.endpoints.results.RemoveResult import RemoveResult
  43. from pycs.frontend.endpoints.results.ResetResults import ResetResults
  44. from pycs.frontend.notifications.NotificationManager import NotificationManager
  45. from pycs.frontend.util.JSONEncoder import JSONEncoder
  46. from pycs.jobs.JobRunner import JobRunner
  47. from pycs.util.PipelineCache import PipelineCache
  48. class WebServer:
  49. """
  50. wrapper class for flask and socket.io which initializes most networking
  51. """
  52. # pylint: disable=line-too-long
  53. def __init__(self, settings: dict, database: Database, jobs: JobRunner, pipelines: PipelineCache):
  54. # initialize web server
  55. if exists('webui/index.html'):
  56. print('production build')
  57. # find static files and folders
  58. static_files = {}
  59. for file_path in glob('webui/*'):
  60. file_path = file_path.replace('\\', '/')
  61. static_files[file_path[5:]] = file_path
  62. # separately add svg files and set their correct mime type
  63. for svg_path in glob('webui/img/*.svg'):
  64. svg_path = svg_path.replace('\\', '/')
  65. static_files[svg_path[5:]] = {'content_type': 'image/svg+xml', 'filename': svg_path}
  66. # create service objects
  67. if len(settings['allowedOrigins']) > 0:
  68. origins = settings['allowedOrigins']
  69. self.__sio = socketio.Server(cors_allowed_origins=origins, async_mode='eventlet')
  70. else:
  71. self.__sio = socketio.Server(async_mode='eventlet')
  72. self.__flask = Flask(__name__)
  73. self.__app = socketio.WSGIApp(self.__sio, self.__flask, static_files=static_files)
  74. # overwrite root path to serve index.html
  75. @self.__flask.route('/', methods=['GET'])
  76. def index():
  77. # pylint: disable=unused-variable
  78. return send_from_directory(path.join(getcwd(), 'webui'), 'index.html')
  79. else:
  80. print('development build')
  81. # create service objects
  82. self.__sio = socketio.Server(cors_allowed_origins='*', async_mode='eventlet')
  83. self.__flask = Flask(__name__)
  84. self.__app = socketio.WSGIApp(self.__sio, self.__flask)
  85. # set access control header to allow requests from Vue.js development server
  86. @self.__flask.after_request
  87. def after_request(response):
  88. # pylint: disable=unused-variable
  89. response.headers['Access-Control-Allow-Origin'] = '*'
  90. return response
  91. # set json encoder so database objects are serialized correctly
  92. self.__flask.json_encoder = JSONEncoder
  93. # create notification manager
  94. notifications = NotificationManager(self.__sio)
  95. jobs.on_create(notifications.create_job)
  96. jobs.on_start(notifications.edit_job)
  97. jobs.on_progress(notifications.edit_job)
  98. jobs.on_finish(notifications.edit_job)
  99. jobs.on_remove(notifications.remove_job)
  100. # additional
  101. self.__flask.add_url_rule(
  102. '/folder',
  103. view_func=FolderInformation.as_view('folder_information')
  104. )
  105. # jobs
  106. self.__flask.add_url_rule(
  107. '/jobs',
  108. view_func=ListJobs.as_view('list_jobs', jobs)
  109. )
  110. self.__flask.add_url_rule(
  111. '/jobs/<identifier>/remove',
  112. view_func=RemoveJob.as_view('remove_job', jobs)
  113. )
  114. # models
  115. self.__flask.add_url_rule(
  116. '/models',
  117. view_func=ListModels.as_view('list_models', database)
  118. )
  119. self.__flask.add_url_rule(
  120. '/projects/<int:identifier>/model',
  121. view_func=GetProjectModel.as_view('get_project_model', database)
  122. )
  123. # labels
  124. self.__flask.add_url_rule(
  125. '/label_providers',
  126. view_func=ListLabelProviders.as_view('label_providers', database)
  127. )
  128. self.__flask.add_url_rule(
  129. '/projects/<int:identifier>/labels',
  130. view_func=ListLabels.as_view('list_labels', database)
  131. )
  132. self.__flask.add_url_rule(
  133. '/projects/<int:identifier>/labels',
  134. view_func=CreateLabel.as_view('create_label', database, notifications)
  135. )
  136. self.__flask.add_url_rule(
  137. '/projects/<int:project_id>/labels/<int:label_id>/remove',
  138. view_func=RemoveLabel.as_view('remove_label', database, notifications)
  139. )
  140. self.__flask.add_url_rule(
  141. '/projects/<int:project_id>/labels/<int:label_id>/name',
  142. view_func=EditLabelName.as_view('edit_label_name', database, notifications)
  143. )
  144. self.__flask.add_url_rule(
  145. '/projects/<int:project_id>/labels/<int:label_id>/parent',
  146. view_func=EditLabelParent.as_view('edit_label_parent', database, notifications)
  147. )
  148. # collections
  149. self.__flask.add_url_rule(
  150. '/projects/<int:project_id>/collections',
  151. view_func=ListCollections.as_view('list_collections', database)
  152. )
  153. self.__flask.add_url_rule(
  154. '/projects/<int:project_id>/data/<int:collection_id>/<int:start>/<int:length>',
  155. view_func=ListFiles.as_view('list_collection_files', database)
  156. )
  157. # data
  158. self.__flask.add_url_rule(
  159. '/projects/<int:identifier>/data',
  160. view_func=UploadFile.as_view('upload_file', database, notifications)
  161. )
  162. self.__flask.add_url_rule(
  163. '/projects/<int:project_id>/data/<int:start>/<int:length>',
  164. view_func=ListFiles.as_view('list_files', database)
  165. )
  166. self.__flask.add_url_rule(
  167. '/data/<int:identifier>/remove',
  168. view_func=RemoveFile.as_view('remove_file', database, notifications)
  169. )
  170. self.__flask.add_url_rule(
  171. '/data/<int:file_id>',
  172. view_func=GetFile.as_view('get_file', database)
  173. )
  174. self.__flask.add_url_rule(
  175. '/data/<int:file_id>/<resolution>',
  176. view_func=GetResizedFile.as_view('get_resized_file', database)
  177. )
  178. self.__flask.add_url_rule(
  179. '/data/<int:file_id>/previous_next',
  180. view_func=GetPreviousAndNextFile.as_view('get_previous_and_next_file', database)
  181. )
  182. # results
  183. self.__flask.add_url_rule(
  184. '/projects/<int:project_id>/results',
  185. view_func=GetProjectResults.as_view('get_project_results', database)
  186. )
  187. self.__flask.add_url_rule(
  188. '/data/<int:file_id>/results',
  189. view_func=GetResults.as_view('get_results', database)
  190. )
  191. self.__flask.add_url_rule(
  192. '/data/<int:file_id>/results',
  193. view_func=CreateResult.as_view('create_result', database, notifications)
  194. )
  195. self.__flask.add_url_rule(
  196. '/data/<int:file_id>/reset',
  197. view_func=ResetResults.as_view('reset_results', database, notifications)
  198. )
  199. self.__flask.add_url_rule(
  200. '/results/<int:result_id>/remove',
  201. view_func=RemoveResult.as_view('remove_result', database, notifications)
  202. )
  203. self.__flask.add_url_rule(
  204. '/results/<int:result_id>/confirm',
  205. view_func=ConfirmResult.as_view('confirm_result', database, notifications)
  206. )
  207. self.__flask.add_url_rule(
  208. '/results/<int:result_id>/label',
  209. view_func=EditResultLabel.as_view('edit_result_label', database, notifications)
  210. )
  211. self.__flask.add_url_rule(
  212. '/results/<int:result_id>/data',
  213. view_func=EditResultData.as_view('edit_result_data', database, notifications)
  214. )
  215. # projects
  216. self.__flask.add_url_rule(
  217. '/projects',
  218. view_func=ListProjects.as_view('list_projects', database)
  219. )
  220. self.__flask.add_url_rule(
  221. '/projects',
  222. view_func=CreateProject.as_view('create_project', database, notifications, jobs)
  223. )
  224. self.__flask.add_url_rule(
  225. '/projects/<int:identifier>/label_provider',
  226. view_func=ExecuteLabelProvider.as_view('execute_label_provider', database,
  227. notifications, jobs)
  228. )
  229. self.__flask.add_url_rule(
  230. '/projects/<int:identifier>/external_storage',
  231. view_func=ExecuteExternalStorage.as_view('execute_external_storage', database,
  232. notifications, jobs)
  233. )
  234. self.__flask.add_url_rule(
  235. '/projects/<int:identifier>/remove',
  236. view_func=RemoveProject.as_view('remove_project', database, notifications)
  237. )
  238. self.__flask.add_url_rule(
  239. '/projects/<int:identifier>/name',
  240. view_func=EditProjectName.as_view('edit_project_name', database, notifications)
  241. )
  242. self.__flask.add_url_rule(
  243. '/projects/<int:identifier>/description',
  244. view_func=EditProjectDescription.as_view('edit_project_description', database,
  245. notifications)
  246. )
  247. # pipelines
  248. self.__flask.add_url_rule(
  249. '/projects/<int:project_id>/pipelines/fit',
  250. view_func=FitModel.as_view('fit_model', database, jobs, pipelines)
  251. )
  252. self.__flask.add_url_rule(
  253. '/projects/<int:project_id>/pipelines/predict',
  254. view_func=PredictModel.as_view('predict_model', database, notifications, jobs,
  255. pipelines)
  256. )
  257. self.__flask.add_url_rule(
  258. '/data/<int:file_id>/predict',
  259. view_func=PredictFile.as_view('predict_file', database, notifications, jobs, pipelines)
  260. )
  261. # finally start web server
  262. eventlet.wsgi.server(eventlet.listen((settings['host'], settings['port'])), self.__app)