fix(downloads): Properly handle network errors, retries of downloads

This commit is contained in:
Ben Gotow 2016-03-08 18:32:39 -08:00
parent 1fc389c804
commit 3e8f7fbfd7
2 changed files with 23 additions and 34 deletions

View file

@ -134,7 +134,6 @@ describe "FileDownloadStore", ->
beforeEach ->
spyOn(FileDownloadStore.Download.prototype, 'run').andCallFake -> Promise.resolve(@)
spyOn(FileDownloadStore, '_prepareFolder').andCallFake -> Promise.resolve(true)
spyOn(FileDownloadStore, '_cleanupDownload')
it "should make sure that the download file path exists", ->
FileDownloadStore._runDownload(@testfile)

View file

@ -56,19 +56,6 @@ class Download
@promise = new Promise (resolve, reject) =>
stream = fs.createWriteStream(@targetPath)
# We need to watch the request for `success` or `error`, but not fire
# a callback until the stream has ended. This helper functions ensure
# that resolve or reject is only fired once the stream has been closed.
checkIfFinished = (action) =>
# Wait for the stream to finish writing to disk and clear the request
return if @request
if @state is State.Finished
resolve(@) # Note: we must resolve with this
else if @state is State.Failed
reject(@)
@state = State.Downloading
NylasAPI.makeRequest
@ -82,21 +69,24 @@ class Download
.on "progress", (progress) =>
@percent = progress.percent
@progressCallback()
.on "end", =>
@request = null
checkIfFinished()
.pipe(stream)
success: =>
# At this point, the file stream has not finished writing to disk.
# Don't resolve yet, or the browser will load only part of the image.
.on "error", (err) =>
@request = null
@state = State.Failed
stream.end()
if fs.existsSync(@targetPath)
fs.unlinkSync(@targetPath)
reject(@)
.on "end", =>
return if @state is State.Failed
@request = null
@state = State.Finished
@percent = 100
checkIfFinished()
stream.end()
resolve(@) # Note: we must resolve with this
error: =>
@state = State.Failed
checkIfFinished()
.pipe(stream)
ensureClosed: ->
@request?.abort()
@ -180,7 +170,10 @@ FileDownloadStore = Reflux.createStore
@_downloads[file.id] = download
@trigger()
return download.run().finally =>
@_cleanupDownload(download)
download.ensureClosed()
if download.state is State.Failed
delete @_downloads[file.id]
@trigger()
# Returns a promise that resolves with true or false. True if the file has
# been downloaded, false if it should be downloaded.
@ -213,7 +206,7 @@ FileDownloadStore = Reflux.createStore
defaultPath = @_defaultSavePath(file)
defaultExtension = path.extname(defaultPath)
NylasEnv.showSaveDialog {defaultPath: defaultPath}, (savePath) =>
NylasEnv.showSaveDialog {defaultPath}, (savePath) =>
return unless savePath
NylasEnv.savedState.lastDownloadDirectory = path.dirname(savePath)
@ -234,16 +227,13 @@ FileDownloadStore = Reflux.createStore
_abortFetchFile: (file) ->
download = @_downloads[file.id]
return unless download
@_cleanupDownload(download)
download.ensureClosed()
@trigger()
downloadPath = @pathForFile(file)
fs.exists downloadPath, (exists) ->
fs.unlink(downloadPath) if exists
_cleanupDownload: (download) ->
download.ensureClosed()
@trigger()
_defaultSavePath: (file) ->
if process.platform is 'win32'
home = process.env.USERPROFILE