from os import path, mkdir, getcwd from time import time from uuid import uuid1 from eventlet import tpool from flask import Flask, request, make_response, send_from_directory from pycs.ApplicationStatus import ApplicationStatus class FileProvider(Flask): def __init__(self, app_status: ApplicationStatus, cors=False): super().__init__(__name__) # add download handler @self.route('/media/', methods=['GET']) def media(identifier): # get current project opened_projects = list(filter(lambda x: x['status'] == 'open', app_status['projects'])) if len(opened_projects) == 0: return make_response('no open project available', 500) current_project = opened_projects[0] file_directory = path.join(getcwd(), 'projects', current_project['id'], 'data') # get object data_objects = list(filter(lambda x: x['id'] == identifier, current_project['data'])) if len(data_objects) == 0: return make_response('data object not avilable', 500) target_object = data_objects[0] # return data file_name = target_object['id'] + target_object['extension'] return send_from_directory(file_directory, file_name) # add upload handler @self.route('/upload', methods=['POST']) def upload(): file_uuid = str(uuid1()) # get current project path opened_projects = list(filter(lambda x: x['status'] == 'open', app_status['projects'])) if len(opened_projects) == 0: return make_response('no open project available', 500) current_project = opened_projects[0] upload_path = path.join('projects', current_project['id'], 'data') # get file object # TODO read stream and parse data # TODO update progress correctly files = request.files if 'file' not in files.keys(): return make_response('no file uploaded', 500) file = files['file'] file_name = file.filename # add job to app status job = app_status['jobs'].append({ 'id': file_uuid, 'type': 'upload', 'progress': 0, 'filename': file_name, 'created': int(time()), 'finished': None }) if not path.exists(upload_path): mkdir(upload_path) # open file handler file_name, file_extension = path.splitext(file_name) file_path = path.join(upload_path, f'{file_uuid}{file_extension}') with open(file_path, 'wb') as file_handler: # prepare some properties file_size = int(request.form['size']) if 'size' in request.form.keys() else None file_stream = file.stream # define handler function def file_write(): data = file_stream.read(262144) # 256 kiB file_handler.write(data) return len(data) # transfer blocks to storage and update progress progress = 0 while True: read_bytes = tpool.execute(file_write) progress += read_bytes if file_size is not None: job['progress'] = progress / file_size if read_bytes == 0: break # set progress to 1 after upload is done job['progress'] = 1 job['finished'] = int(time()) # add to project files if 'data' not in current_project: current_project['data'] = [] current_project['data'].append({ 'id': file_uuid, 'name': file_name, 'extension': file_extension, 'size': progress, 'created': job['created'] }) # create response and allow cors if needed response = make_response() if cors: response.headers['Access-Control-Allow-Origin'] = '*' return response