Browse Source

transloadit: Add connection error reporting (#1484)

transloadit: Add connection error reporting
Renée Kooi 6 years ago
parent
commit
52fb8fdc57
3 changed files with 76 additions and 9 deletions
  1. 1 1
      CHANGELOG.md
  2. 57 7
      packages/@uppy/transloadit/src/Client.js
  3. 18 1
      packages/@uppy/transloadit/src/index.js

+ 1 - 1
CHANGELOG.md

@@ -101,9 +101,9 @@ PRs are welcome! Please do open an issue to discuss first if it's a big feature,
 - [ ] !!! dashboard: Remove the Authorization required tooltip on the authentication screen https://github.com/transloadit/uppy/issues/1425
 - [ ] @uppy/companion: investigate 423 and 500 issues with React Native + Url plugin when pause/resuming an upload
 - [ ] docs: add docs on locales — how to use from NPM and CDN
+- [ ] @uppy/transloadit: finish Transloadit-Client header on https://github.com/transloadit/uppy/tree/feature/transloadit-client
 - [ ] companion: reports an error at first sign in. we did a hotfix in https://github.com/transloadit/uppy/pull/1478#issuecomment-485937942 but need a proper fix for that (@ife). Also: what about changing the location of that tooltip? So legit errors also don't block buttons?
 
-
 ## 1.0 Goals
 
 What we need to do to release Uppy 1.0

+ 57 - 7
packages/@uppy/transloadit/src/Client.js

@@ -4,6 +4,8 @@
 module.exports = class Client {
   constructor (opts = {}) {
     this.opts = opts
+
+    this._reportError = this._reportError.bind(this)
   }
 
   /**
@@ -31,7 +33,8 @@ module.exports = class Client {
     })
     data.append('num_expected_upload_files', expectedFiles)
 
-    return fetch(`${this.opts.service}/assemblies`, {
+    const url = `${this.opts.service}/assemblies`
+    return fetch(url, {
       method: 'post',
       body: data
     }).then((response) => response.json()).then((assembly) => {
@@ -43,7 +46,7 @@ module.exports = class Client {
       }
 
       return assembly
-    })
+    }).catch((err) => this._reportError(err, { url, type: 'API_ERROR' }))
   }
 
   /**
@@ -54,8 +57,10 @@ module.exports = class Client {
    */
   reserveFile (assembly, file) {
     const size = encodeURIComponent(file.size)
-    return fetch(`${assembly.assembly_ssl_url}/reserve_file?size=${size}`, { method: 'post' })
+    const url = `${assembly.assembly_ssl_url}/reserve_file?size=${size}`
+    return fetch(url, { method: 'post' })
       .then((response) => response.json())
+      .catch((err) => this._reportError(err, { assembly, file, url, type: 'API_ERROR' }))
   }
 
   /**
@@ -69,13 +74,15 @@ module.exports = class Client {
       return Promise.reject(new Error('File does not have an `uploadURL`.'))
     }
     const size = encodeURIComponent(file.size)
-    const url = encodeURIComponent(file.uploadURL)
+    const uploadUrl = encodeURIComponent(file.uploadURL)
     const filename = encodeURIComponent(file.name)
     const fieldname = 'file'
 
-    const qs = `size=${size}&filename=${filename}&fieldname=${fieldname}&s3Url=${url}`
-    return fetch(`${assembly.assembly_ssl_url}/add_file?${qs}`, { method: 'post' })
+    const qs = `size=${size}&filename=${filename}&fieldname=${fieldname}&s3Url=${uploadUrl}`
+    const url = `${assembly.assembly_ssl_url}/add_file?${qs}`
+    return fetch(url, { method: 'post' })
       .then((response) => response.json())
+      .catch((err) => this._reportError(err, { assembly, file, url, type: 'API_ERROR' }))
   }
 
   /**
@@ -84,8 +91,10 @@ module.exports = class Client {
    * @param {object} assembly
    */
   cancelAssembly (assembly) {
-    return fetch(assembly.assembly_ssl_url, { method: 'delete' })
+    const url = assembly.assembly_ssl_url
+    return fetch(url, { method: 'delete' })
       .then((response) => response.json())
+      .catch((err) => this._reportError(err, { url, type: 'API_ERROR' }))
   }
 
   /**
@@ -96,5 +105,46 @@ module.exports = class Client {
   getAssemblyStatus (url) {
     return fetch(url)
       .then((response) => response.json())
+      .catch((err) => this._reportError(err, { url, type: 'STATUS_ERROR' }))
+  }
+
+  submitError (err, { endpoint, instance, assembly }) {
+    const message = err.details
+      ? `${err.message} (${err.details})`
+      : err.message
+
+    return fetch('https://status.transloadit.com/client_error', {
+      method: 'post',
+      body: JSON.stringify({
+        endpoint,
+        instance,
+        assembly_id: assembly,
+        agent: typeof navigator !== 'undefined' ? navigator.userAgent : '',
+        error: message
+      })
+    }).then((response) => response.json())
+  }
+
+  _reportError (err, params) {
+    if (this.opts.errorReporting === false) {
+      throw err
+    }
+
+    const opts = {
+      type: params.type
+    }
+    if (params.assembly) {
+      opts.assembly = params.assembly.assembly_id
+      opts.instance = params.assembly.instance
+    }
+    if (params.url) {
+      opts.endpoint = params.url
+    }
+
+    this.submitError(err, opts).catch((_) => {
+      // not much we can do then is there
+    })
+
+    throw err
   }
 }

+ 18 - 1
packages/@uppy/transloadit/src/index.js

@@ -41,6 +41,7 @@ module.exports = class Transloadit extends Plugin {
 
     const defaultOptions = {
       service: 'https://api2.transloadit.com',
+      errorReporting: true,
       waitForEncoding: false,
       waitForMetadata: false,
       alwaysRunAssembly: false,
@@ -64,6 +65,7 @@ module.exports = class Transloadit extends Plugin {
     this._prepareUpload = this._prepareUpload.bind(this)
     this._afterUpload = this._afterUpload.bind(this)
     this._onError = this._onError.bind(this)
+    this._onTusError = this._onTusError.bind(this)
     this._onCancelAll = this._onCancelAll.bind(this)
     this._onFileUploadURLAvailable = this._onFileUploadURLAvailable.bind(this)
     this._onRestored = this._onRestored.bind(this)
@@ -79,7 +81,8 @@ module.exports = class Transloadit extends Plugin {
     }
 
     this.client = new Client({
-      service: this.opts.service
+      service: this.opts.service,
+      errorReporting: this.opts.errorReporting
     })
     // Contains Assembly instances for in-progress Assemblies.
     this.activeAssemblies = {}
@@ -669,6 +672,17 @@ module.exports = class Transloadit extends Plugin {
     })
   }
 
+  _onTusError (err) {
+    if (err && /^tus: /.test(err.message)) {
+      const url = err.originalRequest && err.originalRequest.responseURL
+        ? err.originalRequest.responseURL
+        : null
+      this.client.submitError(err, { url, type: 'TUS_ERROR' }).then((_) => {
+        // if we can't report the error that sucks
+      })
+    }
+  }
+
   install () {
     this.uppy.addPreProcessor(this._prepareUpload)
     this.uppy.addPostProcessor(this._afterUpload)
@@ -679,6 +693,9 @@ module.exports = class Transloadit extends Plugin {
     // Handle cancellation.
     this.uppy.on('cancel-all', this._onCancelAll)
 
+    // For error reporting.
+    this.uppy.on('upload-error', this._onTusError)
+
     if (this.opts.importFromUploadURLs) {
       // No uploader needed when importing; instead we take the upload URL from an existing uploader.
       this.uppy.on('upload-success', this._onFileUploadURLAvailable)