peer目录结构
peer目录结构自身十分清晰,最外面有一个main.go文件,其余文件夹除common,gossip外均为子命令集合,有chaincode,channel,clilogging,node,version五个,供main.go整合使用。子命令文件夹中,与文件夹名称相同的.go文件为主要源码文件,其余的均为按功能划分的动作命令源码。以node目录为例,node自身作为根命令的一个子命令,在node.go中实现,而node这个命令自身又有start,status,stop这三个动作去执行不同的任务,分别在对应start.go,status.go,stop.go中实现。注意,start,status,stop其实也是子命令,是node这个子命令的子命令。
peer命令结构解析
我们现在正式从peer/main.go文件开始解析源码,本文旨在解析peer的命令结构,因此只会涉及相关的源码,其他部分将会在其他主题文章中对应分析。
// The main command describes the service and
// defaults to printing the help message.
var mainCmd = &cobra.Command{
Use: "peer"}
首先定义了一个mainCmd命令的全局变量,var mainCmd = &cobra.Command{…},该命令填充了Use。Use如我们预见的那样被赋值为peer。
// Define command-line flags that are valid for all peer commands and
// subcommands.
mainFlags := mainCmd.PersistentFlags()
生成mainCmd对象的命令行标识对象mainFlags,mainFlags := mainCmd.PersistentFlags(),也就是peer命令的选项。
mainCmd.AddCommand(version.Cmd())
mainCmd.AddCommand(node.Cmd())
mainCmd.AddCommand(chaincode.Cmd(nil))
mainCmd.AddCommand(clilogging.Cmd(nil))
mainCmd.AddCommand(channel.Cmd(nil))
添加子命令,mainCmd.AddCommand(…)。添加的命令有version.Cmd(),node.Cmd(),chaincode.Cmd(nil),clilogging.Cmd(nil),channel.Cmd(nil)五个。Cmd()是每个子命令文件中暴露出的函数,各自整合了各自的动作命令。
// On failure Cobra prints the usage message and error string, so we only
// need to exit with a non-0 status
if mainCmd.Execute() != nil {
os.Exit(1)
}
最后,启动根命令,mainCmd.Execute()。启动了根命令,也就启动了其下的所有命令。
子命令结构解析,以node为例
这里以node为例,其余的子命令类推即可。
在node.go中,首先定义了一个node命令对象:
var nodeCmd = &cobra.Command{
Use: nodeFuncName,
Short: fmt.Sprint(nodeCmdDes),
Long: fmt.Sprint(nodeCmdDes),
}
在Cmd函数中,添加了startCmd(),statusCmd(),两个函数返回的start,status子命令(动作命令),分别实现在start.go,status.go。这两个命令的源码结构也是基本一致,在此仅以start.go为例。
在start.go中,首先定义了一个start命令对象:
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 {
if len(args) != 0 {
return fmt.Errorf("trailing args detected")
}
// Parsing of the command line is done so silence cmd usage
cmd.SilenceUsage = true
return serve(args)
},
}
其中对RunE成员赋值了一个匿名函数,函数体中执行了serve函数,这也是该命令最终会调用的函数。serve函数是一个非常重要,非常复杂的函数,在每个peer容器启动后默认执行的就是peer node start –peer-defaultchain=false命令,该命令最终调用执行的就是serve函数,同时也就是说,serve函数会做了很多很多的准备工作。