2016-06-30 17:29:00 -07:00
|
|
|
/*!
|
|
|
|
|
* async.js - async object class for bcoin
|
2017-02-03 22:47:26 -08:00
|
|
|
* Copyright (c) 2016-2017, Christopher Jeffrey (MIT License).
|
2016-06-30 17:29:00 -07:00
|
|
|
* https://github.com/bcoin-org/bcoin
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
'use strict';
|
|
|
|
|
|
2016-11-19 10:45:31 -08:00
|
|
|
var util = require('./util');
|
2016-11-10 13:33:40 -08:00
|
|
|
var co = require('./co');
|
2017-01-11 21:20:26 -08:00
|
|
|
var Lock = require('./lock');
|
2016-10-02 01:01:16 -07:00
|
|
|
var assert = require('assert');
|
2016-06-30 17:29:00 -07:00
|
|
|
var EventEmitter = require('events').EventEmitter;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* An abstract object that handles state and
|
|
|
|
|
* provides recallable open and close methods.
|
2017-02-03 22:47:26 -08:00
|
|
|
* @alias module:utils.AsyncObject
|
2016-06-30 17:29:00 -07:00
|
|
|
* @constructor
|
|
|
|
|
* @property {Boolean} loading
|
|
|
|
|
* @property {Boolean} closing
|
|
|
|
|
* @property {Boolean} loaded
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
function AsyncObject() {
|
|
|
|
|
assert(this instanceof AsyncObject);
|
|
|
|
|
|
|
|
|
|
EventEmitter.call(this);
|
|
|
|
|
|
2017-01-11 21:20:26 -08:00
|
|
|
this._asyncLock = new Lock();
|
2016-11-10 13:33:40 -08:00
|
|
|
|
2016-06-30 17:29:00 -07:00
|
|
|
this.loading = false;
|
|
|
|
|
this.closing = false;
|
|
|
|
|
this.loaded = false;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-19 10:45:31 -08:00
|
|
|
util.inherits(AsyncObject, EventEmitter);
|
2016-06-30 17:29:00 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Open the object (recallable).
|
2017-02-03 22:47:26 -08:00
|
|
|
* @method
|
2016-09-23 01:05:06 -07:00
|
|
|
* @returns {Promise}
|
2016-06-30 17:29:00 -07:00
|
|
|
*/
|
|
|
|
|
|
2016-09-21 22:59:48 -07:00
|
|
|
AsyncObject.prototype.open = co(function* open() {
|
2016-11-10 13:33:40 -08:00
|
|
|
var unlock = yield this._asyncLock.lock();
|
|
|
|
|
try {
|
|
|
|
|
return yield this.__open();
|
|
|
|
|
} finally {
|
|
|
|
|
unlock();
|
|
|
|
|
}
|
|
|
|
|
});
|
2016-06-30 17:29:00 -07:00
|
|
|
|
2016-11-10 13:33:40 -08:00
|
|
|
/**
|
|
|
|
|
* Open the object (without a lock).
|
2017-02-03 22:47:26 -08:00
|
|
|
* @method
|
2016-11-10 13:33:40 -08:00
|
|
|
* @private
|
|
|
|
|
* @returns {Promise}
|
|
|
|
|
*/
|
2016-06-30 17:29:00 -07:00
|
|
|
|
2016-11-10 13:33:40 -08:00
|
|
|
AsyncObject.prototype.__open = co(function* open() {
|
2016-09-21 22:58:27 -07:00
|
|
|
if (this.loaded)
|
2016-11-10 13:33:40 -08:00
|
|
|
return;
|
2016-07-04 05:36:06 -07:00
|
|
|
|
2016-09-21 22:58:27 -07:00
|
|
|
this.emit('preopen');
|
2016-06-30 17:29:00 -07:00
|
|
|
|
2016-09-21 22:58:27 -07:00
|
|
|
this.loading = true;
|
2016-06-30 17:29:00 -07:00
|
|
|
|
2016-09-21 22:58:27 -07:00
|
|
|
try {
|
|
|
|
|
yield this._open();
|
|
|
|
|
} catch (e) {
|
2016-09-20 14:56:54 -07:00
|
|
|
this.loading = false;
|
2016-11-10 13:33:40 -08:00
|
|
|
this.emit('error', e);
|
|
|
|
|
throw e;
|
2016-09-21 22:58:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.loading = false;
|
|
|
|
|
this.loaded = true;
|
|
|
|
|
|
2016-11-10 13:33:40 -08:00
|
|
|
this.emit('open');
|
2016-09-21 22:58:27 -07:00
|
|
|
});
|
2016-06-30 17:29:00 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Close the object (recallable).
|
2017-02-03 22:47:26 -08:00
|
|
|
* @method
|
2016-09-23 01:05:06 -07:00
|
|
|
* @returns {Promise}
|
2016-06-30 17:29:00 -07:00
|
|
|
*/
|
|
|
|
|
|
2016-09-21 22:59:48 -07:00
|
|
|
AsyncObject.prototype.close = co(function* close() {
|
2016-11-10 13:33:40 -08:00
|
|
|
var unlock = yield this._asyncLock.lock();
|
|
|
|
|
try {
|
|
|
|
|
return yield this.__close();
|
|
|
|
|
} finally {
|
|
|
|
|
unlock();
|
|
|
|
|
}
|
|
|
|
|
});
|
2016-06-30 17:29:00 -07:00
|
|
|
|
2016-11-10 13:33:40 -08:00
|
|
|
/**
|
|
|
|
|
* Close the object (without a lock).
|
2017-02-03 22:47:26 -08:00
|
|
|
* @method
|
2016-11-10 13:33:40 -08:00
|
|
|
* @private
|
|
|
|
|
* @returns {Promise}
|
|
|
|
|
*/
|
2016-06-30 17:29:00 -07:00
|
|
|
|
2016-11-10 13:33:40 -08:00
|
|
|
AsyncObject.prototype.__close = co(function* close() {
|
2016-09-21 22:58:27 -07:00
|
|
|
if (!this.loaded)
|
2016-11-10 13:33:40 -08:00
|
|
|
return;
|
2016-06-30 17:29:00 -07:00
|
|
|
|
2016-09-21 22:58:27 -07:00
|
|
|
this.emit('preclose');
|
2016-07-04 05:36:06 -07:00
|
|
|
|
2016-09-21 22:58:27 -07:00
|
|
|
this.closing = true;
|
2016-06-30 17:29:00 -07:00
|
|
|
|
2016-09-21 22:58:27 -07:00
|
|
|
try {
|
|
|
|
|
yield this._close();
|
|
|
|
|
} catch (e) {
|
2016-09-20 14:56:54 -07:00
|
|
|
this.closing = false;
|
2016-11-10 13:33:40 -08:00
|
|
|
this.emit('error', e);
|
|
|
|
|
throw e;
|
2016-09-21 22:58:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.closing = false;
|
2016-11-10 13:33:40 -08:00
|
|
|
this.loaded = false;
|
2016-09-21 22:58:27 -07:00
|
|
|
|
2016-11-10 13:33:40 -08:00
|
|
|
this.emit('close');
|
2016-09-21 22:58:27 -07:00
|
|
|
});
|
2016-06-30 17:29:00 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Close the object (recallable).
|
|
|
|
|
* @method
|
2016-09-23 01:05:06 -07:00
|
|
|
* @returns {Promise}
|
2016-06-30 17:29:00 -07:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
AsyncObject.prototype.destroy = AsyncObject.prototype.close;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Initialize the object.
|
|
|
|
|
* @private
|
2016-09-23 01:05:06 -07:00
|
|
|
* @returns {Promise}
|
2016-06-30 17:29:00 -07:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
AsyncObject.prototype._open = function _open(callback) {
|
|
|
|
|
throw new Error('Abstract method.');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Close the object.
|
|
|
|
|
* @private
|
2016-09-23 01:05:06 -07:00
|
|
|
* @returns {Promise}
|
2016-06-30 17:29:00 -07:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
AsyncObject.prototype._close = function _close(callback) {
|
|
|
|
|
throw new Error('Abstract method.');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Expose
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
module.exports = AsyncObject;
|