fabric/peer/main.go
main.go
包含全局变量mainCmd
, 使用cobra.Command
赋值,详细流程暂不考虑.
// The main command describes the service and defaults to printing the help message.
var mainCmd = &cobra.Command{
Use: "peer",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
peerCommand := getPeerCommandFromCobraCommand(cmd)
flogging.LoggingInit(peerCommand)
return core.CacheConfiguration()
},
Run: func(cmd *cobra.Command, args []string) {
if versionFlag {
version.Print()
} else {
cmd.HelpFunc()(cmd, args)
}
},
}
mainCmd
的使用主要在func main()
中,主要涉及两种操作:mainCmd.AddCommand()
和mainCmd.Execute()
,如下:
func main() {
...
mainCmd.AddCommand(version.Cmd())
mainCmd.AddCommand(node.Cmd())
mainCmd.AddCommand(network.Cmd())
mainCmd.AddCommand(chaincode.Cmd())
...
if mainCmd.Execute() != nil {
os.Exit(1)
}
logger.Info("Exiting.....")
}
mainCmd
将version
、node
、network
、chaincode
相关的命令作为自己的子命令添加到命令树中,在main()
函数的最后通过调用mainCmd.Execute()
,进一步调用mainCmd.ExecuteC()
,递归执行mainCmd
的所有子命令,具体的函数定义在github.com/spf13/cobra/command.go
中。
version.Cmd()
peer/version/version.go
中定义了func Cmd()
. 如下:
// Cmd returns the Cobra Command for Version
func Cmd() *cobra.Command {
return cobraCommand
}
version.Cmd()
比较简单,对比其他三个(node、network、chaincode)
,该函数只是返回一个构造好的cobraCommand
,唯一不同的是,该cobraCommand
中的Run
成员变量自定义为print()函数,用于输出当前的可执行版本号。
node.Cmd()
peer/node/node.go
中定义了func Cmd()
. 如下:
func Cmd() *cobra.Command {
nodeCmd.AddCommand(startCmd())
nodeCmd.AddCommand(statusCmd())
nodeCmd.AddCommand(stopCmd())
return nodeCmd
}
在node.Cmd()
函数中nodeCmd
将startCmd()
、statusCmd()
、stopCmd()
作为自己的子命令添加到命令树中,其中startCmd()
和项目的启动息息相关,在此只简单提及,后续进一步讨论。
startCmd()
peer/node/start.go
中定义了func startCmd()
. 如下:
func startCmd() *cobra.Command {
// Set the flags on the node start command.
flags := nodeStartCmd.Flags()
flags.BoolVarP(&chaincodeDevMode, "peer-chaincodedev", "", false,
"Whether peer in chaincode development mode")
return nodeStartCmd
}
函数返回值为全局变量,在同一文件定义如下:
var nodeStartCmd = &cobra.Command{
Use: "start",
Short: "Starts the node.",
Long: `Starts a node that interacts with the network.`,
RunE: func(cmd *cobra.Command, args []string) error {
return serve(args)
},
}
其中成员变量RunE
为自定义函数,调用同一文件下的func serve()
函数,至此,fabric开始初始化诸如engine
、peer
、peerServer
等实体。
statusCmd()
peer/node/status.go
中定义了func statusCmd()
.
函数返回值同样为同一文件下的nodeStatusCmd
变量,其成员变量Run
调用同一文件下的status()
函数,打印serverClient
的状态信息。
函数的调用模式同startCmd()
。
stopCmd()
peer/node/stop.go
中定义了func stopCmd()
.
函数返回值同样为同一文件下的nodeStopCmd
变量,其成员变量Run
调用同一文件下的stop()
函数,通过gRPC
关闭serverClient
和database
。
函数的调用模式同startCmd()
。
network.Cmd()
peer/network/network.go
中定义了func Cmd()
. 如下:
func Cmd() *cobra.Command {
networkCmd.AddCommand(loginCmd())
networkCmd.AddCommand(listCmd())
return networkCmd
}
loginCmd()
peer/network/login.go
中定义了func loginCmd()
函数返回值同样为同一文件下的networkLoginCmd
变量,其成员变量RunE
(和之前的Run相同,只是返回值多了一个error类型)调用同一文件下的login()
函数,该函数和PKI相关,官方注释如下:
login() confirms the enrollmentID and secret password of the client with the CA
and stores the enrollment certificate and key in the Devops server.
listCmd()
peer/network/list.go
中定义了func listCmd()
函数返回值同样为同一文件下的networkListCmd
变量,其成员变量RunE
调用同一文件下的networkList()
函数,该函数官方注释如下:
Show a list of all existing network connections for the target peer node,
includes both validating and non-validating peers
chaincode.Cmd()
peer/chaincode/chaincode.go
中定义了func Cmd()
. 如下:
func Cmd() *cobra.Command {
...
chaincodeCmd.AddCommand(deployCmd())
chaincodeCmd.AddCommand(invokeCmd())
chaincodeCmd.AddCommand(queryCmd())
return chaincodeCmd
}
peer/chaincode/deploy.go
中定义了func deployCmd()
. chaincodeDeployCmd
变量,其成员变量RunE调用同一文件下的chaincodeDeploy()
函数,用于部署chaincode
,如下:func chaincodeDeploy(cmd *cobra.Command, args []string) error {
spec, err := getChaincodeSpecification(cmd)
...
devopsClient, err := common.GetDevopsClient(cmd)
...
chaincodeDeploymentSpec, err := devopsClient.Deploy(context.Background(), spec)
...
logger.Infof("Deploy result: %s", chaincodeDeploymentSpec.ChaincodeSpec)
fmt.Printf("Deploy chaincode: %s\n", chaincodeDeploymentSpec.ChaincodeSpec.ChaincodeID.Name)
return nil
}
invokeCmd()
peer/chaincode/invoke.go
中定义了func invokeCmd()
.
函数返回值同样为同一文件下的chaincodeInvokeCmd
变量,其成员变量RunE调用同一文件下的chaincodeInvoke()
函数,该函数又进一步调用chaincodeInvokeOrQuery()
,chaincodeInvokeOrQuery()
定义在peer/chaincode/common.go中,官方注释如下:
chaincodeInvokeOrQuery invokes or queries the chaincode.
If successful, the INVOKE form prints the transaction ID on STDOUT,
and the QUERY form prints the query result on STDOUT.
queryCmd()
peer/chaincode/query.go
中定义了func queryCmd()
.
函数返回值同样为同一文件下的chaincodeQueryCmd
变量,其成员变量RunE
调用同一文件下的chaincodeQuery()
函数,该函数又进一步调用chaincodeInvokeOrQuery()
,即 queryCmd()
和invokeCmd()
最终调用同一个函数,通过chaincodeInvokeOrQuery()
函数的第三个bool
类型的参数区分指令。
version
、node
、network
、chaincode
各自的Cmd()
函数都会返回 XXXCmd
(其中XXX
代表network
、node
等), XXXCmd
也是通过cobra.Command
实现的,只不过version
的Cmd
比较简单,在cobraCommand
中添加一个print()
函数就实现了其功能,而另外三个仍然需要继续为自己的命令树添加子命令,各命令初始化赋值通用格式如下:
var XXXCmd = &cobra.Command{
Use: XXXFuncName,
Short: fmt.Sprintf("%s specific commands.", XXXFuncName),
Long: fmt.Sprintf("%s specific commands.", XXXFuncName),
}
其他命令的初始化也大同小异,只是单纯的成员变量的增删。
在func main()
中, 通过mainCmd.AddCommand(XXX.Cmd())
逐步按功能添加各自的子命令,形成一个命令树;后期通过调用mainCmd.Execute()
递归执行各子命令,比较重要的就是,node.Cmd()最终会调用peer/node/start.go
文件下的func serve()
函数,fabric开始初始化诸如engine
、peer
、peerServer
等实体。详细过程后期会进一步分析。
Cobra既是创建强大的现代CLI(Command Line Applications )应用程序的库,也是用于生成应用程序和命令文件的程序。
* Github源码:https://github.com/spf13/cobra
* Cobra简介:下载源码后github.com/spf13/viper 目录下的Readme.md文件
* ubuntu16.04下配置指令: $ go get github.com/spf13/cobra
* 具体使用:http://studygolang.com/articles/7588
开源配置解决方案,满足不同的对配置文件的使用的要求,fabric采用viper来解决配置问题
* Github源码:https://github.com/spf13/viper
* Viper简介:下载源码后github.com/spf13/viper 目录下的Readme.md文件
* ubuntu16.04下配置指令: $ go get github.com/spf13/viper
* 具体使用:http://studygolang.com/articles/4244