'use strict' ; import * as vscode from 'vscode' ; import * as sinon from 'sinon' ; import * as path from 'path' ; import * as fs from 'fs-extra' ; import * as chai from 'chai' ; import * as sinonChai from 'sinon-chai' ; import * as chaiAsPromised from 'chai-as-promised' ; import { UserInputUtilHelper } from './userInputUtilHelper' ; import { ExtensionCommands } from '../../ExtensionCommands' ; import { BlockchainGatewayExplorerProvider } from '../../extension/explorer/gatewayExplorer' ; import { BlockchainTreeItem } from '../../extension/explorer/model/BlockchainTreeItem' ; import { UserInputUtil } from '../../extension/commands/UserInputUtil' ; import { FabricEnvironmentRegistry , FabricEnvironmentRegistryEntry , FabricNode , FabricNodeType , FabricWalletRegistry , FabricWalletRegistryEntry , FabricEnvironment , FabricGatewayRegistryEntry , FabricGatewayRegistry } from 'ibm-blockchain-platform-common' ; import { ExtensionUtil } from '../../extension/util/ExtensionUtil' ; import { EnvironmentFactory } from '../../extension/fabric/environments/EnvironmentFactory' ; import { FabricGatewayConnectionManager } from '../../extension/fabric/FabricGatewayConnectionManager' ; chai . use ( sinonChai ) ; chai . use ( chaiAsPromised ) ; export class GatewayHelper { mySandBox : sinon . SinonSandbox ; userInputUtilHelper : UserInputUtilHelper ; constructor ( sandbox , userInputUtilHelper ) { this . mySandBox = sandbox ; this . userInputUtilHelper = userInputUtilHelper ; } public async createGateway ( name , fromEnvironment , environmentName ? , mspId ? , caName ? ) { const blockchainGatewayExplorerProvider = ExtensionUtil . getBlockchainGatewayExplorerProvider ( ) ; const treeItems = await blockchainGatewayExplorerProvider . getChildren ( ) ; const treeItem = treeItems . find ( ( item ) => { return item . gateway && item . gateway . name === name ; } ) ; if ( ! treeItem ) { this . userInputUtilHelper . inputBoxStub . withArgs ( 'Enter a name for the gateway' ) . resolves ( name ) ; if ( ! fromEnvironment ) { this . userInputUtilHelper . showQuickPickStub . resolves ( UserInputUtil . ADD_GATEWAY_FROM_CCP ) ; this . userInputUtilHelper . browseStub . withArgs ( 'Enter a file path to a connection profile file' ) . resolves ( path . join ( this . userInputUtilHelper . cucumberDir , 'hlfv1' , 'connection.json' ) ) ; } else { this . userInputUtilHelper . showQuickPickStub . resolves ( UserInputUtil . ADD_GATEWAY_FROM_ENVIRONMENT ) ; const fabricEnvironmentRegistryEntry = await FabricEnvironmentRegistry . instance ( ) . get ( environmentName ) ; this . userInputUtilHelper . showEnvironmentQuickPickStub . resolves ( { label : environmentName , data : fabricEnvironmentRegistryEntry } ) ; const environment = EnvironmentFactory . getEnvironment ( fabricEnvironmentRegistryEntry ) ; const nodes = await environment . getNodes ( ) ; let peerNode ; if ( mspId ) { peerNode = nodes . find ( ( _node ) => { return _node . type === FabricNodeType . PEER && _node . msp_id === mspId ; } ) ; } else { peerNode = nodes . find ( ( _node ) => { return _node . type === FabricNodeType . PEER ; } ) ; } this . userInputUtilHelper . showOrgQuickPickStub . resolves ( { label : peerNode . msp_id , data : peerNode } ) ; let caNode ; if ( caName ) { caNode = nodes . find ( ( _node ) => { return _node . type === FabricNodeType . CERTIFICATE_AUTHORITY && _node . name === caName ; } ) ; } else { caNode = nodes . find ( ( _node ) => { return _node . type === FabricNodeType . CERTIFICATE_AUTHORITY ; } ) ; } this . userInputUtilHelper . showNodesInEnvironmentQuickPickStub . resolves ( { label : caNode . name , data : caNode } ) ; } await vscode . commands . executeCommand ( ExtensionCommands . ADD_GATEWAY ) ; } } public async connectToFabric ( name , walletName , identityName = 'greenConga' , expectAssociated = true ) { let gatewayEntry ; gatewayEntry = await FabricGatewayRegistry . instance ( ) . get ( name ) ; if ( ! expectAssociated ) { const walletEntry = await FabricWalletRegistry . instance ( ) . get ( walletName , gatewayEntry . fromEnvironment ) ; this . userInputUtilHelper . showWalletsQuickPickStub . resolves ( { name : walletEntry . name , data : walletEntry } ) ; } this . userInputUtilHelper . showIdentitiesQuickPickStub . withArgs ( 'Choose an identity to connect with' ) . resolves ( identityName ) ; await vscode . commands . executeCommand ( ExtensionCommands . CONNECT_TO_GATEWAY , gatewayEntry ) ; } public async submitTransaction ( name , version , contractLanguage , transaction , channel , args , gatewayName , contractName ? , transientData ? , evaluate ? , transactionLabel ? ) { let gatewayEntry ; try { gatewayEntry = await FabricGatewayConnectionManager . instance ( ) . getGatewayRegistryEntry ( ) ; } catch ( error ) { gatewayEntry = new FabricGatewayRegistryEntry ( ) ; gatewayEntry . name = gatewayName ; gatewayEntry . associatedWallet = 'Org1' ; } if ( process . env . OPSTOOLS_FABRIC ) { this . userInputUtilHelper . showChannelFromGatewayQuickPickBoxStub . withArgs ( 'Choose a channel to select a smart contract from' ) . resolves ( { label : channel , data : [ 'Org1 Peer' , 'Org2 Peer' ] } ) ; } if ( gatewayEntry . transactionDataDirectories ) { if ( transactionLabel !== undefined ) { interface ITransactionData { transactionName : string ; transactionLabel ? : string ; arguments ? : string [ ] ; transientData ? : any ; } const txdataFilePath = path . join ( gatewayEntry . transactionDataDirectories [ 0 ] . transactionDataPath , 'conga-transactions.txdata' ) ; const fileJson = await fs . readJSON ( txdataFilePath ) ; const chosenTransaction = fileJson . find ( ( txdata ) => { return txdata . transactionLabel === transactionLabel ; } ) ; this . userInputUtilHelper . showQuickPickItemStub . withArgs ( 'Do you want to provide a file of transaction data for this transaction?' ) . resolves ( { label : txdataFilePath , description : chosenTransaction . transactionLabel , data : chosenTransaction } ) ; } else { this . userInputUtilHelper . showQuickPickItemStub . withArgs ( 'Do you want to provide a file of transaction data for this transaction?' ) . resolves ( { label : 'No (manual entry)' , description : '' , data : undefined } ) ; } } this . userInputUtilHelper . showGatewayQuickPickStub . resolves ( { label : gatewayName , data : gatewayEntry } ) ; if ( contractLanguage === 'Go' || contractLanguage === 'Java' ) { this . userInputUtilHelper . showClientInstantiatedSmartContractsStub . resolves ( { label : `${ name }@${ version }` , data : { name : name , channel : channel , version : version } } ) ; this . userInputUtilHelper . showTransactionStub . resolves ( { label : null , data : { name : transaction , contract : null } } ) ; } else { this . userInputUtilHelper . showClientInstantiatedSmartContractsStub . resolves ( { label : `${ name }@${ version }` , data : { name : name , channel : channel , version : version } } ) ; this . userInputUtilHelper . showTransactionStub . resolves ( { label : `${ name } - ${ transaction }` , data : { name : transaction , contract : contractName } } ) ; } this . userInputUtilHelper . inputBoxStub . withArgs ( 'optional: What are the arguments to the transaction, (e.g. ["arg1", "arg2"])' ) . resolves ( args ) ; if ( ! transientData ) { transientData = '' ; } const transientDataWithoutQuotes = transientData . slice ( 1 , - 1 ) ; this . userInputUtilHelper . inputBoxStub . withArgs ( 'optional: What is the transient data for the transaction, e.g. {"key": "value"}' , '{}' ) . resolves ( transientDataWithoutQuotes ) ; this . userInputUtilHelper . showQuickPickStub . withArgs ( 'Select a peer-targeting policy for this transaction' , [ UserInputUtil . DEFAULT , UserInputUtil . CUSTOM ] ) . resolves ( UserInputUtil . DEFAULT ) ; if ( evaluate ) { await vscode . commands . executeCommand ( ExtensionCommands . EVALUATE_TRANSACTION ) ; } else { await vscode . commands . executeCommand ( ExtensionCommands . SUBMIT_TRANSACTION ) ; } } public async exportConnectionProfile ( gatewayName ) { const gatewayEntry = await FabricGatewayRegistry . instance ( ) . get ( gatewayName ) ; const profilePath = path . join ( this . userInputUtilHelper . cucumberDir , 'tmp' , 'profiles' ) ; await fs . ensureDir ( profilePath ) ; const profileFile = path . join ( profilePath , `${ gatewayEntry . name }_connection.json` ) ; const profileUri = vscode . Uri . file ( profileFile ) ; this . userInputUtilHelper . showSaveDialogStub . withArgs ( sinon . match . any ) . resolves ( profileUri ) ; this . userInputUtilHelper . showGatewayQuickPickStub . resolves ( { label : gatewayEntry . name , data : gatewayEntry } ) ; this . userInputUtilHelper . getWorkspaceFoldersStub . callThrough ( ) ; await vscode . commands . executeCommand ( ExtensionCommands . EXPORT_CONNECTION_PROFILE ) ; } public async associateTransactionDataDirectory ( name , version , gatewayName ) { let gatewayEntry ; try { gatewayEntry = await FabricGatewayConnectionManager . instance ( ) . getGatewayRegistryEntry ( ) ; } catch ( error ) { gatewayEntry = new FabricGatewayRegistryEntry ( ) ; gatewayEntry . name = gatewayName ; gatewayEntry . associatedWallet = 'Org1' ; } this . userInputUtilHelper . showClientInstantiatedSmartContractsStub . resolves ( { label : `${ name }@${ version }` , data : { name : name , channel : 'mychannel' , version : version } } ) ; const contractDirectory = path . join ( __dirname , '..' , '..' , '..' , 'cucumber' , 'tmp' , 'contracts' , name ) ; const workspaceFolder = { index : 0 , name : name , uri : vscode . Uri . file ( contractDirectory ) } ; this . userInputUtilHelper . getWorkspaceFoldersStub . returns ( [ workspaceFolder ] ) ; this . userInputUtilHelper . browseWithOptionsStub . resolves ( { description : path . join ( contractDirectory , 'transaction_data' ) } ) ; await vscode . commands . executeCommand ( ExtensionCommands . ASSOCIATE_TRANSACTION_DATA_DIRECTORY ) ; } }