Improve IndexedDB versioning and recover from version mismatch

This commit is contained in:
Thibaut Courouble 2017-03-05 18:48:35 -05:00
parent d63aadb27e
commit 684355cc52
3 changed files with 58 additions and 28 deletions

View file

@ -201,7 +201,6 @@
return if @quotaExceeded
@quotaExceeded = true
new app.views.Notif 'QuotaExceeded', autoHide: null
Raven.captureMessage 'QuotaExceededError', level: 'warning'
return
onCookieBlocked: (key, value, actual) ->

View file

@ -1,9 +1,9 @@
class app.DB
NAME = 'docs'
VERSION = 15
constructor: ->
@useIndexedDB = @useIndexedDB()
@appVersion = @appVersion()
@callbacks = []
db: (fn) ->
@ -13,7 +13,7 @@ class app.DB
try
@open = true
req = indexedDB.open(NAME, @schemaVersion())
req = indexedDB.open(NAME, VERSION * 1e9 + @userVersion())
req.onsuccess = @onOpenSuccess
req.onerror = @onOpenError
req.onupgradeneeded = @onUpgradeNeeded
@ -26,18 +26,13 @@ class app.DB
if db.objectStoreNames.length is 0
try db.close()
@open = false
@fail 'empty'
return
unless @checkedBuggyIDB
@checkedBuggyIDB = true
try
@idbTransaction(db, stores: $.makeArray(db.objectStoreNames)[0..1], mode: 'readwrite').abort() # https://bugs.webkit.org/show_bug.cgi?id=136937
catch error
else if error = @buggyIDB(db)
try db.close()
@open = false
@fail 'buggy', error
return
else
@runCallbacks(db)
@open = false
db.close()
@ -48,15 +43,17 @@ class app.DB
@open = false
error = event.target.error
if error.name is 'QuotaExceededError'
@reset()
@db()
app.onQuotaExceeded()
switch error.name
when 'QuotaExceededError'
@onQuotaExceededError()
when 'VersionError'
@onVersionError()
else
@fail 'cant_open', error
return
fail: (reason, error) ->
@cachedDocs = null
@useIndexedDB = false
@reason or= reason
@error or= error
@ -65,6 +62,39 @@ class app.DB
Raven.captureException error, level: 'warning' if error
return
onQuotaExceededError: ->
@reset()
@db()
app.onQuotaExceeded()
Raven.captureMessage 'QuotaExceededError', level: 'warning'
return
onVersionError: ->
req = indexedDB.open(NAME)
req.onsuccess = (event) =>
@handleVersionMismatch event.target.result.version
req.onerror = (event) ->
event.preventDefault()
@fail 'cant_open', error
return
handleVersionMismatch: (actualVersion) ->
if Math.floor(actualVersion / 1e9) isnt VERSION
@fail 'version'
else
@setUserVersion actualVersion - VERSION * 1e9
@db()
return
buggyIDB: (db) ->
return if @checkedBuggyIDB
@checkedBuggyIDB = true
try
@idbTransaction(db, stores: $.makeArray(db.objectStoreNames)[0..1], mode: 'readwrite').abort() # https://bugs.webkit.org/show_bug.cgi?id=136937
return
catch error
return error
runCallbacks: (db) ->
fn(db) while fn = @callbacks.shift()
return
@ -340,11 +370,9 @@ class app.DB
app.settings.set('schema', @userVersion() + 1)
return
schemaVersion: ->
@appVersion * 10 + @userVersion()
setUserVersion: (version) ->
app.settings.set('schema', version)
return
userVersion: ->
app.settings.get('schema')
appVersion: ->
if app.config.env is 'production' then app.config.version else Math.floor(Date.now() / 1000)

View file

@ -40,6 +40,9 @@ app.templates.offlineError = (reason, exception) ->
""" An error occured when trying to open the IndexedDB database:<br>
<code class="_label">#{exception.name}: #{exception.message}</code><br>
This could be because you're browsing in private mode or have disallowed offline storage on the domain. """
when 'version'
""" The IndexedDB database was modified with a newer version of the app.<br>
<a href="#" data-behavior="reload">Reload the page</a> to use offline mode. """
when 'empty'
""" The IndexedDB database appears to be corrupted. Try <a href="#" data-behavior="reset">resetting the app</a>. """