Skip to content

Instantly share code, notes, and snippets.

@arpanpal010
Created October 19, 2017 14:37
Show Gist options
  • Save arpanpal010/a8221c61009951db81cb75c6ea550e40 to your computer and use it in GitHub Desktop.
Save arpanpal010/a8221c61009951db81cb75c6ea550e40 to your computer and use it in GitHub Desktop.
A generic caching mechanism that stores in localstorage.
export static class CacheService {
// static $inject = ["localStorageService", "$rootScope", "$timeout"]
private static ls : localStorageService = undefined; // wrap localstorage to hide data
private static instance : CacheService = undefined;
private callables : Object = {};
private asyncCallables : Object = {};
constructor(ls : any, rootScope : any, timeout : any) {
if(!this.instance) {
this.enabled = true; // toggle this to disable cache.
this.ls = ls;
this.timeout = timeout;
this.ls.setStorageType("sessionStorage");
this.clearAtInterval(1200); // clear every 20 mins
// this.clearAll();
if(!this.enabled) {
this.clearAll();
}
this.rs = rootScope;
this.instance = this;
// window.lc = this; // for debug only
}
return this.instance;
}
create(key : string, callable : Function) {
const self = this;
self.callables[key] = callable;
return (refetch) => {
if(refetch) {
self.ls.remove(key);
}
if(self.isKeySet(key)) {
return self.getValue(key);
} else {
return self.setValue(key, callable());
}
}
}
createAsync(key : string, callable : Function) {
const self = this;
self.asyncCallables[key] = callable;
return async (refetch) => {
if(refetch) {
self.ls.remove(key);
}
if(self.isKeySet(key)) {
return self.getValue(key);
} else {
return self.setValue(key, await callable());
}
}
}
setValue(key : string, value : any) {
let now = Date.now();
let old = this.getValue(key);
if (this.enabled) {
this.ls.set(key, JSON.stringify({ "timestamp": now, "value" : value }));
this.ls.set("CacheChangedLast", now);
this.rs.$broadcast("set-" + key, value, old);
}
return value;
}
updateValue(key : string, value? : any) {
this.setValue(key, value);
}
updateValueAsync(key : string) {
return async () => {
if(this.enabled) {
let v = await this.getCallable(key)();
return this.setValue(key, v);
}
};
}
getValue(key: string) {
//console.log(key);
if(this.isKeySet(key)) {
return JSON.parse(this.ls.get(key))["value"];
}
return undefined;
}
getLastModified(key? : string) {
if(this.isKeySet(key)) {
return JSON.parse(this.ls.get(key))["timestamp"];
}
return this.ls.get("CacheChangedLast") as number;
}
isKeySet(key) {
return this.ls.keys().filter(function(v) {
return v == key;
}).length > 0;
}
getCallable(key : string) {
if(typeof this.callables[key] === 'function') {
return this.callables[key];
}
if(typeof this.asyncCallables[key] === 'function') {
return this.asyncCallables[key];
}
return () => {
return undefined;
}
}
clearAtInterval(ts: number) {
let now = Date.now();
// console.log( ts, now, this.getLastModified(), (ts - (now - this.getLastModified())/1000) )
return this.timeout(() => {
this.clearAll();
this.clearAtInterval(ts);
}, ((td : number) => {
let tl = Math.abs(td) > ts ? 10 : ((ts-td)>5 ? ts-td : ts)*1000;
//console.log("Last cache update", td , "seconds ago at", new Date(Date.now() - td));
//console.log("Clear cache in", tl/1000, "seconds at", new Date(Date.now() + tl));
return tl;
})(parseInt((now - this.getLastModified())/1000)));
}
clearAll() {
let now = Date.now();
//console.log( "Clearing cache now at", new Date() );
this.ls.clearAll();
this.ls.set("CacheChangedLast", now);
}
clearStores(storeNames) {
storeNames.map( (v) => {
return this.ls.remove(v);
})
}
clearStoresMatchingName(name) {
this.ls.keys().filter((v) => {
return new RegExp(name).test(v);
}).forEach((w) => {
return this.ls.remove(w);
})
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment