Przeglądaj źródła

xhrupload: Add back the `bundle` option.

Renée Kooi 7 lat temu
rodzic
commit
33c57d5cc4
2 zmienionych plików z 81 dodań i 3 usunięć
  1. 1 0
      CHANGELOG.md
  2. 80 3
      src/plugins/XHRUpload.js

+ 1 - 0
CHANGELOG.md

@@ -112,6 +112,7 @@ To be released: 2018-01-26.
 - [ ] goldenretriever: add “ghost” files (@arturi)
 - [ ] webcam: URL.createObjectURL(MediaStream) is deprecated and will be removed soon: https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/srcObject
 - [ ] xhrupload: add bundle option to send multiple files in one request (#442 / @goto-bus-stop)
+- [ ] uppy-server: benchmarks / stress test, large file, uppy-server / tus / S3 (10 GB)
 - [ ] uppy-server: security audit, ask @acconut
 - [ ] uppy-server: benchmarks / stress test, large file, uppy-server / tus / S3 (10 GB)
 

+ 80 - 3
src/plugins/XHRUpload.js

@@ -59,6 +59,10 @@ module.exports = class XHRUpload extends Plugin {
     } else {
       this.limitUploads = (fn) => fn
     }
+
+    if (this.opts.bundle && !this.opts.formData) {
+      throw new Error('`opts.formData` must be true when `opts.bundle` is enabled.')
+    }
   }
 
   getOptions (file) {
@@ -261,6 +265,78 @@ module.exports = class XHRUpload extends Plugin {
     })
   }
 
+  uploadBundle (files) {
+    return new Promise((resolve, reject) => {
+      const endpoint = this.opts.endpoint
+      const method = this.opts.method
+
+      const formData = new FormData()
+      files.forEach((file, i) => {
+        const opts = this.getOptions(file)
+        formData.append(opts.fieldName, file.data)
+      })
+
+      const xhr = new XMLHttpRequest()
+
+      const emitError = (error) => {
+        files.forEach((file) => {
+          this.uppy.emit('upload-error', file.id, error)
+        })
+      }
+
+      xhr.upload.addEventListener('progress', (ev) => {
+        if (!ev.lengthComputable) return
+        files.forEach((file) => {
+          this.uppy.emit('upload-progress', {
+            uploader: this,
+            id: file.id,
+            bytesUploaded: ev.loaded,
+            bytesTotal: ev.total
+          })
+        })
+      })
+
+      xhr.addEventListener('load', (ev) => {
+        if (ev.target.status >= 200 && ev.target.status < 300) {
+          const resp = this.opts.getResponseData(xhr)
+          files.forEach((file) => {
+            this.uppy.emit('upload-success', file.id, resp)
+          })
+          return resolve()
+        }
+
+        const error = this.opts.getResponseError(xhr) || new Error('Upload error')
+        error.request = xhr
+        emitError(error)
+        return reject(error)
+      })
+
+      xhr.addEventListener('error', (ev) => {
+        const error = this.opts.getResponseError(xhr) || new Error('Upload error')
+        emitError(error)
+        return reject(error)
+      })
+
+      this.uppy.on('cancel-all', () => {
+        // const files = this.uppy.getState().files
+        // if (!files[file.id]) return
+        xhr.abort()
+      })
+
+      xhr.open(method.toUpperCase(), endpoint, true)
+
+      Object.keys(this.opts.headers).forEach((header) => {
+        xhr.setRequestHeader(header, this.opts.headers[header])
+      })
+
+      xhr.send(formData)
+
+      files.forEach((file) => {
+        this.uppy.emit('upload-started', file.id)
+      })
+    })
+  }
+
   uploadFiles (files) {
     const actions = files.map((file, i) => {
       const current = parseInt(i, 10) + 1
@@ -290,9 +366,10 @@ module.exports = class XHRUpload extends Plugin {
     }
 
     this.uppy.log('[XHRUpload] Uploading...')
-    const files = fileIDs.map(getFile, this)
-    function getFile (fileID) {
-      return this.uppy.state.files[fileID]
+    const files = fileIDs.map((fileID) => this.uppy.getFile(fileID))
+
+    if (this.opts.bundle) {
+      return this.uploadBundle(files)
     }
 
     return this.uploadFiles(files).then(() => null)