Explorar o código

tus: Remove old upload and events when starting a new upload.

Renée Kooi %!s(int64=7) %!d(string=hai) anos
pai
achega
b3cc48130e
Modificáronse 1 ficheiros con 63 adicións e 24 borrados
  1. 63 24
      src/plugins/Tus10.js

+ 63 - 24
src/plugins/Tus10.js

@@ -26,6 +26,25 @@ const tusDefaultOptions = {
   retryDelays: null
   retryDelays: null
 }
 }
 
 
+/**
+ * Create a wrapper around an event emitter with a `remove` method to remove
+ * all events that were added using the wrapped emitter.
+ */
+function createEventTracker (emitter) {
+  const events = []
+  return {
+    on (event, fn) {
+      events.push([ event, fn ])
+      return emitter.on(event, fn)
+    },
+    remove () {
+      events.forEach(([ event, fn ]) => {
+        emitter.off(event, fn)
+      })
+    }
+  }
+}
+
 /**
 /**
  * Tus resumable file uploader
  * Tus resumable file uploader
  *
  *
@@ -47,6 +66,10 @@ module.exports = class Tus10 extends Plugin {
     // merge default options with the ones set by user
     // merge default options with the ones set by user
     this.opts = Object.assign({}, defaultOptions, opts)
     this.opts = Object.assign({}, defaultOptions, opts)
 
 
+    this.uploaders = Object.create(null)
+    this.uploaderEvents = Object.create(null)
+    this.uploaderSockets = Object.create(null)
+
     this.handleResetProgress = this.handleResetProgress.bind(this)
     this.handleResetProgress = this.handleResetProgress.bind(this)
     this.handleUpload = this.handleUpload.bind(this)
     this.handleUpload = this.handleUpload.bind(this)
   }
   }
@@ -65,6 +88,25 @@ module.exports = class Tus10 extends Plugin {
     this.core.setState({ files })
     this.core.setState({ files })
   }
   }
 
 
+  /**
+   * Clean up all references for a file's upload: the tus.Upload instance,
+   * any events related to the file, and the uppy-server WebSocket connection.
+   */
+  resetUploaderReferences (fileID) {
+    if (this.uploaders[fileID]) {
+      this.uploaders[fileID].abort()
+      this.uploaders[fileID] = null
+    }
+    if (this.uploaderEvents[fileID]) {
+      this.uploaderEvents[fileID].remove()
+      this.uploaderEvents[fileID] = null
+    }
+    if (this.uploaderSockets[fileID]) {
+      this.uploaderSockets[fileID].close()
+      this.uploaderSockets[fileID] = null
+    }
+  }
+
   /**
   /**
    * Create a new Tus upload
    * Create a new Tus upload
    *
    *
@@ -76,6 +118,8 @@ module.exports = class Tus10 extends Plugin {
   upload (file, current, total) {
   upload (file, current, total) {
     this.core.log(`uploading ${current} of ${total}`)
     this.core.log(`uploading ${current} of ${total}`)
 
 
+    this.resetUploaderReferences(file.id)
+
     // Create a new tus upload
     // Create a new tus upload
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
       const optsTus = Object.assign(
       const optsTus = Object.assign(
@@ -90,6 +134,8 @@ module.exports = class Tus10 extends Plugin {
         this.core.log(err)
         this.core.log(err)
         this.core.emit('core:upload-error', file.id, err)
         this.core.emit('core:upload-error', file.id, err)
         err.message = `Failed because: ${err.message}`
         err.message = `Failed because: ${err.message}`
+
+        this.resetUploaderReferences(file.id)
         reject(err)
         reject(err)
       }
       }
 
 
@@ -110,14 +156,17 @@ module.exports = class Tus10 extends Plugin {
           this.core.log('Download ' + upload.file.name + ' from ' + upload.url)
           this.core.log('Download ' + upload.file.name + ' from ' + upload.url)
         }
         }
 
 
+        this.resetUploaderReferences(file.id)
         resolve(upload)
         resolve(upload)
       }
       }
       optsTus.metadata = file.meta
       optsTus.metadata = file.meta
 
 
       const upload = new tus.Upload(file.data, optsTus)
       const upload = new tus.Upload(file.data, optsTus)
+      this.uploaders[file.id] = upload
+      this.uploaderEvents[file.id] = createEventTracker(this.core)
 
 
       this.onFileRemove(file.id, (targetFileID) => {
       this.onFileRemove(file.id, (targetFileID) => {
-        upload.abort()
+        this.resetUploaderReferences(file.id)
         resolve(`upload ${targetFileID} was removed`)
         resolve(`upload ${targetFileID} was removed`)
       })
       })
 
 
@@ -130,8 +179,7 @@ module.exports = class Tus10 extends Plugin {
       })
       })
 
 
       this.onCancelAll(file.id, () => {
       this.onCancelAll(file.id, () => {
-        upload.abort()
-        this.removeUploadURL(file.id)
+        this.resetUploaderReferences(file.id)
       })
       })
 
 
       this.onResumeAll(file.id, () => {
       this.onResumeAll(file.id, () => {
@@ -147,6 +195,8 @@ module.exports = class Tus10 extends Plugin {
   }
   }
 
 
   uploadRemote (file, current, total) {
   uploadRemote (file, current, total) {
+    this.resetUploaderReferences(file.id)
+
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
       this.core.log(file.remote.url)
       this.core.log(file.remote.url)
       if (file.serverToken) {
       if (file.serverToken) {
@@ -195,6 +245,8 @@ module.exports = class Tus10 extends Plugin {
     const token = file.serverToken
     const token = file.serverToken
     const host = getSocketHost(file.remote.host)
     const host = getSocketHost(file.remote.host)
     const socket = new UppySocket({ target: `${host}/api/${token}` })
     const socket = new UppySocket({ target: `${host}/api/${token}` })
+    this.uploaderSockets[file.id] = socket
+    this.uploaderEvents[file.id] = createEventTracker(this.core)
 
 
     this.onFileRemove(file.id, () => socket.send('pause', {}))
     this.onFileRemove(file.id, () => socket.send('pause', {}))
 
 
@@ -227,7 +279,7 @@ module.exports = class Tus10 extends Plugin {
 
 
     socket.on('success', (data) => {
     socket.on('success', (data) => {
       this.core.emitter.emit('core:upload-success', file.id, data, data.url)
       this.core.emitter.emit('core:upload-success', file.id, data, data.url)
-      socket.close()
+      this.resetUploaderReferences(file.id)
     })
     })
   }
   }
 
 
@@ -256,27 +308,14 @@ module.exports = class Tus10 extends Plugin {
     }
     }
   }
   }
 
 
-  removeUploadURL (fileID) {
-    const file = this.core.getFile(fileID)
-
-    // No need to change state if we didn't have an `uploadUrl`.
-    if (!file || !file.tus || !file.tus.uploadUrl) return
-
-    this.updateFile(Object.assign({}, file, {
-      tus: Object.assign({}, file.tus, {
-        uploadUrl: null
-      })
-    }))
-  }
-
   onFileRemove (fileID, cb) {
   onFileRemove (fileID, cb) {
-    this.core.on('core:file-removed', (targetFileID) => {
+    this.uploaderEvents[fileID].on('core:file-removed', (targetFileID) => {
       if (fileID === targetFileID) cb(targetFileID)
       if (fileID === targetFileID) cb(targetFileID)
     })
     })
   }
   }
 
 
   onPause (fileID, cb) {
   onPause (fileID, cb) {
-    this.core.on('core:upload-pause', (targetFileID, isPaused) => {
+    this.uploaderEvents[fileID].on('core:upload-pause', (targetFileID, isPaused) => {
       if (fileID === targetFileID) {
       if (fileID === targetFileID) {
         // const isPaused = this.core.pauseResume(fileID)
         // const isPaused = this.core.pauseResume(fileID)
         cb(isPaused)
         cb(isPaused)
@@ -285,7 +324,7 @@ module.exports = class Tus10 extends Plugin {
   }
   }
 
 
   onRetry (fileID, cb) {
   onRetry (fileID, cb) {
-    this.core.on('core:upload-retry', (targetFileID) => {
+    this.uploaderEvents[fileID].on('core:upload-retry', (targetFileID) => {
       if (fileID === targetFileID) {
       if (fileID === targetFileID) {
         cb()
         cb()
       }
       }
@@ -293,28 +332,28 @@ module.exports = class Tus10 extends Plugin {
   }
   }
 
 
   onRetryAll (fileID, cb) {
   onRetryAll (fileID, cb) {
-    this.core.on('core:retry-all', (filesToRetry) => {
+    this.uploaderEvents[fileID].on('core:retry-all', (filesToRetry) => {
       if (!this.core.getFile(fileID)) return
       if (!this.core.getFile(fileID)) return
       cb()
       cb()
     })
     })
   }
   }
 
 
   onPauseAll (fileID, cb) {
   onPauseAll (fileID, cb) {
-    this.core.on('core:pause-all', () => {
+    this.uploaderEvents[fileID].on('core:pause-all', () => {
       if (!this.core.getFile(fileID)) return
       if (!this.core.getFile(fileID)) return
       cb()
       cb()
     })
     })
   }
   }
 
 
   onCancelAll (fileID, cb) {
   onCancelAll (fileID, cb) {
-    this.core.on('core:cancel-all', () => {
+    this.uploaderEvents[fileID].on('core:cancel-all', () => {
       if (!this.core.getFile(fileID)) return
       if (!this.core.getFile(fileID)) return
       cb()
       cb()
     })
     })
   }
   }
 
 
   onResumeAll (fileID, cb) {
   onResumeAll (fileID, cb) {
-    this.core.on('core:resume-all', () => {
+    this.uploaderEvents[fileID].on('core:resume-all', () => {
       if (!this.core.getFile(fileID)) return
       if (!this.core.getFile(fileID)) return
       cb()
       cb()
     })
     })