原文链接:超级账本源码分析: peer命令结构
本文介绍fabric peer命令的结构。
Peer节点是Fabric中处理交易和存储区块的重要角色,peer命令提供了很多命令供用户使用,比如创建通道、加入通道、安装和调用链码等等。我们后面很多文章会通过分析某些命令的执行流程来理解Fabric各个模块,本小节首先分析peer命令的结构。
Peer命令有四个子命令分别是channel、chaincode、clilogging、node,从字面意思上很好理解,比如channel子命令负责通道相关的操作,chaincode负责链码相关的操作。这些子命令都会被main函数调用, 因为main函数是程序的入口。从官方的实例中我们可以看出,peer命令的输入都是类似的格式,比如 peer channel …、peer node …、peer chaincode…,这种命令的风格是“命令 + 子命令 + 选项”,下图是peer完整的命令结构:
peer |
chaincode |
instantiate |
invoke |
||
query |
||
upgrade |
||
package |
||
install |
||
signpackage |
||
channel |
join |
|
create |
||
fetch |
||
list |
||
clilogging |
getlevel |
|
Setlevel |
||
Revertlevel |
||
node |
start |
|
status |
||
stop |
||
version |
peer模块位置在fabric/peer,目录结构如下:
目录结构很清晰,peer目录下只有一个main文件,peer的子命令都在peer的子目录下,比chaincode、channel、clilogging等。
peer命令使用的是第三方包github.com/spf13/cobra,cobra是一个用于生成命令行程序的库, cobra基本用法如下:
1. 创建一个根命令对象,类型为Command,每个命令都是一个Command对象实例。创建一个命令对象就是实现和填充Command中的成员。
type Command struct { Use string //命令的名称,比如在命令行敲peer version,这个字段就是“peer” Short string Long string Run func(cmd *Command, args []string) ... } RootCmd := &cobra.Command{...}
例如fabric的peer命令的定义如下:
var mainCmd = &cobra.Command{ Use: "peer", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { // check for CORE_LOGGING_LEVEL environment variable, which should override // all other log settings loggingSpec := viper.GetString("logging_level") if loggingSpec == "" { // if CORE_LOGGING_LEVEL not set, use the value for 'peer' from core.yaml loggingSpec = viper.GetString("logging.peer") } flogging.InitFromSpec(loggingSpec) return nil }, Run: func(cmd *cobra.Command, args []string) { if versionFlag { fmt.Print(version.GetInfo()) } else { cmd.HelpFunc()(cmd, args) } }, }
2. 为命令添加flag,也就是添加命令行选项,比如下面这个就是peer的主命令添加了一个version选项,各个用法类似于go的flag包。
mainFlags := mainCmd.PersistentFlags() mainFlags.BoolVarP(&versionFlag, "version", "v", false, "Display current version of fabric peer server")
3. 添加子命令
mainCmd.AddCommand(version.Cmd()) mainCmd.AddCommand(node.Cmd()) mainCmd.AddCommand(chaincode.Cmd(nil)) mainCmd.AddCommand(clilogging.Cmd(nil)) mainCmd.AddCommand(channel.Cmd(nil))
4. 执行命令
if mainCmd.Execute() != nil { os.Exit(1) }
我们以node子命令为例来介绍:
1.在node.go中,首先定义了一个node命令对象,var nodeCmd = &cobra.Command{…}
// Cmd returns the cobra command for Node
func Cmd() *cobra.Command {
nodeCmd.AddCommand(startCmd())
nodeCmd.AddCommand(statusCmd())
return nodeCmd
}
var nodeCmd = &cobra.Command{
Use: nodeFuncName,
Short: fmt.Sprint(shortDes),
Long: fmt.Sprint(longDes),
}
2.在Cmd函数中,添加了start、stop、status三个子命令,子命令又分别在start.go,status.go,stop.go文件中实现。
3.在start.go中,首先定义了一个start命令对象,var nodeStartCmd = &cobra.Command{…},其中对RunE成员赋值了一个匿名函数,函数体中执行了serve函数,这也是该命令最终会调用的函数。如果我们在命令行中输入peer node start, 这个serve函数就会被调用,顾名思义serve会启动很多peer的服务。后面我们在分析serve函数具体细节。
本章节主要介绍了fabric peer的命令处理方式,由于peer使用了cobra库,流程上跟cobra使用方法一致,下面一节我们会介绍peer node start命令的具体实现。
-END-