2
0
Fork 0

added cache clean code

This commit is contained in:
Willem 2016-01-21 01:40:15 +01:00
parent 2010e420d8
commit e9c8d1a45a
2 changed files with 109 additions and 77 deletions

View file

@ -92,7 +92,7 @@ A javascript library providing server defined loading of assets for a single pag
* server.question.title = The question ui title. (default: 'Server')
* server.question.text = The question ui text. (default: 'Please provide the server name;')
* server.question.style = The question ui css style.(note: pending change) (default: green border box)
* cache.meta = The cache backend for the meta information, null is auto select. (default: null)
* cache.meta = The cache backend for the meta information(server.url+content), null is auto select. (default: null)
* cache.js = The cache backend for for js, null is auto select. (default: null)
* cache.css = The cache backend for for css, null is auto select. (default: null)
* cache.cssData = The cache backend for for cssData, null is auto select. (default: null)
@ -121,7 +121,7 @@ A javascript library providing server defined loading of assets for a single pag
More custom schemas are possible like; (todo: needs testing)
FFSpaLoader.options.cache.meta = null; // use auto -> TODO: currently other cached need meta needs fixing.
FFSpaLoader.options.cache.meta = false;
FFSpaLoader.options.cache.js = false;
FFSpaLoader.options.cache.css = false;
FFSpaLoader.options.cache.cssData = false;
@ -148,7 +148,6 @@ A javascript library providing server defined loading of assets for a single pag
## Todo
* Auto cache cleanup code. (!! required before production !!)
* test in production
* Server header set+check support
* Redo css(?divs) of server question
@ -166,9 +165,10 @@ Add unit tests for any new or changed functionality. Lint and test your code.
## Release History
### 0.0.4
* Added auto cache clean code
* Disable cordova timeout per default.
* Remove unused mobileAgent detect.
* Fixed cached resources loading.
* Fixed cached resources injection order.
### 0.0.3

View file

