webtrack-extension / src / background / core / CacheHandler.js
CacheHandler.js
Raw
import LocalstoreDB from './LocalstoreDB';
// import SourceCache from './SourceCache';

export default class CacheHandler {

  /**
   * [constructor
   * - create instance of FileHandler
   * - create instance of LocalstorageHandler
   * ]
   * @param {Number} projectId
   */
  constructor(projectId=''){
    this.debug = false;
    this.DEFAULTCONTENT = {};
    this.storage = new LocalstoreDB({objectStoreName: 'cachehandler_'+projectId, defaultContent: {}});
    //if (this.debug) console.log('-: CacheHandler.constructor() - ', 'objectStoreName: ', 'cachehandler_' + projectId, ' this.storage: ', this.storage);
    // this.source = new SourceCache(projectId);
    this.content = {};
    this.id = 'id';
    this.typeofId = 'string';
    this.ids = [];
    this.DELAY = 500;
    this.last = 0
    this.timeouts = {};
  }

  /**
   * [initialize the content]
   * @return {Promise}
   */
  init(){
    return new Promise(async (resolve, reject) => {
      try {
        this.content = await this.storage.getAll();
        //if (this.debug) console.log('-: CacheHandler.init() - ', 'this.content:', this.content);
        resolve();
      } catch (e) {
        reject(e)
      }
    });
  }


  /**
   * [getIds return list of ids]
   * @return {Array}
   */
  getIds(){
    return Object.keys(this.content).map(nr => parseInt(nr, 10))
  }

  /**
   * [is check if id exist]
   * @param  {Number}  id
   * @return {Boolean}
   */
  is(id){
    console.assert(typeof id == this.typeofId, 'id is ', typeof id)
    return this.content.hasOwnProperty(id.toString());
  }

  /**
   * [add // add nur content]
   * @param {Object} props [default: {}]
   * @param  {Integer} now [time as number]
   * @param {Boolean} [inspect=false] [if the inspect is false the props will be not validate]
   */
  add(props={}, now, inspect=false){
    let id = props[this.id];
    //if (this.debug) console.assert(typeof id == this.typeofId, 'id is not '+this.typeofId, typeof id);
    //if (this.debug) console.log(' -: CacheHandler.add()', id);
    if(!this.is(id)){
      // console.log('Set %s default value', id, this.DEFAULTCONTENT);
      this.content[id] = this.DEFAULTCONTENT;
    }else{
      this.content[id] = props;
    }
    return this.update(props, now, inspect);
  }

  /**
   * [get return the content]
   * @return {Object} this.content
   */
  get(){
    return this.content;
  }

  /**
   * [getOnly return the content of id. If the content not exist, than will be return the default content]
   * @param  {Number} id
   * @return {Object}
   */
  getOnly(id){
    console.assert(typeof id == this.typeofId, 'id is not number')
    if(this.is(id)){
      return this.content[id];
    }else{
      //if (this.debug) console.log(this.constructor.name, 'Content from id '+id+' not found');
      return this.DEFAULTCONTENT
    }
  }

  /**
   * [update // update the content of id and save it in the storage]
   * @param  {Object} props [default: {}]
   * @param  {Integer} now [time as number]
   * @return {Promise}
   */
  update(props={}, now=+new Date(), force=false){
    return new Promise(async (resolve, reject) => {
      let id = props[this.id];
      console.assert(typeof id == this.typeofId, 'id is '+ typeof id)

      try {
        this.content[id] = Object.assign({}, this.content[id], props);
        // do big update if 5 seconds have passed
        // ii might be unnecessary
        let bigUpdate = Math.round(+ new Date() / 1000)%5==0;
        // console.log(Object.keys(props).length == 2 , props.hasOwnProperty('duration') , this.timeouts.hasOwnProperty(id) , this.timeouts[id], bigUpdate);
        // if(!force && Object.keys(props).length == 2 && props.hasOwnProperty('duration') && this.timeouts.hasOwnProperty(id) && this.timeouts[id].timeout==null && !bigUpdate){
        //   console.log('update duration');
        //   this.storage.set(props, true, false);
        // }else 
        if(!force && Object.keys(props).length == 2 && props.hasOwnProperty('elapsed') && this.timeouts.hasOwnProperty(id) && this.timeouts[id].timeout==null && !bigUpdate){
          //if (this.debug) console.log('-: CacheHandler.update() - Update elapsed');
          this.storage.set(props, true, false);
        }else if(Object.keys(props).length > 2 || bigUpdate || force){
          //if (this.debug) console.log('-: CacheHandler.update() - props: ', props);
          if(this.timeouts.hasOwnProperty(id) && this.timeouts[id].timeout!=null){
            clearTimeout(this.timeouts[id].timeout);
            this.timeouts[id].resolve();
            this.timeouts[id].resolve = resolve
          }else{
            this.timeouts[id] = {
              timeout: null,
              resolve: resolve
            }
          }
          this.timeouts[id].timeout = setTimeout(()=>{
            let merge = Object.assign(typeof now == 'boolean' && now == false? {}: {timestamp: now}, this.content[id], {[this.id]: id} );
            this.storage.set(merge).catch(console.warn)
            this.timeouts[id].timeout = null
            this.timeouts[id].resolve()
          }, this.DELAY)
        }
      } catch (err) {
        reject(err);
      }
    });
  }

  /**
   * [del delete the content of id]
   * @param  {Number}  id
   */
  del(id){
    return new Promise(async (resolve, reject) => {
      try {
        if(this.is(id)){
          // if(this.content[id].hasOwnProperty('source')){
          //   let urls = this.content[id].source.map(e => e.url)
          // }
          delete this.content[id];
          await this.storage.delete(id);
          resolve();
        }else{
          console.log(this.constructor.name, 'Id '+id+' not found in content');
        }
      } catch (err) {
        reject(err)
      }
    });
  }


}