'use strict' ; import * as vscode from 'vscode' ; import * as path from 'path' ; import * as fs from 'fs-extra' ; import { ReactView } from './ReactView' ; import { ExtensionUtil } from '../util/ExtensionUtil' ; import { Reporter } from '../util/Reporter' ; import { PackageRegistryEntry } from '../registries/PackageRegistryEntry' ; import { ExtensionCommands } from '../../ExtensionCommands' ; import { FabricEnvironmentRegistryEntry , FabricEnvironmentRegistry , IFabricEnvironmentConnection , FabricSmartContractDefinition , LogType , FabricCollectionDefinition } from 'ibm-blockchain-platform-common' ; import { FabricEnvironmentManager } from '../fabric/environments/FabricEnvironmentManager' ; import { VSCodeBlockchainOutputAdapter } from '../logging/VSCodeBlockchainOutputAdapter' ; import { PackageRegistry } from '../registries/PackageRegistry' ; import { UserInputUtil } from '../commands/UserInputUtil' ; import IInstantiateFunction from '../interfaces/IDeployV1InstantiateFunction' ; export class DeployView extends ReactView { public static panel : vscode . WebviewPanel ; public static appState : any ; static async updatePackages ( ) { let packageEntries = [ ] ; const allPackageEntries = await PackageRegistry . instance ( ) . getAll ( ) ; packageEntries = allPackageEntries . filter ( ( entry ) => { const fileExtension = UserInputUtil . getPackageFileExtension ( entry . path ) ; return DeployView . appState . hasV1Capabilities ? fileExtension === '.cds' : fileExtension !== '.cds' ; } ) ; DeployView . appState . packageEntries = packageEntries ; DeployView . panel . webview . postMessage ( { path : '/deploy' , deployData : DeployView . appState } ) ; } constructor ( context , appState ) { super ( context , 'deploySmartContract' , 'Deploy Smart Contract' ) ; DeployView . appState = appState ; } async openPanelInner ( panel ) { Reporter . instance ( ) . sendTelemetryEvent ( 'openedView' , { openedView : panel . title } ) ; DeployView . panel = panel ; panel . onDidDispose ( ( ) => { DeployView . panel = undefined ; } ) ; const extensionPath = ExtensionUtil . getExtensionPath ( ) ; const panelIcon = vscode . Uri . file ( path . join ( extensionPath , 'resources' , 'logo.svg' ) ) ; panel . iconPath = panelIcon ; panel . webview . onDidReceiveMessage ( async ( message ) => { if ( message . command === 'deploy' ) { const channelName = message . data . channelName ; const environmentName = message . data . environmentName ; const selectedPackage = message . data . selectedPackage ; const definitionName = message . data . definitionName ; const definitionVersion = message . data . definitionVersion ; const commitSmartContract = message . data . commitSmartContract ; const endorsementPolicy = message . data . endorsementPolicy ; const collectionConfigString = message . data . collectionConfig ; const selectedPeers = message . data . selectedPeers ; await this . deploy ( channelName , environmentName , selectedPackage , definitionName , definitionVersion , commitSmartContract , endorsementPolicy , collectionConfigString , selectedPeers ) ; } else if ( message . command === 'instantiate' || message . command === 'upgrade' ) { const channelName = message . data . channelName ; const environmentName = message . data . environmentName ; const selectedPackage = message . data . selectedPackage ; const instantiateFunction = { name : message . data . instantiateFunctionName , args : message . data . instantiateFunctionArgs , } ; const endorsementPolicy = message . data . endorsementPolicy ; const collectionConfigString = message . data . collectionConfig ; await this . deployV1 ( message . command , channelName , environmentName , selectedPackage , instantiateFunction , endorsementPolicy , collectionConfigString ) ; } else if ( message . command === 'package' ) { const workspaceName = message . data . workspaceName ; const packageName = message . data . packageName ; const packageVersion = message . data . packageVersion ; const versionNumber = message . data . versionNumber ; const entry = await this . package ( workspaceName , packageName , packageVersion , versionNumber ) ; if ( entry ) { DeployView . appState . selectedPackage = entry ; await DeployView . updatePackages ( ) ; } } else if ( message . command === 'getOrgApprovals' ) { const environmentName = message . data . environmentName ; const channelName = message . data . channelName ; const definitionName = message . data . definitionName ; const definitionVersion = message . data . definitionVersion ; const endorsementPolicy = message . data . endorsementPolicy ; const collectionConfigString = message . data . collectionConfig ; await this . getOrgApprovals ( environmentName , channelName , definitionName , definitionVersion , endorsementPolicy , collectionConfigString ) ; } else if ( message . command === 'getPackageLanguage' ) { const chosenWorkspaceData = { language : '' , name : '' , version : '' } ; const workspace = this . getWorkspace ( message . data . workspaceName ) ; chosenWorkspaceData . language = await UserInputUtil . getLanguage ( workspace ) ; if ( chosenWorkspaceData . language === 'node' ) { const workspacePackage = path . join ( workspace . uri . fsPath , '/package.json' ) ; const workspacePackageContents = await fs . readFile ( workspacePackage ) ; const workspacePackageObj = JSON . parse ( workspacePackageContents . toString ( 'utf8' ) ) ; chosenWorkspaceData . name = workspacePackageObj . name ; chosenWorkspaceData . version = workspacePackageObj . version ; } DeployView . appState . selectedPackage = undefined ; DeployView . appState . selectedWorkspace = message . data . workspaceName ; DeployView . appState . chosenWorkspaceData = chosenWorkspaceData ; panel . webview . postMessage ( { path : 'deploy' , deployData : DeployView . appState } ) ; } } ) ; await this . loadComponent ( panel ) ; } async loadComponent ( panel ) { panel . webview . postMessage ( { path : '/deploy' , deployData : DeployView . appState } ) ; } async deploy ( channelName , environmentName , selectedPackage , definitionName , definitionVersion , commitSmartContract , endorsementPolicy , collectionConfigString , selectedPeers ) { const outputAdapter = VSCodeBlockchainOutputAdapter . instance ( ) ; try { DeployView . panel . dispose ( ) ; const environmentEntry = await FabricEnvironmentRegistry . instance ( ) . get ( environmentName ) ; let connection = FabricEnvironmentManager . instance ( ) . getConnection ( ) ; if ( connection ) { const connectedName = connection . environmentName ; if ( connectedName !== environmentEntry . name ) { await vscode . commands . executeCommand ( ExtensionCommands . DISCONNECT_ENVIRONMENT ) ; await vscode . commands . executeCommand ( ExtensionCommands . CONNECT_TO_ENVIRONMENT , environmentEntry ) ; connection = FabricEnvironmentManager . instance ( ) . getConnection ( ) ; } } else { await vscode . commands . executeCommand ( ExtensionCommands . CONNECT_TO_ENVIRONMENT , environmentEntry ) ; connection = FabricEnvironmentManager . instance ( ) . getConnection ( ) ; } if ( ! connection ) { throw new Error ( `Unable to deploy, cannot connect to environment: ${ environmentEntry . name }` ) ; } const orgMap = await connection . getDiscoveredOrgs ( channelName ) ; const channelMap = await connection . createChannelMap ( ) ; const channelPeers = channelMap . get ( channelName ) ; const installApproveMap = new Map ( ) ; const commitMap = new Map ( ) ; for ( const [ org , peers ] of orgMap . entries ( ) ) { for ( const peer of peers ) { if ( channelPeers . includes ( peer ) ) { if ( ! installApproveMap . has ( org ) ) { installApproveMap . set ( org , [ peer ] ) ; commitMap . set ( org , [ peer ] ) ; } else { installApproveMap . get ( org ) . push ( peer ) ; commitMap . get ( org ) . push ( peer ) ; } } else { if ( selectedPeers . includes ( peer ) ) { if ( ! commitMap . has ( org ) ) { commitMap . set ( org , [ peer ] ) ; } else { commitMap . get ( org ) . push ( peer ) ; } } } } } const ordererNames = connection . getAllOrdererNames ( ) ; const allCommittedContracts = await connection . getCommittedSmartContractDefinitions ( channelPeers , channelName ) ; const committedContract = allCommittedContracts . find ( ( _contract ) => { return _contract . name === definitionName ; } ) ; let sequenceNumber ; if ( ! committedContract ) { sequenceNumber = 1 ; } else { if ( committedContract . version !== definitionVersion ) { sequenceNumber = committedContract . sequence + 1 ; } else { sequenceNumber = committedContract . sequence ; if ( commitSmartContract === undefined ) { commitSmartContract = false ; } } } if ( collectionConfigString || endorsementPolicy ) { sequenceNumber = committedContract ? committedContract . sequence + 1 : 1 ; } let collectionFile ; if ( collectionConfigString && collectionConfigString !== '' ) { collectionFile = JSON . parse ( collectionConfigString ) as FabricCollectionDefinition [ ] ; } if ( endorsementPolicy ) { endorsementPolicy = endorsementPolicy . replace ( /"/g , "\'" ) ; } if ( commitSmartContract === undefined ) { commitSmartContract = true ; } await vscode . commands . executeCommand ( ExtensionCommands . DEPLOY_SMART_CONTRACT , commitSmartContract , environmentEntry , ordererNames [ 0 ] , channelName , installApproveMap , selectedPackage , new FabricSmartContractDefinition ( definitionName , definitionVersion , sequenceNumber , undefined , endorsementPolicy , collectionFile ) , commitMap ) ; } catch ( error ) { outputAdapter . log ( LogType . ERROR , error . message , error . toString ( ) ) ; } } async deployV1 ( command , channelName , environmentName , selectedPackage , instantiateFunction , endorsementPolicy , collectionConfigString ) { const outputAdapter = VSCodeBlockchainOutputAdapter . instance ( ) ; try { DeployView . panel . dispose ( ) ; const environmentEntry = await FabricEnvironmentRegistry . instance ( ) . get ( environmentName ) ; let connection = FabricEnvironmentManager . instance ( ) . getConnection ( ) ; if ( connection ) { const connectedName = connection . environmentName ; if ( connectedName !== environmentEntry . name ) { await vscode . commands . executeCommand ( ExtensionCommands . DISCONNECT_ENVIRONMENT ) ; await vscode . commands . executeCommand ( ExtensionCommands . CONNECT_TO_ENVIRONMENT , environmentEntry ) ; connection = FabricEnvironmentManager . instance ( ) . getConnection ( ) ; } } else { await vscode . commands . executeCommand ( ExtensionCommands . CONNECT_TO_ENVIRONMENT , environmentEntry ) ; connection = FabricEnvironmentManager . instance ( ) . getConnection ( ) ; } if ( ! connection ) { throw new Error ( `Unable to deploy, cannot connect to environment: ${ environmentEntry . name }` ) ; } const channelMap = await connection . createChannelMap ( ) ; const peerNames = channelMap . get ( channelName ) ; let parsedArgs ; if ( instantiateFunction . name === '' ) { parsedArgs = [ ] ; } else { if ( ! instantiateFunction . args . startsWith ( '[' ) || ! instantiateFunction . args . endsWith ( ']' ) ) { throw new Error ( 'instantiate function arguments should be in the format ["arg1", {"key" : "value"}]' ) ; } parsedArgs = JSON . parse ( instantiateFunction . args ) ; } if ( endorsementPolicy ) { endorsementPolicy = endorsementPolicy . replace ( /"/g , "\'" ) ; } const extensionCommand = ( command === 'instantiate' ) ? ExtensionCommands . INSTANTIATE_SMART_CONTRACT : ExtensionCommands . UPGRADE_SMART_CONTRACT ; await vscode . commands . executeCommand ( extensionCommand , channelName , peerNames , selectedPackage , instantiateFunction . name , parsedArgs , endorsementPolicy , collectionConfigString ) ; } catch ( error ) { outputAdapter . log ( LogType . ERROR , error . message , error . toString ( ) ) ; } } getWorkspace ( workspaceName ) { const workspaces = UserInputUtil . getWorkspaceFolders ( ) ; return workspaces . find ( ( _workspace ) => _workspace . name === workspaceName ) ; } async package ( workspaceName , packageName , packageVersion , versionNumber ) { const workspace = this . getWorkspace ( workspaceName ) ; const packageEntry = await vscode . commands . executeCommand ( ExtensionCommands . PACKAGE_SMART_CONTRACT , workspace , packageName , packageVersion , versionNumber ) ; return packageEntry ; } async getOrgApprovals ( environmentName , channelName , definitionName , definitionVersion , endorsementPolicy , collectionConfigString ) { const outputAdapter = VSCodeBlockchainOutputAdapter . instance ( ) ; try { const environmentEntry = await FabricEnvironmentRegistry . instance ( ) . get ( environmentName ) ; let connection = FabricEnvironmentManager . instance ( ) . getConnection ( ) ; if ( connection ) { const connectedName = connection . environmentName ; if ( connectedName !== environmentEntry . name ) { await vscode . commands . executeCommand ( ExtensionCommands . DISCONNECT_ENVIRONMENT ) ; await vscode . commands . executeCommand ( ExtensionCommands . CONNECT_TO_ENVIRONMENT , environmentEntry ) ; connection = FabricEnvironmentManager . instance ( ) . getConnection ( ) ; } } else { await vscode . commands . executeCommand ( ExtensionCommands . CONNECT_TO_ENVIRONMENT , environmentEntry ) ; connection = FabricEnvironmentManager . instance ( ) . getConnection ( ) ; } if ( ! connection ) { throw new Error ( `Unable to deploy, cannot connect to environment: ${ environmentEntry . name }` ) ; } const channelMap = await connection . createChannelMap ( ) ; const channelPeers = channelMap . get ( channelName ) ; const allCommittedContracts = await connection . getCommittedSmartContractDefinitions ( channelPeers , channelName ) ; const committedContract = allCommittedContracts . find ( ( _contract ) => { return _contract . name === definitionName ; } ) ; let sequenceNumber ; if ( ! committedContract ) { sequenceNumber = 1 ; } else if ( committedContract && committedContract . version !== definitionVersion ) { sequenceNumber = committedContract . sequence + 1 ; } else { sequenceNumber = committedContract . sequence ; } const definition = new FabricSmartContractDefinition ( definitionName , definitionVersion , sequenceNumber ) ; if ( collectionConfigString && collectionConfigString !== '' ) { const collectionFile = JSON . parse ( collectionConfigString ) as FabricCollectionDefinition [ ] ; definition . collectionConfig = collectionFile ; } if ( endorsementPolicy ) { definition . endorsementPolicy = endorsementPolicy . replace ( /"/g , "\'" ) ; } let orgApprovals = new Map ( ) ; try { orgApprovals = await connection . getOrgApprovals ( channelName , channelPeers [ 0 ] , definition ) ; } catch ( error ) { } const orgObject = { } ; orgApprovals . forEach ( ( approval , org ) => { orgObject [ org ] = approval ; } ) ; DeployView . appState . orgApprovals = orgObject ; if ( DeployView . panel ) { DeployView . panel . webview . postMessage ( { path : '/deploy' , deployData : DeployView . appState } ) ; } } catch ( error ) { outputAdapter . log ( LogType . ERROR , error . message , error . toString ( ) ) ; } } }