All files / src/store/sources BaseIntervalSource.js

100% Statements 30/30
71.42% Branches 10/14
100% Functions 12/12
100% Lines 30/30

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107                          1x 1x 1x   1x   1x 1x 1x               3x 1x   3x 3x 3x 4x           2x           1x 1x 1x   1x   1x 1x                   7x         4x 4x                     1x 1x       2x 4x     1x                     1x 1x        
// @ts-check
import { set } from "lodash";
 
/**
 * @brief ticker source updates the store every "interval"
 */
export default class BaseIntervalSource extends EventTarget {
  /**
   * @param {V.Store<BaseVue.StoreState>} [store]
   * @param {string} [namespace] store namespace
   * @param {number} [interval] interval in milliseconds
   */
  constructor(store, namespace, interval) {
    super();
    this.store = store ?? null;
    this.namespace = namespace;
    /** @type {number} */
    this.interval = 0;
    /** @type {NodeJS.Timeout|null} */
    this._timer = null;
    this._evt = new CustomEvent("tick");
    this.start(interval);
  }
 
  /**
   * @brief start or restart the timer
   * @param  {number} [interval] interval in milliseconds
   */
  start(interval) {
    if (this._timer) {
      clearInterval(this._timer);
    }
    this.interval = interval ?? 0;
    this._commit("reset");
    this._timer = this.interval ?
      setInterval(() => this.tick(), interval) : null;
  }
 
  /**
   * @brief stop timer
   */
  stop() { this.start(0); }
 
  /**
   * @brief release resources
   */
  destroy() {
    const store = this.store;
    this.store = null; // prevent any store interaction
    this.stop();
 
    Eif (store && this.namespace) {
      // @ts-ignore
      delete store.sources[this.namespace];
      store.unregisterModule(this.namespace.split("/"));
    }
  }
 
  /**
   * commit in the store
   * @param  {string} method
   * @param  {any} [arg]
   */
  _commit(method, arg) {
    this.store?.commit(this.namespace ? `${this.namespace}/${method}` : method,
      arg);
  }
 
  tick() {
    this._commit("tick");
    this.dispatchEvent(this._evt);
  }
 
  /**
   * @brief remove plugin
   * @param {V.Store<BaseVue.StoreState>} store
   * @param {string} namespace
   * @param {number} [interval]
   */
  static register(store, namespace, interval) {
    // @ts-ignore
    store.sources?.[namespace]?.destroy();
    store.registerModule(namespace.split("/"), {
      namespaced: true,
      state: { count: 0 },
      mutations: {
        reset(state) { state.count = 0; },
        tick(state) { state.count += 1; }
      }
    });
    set(store, [ "sources", namespace ], new BaseIntervalSource(store, namespace, interval));
  }
 
  /**
   * @brief ticker plugin register module and source
   * @details this is mainly there as an example implementation
   * @param {string} namespace
   * @param {number} [interval]
   * @return {(store: V.Store<BaseVue.StoreState>) => void}
   */
  static plugin(namespace, interval) {
    return function(store) {
      return BaseIntervalSource.register(store, namespace, interval);
    };
  }
}