Browse Source

common interface for locks

activeAddress
Ivan Socolsky 10 years ago
parent
commit
0631083bae
  1. 34
      lib/locallock.js
  2. 40
      lib/lock.js
  3. 21
      lib/server.js
  4. 16
      lib/utils.js
  5. 4
      test/locallock.js

34
lib/locallock.js

@ -0,0 +1,34 @@
var _ = require('lodash');
var $ = require('preconditions').singleton();
var locks = {};
var Lock = function() {
this.taken = false;
this.queue = [];
};
Lock.prototype.free = function() {
if (this.queue.length > 0) {
var f = this.queue.shift();
f(this);
} else {
this.taken = false;
}
};
Lock.get = function(key, callback) {
if (_.isUndefined(locks[key])) {
locks[key] = new Lock();
}
var lock = locks[key];
if (lock.taken) {
lock.queue.push(callback);
} else {
lock.taken = true;
callback(lock);
}
};
module.exports = Lock;

40
lib/lock.js

@ -1,34 +1,20 @@
var _ = require('lodash');
var $ = require('preconditions').singleton();
var _ = require('lodash');
var LocalLock = require('./locallock');
var RemoteLock = require('locker');
var locks = {};
var Lock = function() {
this.taken = false;
this.queue = [];
};
Lock.prototype.free = function() {
if (this.queue.length > 0) {
var f = this.queue.shift();
f(this);
} else {
this.taken = false;
}
};
function Lock(opts) {};
Lock.get = function(key, callback) {
if (_.isUndefined(locks[key])) {
locks[key] = new Lock();
}
var lock = locks[key];
Lock.prototype.runLocked = function(token, cb, task) {
$.shouldBeDefined(token);
if (lock.taken) {
lock.queue.push(callback);
} else {
lock.taken = true;
callback(lock);
}
LocalLock.get(token, function(lock) {
var _cb = function() {
cb.apply(null, arguments);
lock.free();
};
task(_cb);
});
};
module.exports = Lock;

21
lib/server.js

@ -13,6 +13,7 @@ var Address = Bitcore.Address;
var ClientError = require('./clienterror');
var Utils = require('./utils');
var Lock = require('./lock');
var Storage = require('./storage');
var NotificationBroadcaster = require('./notificationbroadcaster');
var BlockchainExplorer = require('./blockchainexplorer');
@ -24,7 +25,7 @@ var TxProposal = require('./model/txproposal');
var Notification = require('./model/notification');
var initialized = false;
var storage, blockchainExplorer;
var lock, storage, blockchainExplorer;
/**
@ -35,6 +36,7 @@ function WalletService() {
if (!initialized)
throw new Error('Server not initialized');
this.lock = lock;
this.storage = storage;
this.blockchainExplorer = blockchainExplorer;
this.notifyTicker = 0;
@ -52,7 +54,8 @@ WalletService.onNotification = function(func) {
*/
WalletService.initialize = function(opts) {
opts = opts || {};
storage = opts.storage ||  new Storage(opts.storageOpts);
lock = opts.lock || new Lock(opts.lockOpts);
storage = opts.storage || new Storage(opts.storageOpts);
blockchainExplorer = opts.blockchainExplorer;
initialized = true;
};
@ -190,7 +193,7 @@ WalletService.prototype.replaceTemporaryRequestKey = function(opts, cb) {
if (opts.isTemporaryRequestKey)
return cb(new ClientError('Bad arguments'));
Utils.runLocked(self.walletId, cb, function(cb) {
self.lock.runLocked(self.walletId, cb, function(cb) {
self.storage.fetchWallet(self.walletId, function(err, wallet) {
if (err) return cb(err);
@ -298,7 +301,7 @@ WalletService.prototype.joinWallet = function(opts, cb) {
if (_.isEmpty(opts.name))
return cb(new ClientError('Invalid copayer name'));
Utils.runLocked(opts.walletId, cb, function(cb) {
self.lock.runLocked(opts.walletId, cb, function(cb) {
self.storage.fetchWallet(opts.walletId, function(err, wallet) {
if (err) return cb(err);
@ -357,7 +360,7 @@ WalletService.prototype.joinWallet = function(opts, cb) {
WalletService.prototype.createAddress = function(opts, cb) {
var self = this;
Utils.runLocked(self.walletId, cb, function(cb) {
self.lock.runLocked(self.walletId, cb, function(cb) {
self.getWallet({}, function(err, wallet) {
if (err) return cb(err);
if (!wallet.isComplete())
@ -612,7 +615,7 @@ WalletService.prototype.createTx = function(opts, cb) {
if (!Utils.checkRequired(opts, ['toAddress', 'amount', 'proposalSignature']))
return cb(new ClientError('Required argument missing'));
Utils.runLocked(self.walletId, cb, function(cb) {
self.lock.runLocked(self.walletId, cb, function(cb) {
self.getWallet({}, function(err, wallet) {
if (err) return cb(err);
if (!wallet.isComplete()) return cb(new ClientError('Wallet is not complete'));
@ -702,7 +705,7 @@ WalletService.prototype.getTx = function(opts, cb) {
WalletService.prototype.removeWallet = function(opts, cb) {
var self = this;
Utils.runLocked(self.walletId, cb, function(cb) {
self.lock.runLocked(self.walletId, cb, function(cb) {
self.storage.removeWallet(self.walletId, cb);
});
};
@ -720,7 +723,7 @@ WalletService.prototype.removePendingTx = function(opts, cb) {
if (!Utils.checkRequired(opts, ['txProposalId']))
return cb(new ClientError('Required argument missing'));
Utils.runLocked(self.walletId, cb, function(cb) {
self.lock.runLocked(self.walletId, cb, function(cb) {
self.getTx({
txProposalId: opts.txProposalId,
@ -1178,7 +1181,7 @@ WalletService.prototype.scan = function(opts, cb) {
};
Utils.runLocked(self.walletId, cb, function(cb) {
self.lock.runLocked(self.walletId, cb, function(cb) {
self.getWallet({}, function(err, wallet) {
if (err) return cb(err);
if (!wallet.isComplete()) return cb(new ClientError('Wallet is not complete'));

16
lib/utils.js

@ -1,24 +1,8 @@
var $ = require('preconditions').singleton();
var _ = require('lodash');
var Lock = require('./lock');
var Utils = {};
Utils.runLocked = function(token, cb, task) {
var self = this;
$.shouldBeDefined(token);
Lock.get(token, function(lock) {
var _cb = function() {
cb.apply(null, arguments);
lock.free();
};
task(_cb);
});
};
Utils.checkRequired = function(obj, args) {
args = [].concat(args);
if (!_.isObject(obj)) return false;

4
test/lock.js → test/locallock.js

@ -4,9 +4,9 @@ var _ = require('lodash');
var chai = require('chai');
var sinon = require('sinon');
var should = chai.should();
var Lock = require('../lib/lock');
var Lock = require('../lib/locallock');
describe('Lock', function() {
describe('Local lock', function() {
it('should lock tasks using the same token', function(done) {
var a = false,
b = false;
Loading…
Cancel
Save