1
- /* global tryCatch chromeLocal ignoreChromeError */
1
+ /* global chromeLocal ignoreChromeError workerUtil */
2
2
/* exported db */
3
3
/*
4
4
Initialize a database. There are some problems using IndexedDB in Firefox:
@@ -18,52 +18,78 @@ const db = (() => {
18
18
} ;
19
19
20
20
function prepare ( ) {
21
+ return shouldUseIndexedDB ( ) . then (
22
+ ok => {
23
+ if ( ok ) {
24
+ useIndexedDB ( ) ;
25
+ } else {
26
+ useChromeStorage ( ) ;
27
+ }
28
+ } ,
29
+ err => {
30
+ useChromeStorage ( err ) ;
31
+ }
32
+ ) ;
33
+ }
34
+
35
+ function shouldUseIndexedDB ( ) {
21
36
// we use chrome.storage.local fallback if IndexedDB doesn't save data,
22
37
// which, once detected on the first run, is remembered in chrome.storage.local
23
38
// for reliablility and in localStorage for fast synchronous access
24
39
// (FF may block localStorage depending on its privacy options)
25
-
40
+ if ( typeof indexedDB === 'undefined' ) {
41
+ return Promise . reject ( new Error ( 'indexedDB is undefined' ) ) ;
42
+ }
26
43
// test localStorage
27
44
const fallbackSet = localStorage . dbInChromeStorage ;
28
- if ( fallbackSet === 'true' || ! tryCatch ( ( ) => indexedDB ) ) {
29
- useChromeStorage ( ) ;
30
- return Promise . resolve ( ) ;
45
+ if ( fallbackSet === 'true' ) {
46
+ return Promise . resolve ( false ) ;
31
47
}
32
48
if ( fallbackSet === 'false' ) {
33
- useIndexedDB ( ) ;
34
- return Promise . resolve ( ) ;
49
+ return Promise . resolve ( true ) ;
35
50
}
36
51
// test storage.local
37
52
return chromeLocal . get ( 'dbInChromeStorage' )
38
- . then ( data =>
39
- data && data . dbInChromeStorage && Promise . reject ( ) )
40
- . then ( ( ) =>
41
- tryCatch ( dbExecIndexedDB , 'getAllKeys' , IDBKeyRange . lowerBound ( 1 ) , 1 ) ||
42
- Promise . reject ( ) )
43
- . then ( ( { target} ) => (
44
- ( target . result || [ ] ) [ 0 ] ?
45
- Promise . reject ( 'ok' ) :
46
- dbExecIndexedDB ( 'put' , { id : - 1 } ) ) )
47
- . then ( ( ) =>
48
- dbExecIndexedDB ( 'get' , - 1 ) )
49
- . then ( ( { target} ) => (
50
- ( target . result || { } ) . id === - 1 ?
51
- dbExecIndexedDB ( 'delete' , - 1 ) :
52
- Promise . reject ( ) ) )
53
- . then ( ( ) =>
54
- Promise . reject ( 'ok' ) )
55
- . catch ( result => {
56
- if ( result === 'ok' ) {
57
- useIndexedDB ( ) ;
58
- } else {
59
- useChromeStorage ( ) ;
53
+ . then ( data => {
54
+ if ( data && data . dbInChromeStorage ) {
55
+ return false ;
60
56
}
57
+ return testDBSize ( )
58
+ . then ( ok => ok || testDBMutation ( ) ) ;
61
59
} ) ;
62
60
}
63
61
64
- function useChromeStorage ( ) {
62
+ function testDBSize ( ) {
63
+ return dbExecIndexedDB ( 'getAllKeys' , IDBKeyRange . lowerBound ( 1 ) , 1 )
64
+ . then ( event => (
65
+ event . target . result &&
66
+ event . target . result . length &&
67
+ event . target . result [ 0 ]
68
+ ) ) ;
69
+ }
70
+
71
+ function testDBMutation ( ) {
72
+ return dbExecIndexedDB ( 'put' , { id : - 1 } )
73
+ . then ( ( ) => dbExecIndexedDB ( 'get' , - 1 ) )
74
+ . then ( event => {
75
+ if ( ! event . target . result ) {
76
+ throw new Error ( 'failed to get previously put item' ) ;
77
+ }
78
+ if ( event . target . result . id !== - 1 ) {
79
+ throw new Error ( 'item id is wrong' ) ;
80
+ }
81
+ return dbExecIndexedDB ( 'delete' , - 1 ) ;
82
+ } )
83
+ . then ( ( ) => true ) ;
84
+ }
85
+
86
+ function useChromeStorage ( err ) {
65
87
exec = dbExecChromeStorage ;
66
88
chromeLocal . set ( { dbInChromeStorage : true } , ignoreChromeError ) ;
89
+ if ( err ) {
90
+ chromeLocal . setValue ( 'dbInChromeStorageReason' , workerUtil . cloneError ( err ) ) ;
91
+ console . warn ( 'Failed to access indexedDB. Switched to storage API.' , err ) ;
92
+ }
67
93
localStorage . dbInChromeStorage = 'true' ;
68
94
}
69
95
0 commit comments