Eric Tröbs 4 năm trước cách đây
mục cha
commit
cfd53464a5

+ 41 - 46
pycs/frontend/FileProvider.py

@@ -2,10 +2,12 @@ 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 flask import Flask, make_response, send_from_directory, request
+from werkzeug import formparser
 
 from pycs.ApplicationStatus import ApplicationStatus
+from pycs.util.GenericWrapper import GenericWrapper
+from pycs.util.ProgressFileWriter import ProgressFileWriter
 
 
 class FileProvider(Flask):
@@ -47,58 +49,51 @@ class FileProvider(Flask):
             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
+            job = GenericWrapper()
+            file_name = GenericWrapper()
+            file_extension = GenericWrapper()
+            file_size = GenericWrapper(0)
 
-            if 'file' not in files.keys():
-                return make_response('no file uploaded', 500)
+            # save upload to file
+            def custom_stream_factory(total_content_length, filename, content_type, content_length=None):
+                file_name.value, file_extension.value = path.splitext(filename)
+                file_path = path.join(upload_path, f'{file_uuid}{file_extension.value}')
 
-            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
-            })
+                # add job to app status
+                job.value = app_status['jobs'].append({
+                    'id': file_uuid,
+                    'type': 'upload',
+                    'progress': 0,
+                    'filename': filename,
+                    'created': int(time()),
+                    'finished': None
+                })
 
-            if not path.exists(upload_path):
-                mkdir(upload_path)
+                # create upload path if not exists
+                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}')
+                # define progress callback
+                length = content_length if content_length is not None and content_length != 0 else total_content_length
 
-            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
+                def callback(progress):
+                    file_size.value += progress
+                    relative = progress / length
 
-                # define handler function
-                def file_write():
-                    data = file_stream.read(262144)  # 256 kiB
-                    file_handler.write(data)
-                    return len(data)
+                    if relative - job.value['progress'] > 0.02:
+                        job.value['progress'] = relative
 
-                # transfer blocks to storage and update progress
-                progress = 0
-                while True:
-                    read_bytes = tpool.execute(file_write)
-                    progress += read_bytes
+                # open file handler
+                return ProgressFileWriter(file_path, 'wb', callback)
 
-                    if file_size is not None:
-                        job['progress'] = progress / file_size
+            stream, form, files = formparser.parse_form_data(request.environ, stream_factory=custom_stream_factory)
 
-                    if read_bytes == 0:
-                        break
+            if 'file' not in files.keys():
+                return make_response('no file uploaded', 500)
 
             # set progress to 1 after upload is done
+            job = job.value
+
             job['progress'] = 1
             job['finished'] = int(time())
 
@@ -108,9 +103,9 @@ class FileProvider(Flask):
 
             current_project['data'].append({
                 'id': file_uuid,
-                'name': file_name,
-                'extension': file_extension,
-                'size': progress,
+                'name': file_name.value,
+                'extension': file_extension.value,
+                'size': file_size.value,
                 'created': job['created']
             })
 

+ 3 - 0
pycs/util/GenericWrapper.py

@@ -0,0 +1,3 @@
+class GenericWrapper:
+    def __init__(self, value=None):
+        self.value = value

+ 20 - 0
pycs/util/ProgressFileWriter.py

@@ -0,0 +1,20 @@
+from io import BufferedWriter
+
+
+class ProgressFileWriter(BufferedWriter):
+    def __init__(self, path, mode, callback=None):
+        self.file_handler = open(path, mode)
+
+        self.progress = 0
+        self.callback = callback
+
+        super().__init__(self.file_handler, 262144)
+
+    def write(self, s):
+        value = super().write(s)
+
+        if self.callback is not None:
+            self.progress += value
+            self.callback(self.progress)
+
+        return value

+ 1 - 1
webui/src/components/base/file-input.vue

@@ -63,8 +63,8 @@ export default {
     upload: function(files) {
       for (let file of files) {
         const form = new FormData();
+        // form.append('size', file.size);
         form.append('file', file);
-        form.append('size', file.size);
 
         fetch(this.url, {
           method: 'POST',