Source: data.js

const EventEmitter = require('events').EventEmitter

/**
 * Global Data Store.
 *
 * Powered By GUN (http://gun.js.org/)
 */
class DataStore extends EventEmitter {
  constructor () {
    super()
    /**
     * Is the connection active?
     * @type {boolean}
     */
    this.connected = false
    this.ready = false
    this.connect()
  }

  async connect () {
    try {
      /**
       * Database object.
       *
       * Don't use this directly unless necessary
       */
      this.db = await require('./db').createServer()
      this.connected = true
      this.ready = true
      this.emit('connected')
    } catch (e) {
      Core.log(e, 2)
      process.exit(1)
    }
  }

  /**
   * Returns a Promise that resolves either when the Redis connection
   * or the fallback cache are ready
   * @return {Promise<Boolean>}
   */
  ensureReady () {
    if (this.ready) return Promise.resolve()
    return new Promise(resolve => {
      this.once('connected', () => resolve())
    })
  }

  /**
   * Gets an object by its key
   * @param {string} key - Key to find
   * @returns {object}
   */
  async get (key) {
    await this.ensureReady()
    return new Promise(resolve => {
      this.db.get(key).path('val').val(v => resolve(JSON.parse(v || null)))
    })
  }

  /**
   * Sets the value of a key
   * NOTE: Objects get converted to JSON before saving
   * @param {string} key - Key to set
   * @param {object} val - New value
   */
  async set (key, val) {
    await this.ensureReady()
    return new Promise((resolve, reject) => {
      this.db.get(key).put({ val: JSON.stringify(val) }, ({ err }) => err == null ? resolve('OK') : reject(err))
    })
  }

  /**
   * Deletes a key
   * @param {string} key - Key to delete
   */
  async del (key) {
    return await this.set(key, null)
  }

  /**
   * Subscribes to a key and listens for changes
   * @param {string} key - Key
   * @param {function} handler - Event handler
   * @return {Gun} - Gun chain
   */
  subscribe (key, handler) {
    this.db.get(key).path('val').on(data => handler(JSON.parse(data || null)))
  }
}

module.exports = DataStore