|
25 | 25 | } |
26 | 26 |
|
27 | 27 | // set cache api db controller |
28 | | - function setCacheApiDB(factory) { |
| 28 | + function setCacheApiDB(fallbackFactory) { |
29 | 29 |
|
30 | | - _root.CacheApiDB = factory; |
| 30 | + // set fallback |
| 31 | + if (fallbackFactory) { |
| 32 | + _root.CacheApiDB = fallbackFactory; |
| 33 | + } |
31 | 34 |
|
32 | 35 | // process callback queue |
33 | 36 | var callback = queue.shift(); |
|
36 | 39 | } |
37 | 40 | } |
38 | 41 |
|
39 | | - var nosupport_error = 'Browser does not support Cache API'; |
| 42 | + var nosupport_error = 'No Cache API'; |
40 | 43 |
|
41 | 44 | if (!_root.CacheApiDBFallback) { |
42 | 45 | _root.CacheApiDBFallback = function() { |
43 | 46 | var that = this; |
44 | | - that.supported = 0; |
| 47 | + that.no = 1; |
45 | 48 | ['get', 'set', 'del', 'prune'].forEach(function(method) { |
46 | 49 | that[method] = function() { |
47 | 50 | return Promise.reject(nosupport_error); |
|
56 | 59 | _root.CacheApiDB = _root.CacheApiDBFallback; |
57 | 60 | } else { |
58 | 61 |
|
59 | | - // test cache support |
60 | | - // Cache API could be blocked by browser privacy settings |
| 62 | + // enable instant usage of Cache API store |
| 63 | + _root.CacheApiDB = factory(); |
| 64 | + |
| 65 | + // test if Cache API is blocked by browser privacy settings |
61 | 66 | caches.open('x').catch(function(e) { |
62 | | - if (e.name == 'SecurityError') { |
63 | | - print_error('Cache API is blocked by browser. Please check privacy settings (cookies, no-track option etc).'); |
64 | | - } else { |
65 | | - print_error('Cache API error: ' + e.message); |
| 67 | + |
| 68 | + // report errors unrelated to privacy settings |
| 69 | + if (e.name != 'SecurityError') { |
| 70 | + print_error('Cache API: ' + e.message); |
66 | 71 | } |
| 72 | + |
| 73 | + // fallback |
67 | 74 | setCacheApiDB(_root.CacheApiDBFallback); |
| 75 | + |
68 | 76 | }).then(function() { |
69 | | - setCacheApiDB(factory()); |
| 77 | + |
| 78 | + // continue with Cache API |
| 79 | + setCacheApiDB(); |
70 | 80 | }) |
71 | 81 |
|
72 | 82 | } |
73 | 83 | })(function() { |
74 | 84 |
|
75 | | - var DATE_HEADER = 'x-date'; |
76 | | - var EXPIRE_HEADER = 'x-expire'; |
| 85 | + var DATE_HEADER = 'x-d'; |
| 86 | + var EXPIRE_HEADER = 'x-e'; |
77 | 87 | var CONTENT_TYPE_HEADER = 'Content-Type'; |
78 | 88 |
|
79 | 89 | // return timestamp |
|
95 | 105 | function CACHE_GET(store, key) { |
96 | 106 | return CACHE_OPEN(store, function(cache) { |
97 | 107 |
|
| 108 | + if (IS_UNDEFINED(key)) { |
| 109 | + ERROR(); |
| 110 | + } |
| 111 | + |
98 | 112 | var cache_key = CACHE_KEY(key); |
99 | 113 |
|
100 | 114 | return cache.match(cache_key).then(function(cachedata) { |
101 | 115 |
|
102 | 116 | // handle expiration |
103 | | - if (!cachedata || CACHE_EXPIRED(cachedata)) { |
| 117 | + if (!cachedata || CACHE_EXPIRED(store, cache_key, cachedata, 1)) { |
104 | 118 | return false; |
105 | 119 | } |
106 | 120 |
|
|
114 | 128 | function CACHE_SET(store, key, data, expire) { |
115 | 129 | return CACHE_OPEN(store, function(cache) { |
116 | 130 |
|
| 131 | + if (IS_UNDEFINED(key) || IS_UNDEFINED(data)) { |
| 132 | + ERROR(); |
| 133 | + } |
| 134 | + |
117 | 135 | var cache_key = CACHE_KEY(key); |
118 | 136 |
|
119 | 137 | var cache_headers = {}; |
120 | 138 |
|
121 | | - // cache date |
122 | | - cache_headers[DATE_HEADER] = NOW(); |
123 | | - |
124 | 139 | // JSON |
125 | 140 | cache_headers[CONTENT_TYPE_HEADER] = 'application/json'; |
126 | 141 | data = JSON.stringify(data); |
127 | 142 |
|
128 | 143 | // expire time |
129 | 144 | if (expire) { |
130 | | - expire = parseInt(expire); |
| 145 | + |
| 146 | + // cache date |
| 147 | + cache_headers[DATE_HEADER] = NOW(); |
| 148 | + |
| 149 | + expire = INT(expire); |
131 | 150 | if (isNaN(expire) || expire < 0) { |
132 | | - ERROR('Expire time not numeric'); |
| 151 | + ERROR(); |
133 | 152 | } |
134 | 153 | cache_headers[EXPIRE_HEADER] = STRING(expire); |
135 | 154 | } |
|
144 | 163 | } |
145 | 164 |
|
146 | 165 | // return cache expired state |
147 | | - function CACHE_EXPIRED(cachedata) { |
| 166 | + function CACHE_EXPIRED(store, cache_key, cachedata) { |
148 | 167 | var exp = cachedata.headers.get(EXPIRE_HEADER); |
149 | | - if (exp) { |
150 | | - |
151 | | - var date = cachedata.headers.get(DATE_HEADER); |
| 168 | + var date = cachedata.headers.get(DATE_HEADER); |
| 169 | + if (exp && date) { |
| 170 | + exp = INT(exp); |
| 171 | + date = INT(date); |
152 | 172 |
|
153 | 173 | // expired |
154 | 174 | if ((date + exp) < NOW()) { |
155 | | - CACHE_DELETE(store, key); |
| 175 | + CACHE_DELETE(store, cache_key, 1); |
156 | 176 | return true; |
157 | 177 | } |
158 | 178 | } |
159 | 179 | } |
160 | 180 |
|
161 | 181 | // set key in cache |
162 | | - function CACHE_DELETE(store, key) { |
| 182 | + function CACHE_DELETE(store, key, cache_key) { |
163 | 183 | return CACHE_OPEN(store, function(cache) { |
164 | | - var cache_key = CACHE_KEY(key); |
165 | | - return cache.delete(cache_key); |
| 184 | + |
| 185 | + if (IS_UNDEFINED(key)) { |
| 186 | + ERROR(); |
| 187 | + } |
| 188 | + |
| 189 | + key = (cache_key) ? key : CACHE_KEY(key); |
| 190 | + return cache.delete(key); |
166 | 191 | }); |
167 | 192 | } |
168 | 193 |
|
169 | 194 | // set key in cache |
170 | | - function CACHE_PRUNE(store, key) { |
| 195 | + function CACHE_PRUNE(store) { |
171 | 196 | return CACHE_OPEN(store, function(cache) { |
172 | 197 |
|
173 | 198 | // get all keys from store |
|
188 | 213 | cacheEntries.forEach(function(cachedata, key) { |
189 | 214 |
|
190 | 215 | // run expired check, auto-deletes expired entry |
191 | | - CACHE_EXPIRED(cachedata); |
| 216 | + CACHE_EXPIRED(store, key, cachedata); |
192 | 217 | }); |
193 | 218 | }); |
194 | 219 | }); |
|
200 | 225 | var that = this; |
201 | 226 | if (that instanceof CACHE) { |
202 | 227 | that.store = store; |
203 | | - that.supported = 1; |
204 | 228 |
|
205 | 229 | if (IS_OBJECT(options)) { |
206 | 230 | if (options.namespace) { |
|
224 | 248 | return str.toString(); |
225 | 249 | } |
226 | 250 |
|
| 251 | + // return INTEGER |
| 252 | + function INT(num) { |
| 253 | + return parseInt(num); |
| 254 | + } |
| 255 | + |
| 256 | + // type check |
| 257 | + function IS(obj, type) { |
| 258 | + return typeof obj === type; |
| 259 | + } |
| 260 | + |
227 | 261 | // detect if object |
228 | 262 | function IS_OBJECT(obj) { |
229 | | - return typeof obj == 'object'; |
| 263 | + return IS(obj, 'object'); |
| 264 | + } |
| 265 | + |
| 266 | + // detect if undefined |
| 267 | + function IS_UNDEFINED(obj) { |
| 268 | + return IS(obj, 'undefined'); |
230 | 269 | } |
231 | 270 |
|
232 | 271 | // output error |
233 | 272 | function ERROR(msg) { |
234 | | - throw new Error(msg); |
| 273 | + throw new Error(msg || 'input'); |
235 | 274 | } |
236 | 275 |
|
237 | 276 | // public get method |
|
241 | 280 |
|
242 | 281 | // public set method |
243 | 282 | CACHE.prototype.set = function(key, value, expire) { |
244 | | - return CACHE_SET(this.store, NAMESPACE(this.ns, key), value); |
| 283 | + return CACHE_SET(this.store, NAMESPACE(this.ns, key), value, expire); |
245 | 284 | } |
246 | 285 |
|
247 | 286 | // public delete method |
|
0 commit comments