'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _nanoid = require('nanoid');

var _nanoid2 = _interopRequireDefault(_nanoid);

var _bluebird = require('bluebird');

var _bluebird2 = _interopRequireDefault(_bluebird);

var _lodash = require('lodash');

var _lodash2 = _interopRequireDefault(_lodash);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new _bluebird2.default(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return _bluebird2.default.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }

class MemoryQueue {
  constructor(name, logger, options = {}) {
    this.drain = () => {
      this.queue.length > 0 && this.tick();
    };

    this.name = name;
    this.logger = logger;
    this.options = Object.assign({ retries: 2, drainInterval: 2000 }, options);
    this.queue = [];
    this.subscribers = [];
    this._lock = {};

    this._drain = setInterval(this.drain, this.options.drainInterval);
  }

  getQueueId(job) {
    const event = job.event || job;

    return _lodash2.default.get(event, 'user.id') || _lodash2.default.get(event, 'user.userId') || _lodash2.default.get(event, 'userId') || _lodash2.default.get(event, 'raw.user.id') || _lodash2.default.get(event, 'raw.userId') || _lodash2.default.get(event, 'raw.to') || 'default';
  }

  enqueue(job, retries = 0, isPriority = false) {
    const jobWrapped = { job, id: (0, _nanoid2.default)(), timestamp: new Date(), retries };
    if (isPriority) {
      this.queue.unshift(jobWrapped);
    } else {
      this.queue.push(jobWrapped);
    }
    this.tick();
  }

  dequeue() {
    return this.queue.shift();
  }

  cancelAll(job) {
    const jobQueueId = this.getQueueId(job);
    this.queue = this.queue.filter(item => this.getQueueId(item.job) !== jobQueueId);
  }

  peek(job) {
    const jobQueueId = this.getQueueId(job);
    return this.queue.find(item => this.getQueueId(item.job) === jobQueueId);
  }

  tick() {
    var _this = this;

    return _asyncToGenerator(function* () {
      const toDequeueIdx = _lodash2.default.findIndex(_this.queue, function (el) {
        const queueId = _this.getQueueId(el.job);
        return !_this._lock[queueId];
      });

      if (toDequeueIdx === -1) {
        return;
      }

      const [{ job, retries }] = _lodash2.default.pullAt(_this.queue, [toDequeueIdx]);
      const queueId = _this.getQueueId(job);
      _this._lock[queueId] = true;

      try {
        yield _bluebird2.default.mapSeries(_this.subscribers, function (fn) {
          return fn(job);
        });
      } catch (err) {
        _this.logger.warn(`${_this.name} queue failed to process job: ${err.message}`);

        if (retries + 1 <= _this.options.retries) {
          _this.enqueue(job, retries + 1, true);
        } else {
          _this.logger.error(`Retrying job within ${_this.name} queue failed ${_this.options.retries} times. Abandoning the job.`);
        }
      } finally {
        delete _this._lock[queueId];
        if (_this.queue.length) {
          _this.tick();
        }
      }
    })();
  }

  subscribe(fn) {
    this.subscribers.push(fn);
  }
}
exports.default = MemoryQueue;
//# sourceMappingURL=memory.js.map