mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-27 11:18:14 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			159 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			159 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
function RetryOperation(timeouts, options) {
 | 
						|
  // Compatibility for the old (timeouts, retryForever) signature
 | 
						|
  if (typeof options === 'boolean') {
 | 
						|
    options = { forever: options };
 | 
						|
  }
 | 
						|
 | 
						|
  this._originalTimeouts = JSON.parse(JSON.stringify(timeouts));
 | 
						|
  this._timeouts = timeouts;
 | 
						|
  this._options = options || {};
 | 
						|
  this._maxRetryTime = options && options.maxRetryTime || Infinity;
 | 
						|
  this._fn = null;
 | 
						|
  this._errors = [];
 | 
						|
  this._attempts = 1;
 | 
						|
  this._operationTimeout = null;
 | 
						|
  this._operationTimeoutCb = null;
 | 
						|
  this._timeout = null;
 | 
						|
  this._operationStart = null;
 | 
						|
 | 
						|
  if (this._options.forever) {
 | 
						|
    this._cachedTimeouts = this._timeouts.slice(0);
 | 
						|
  }
 | 
						|
}
 | 
						|
module.exports = RetryOperation;
 | 
						|
 | 
						|
RetryOperation.prototype.reset = function() {
 | 
						|
  this._attempts = 1;
 | 
						|
  this._timeouts = this._originalTimeouts;
 | 
						|
}
 | 
						|
 | 
						|
RetryOperation.prototype.stop = function() {
 | 
						|
  if (this._timeout) {
 | 
						|
    clearTimeout(this._timeout);
 | 
						|
  }
 | 
						|
 | 
						|
  this._timeouts       = [];
 | 
						|
  this._cachedTimeouts = null;
 | 
						|
};
 | 
						|
 | 
						|
RetryOperation.prototype.retry = function(err) {
 | 
						|
  if (this._timeout) {
 | 
						|
    clearTimeout(this._timeout);
 | 
						|
  }
 | 
						|
 | 
						|
  if (!err) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  var currentTime = new Date().getTime();
 | 
						|
  if (err && currentTime - this._operationStart >= this._maxRetryTime) {
 | 
						|
    this._errors.unshift(new Error('RetryOperation timeout occurred'));
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  this._errors.push(err);
 | 
						|
 | 
						|
  var timeout = this._timeouts.shift();
 | 
						|
  if (timeout === undefined) {
 | 
						|
    if (this._cachedTimeouts) {
 | 
						|
      // retry forever, only keep last error
 | 
						|
      this._errors.splice(this._errors.length - 1, this._errors.length);
 | 
						|
      this._timeouts = this._cachedTimeouts.slice(0);
 | 
						|
      timeout = this._timeouts.shift();
 | 
						|
    } else {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  var self = this;
 | 
						|
  var timer = setTimeout(function() {
 | 
						|
    self._attempts++;
 | 
						|
 | 
						|
    if (self._operationTimeoutCb) {
 | 
						|
      self._timeout = setTimeout(function() {
 | 
						|
        self._operationTimeoutCb(self._attempts);
 | 
						|
      }, self._operationTimeout);
 | 
						|
 | 
						|
      if (self._options.unref) {
 | 
						|
          self._timeout.unref();
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    self._fn(self._attempts);
 | 
						|
  }, timeout);
 | 
						|
 | 
						|
  if (this._options.unref) {
 | 
						|
      timer.unref();
 | 
						|
  }
 | 
						|
 | 
						|
  return true;
 | 
						|
};
 | 
						|
 | 
						|
RetryOperation.prototype.attempt = function(fn, timeoutOps) {
 | 
						|
  this._fn = fn;
 | 
						|
 | 
						|
  if (timeoutOps) {
 | 
						|
    if (timeoutOps.timeout) {
 | 
						|
      this._operationTimeout = timeoutOps.timeout;
 | 
						|
    }
 | 
						|
    if (timeoutOps.cb) {
 | 
						|
      this._operationTimeoutCb = timeoutOps.cb;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  var self = this;
 | 
						|
  if (this._operationTimeoutCb) {
 | 
						|
    this._timeout = setTimeout(function() {
 | 
						|
      self._operationTimeoutCb();
 | 
						|
    }, self._operationTimeout);
 | 
						|
  }
 | 
						|
 | 
						|
  this._operationStart = new Date().getTime();
 | 
						|
 | 
						|
  this._fn(this._attempts);
 | 
						|
};
 | 
						|
 | 
						|
RetryOperation.prototype.try = function(fn) {
 | 
						|
  console.log('Using RetryOperation.try() is deprecated');
 | 
						|
  this.attempt(fn);
 | 
						|
};
 | 
						|
 | 
						|
RetryOperation.prototype.start = function(fn) {
 | 
						|
  console.log('Using RetryOperation.start() is deprecated');
 | 
						|
  this.attempt(fn);
 | 
						|
};
 | 
						|
 | 
						|
RetryOperation.prototype.start = RetryOperation.prototype.try;
 | 
						|
 | 
						|
RetryOperation.prototype.errors = function() {
 | 
						|
  return this._errors;
 | 
						|
};
 | 
						|
 | 
						|
RetryOperation.prototype.attempts = function() {
 | 
						|
  return this._attempts;
 | 
						|
};
 | 
						|
 | 
						|
RetryOperation.prototype.mainError = function() {
 | 
						|
  if (this._errors.length === 0) {
 | 
						|
    return null;
 | 
						|
  }
 | 
						|
 | 
						|
  var counts = {};
 | 
						|
  var mainError = null;
 | 
						|
  var mainErrorCount = 0;
 | 
						|
 | 
						|
  for (var i = 0; i < this._errors.length; i++) {
 | 
						|
    var error = this._errors[i];
 | 
						|
    var message = error.message;
 | 
						|
    var count = (counts[message] || 0) + 1;
 | 
						|
 | 
						|
    counts[message] = count;
 | 
						|
 | 
						|
    if (count >= mainErrorCount) {
 | 
						|
      mainError = error;
 | 
						|
      mainErrorCount = count;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return mainError;
 | 
						|
};
 |