Merge pull request #70 from ryanxcharles/feature/command-line-3
Command Line Interface #3
This commit is contained in:
commit
4e4dd249a8
10 changed files with 295 additions and 53 deletions
22
API.js
22
API.js
|
|
@ -10,23 +10,13 @@ API.prototype._init = function(opts) {
|
|||
opts = opts || {};
|
||||
self.opts = opts;
|
||||
|
||||
var Wallet = require('soop').load('./js/models/core/Wallet', {
|
||||
var WalletFactory = require('soop').load('./js/models/core/WalletFactory', {
|
||||
Storage: opts.Storage || require('./test/mocks/FakeStorage'),
|
||||
Network: opts.Network || require('./js/models/network/WebRTC'),
|
||||
Network: opts.Network || require('./js/models/network/Base'),
|
||||
Blockchain: opts.Blockchain || require('./js/models/blockchain/Insight')
|
||||
});
|
||||
|
||||
var config = {
|
||||
wallet: {
|
||||
requiredCopayers: opts.requiredCopayers || 3,
|
||||
totalCopayers: opts.totalCopayers || 5,
|
||||
}
|
||||
};
|
||||
|
||||
var walletConfig = opts.walletConfig || config;
|
||||
var walletOpts = opts.walletOpts || {};
|
||||
|
||||
self.wallet = self.opts.wallet || Wallet.factory.create(walletConfig, walletOpts);
|
||||
this.walletFactory = new WalletFactory(opts);
|
||||
};
|
||||
|
||||
API._coerceArgTypes = function(args, argTypes) {
|
||||
|
|
@ -179,13 +169,13 @@ API.prototype.getCommands = decorate('getCommands', [
|
|||
['callback', 'function']
|
||||
]);
|
||||
|
||||
API.prototype._cmd_getPublicKeyRingId = function(callback) {
|
||||
API.prototype._cmd_getWalletIds = function(callback) {
|
||||
var self = this;
|
||||
|
||||
return callback(null, self.wallet.publicKeyRing.walletId);
|
||||
return callback(null, self.walletFactory.getWalletIds());
|
||||
};
|
||||
|
||||
API.prototype.getPublicKeyRingId = decorate('getPublicKeyRingId', [
|
||||
API.prototype.getWalletIds = decorate('getWalletIds', [
|
||||
['callback', 'function']
|
||||
]);
|
||||
|
||||
|
|
|
|||
|
|
@ -18,11 +18,10 @@ var main = function() {
|
|||
var api = new API(commander);
|
||||
|
||||
var args = commander.args;
|
||||
var command = args[0];
|
||||
var commandArgs = args.slice(1);
|
||||
|
||||
try {
|
||||
var command = args[0];
|
||||
var commandArgs = args.slice(1);
|
||||
|
||||
if (command[0] == '_' || typeof api[command] != 'function')
|
||||
throw new Error('invalid command');
|
||||
|
||||
|
|
|
|||
|
|
@ -110,7 +110,6 @@ WalletFactory.prototype.create = function(opts) {
|
|||
opts.totalCopayers = totalCopayers;
|
||||
var w = new Wallet(opts);
|
||||
w.store();
|
||||
this.addWalletId(w.id);
|
||||
return w;
|
||||
};
|
||||
|
||||
|
|
@ -156,28 +155,11 @@ WalletFactory.prototype.openRemote = function(peedId) {
|
|||
};
|
||||
|
||||
WalletFactory.prototype.getWalletIds = function() {
|
||||
var ids = this.storage.getGlobal('walletIds');
|
||||
return ids || [];
|
||||
return this.storage.getWalletIds();
|
||||
}
|
||||
|
||||
WalletFactory.prototype._delWalletId = function(walletId) {
|
||||
var ids = this.getWalletIds();
|
||||
var index = ids.indexOf(walletId);
|
||||
if (index === -1) return;
|
||||
ids.splice(index, 1); // removes walletId
|
||||
this.storage.setGlobal('walletIds', ids);
|
||||
};
|
||||
|
||||
WalletFactory.prototype.remove = function(walletId) {
|
||||
WalletFactory._delWalletId(walletId);
|
||||
// TODO remove wallet contents, not only the id (Wallet.remove?)
|
||||
};
|
||||
|
||||
WalletFactory.prototype.addWalletId = function(walletId) {
|
||||
var ids = this.getWalletIds();
|
||||
if (ids.indexOf(walletId) !== -1) return;
|
||||
ids.push(walletId);
|
||||
this.storage.setGlobal('walletIds', ids);
|
||||
// TODO remove wallet contents
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@ Storage.prototype.set = function(walletId,v) {
|
|||
Storage.prototype.remove = function(walletId, k) {
|
||||
};
|
||||
|
||||
Storage.prototype.getWalletIds = function() {
|
||||
};
|
||||
|
||||
// remove all values
|
||||
Storage.prototype.clearAll = function() {
|
||||
};
|
||||
|
|
|
|||
102
js/models/storage/File.js
Normal file
102
js/models/storage/File.js
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
'use strict';
|
||||
var imports = require('soop').imports();
|
||||
var fs = imports.fs || require('fs');
|
||||
|
||||
function Storage(opts) {
|
||||
opts = opts || {};
|
||||
|
||||
this.data = {};
|
||||
}
|
||||
|
||||
Storage.prototype.load = function(walletId, callback) {
|
||||
fs.readFile(walletId, function(err, data) {
|
||||
if (err) return callback(err);
|
||||
|
||||
try {
|
||||
this.data[walletId] = JSON.parse(data);
|
||||
} catch (err) {
|
||||
if (callback)
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (callback)
|
||||
return callback(null);
|
||||
});
|
||||
};
|
||||
|
||||
Storage.prototype.save = function(walletId, callback) {
|
||||
var data = JSON.stringify(this.data[walletId]);
|
||||
|
||||
//TODO: update to use a queue to ensure that saves are made sequentially
|
||||
fs.writeFile(walletId, data, function(err) {
|
||||
if (callback)
|
||||
return callback(err);
|
||||
});
|
||||
};
|
||||
|
||||
Storage.prototype._read = function(k) {
|
||||
var split = k.split('::');
|
||||
var walletId = split[0];
|
||||
var key = split[1];
|
||||
return this.data[walletId][key];
|
||||
};
|
||||
|
||||
Storage.prototype._write = function(k, v, callback) {
|
||||
var split = k.split('::');
|
||||
var walletId = split[0];
|
||||
var key = split[1];
|
||||
if (!this.data[walletId])
|
||||
this.data[walletId] = {};
|
||||
this.data[walletId][key] = v;
|
||||
this.save(walletId, callback);
|
||||
};
|
||||
|
||||
// get value by key
|
||||
Storage.prototype.getGlobal = function(k) {
|
||||
return this._read(k);
|
||||
};
|
||||
|
||||
// set value for key
|
||||
Storage.prototype.setGlobal = function(k, v, callback) {
|
||||
this._write(k, v, callback);
|
||||
};
|
||||
|
||||
// remove value for key
|
||||
Storage.prototype.removeGlobal = function(k, callback) {
|
||||
var split = k.split('::');
|
||||
var walletId = split[0];
|
||||
var key = split[1];
|
||||
delete this.data[walletId][key];
|
||||
this.save(walletId, callback);
|
||||
};
|
||||
|
||||
Storage.prototype._key = function(walletId, k) {
|
||||
return walletId + '::' + k;
|
||||
};
|
||||
|
||||
// get value by key
|
||||
Storage.prototype.get = function(walletId, k) {
|
||||
return this.getGlobal(this._key(walletId, k));
|
||||
};
|
||||
|
||||
// set value for key
|
||||
Storage.prototype.set = function(walletId, k, v, callback) {
|
||||
this.setGlobal(this._key(walletId,k), v, callback);
|
||||
};
|
||||
|
||||
// remove value for key
|
||||
Storage.prototype.remove = function(walletId, k, callback) {
|
||||
this.removeGlobal(this._key(walletId, k), callback);
|
||||
};
|
||||
|
||||
Storage.prototype.getWalletIds = function() {
|
||||
return [];
|
||||
};
|
||||
|
||||
// remove all values
|
||||
Storage.prototype.clearAll = function(callback) {
|
||||
this.data = {};
|
||||
this.save(callback);
|
||||
};
|
||||
|
||||
module.exports = require('soop')(Storage);
|
||||
|
|
@ -52,6 +52,21 @@ Storage.prototype.remove = function(walletId, k) {
|
|||
this.removeGlobal(this._key(walletId,k));
|
||||
};
|
||||
|
||||
Storage.prototype.getWalletIds = function() {
|
||||
var walletIds = [];
|
||||
|
||||
for (var i = 0; i < localStorage.length; i++) {
|
||||
var key = localStorage.key(i);
|
||||
var split = key.split('::');
|
||||
if (split.length == 2) {
|
||||
var walletId = split[0];
|
||||
walletIds.push(walletId);
|
||||
}
|
||||
}
|
||||
|
||||
return walletIds;
|
||||
};
|
||||
|
||||
// remove all values
|
||||
Storage.prototype.clearAll = function() {
|
||||
localStorage.clear();
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
"uglifyify": "~1.2.3",
|
||||
"soop": "~0.1.5",
|
||||
"bitcore": "git://github.com/maraoz/bitcore.git#5e636f6b9c7f8e629b1a502025556e886c3b75e1",
|
||||
"chai": "~1.9.1"
|
||||
"chai": "~1.9.1",
|
||||
"sinon": "~1.9.1"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,4 +23,8 @@ FakeStorage.prototype.clear = function() {
|
|||
delete this['storage'];
|
||||
}
|
||||
|
||||
FakeStorage.prototype.getWalletIds = function() {
|
||||
return [];
|
||||
};
|
||||
|
||||
module.exports = require('soop')(FakeStorage);
|
||||
|
|
|
|||
|
|
@ -4,11 +4,13 @@ var chai = chai || require('chai');
|
|||
var should = chai.should();
|
||||
var copay = copay || require('../copay');
|
||||
var API = API || copay.API;
|
||||
var Storage = Storage || require('../test/mocks/FakeStorage');
|
||||
|
||||
describe('API', function() {
|
||||
|
||||
it('should have a command called "echo"', function() {
|
||||
var api = new API();
|
||||
|
||||
var api = new API({Storage: Storage});
|
||||
should.exist(api.echo);
|
||||
});
|
||||
|
||||
|
|
@ -22,7 +24,7 @@ describe('API', function() {
|
|||
})
|
||||
|
||||
it('should throw an error for all commands when called with wrong number of arguments', function() {
|
||||
var api = new API();
|
||||
var api = new API({Storage: Storage});
|
||||
for (var i in API.prototype) {
|
||||
var f = API.prototype[i];
|
||||
if (i[0] != '_' && typeof f == 'function') {
|
||||
|
|
@ -49,7 +51,7 @@ describe('API', function() {
|
|||
|
||||
describe('#echo', function() {
|
||||
it('should echo a string', function(done) {
|
||||
var api = new API();
|
||||
var api = new API({Storage: Storage});
|
||||
var str = 'mystr';
|
||||
api.echo(str, function(err, result) {
|
||||
result.should.equal(str);
|
||||
|
|
@ -60,7 +62,7 @@ describe('API', function() {
|
|||
|
||||
describe('#echoNumber', function() {
|
||||
it('should echo a number', function(done) {
|
||||
var api = new API();
|
||||
var api = new API({Storage: Storage});
|
||||
var num = 500;
|
||||
api.echoNumber(num, function(err, result) {
|
||||
result.should.equal(num);
|
||||
|
|
@ -72,7 +74,7 @@ describe('API', function() {
|
|||
|
||||
describe('#echoObject', function() {
|
||||
it('should echo an object', function(done) {
|
||||
var api = new API();
|
||||
var api = new API({Storage: Storage});
|
||||
var obj = {test:'test'};
|
||||
api.echoObject(obj, function(err, result) {
|
||||
result.test.should.equal(obj.test);
|
||||
|
|
@ -84,7 +86,7 @@ describe('API', function() {
|
|||
|
||||
describe('#getArgTypes', function() {
|
||||
it('should get the argTypes of echo', function(done) {
|
||||
var api = new API();
|
||||
var api = new API({Storage: Storage});
|
||||
api.getArgTypes('echo', function(err, result) {
|
||||
result[0][1].should.equal('string');
|
||||
done();
|
||||
|
|
@ -94,7 +96,7 @@ describe('API', function() {
|
|||
|
||||
describe('#getCommands', function() {
|
||||
it('should get all the commands', function(done) {
|
||||
var api = new API();
|
||||
var api = new API({Storage: Storage});
|
||||
var n = 0;
|
||||
|
||||
for (var i in api)
|
||||
|
|
@ -108,11 +110,11 @@ describe('API', function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe('#getPublicKeyRingId', function() {
|
||||
it('should get a public key ring ID', function(done) {
|
||||
var api = new API();
|
||||
api.getPublicKeyRingId(function(err, result) {
|
||||
result.length.should.be.greaterThan(5);
|
||||
describe('#getWalletIds', function() {
|
||||
it('should get the wallet ids', function(done) {
|
||||
var api = new API({Storage: Storage});
|
||||
api.getWalletIds(function(err, result) {
|
||||
result.length.should.be.greaterThan(-1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
|
@ -120,7 +122,7 @@ describe('API', function() {
|
|||
|
||||
describe('#help', function() {
|
||||
it('should call _cmd_getCommands', function(done) {
|
||||
var api = new API();
|
||||
var api = new API({Storage: Storage});
|
||||
api._cmd_getCommands = function(callback) {
|
||||
(typeof arguments[0]).should.equal('function');
|
||||
callback(null, ['item']);
|
||||
|
|
|
|||
144
test/test.storage.File.js
Normal file
144
test/test.storage.File.js
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
'use strict';
|
||||
|
||||
var chai = chai || require('chai');
|
||||
var should = chai.should();
|
||||
var Storage = Storage || require('../js/models/storage/File.js');
|
||||
var sinon = sinon || require('sinon');
|
||||
|
||||
describe('Storage/File', function() {
|
||||
it('should exist', function() {
|
||||
should.exist(Storage);
|
||||
});
|
||||
|
||||
describe('#load', function(done) {
|
||||
it('should call fs.readFile', function(done) {
|
||||
var fs = {}
|
||||
fs.readFile = function(filename, callback) {
|
||||
filename.should.equal('myfilename');
|
||||
callback();
|
||||
};
|
||||
var Storage = require('soop').load('../js/models/storage/File.js', {fs: fs});
|
||||
var storage = new Storage({password: 'password'});
|
||||
storage.load('myfilename', function(err) {
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#save', function(done) {
|
||||
it('should call fs.writeFile', function(done) {
|
||||
var fs = {}
|
||||
fs.writeFile = function(filename, data, callback) {
|
||||
filename.should.equal('myfilename');
|
||||
callback();
|
||||
};
|
||||
var Storage = require('soop').load('../js/models/storage/File.js', {fs: fs});
|
||||
var storage = new Storage({password: 'password'});
|
||||
storage.save('myfilename', function(err) {
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#_read', function() {
|
||||
it('should return the value of a key', function() {
|
||||
var storage = new Storage();
|
||||
storage.data = {'walletId':{'test':'data'}};
|
||||
storage._read('walletId::test').should.equal('data');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#_write', function() {
|
||||
it('should save the value of a key and then run save', function(done) {
|
||||
var storage = new Storage();
|
||||
storage.save = function(walletId, callback) {
|
||||
storage.data[walletId]['key'].should.equal('value');
|
||||
callback();
|
||||
};
|
||||
storage._write('walletId::key', 'value', function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getGlobal', function() {
|
||||
it('should call storage._read', function() {
|
||||
var storage = new Storage();
|
||||
storage.data = {'walletId':{'test':'test'}};
|
||||
storage._read = sinon.spy();
|
||||
storage.getGlobal('walletId::test');
|
||||
storage._read.calledOnce.should.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#setGlobal', function() {
|
||||
it('should store a global key', function(done) {
|
||||
var storage = new Storage();
|
||||
storage.save = function(walletId, callback) {
|
||||
storage.data[walletId]['key'].should.equal('value');
|
||||
callback();
|
||||
};
|
||||
storage.setGlobal('walletId::key', 'value', function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#removeGlobal', function() {
|
||||
it('should remove a global key', function(done) {
|
||||
var storage = new Storage();
|
||||
storage.data = {'walletId':{'key':'value'}};
|
||||
storage.save = function(walletId, callback) {
|
||||
should.not.exist(storage.data[walletId]['key']);
|
||||
callback();
|
||||
};
|
||||
storage.removeGlobal('walletId::key', function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#_key', function() {
|
||||
it('should merge the wallet id and item key', function() {
|
||||
var storage = new Storage();
|
||||
storage._key('wallet', 'key').should.equal('wallet::key');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#get', function() {
|
||||
it('should call getGlobal with the correct key', function() {
|
||||
var storage = new Storage();
|
||||
storage.getGlobal = sinon.spy();
|
||||
storage.get('wallet', 'key');
|
||||
storage.getGlobal.calledOnce.should.equal(true);
|
||||
storage.getGlobal.calledWith('wallet::key').should.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#set', function() {
|
||||
it('should call setGlobal with the correct key', function() {
|
||||
var storage = new Storage();
|
||||
storage.setGlobal = sinon.spy();
|
||||
storage.set('wallet', 'key');
|
||||
storage.setGlobal.calledOnce.should.equal(true);
|
||||
storage.setGlobal.calledWith('wallet::key').should.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#remove', function() {
|
||||
it('should call removeGlobal with the correct key', function() {
|
||||
var storage = new Storage();
|
||||
storage.removeGlobal = sinon.spy();
|
||||
storage.remove('wallet', 'key');
|
||||
storage.removeGlobal.calledOnce.should.equal(true);
|
||||
storage.removeGlobal.calledWith('wallet::key').should.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#clearAll', function() {
|
||||
it('should set data to {}', function() {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue