Skip to content

Commit

Permalink
updates to remove promisification (hyperledger-archives#4134)
Browse files Browse the repository at this point in the history
Signed-off-by: Matthew B White <[email protected]>
  • Loading branch information
mbwhite authored and cazfletch committed Jun 12, 2018
1 parent 2f143b3 commit 3588d51
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,8 @@ class HLFConnectionManager extends ConnectionManager {
});
LOG.exit(method);
} catch (error) {
let newError = `Failed to import identity. ${error}`;
let newError = new Error(`Failed to import identity. ${error}`);
newError.cause = error;
LOG.error(method, newError);
throw newError;
}
Expand Down
144 changes: 79 additions & 65 deletions packages/composer-wallet-filesystem/lib/filesystemwallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,10 @@
const Wallet = require('composer-common').Wallet;
const nodefs = require('fs');
const path = require('path');
const util = require('util');
const composerUtil = require('composer-common').Util;
const mkdirp = require('mkdirp');
const IdCard = require('composer-common').IdCard;
const rimraf = util.promisify(require('rimraf'));
const rimraf = require('rimraf');
/**
* String based key-val store, A 'client-data' directory is created under the storePath option (or ~/.composer)
* @private
Expand All @@ -48,12 +47,19 @@ class FileSystemWallet extends Wallet{
* @return {boolean} true if directory, false otherwise
*/
_isDirectory(name){
return this._stat(this._path(name))
.then(status=>{
return status.isDirectory();

return new Promise((resolve,reject)=>{
this.fs.stat(this._path(name),(err,status)=>{
if (err){
resolve(false);
}else {
resolve(status.isDirectory());
}
});
});

}

/**
* @param {Object} options Configuration options
* @param {Object} options.storePath The root directory where this wallet can put things
Expand All @@ -62,18 +68,14 @@ class FileSystemWallet extends Wallet{
*/
constructor(options){
super();

let root = options.storePath || path.resolve(composerUtil.homeDirectory(),'.composer');
this.storePath = path.join(root,options.namePrefix);
let prefix = options.namePrefix || '';
this.storePath = path.join(root,prefix);

this.fs = options.fs || nodefs;
mkdirp.sync(this.storePath,{fs:this.fs});

this._readFile = util.promisify(this.fs.readFile);
this._writeFile = util.promisify(this.fs.writeFile);
this._stat = util.promisify(this.fs.stat);
this._readdir = util.promisify(this.fs.readdir);
this._unlink = util.promisify(this.fs.unlink);

this.rimrafOptions = Object.assign({}, this.fs);
this.rimrafOptions.disableGlob = true;
}
Expand All @@ -86,34 +88,40 @@ class FileSystemWallet extends Wallet{
* error.
*/
listNames() {
return this._readdir(this.storePath)
.then((result)=>{

return result;
});
return new Promise((resolve,reject)=>{
try {
resolve(this.fs.readdirSync(this.storePath));
} catch (err){
reject(err);
}
});

}

/**
* Check to see if the named credentials are in
* the wallet.
* Check to see if the named keys is in the wallet.
*
* @abstract
* @param {string} name The name of the credentials.
* @return {Promise} A promise that is resolved with
* a boolean; true if the named credentials are in the
* a boolean; true if the named key is in the
* wallet, false otherwise.
*/
contains(name) {
if (!name) {
return Promise.reject(new Error('Name must be specified'));
}
return this._stat(this._path(name))
.then(()=>{
return true;
})
.catch((error)=>{
return false;
});

return new Promise((resolve,reject)=>{
this.fs.stat(this._path(name),(err)=>{
if (err){
resolve(false);
}else {
resolve(true);
}
});
});

}

Expand All @@ -124,28 +132,23 @@ class FileSystemWallet extends Wallet{
* @return {Promise} A promise that is resolved with
* the named credentials, or rejected with an error.
*/
get(name) {
async get(name) {
if (!name) {
return Promise.reject(new Error('Name must be specified'));
}
return this._isDirectory(this._path(name))
.then((dir)=>{
if(dir){
return IdCard.fromDirectory(this._path(name), this.fs)
.then((card)=>{
return card.toArchive({ type: 'nodebuffer' });
});
} else {
return this._readFile(this._path(name),'utf8')
.then((result)=>{
if (result.startsWith('BASE64')){
return Buffer.from(result.replace('BASE64::',''),'base64');
}
return result;
});

let dir = await this._isDirectory(this._path(name));
if(dir){
let card = await IdCard.fromDirectory(this._path(name), this.fs);
return card.toArchive({ type: 'nodebuffer' });
} else {
let result = this.fs.readFileSync(this._path(name),'utf8');
if (result.startsWith('BASE64')){
return Buffer.from(result.replace('BASE64::',''),'base64');
}
return result;
}

});
}

/**
Expand All @@ -166,46 +169,57 @@ class FileSystemWallet extends Wallet{
return card.toDirectory(this._path(name));

} else if (value instanceof Buffer){
// base 64 encode the buffer and write it as a string.
return this._writeFile(this._path(name),'BASE64::'+value.toString('base64'));
return new Promise((resolve,reject)=>{
this.fs.writeFile(this._path(name),'BASE64::'+value.toString('base64'),(err)=>{
if (err){
reject(err);
} else {
resolve();
}
});
});

} else if (value instanceof String || typeof value === 'string'){
return this._writeFile(this._path(name),value);
return new Promise((resolve,reject)=>{
this.fs.writeFile(this._path(name),value,(err)=>{
if (err){
reject(err);
} else {
resolve();
}
});
});
} else {
return Promise.reject(new Error('Unkown type being stored'));
}
}



/**
* Remove existing credentials from the wallet.
* @abstract
* @param {string} name The name of the credentials.
* @return {Promise} A promise that is resolved when
* complete, or rejected with an error.
*/
remove(name) {
async remove(name) {
if (!name) {
return Promise.reject(new Error('Name must be specified'));
}
return this.contains(name).then(
(result)=>{
if (result){
return this._isDirectory(name)
.then((dir)=>{
if(dir){
return rimraf(this._path(name),this.rimrafOptions);
}else {
return this._unlink(this._path(name));
}
}).then(()=>{return true;});
} else {
return false;
}
}
);

let result = await this.contains(name);
if (result){
let dir = await this._isDirectory(name);

if(dir){
rimraf.sync(this._path(name),this.rimrafOptions);
}else {
this.fs.unlinkSync(this._path(name));
}
return true;

} else {
return false;
}
}

/**
Expand Down
8 changes: 4 additions & 4 deletions packages/composer-wallet-filesystem/test/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ const path= require('path');
module.exports.getStore = require('../index.js').getStore;
module.exports.wrongConfigs = [
{ c: null, text: 'Cannot read property' },
{ c: {}, text: 'Path must be a string' },
{ c: { storePath : '/nothere' }, text: 'Path'}
{ c: { storePath : {} }, text: 'Path must be a string' },
{ c: { storePath : '/nothere' }, text: 'permission denied'}
];
module.exports.correctConfigs=[
{ c: null, text: 'Need configuration' },
{ c: { storePath : '/tmp' }, text: 'custom location'}
{ c: {}, text: 'Default Locations' },
{ c: { storePath : '/tmp/filestemwallet' }, text: 'custom location'}
];
module.exports.clean=async ()=>{
await rimraf('/tmp/filestemwallet');
Expand Down
28 changes: 25 additions & 3 deletions packages/composer-wallet-filesystem/test/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const expect = chai.expect;
chai.use(require('chai-as-promised'));
chai.use(require('chai-things'));
const sinon = require('sinon');
const fs = require('fs');

const CLOUD_CONFIG = require('./config');
const cloneDeep = require('lodash').cloneDeep;
Expand All @@ -32,9 +33,13 @@ describe('Composer wallet implementation', function () {
describe('Wrong Config settings', function () {

CLOUD_CONFIG.wrongConfigs.forEach((cfg) => {
it('should fail to create with faulty config', function () {
it(`should fail to create with faulty config: \"${cfg.text}\"`, function () {
(function () {
CLOUD_CONFIG.getStore(cfg.c);
try {
CLOUD_CONFIG.getStore(cfg.c);
} catch (err){
throw err;
}
}).should.throw(Error, cfg.text);

});
Expand All @@ -51,7 +56,7 @@ describe('Composer wallet implementation', function () {
let wallet;
beforeEach(async () => {
sandbox = sinon.sandbox.create();
let config = cfg;
let config = cfg.c;
config.namePrefix = 'testing';

await CLOUD_CONFIG.clean();
Expand All @@ -64,6 +69,10 @@ describe('Composer wallet implementation', function () {
});

describe('#listNames', async function () {
it('should be rejected if an error', async function () {
sandbox.stub(fs,'readdirSync').throws(new Error('Error'));
return wallet.listNames().should.be.rejectedWith(/Error/);
});
it('should return empty list for nothing present', async function () {
let result = await wallet.listNames();
return expect(result).to.be.an('array').that.is.empty;
Expand All @@ -73,6 +82,7 @@ describe('Composer wallet implementation', function () {
await wallet.put('Batman-Reloaded', 'It\'s not who I am underneath, but what I do that defines me');

let result = await wallet.listNames();

let expected = ['Batman-Original','Batman-Reloaded'];
expect(result).to.be.an('array');
expect(result.length).to.equal(2);
Expand Down Expand Up @@ -189,6 +199,18 @@ describe('Composer wallet implementation', function () {
let Umbrella = class Umbrella { };
return wallet.put('ThePenguin', new Umbrella()).should.be.rejectedWith('Unkown type being stored');
});

it('should return error if unable to write to the filesystem (for string values)', async function(){
sandbox.stub(fs,'writeFile').callsArgWith(2,new Error('Alfred says no'));
return wallet.put('Batman','I only work in black and sometimes very, very dark grey.').should.be.rejectedWith('Alfred says no');
});

it('should return error if unable to write to the filesystem (for buffer values)', async function () {
sandbox.stub(fs,'writeFile').callsArgWith(2,new Error('Alfred says no'));
// Creates a Buffer containing [0x1, 0x2, 0x3].
const buffer = Buffer.from([1, 2, 3]);
return wallet.put('Batman', buffer).should.be.rejectedWith('Alfred says no');
});
});
});

Expand Down

0 comments on commit 3588d51

Please sign in to comment.