@ -159,6 +159,7 @@
};
};
var executeSql = function(tx, query, values, resultHandler, errorHandler) {
utilDebug('websql.executeSql '+query);
tx.executeSql(query, values, resultHandler, function(tx,err) {
errorHandler(new Error('Code: '+err.code+' '+err.message+' by query: '+query));
});
@ -166,11 +167,8 @@
var cacheDBInit = function(cb) {
cacheDB.transaction(function(tx) {
var query = 'CREATE TABLE cache_store(id INTEGER PRIMARY KEY AUTOINCREMENT, key TEXT NOT NULL, value TEXT NOT NULL)';
utilDebug('websql.init query '+query);
executeSql(tx, query, [], function(tx) {
var query = 'CREATE UNIQUE INDEX cache_store__key__udx ON cache_store (key)';
utilDebug('websql.init query '+query);
executeSql(tx, query, [], nullDataHandler(cb), cb);
executeSql(tx, 'CREATE UNIQUE INDEX cache_store__key__udx ON cache_store (key)', [], nullDataHandler(cb), cb);
}, cb);
});
};
@ -185,9 +183,7 @@
return cb(e);
}
cacheDB.transaction(function(tx) {
var query = 'SELECT value FROM cache_store WHERE key = \"test-for-table\"';
utilDebug('websql.cacheOpen query '+query);
executeSql(tx, query, [], function() {
executeSql(tx,'SELECT value FROM cache_store WHERE key = \"test-for-table\"', [], function() {
cb(null);
}, function() {
cacheDBInit(cb);
@ -196,9 +192,7 @@
},
cacheGetValue: function(key, cb) {
cacheDB.transaction(function(tx) {
var query = 'SELECT value FROM cache_store WHERE key = ?';
utilDebug('websql.cacheGetValue query '+query);
executeSql(tx, query,[key], function(tx, res) {
executeSql(tx, 'SELECT value FROM cache_store WHERE key = ?',[key], function(tx, res) {
if (res.rows.length === 0) {
cb(null, null);
} else {
@ -210,16 +204,12 @@
},
cacheSetValue: function(key, value, cb) {
cacheDB.transaction(function(tx) {
var query = 'SELECT value FROM cache_store WHERE key = ?';
utilDebug('websql.cacheSetValue query '+query);
executeSql(tx, query,[key], function(tx, res) {
executeSql(tx, 'SELECT value FROM cache_store WHERE key = ?',[key], function(tx, res) {
if (res.rows.length === 0) {
var queryInsert = 'INSERT INTO cache_store (key,value) VALUES (?,?)';
utilDebug('websql.cacheSetValue query '+queryInsert);
executeSql(tx, queryInsert, [key,JSON.stringify(value)], nullDataHandler(cb), cb);
} else {
var queryUpdate = 'UPDATE cache_store SET value = ? WHERE key = ?';
utilDebug('websql.cacheSetValue query '+queryUpdate);
executeSql(tx, queryUpdate, [JSON.stringify(value),key], nullDataHandler(cb), cb);
}
}, cb);
@ -227,9 +217,7 @@
},
cacheDeleteValue: function(key, cb) {
cacheDB.transaction(function(tx) {
var query = 'DELETE FROM cache_store WHERE key = ?';
utilDebug('websql.cacheDeleteValue query '+query);
executeSql(tx, query, [key], function () {
executeSql(tx, 'DELETE FROM cache_store WHERE key = ?', [key], function () {
setTimeout(nullDataHandler(cb)); // return next tick so transaction is flushed before location.reload
}, cb);
});
@ -282,7 +270,7 @@
try {
var stack = err.stack || '';
stack = stack.split('\n').map(function (line) { return line.trim(); });
var stackText = stack.splice(stack[0] == 'Error' ? 2 : 1);
var stackText = stack.splice(stack[0] === 'Error' ? 2 : 1);
var traceTag = document.createElement('div');
traceTag.appendChild(document.createTextNode(stackText));
@ -316,6 +304,26 @@
};
httpRequest.send();
};
var utilRunStack = function(runType, stack, step, cb) {
if (stack.length === 0) {
return cb(null);
}
utilDebug(runType);
var startTime = new Date().getTime();
var runStack = stack;
var runStackStep = function(err) {
if (err !== null) { return cb(err); }
runStack = runStack.slice(1);
if (runStack.length === 0) {
utilDebug(runType+' done '+stack.length+' in '+(new Date().getTime()-startTime)+' ms.');
cb(null);
} else {
step(runStack[0],runStackStep);
}
};
step(runStack[0],runStackStep);
};
var cacheGetService = function (type) {
if (options.cache[type]) {
@ -356,11 +364,64 @@
});
};
// var cleanupCache = function (resources, cb) {
// utilDebug('cleanupCache TODO cacheList '+0+' resources '+resources.length);
// // TODO: impl for removes in resource lists
// cb(null);
// };
var cleanupCache = function (resources, cb) {
var typedKeys = {};
resources.forEach(function (r) {
var typeKey = typedKeys[r.type];
if (typeKey === undefined) {
typeKey = [];
typedKeys[r.type] = typeKey;
}
typeKey.push(r.hash);
});
var steps = [];
var keys = Object.keys(typedKeys);
for (var keyIdx in keys) {
var type = keys[keyIdx];
if (!cacheHasService(type)) {
continue;
}
steps.push({keys: typedKeys[type], type: type});
}
utilRunStack('cleanupCacheKeys',steps, function(typeKey, cb) {
cacheGetValue(typeKey.type,'keys',function (err,value) {
if (err !== null) {
return cb(err);
}
if (value === null) {
return cb(null);
}
var diff = [];
for (var i=0;i<value.length;i++) {
if (typeKey.keys.indexOf(value[i]) === -1) {
diff.push(value[i]);
}
}
var valueNew = value;
for (var i2=0;i2<diff.length;i2++) {
var keyIdx = valueNew.indexOf(diff[i2]);
if (keyIdx !== -1) {
valueNew.splice(keyIdx,1);
}
}
//utilDebug('cleanupCache value1: '+JSON.stringify(value));
//utilDebug('cleanupCache value2: '+JSON.stringify(valueNew));
utilRunStack('cleanupCacheItems',diff, function(key, cb) {
cacheDeleteValue(typeKey.type,key,cb);
}, function(err) {
if (err !== null) {
return cb(err);
}
if (diff.length === 0) {
cb(null);
} else {
cacheSetValue(typeKey.type,'keys',valueNew ,cb);
}
});
});
}, cb);
};
var injectResourceData = function(resource, data, cb) {
utilDebug('injectResourceData resource '+JSON.stringify(resource)+' data '+data.length);
@ -381,19 +442,23 @@
cb(null);
};
/**
* Add all cache keys in central list so we can clear the cache item if resources are removed.
* @param {Resource} resource The resource object with the type and hash.
* @param {function} cb The callback for error and request if ready.
* @private
*/
var storeResourceKey = function (resource, cb) {
// Add all cache keys in central list so we can clear the cache item if resources are removed.
var cacheKey = resource.type+'_keys';
cacheGetValue('meta',cacheKey,function (err,value) { // TODO: move to resource.type
var cacheKey = 'keys';
cacheGetValue(resource.type,cacheKey,function (err,value) {
if (err !== null) {
cb(err);
return;
return cb(err);
}
if (value === null) {
value = [];
}
value.push(resource.hash);
cacheSetValue('meta',cacheKey,value, cb);
cacheSetValue(resource.type,cacheKey,value, cb);
});
};
@ -447,46 +512,6 @@
}
};
var loadResources = function(resources, cb) {
var startTime = new Date().getTime();
utilDebug('loadResources');
var resourceStack = resources;
var resourceLoader = function(err) {
if (err !== null) { return cb(err); }
resourceStack = resourceStack.slice(1);
if (resourceStack.length === 0) {
utilDebug('loadResources done in '+(new Date().getTime()-startTime)+' ms.');
cb(null);
} else {
loadResource(resourceStack[0],resourceLoader);
}
};
loadResource(resourceStack[0],resourceLoader);
};
var injectResource = function(resource, cb) {
cacheGetValue(resource.type,resource.hash,function(err,item) {
injectResourceData(resource,item.data,cb);
});
}
var injectResources = function(resources, cb) {
var startTime = new Date().getTime();
utilDebug('injectResources');
var resourceStack = resources;
var resourceLoader = function(err) {
if (err !== null) { return cb(err); }
resourceStack = resourceStack.slice(1);
if (resourceStack.length === 0) {
utilDebug('injectResources done in '+(new Date().getTime()-startTime)+' ms.');
cb(null);
} else {
injectResource(resourceStack[0],resourceLoader);
}
};
injectResource(resourceStack[0],resourceLoader);
};
/**
* Starts loader by downloading resource list or using cache version to
* load/refresh/inject the resources.
@ -517,7 +542,11 @@
} else if (value === null) {
cb(new Error('Have no cache of server resouces from '+options.server.url));
} else {
injectResources(value, cb);
utilRunStack('injectResources', value, function(resource, cb) {
cacheGetValue(resource.type,resource.hash,function(err,item) {
injectResourceData(resource,item.data,cb);
});
} , cb);
}
});
} else {
@ -533,10 +562,13 @@
if (cacheHasService('meta')) {
cacheSetValue('meta','server_resources',resources, function (err) {
if (err !== null) { return cb(err); }
loadResources(resources, cb);
utilRunStack('loadResources', resources, loadResource , function (err) {
if (err !== null) { return cb(err); }
cleanupCache(resources,cb); // only clean when fetched + cached
});
});
} else {
loadResources(resources, cb);
utilRunStack('loadResources', resources, loadResource , cb);
}
});
};