'use strict' ; import * as vscode from 'vscode' ; import { BlockchainTreeItem } from './model/BlockchainTreeItem' ; import { BlockchainExplorerProvider } from './BlockchainExplorerProvider' ; import { WalletTreeItem } from './wallets/WalletTreeItem' ; import { LocalWalletTreeItem } from './wallets/LocalWalletTreeItem' ; import { FabricCertificate , Attribute , FabricWalletRegistry , FabricWalletRegistryEntry , IFabricWalletGenerator , IFabricWallet , LogType , FabricWalletGeneratorFactory , FabricNode , FabricEnvironmentRegistryEntry , FabricEnvironmentRegistry , FabricEnvironment , FabricIdentity , EnvironmentType } from 'ibm-blockchain-platform-common' ; import { VSCodeBlockchainOutputAdapter } from '../logging/VSCodeBlockchainOutputAdapter' ; import { IdentityTreeItem } from './model/IdentityTreeItem' ; import { AdminIdentityTreeItem } from './model/AdminIdentityTreeItem' ; import { TextTreeItem } from './model/TextTreeItem' ; import { WalletGroupTreeItem } from './model/WalletGroupTreeItem' ; import { ExplorerUtil } from '../util/ExplorerUtil' ; import { EnvironmentFactory } from '../fabric/environments/EnvironmentFactory' ; import { LocalMicroEnvironmentManager } from '../fabric/environments/LocalMicroEnvironmentManager' ; import { LocalMicroEnvironment } from '../fabric/environments/LocalMicroEnvironment' ; import { FabricWalletHelper } from '../fabric/FabricWalletHelper' ; export class BlockchainWalletExplorerProvider implements BlockchainExplorerProvider { public tree : Array < BlockchainTreeItem > = [ ] ; private _onDidChangeTreeData : vscode . EventEmitter < any | undefined > = new vscode . EventEmitter < any | undefined > ( ) ; readonly onDidChangeTreeData : vscode . Event < any | undefined > = this . _onDidChangeTreeData . event ; getTreeItem ( element ) { return element ; } async getChildren ( element ? ) { const outputAdapter = VSCodeBlockchainOutputAdapter . instance ( ) ; try { if ( element ) { if ( element instanceof WalletTreeItem || element instanceof LocalWalletTreeItem ) { this . tree = await this . createIdentityTree ( element ) ; } if ( element instanceof WalletGroupTreeItem ) { this . tree = await this . populateWallets ( element . wallets ) ; } } else { this . tree = await this . createWalletTree ( ) ; } } catch ( error ) { outputAdapter . log ( LogType . ERROR , `Error displaying Fabric Wallets: ${ error . message }` , `Error displaying Fabric Wallets: ${ error . message }` ) ; } return this . tree ; } async refresh ( element ? ) { this . _onDidChangeTreeData . fire ( element ) ; } private async createWalletTree ( ) { const tree = [ ] ; let walletRegistryEntries = await FabricWalletRegistry . instance ( ) . getAll ( ) ; walletRegistryEntries = await this . updateWalletEnvironmentGroups ( walletRegistryEntries ) ; const newEntries = [ ] ; for ( const _entry of walletRegistryEntries ) { try { const walletGenerator = FabricWalletGeneratorFactory . getFabricWalletGenerator ( ) ; await walletGenerator . getWallet ( _entry ) ; newEntries . push ( _entry ) ; } catch ( err ) { } } walletRegistryEntries = newEntries ; const walletGroups = [ ] ; const otherWallets = [ ] ; let totalWallets = walletRegistryEntries . length ; while ( 0 < totalWallets ) { const wallet = walletRegistryEntries [ 0 ] ; if ( ! wallet . fromEnvironment && ( ! wallet . environmentGroups || wallet . environmentGroups . length < 1 ) ) { otherWallets . push ( wallet ) ; walletRegistryEntries . splice ( 0 , 1 ) ; totalWallets -- ; } else { const group = [ wallet ] ; let pushToOtherWallets = false ; if ( wallet . environmentGroups ) { pushToOtherWallets = ( wallet . environmentGroups . length > 1 ) ? true : false ; } let otherGroupWallets = [ ] ; if ( ! wallet . environmentGroups ) { otherGroupWallets = walletRegistryEntries . filter ( ( entry , index ) => { if ( index > 0 && entry . environmentGroups ) { if ( wallet . fromEnvironment === entry . environmentGroups [ 0 ] || wallet . fromEnvironment === entry . fromEnvironment ) { if ( ! pushToOtherWallets ) { pushToOtherWallets = ( entry . environmentGroups . length > 1 ) ? true : false ; if ( entry . environmentGroups . length > 1 || ( entry . fromEnvironment && entry . fromEnvironment !== entry . environmentGroups [ 0 ] ) ) { pushToOtherWallets = true ; } } return true ; } } else if ( index > 0 && entry . fromEnvironment ) { return wallet . fromEnvironment === entry . fromEnvironment ; } } ) ; } else { otherGroupWallets = walletRegistryEntries . filter ( ( entry , index ) => { if ( index > 0 && entry . environmentGroups ) { if ( wallet . environmentGroups [ 0 ] === entry . environmentGroups [ 0 ] ) { if ( ! pushToOtherWallets ) { pushToOtherWallets = ( entry . environmentGroups . length > 1 ) ? true : false ; } return true ; } } else if ( index > 0 && entry . fromEnvironment ) { return wallet . environmentGroups [ 0 ] === entry . fromEnvironment ; } } ) ; } group . push ( ... otherGroupWallets ) ; pushToOtherWallets === true ? otherWallets . push ( group ) : walletGroups . push ( group ) ; walletRegistryEntries = walletRegistryEntries . filter ( ( entry ) => { return ! group . includes ( entry ) ; } ) ; totalWallets = totalWallets - group . length ; } } if ( otherWallets . length > 0 ) { walletGroups . push ( otherWallets ) ; } if ( walletGroups . length === 0 ) { tree . push ( new TextTreeItem ( this , 'No wallets found' ) ) ; } else { const otherWalletsGroupName = 'Other/shared wallets' ; for ( const group of walletGroups ) { let groupName ; if ( group [ 0 ] . fromEnvironment ) { groupName = group [ 0 ] . fromEnvironment ; } else if ( group [ 0 ] . environmentGroups && group [ 0 ] . environmentGroups . length === 1 ) { groupName = group [ 0 ] . environmentGroups [ 0 ] ; } else { groupName = otherWalletsGroupName ; } const groupTreeItem = new WalletGroupTreeItem ( this , groupName , group , vscode . TreeItemCollapsibleState . Expanded ) ; if ( groupName !== otherWalletsGroupName ) { groupTreeItem . iconPath = await ExplorerUtil . getGroupIcon ( groupName ) ; } tree . push ( groupTreeItem ) ; } } return tree ; } private async populateWallets ( walletItems ) { const tree = [ ] ; for ( const walletItem of walletItems ) { if ( Array . isArray ( walletItem ) ) { const groupName = walletItem [ 0 ] . fromEnvironment ? walletItem [ 0 ] . fromEnvironment : walletItem [ 0 ] . environmentGroups [ 0 ] ; const groupTreeItem = new WalletGroupTreeItem ( this , groupName , walletItem , vscode . TreeItemCollapsibleState . Expanded ) ; groupTreeItem . iconPath = await ExplorerUtil . getGroupIcon ( groupName ) ; tree . push ( groupTreeItem ) ; } else { const walletGenerator = FabricWalletGeneratorFactory . getFabricWalletGenerator ( ) ; const wallet = await walletGenerator . getWallet ( walletItem ) ; let identityNames ; if ( walletItem . fromEnvironment ) { const environmentEntry = await FabricEnvironmentRegistry . instance ( ) . get ( walletItem . fromEnvironment ) ; if ( environmentEntry . environmentType === EnvironmentType . LOCAL_MICROFAB_ENVIRONMENT ) { const environment = EnvironmentFactory . getEnvironment ( environmentEntry ) as LocalMicroEnvironment ; const visibleIdentities = await environment . getVisibleIdentities ( walletItem . name ) ; identityNames = visibleIdentities . map ( ( identity ) => { return identity . name ; } ) ; } } if ( identityNames === undefined ) { identityNames = await wallet . getIdentityNames ( ) ; } const treeState = identityNames . length > 0 ? vscode . TreeItemCollapsibleState . Collapsed : vscode . TreeItemCollapsibleState . None ; if ( walletItem . managedWallet ) { tree . push ( new LocalWalletTreeItem ( this , walletItem . name , identityNames , treeState , walletItem ) ) ; } else { tree . push ( new WalletTreeItem ( this , walletItem . name , identityNames , treeState , walletItem ) ) ; } } } return tree ; } private async createIdentityTree ( walletTreeItem ) { const tree = [ ] ; const fabricWalletGenerator = FabricWalletGeneratorFactory . getFabricWalletGenerator ( ) ; const wallet = await fabricWalletGenerator . getWallet ( walletTreeItem . registryEntry ) ; let identities ; if ( walletTreeItem . registryEntry . fromEnvironment ) { const environmentEntry = await FabricEnvironmentRegistry . instance ( ) . get ( walletTreeItem . registryEntry . fromEnvironment ) ; if ( environmentEntry . environmentType === EnvironmentType . LOCAL_MICROFAB_ENVIRONMENT ) { identities = await FabricWalletHelper . getVisibleIdentities ( environmentEntry , walletTreeItem . registryEntry ) ; } } if ( identities === undefined ) { identities = await wallet . getIdentities ( ) ; } for ( const identity of identities ) { let isAdminIdentity = false ; if ( walletTreeItem instanceof LocalWalletTreeItem ) { isAdminIdentity = true ; } const certificate = new FabricCertificate ( identity . cert ) ; const attributes = certificate . getAttributes ( ) ; if ( isAdminIdentity ) { tree . push ( new AdminIdentityTreeItem ( this , identity . name , walletTreeItem . name , attributes , walletTreeItem . registryEntry ) ) ; } else { tree . push ( new IdentityTreeItem ( this , identity . name , walletTreeItem . name , attributes , walletTreeItem . registryEntry ) ) ; } } return tree ; } private async updateWalletEnvironmentGroups ( walletRegistryEntries ) { const outputAdapter = VSCodeBlockchainOutputAdapter . instance ( ) ; const finalEntries = [ ] ; let includeWallet ; for ( const wallet of walletRegistryEntries ) { includeWallet = true ; if ( wallet . environmentGroups ) { const updatedGroups = [ ] ; for ( const env of wallet . environmentGroups ) { if ( await FabricEnvironmentRegistry . instance ( ) . exists ( env ) ) { try { const fabricEnvironmentRegistryEntry = await FabricEnvironmentRegistry . instance ( ) . get ( env ) ; if ( fabricEnvironmentRegistryEntry . environmentType === EnvironmentType . LOCAL_MICROFAB_ENVIRONMENT ) { await LocalMicroEnvironmentManager . instance ( ) . ensureRuntime ( fabricEnvironmentRegistryEntry . name , undefined , fabricEnvironmentRegistryEntry . numberOfOrgs ) ; } const environment = EnvironmentFactory . getEnvironment ( fabricEnvironmentRegistryEntry ) ; const nodes = await environment . getNodes ( ) ; const associatedNodes = nodes . some ( ( node ) => { return node . wallet === wallet . name ; } ) ; if ( associatedNodes ) { updatedGroups . push ( env ) ; } } catch ( error ) { outputAdapter . log ( LogType . ERROR , `Error displaying Fabric Wallets: ${ error . message }` , `Error displaying Fabric Wallets: ${ error . message }` ) ; includeWallet = false ; } } } if ( wallet . environmentGroups . length !== updatedGroups . length ) { wallet . environmentGroups = updatedGroups ; await FabricWalletRegistry . instance ( ) . update ( wallet ) ; } } if ( includeWallet ) { finalEntries . push ( wallet ) ; } } return finalEntries ; } }