FileProvider.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. from os import path, mkdir, getcwd
  2. from time import time
  3. from uuid import uuid1
  4. from eventlet import tpool
  5. from flask import Flask, request, make_response, send_from_directory
  6. from pycs.ApplicationStatus import ApplicationStatus
  7. class FileProvider(Flask):
  8. def __init__(self, app_status: ApplicationStatus, cors=False):
  9. super().__init__(__name__)
  10. # add download handler
  11. @self.route('/media/<identifier>', methods=['GET'])
  12. def media(identifier):
  13. # get current project
  14. opened_projects = list(filter(lambda x: x['status'] == 'open', app_status['projects']))
  15. if len(opened_projects) == 0:
  16. return make_response('no open project available', 500)
  17. current_project = opened_projects[0]
  18. file_directory = path.join(getcwd(), 'projects', current_project['id'], 'data')
  19. # get object
  20. data_objects = list(filter(lambda x: x['id'] == identifier, current_project['data']))
  21. if len(data_objects) == 0:
  22. return make_response('data object not avilable', 500)
  23. target_object = data_objects[0]
  24. # return data
  25. file_name = target_object['id'] + target_object['extension']
  26. return send_from_directory(file_directory, file_name)
  27. # add upload handler
  28. @self.route('/upload', methods=['POST'])
  29. def upload():
  30. file_uuid = str(uuid1())
  31. # get current project path
  32. opened_projects = list(filter(lambda x: x['status'] == 'open', app_status['projects']))
  33. if len(opened_projects) == 0:
  34. return make_response('no open project available', 500)
  35. current_project = opened_projects[0]
  36. upload_path = path.join('projects', current_project['id'], 'data')
  37. # get file object
  38. # TODO read stream and parse data
  39. # TODO update progress correctly
  40. files = request.files
  41. if 'file' not in files.keys():
  42. return make_response('no file uploaded', 500)
  43. file = files['file']
  44. file_name = file.filename
  45. # add job to app status
  46. job = app_status['jobs'].append({
  47. 'id': file_uuid,
  48. 'type': 'upload',
  49. 'progress': 0,
  50. 'filename': file_name,
  51. 'created': int(time()),
  52. 'finished': None
  53. })
  54. if not path.exists(upload_path):
  55. mkdir(upload_path)
  56. # open file handler
  57. file_name, file_extension = path.splitext(file_name)
  58. file_path = path.join(upload_path, f'{file_uuid}{file_extension}')
  59. with open(file_path, 'wb') as file_handler:
  60. # prepare some properties
  61. file_size = int(request.form['size']) if 'size' in request.form.keys() else None
  62. file_stream = file.stream
  63. # define handler function
  64. def file_write():
  65. data = file_stream.read(262144) # 256 kiB
  66. file_handler.write(data)
  67. return len(data)
  68. # transfer blocks to storage and update progress
  69. progress = 0
  70. while True:
  71. read_bytes = tpool.execute(file_write)
  72. progress += read_bytes
  73. if file_size is not None:
  74. job['progress'] = progress / file_size
  75. if read_bytes == 0:
  76. break
  77. # set progress to 1 after upload is done
  78. job['progress'] = 1
  79. job['finished'] = int(time())
  80. # add to project files
  81. if 'data' not in current_project:
  82. current_project['data'] = []
  83. current_project['data'].append({
  84. 'id': file_uuid,
  85. 'name': file_name,
  86. 'extension': file_extension,
  87. 'size': progress,
  88. 'created': job['created']
  89. })
  90. # create response and allow cors if needed
  91. response = make_response()
  92. if cors:
  93. response.headers['Access-Control-Allow-Origin'] = '*'
  94. return response