btcjson

btcd/btcjson 如何管理命令

以debuglevel命令为例来说明btcd对于rpc命令是如何组织的.

1. 注册

通过此方式可以注册一个新的命令,

// DebugLevelCmd defines the debuglevel JSON-RPC command.  This command is not a
// standard Bitcoin command.  It is an extension for btcd.
type DebugLevelCmd struct {
	LevelSpec string
}
MustRegisterCmd("debuglevel", (*DebugLevelCmd)(nil), flags)

MustRegisterCmd 最终通过RegisterCmd来实现命令注册,这里面用到了不少反射代码来简化函数的调用.

最终MustRegisterCmd提供信息会保存到三个全局map中,

	methodToConcreteType = make(map[string]reflect.Type)
	methodToInfo         = make(map[string]methodInfo)
	concreteTypeToMethod = make(map[reflect.Type]string)

其中methodToInfo 的key是debuglevel,用于对该命令进行描述,为btcctl help 提供信息,也是rpc server检测提供参数格式是否正确的依据.

btcctl help中的信息还有一部分来源就是helpDescsEnUS中,

其中methodToConcreteType和concreteTypeToMethod是互为映射,主要是为了帮助创建DebugLevelCmd结构体.以及根据这个结构体找到对应的命令.
针对这个命令来说,三个map中会写入如下信息

methodToConcreteType["debuglevel"]=reflect.TypeOf(&DebugLevelCmd{})
methodToInfo["debuglevel"]="该结构体的信息"
concreteTypeToMethod[reflect.TypeOf(&DebugLevelCmd{})]="debuglevel"

**注意这里面并没有定义如何处理这个命令. **

2. 命令处理

rpc server对一个命令的处理入口主要在rpcserver.go中,还是以debuglevel这个命令为例.
在rpcHandlersBeforeInit可以看到 "debuglevel"对应的处理函数是handleDebugLevel


// handleDebugLevel handles debuglevel commands.
func handleDebugLevel(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
	c := cmd.(*btcjson.DebugLevelCmd)

	// Special show command to list supported subsystems.
	if c.LevelSpec == "show" {
		return fmt.Sprintf("Supported subsystems %v",
			supportedSubsystems()), nil
	}

	err := parseAndSetDebugLevels(c.LevelSpec)
	if err != nil {
		return nil, &btcjson.RPCError{
			Code:    btcjson.ErrRPCInvalidParams.Code,
			Message: err.Error(),
		}
	}

	return "Done.", nil
}

走到这里的时候,框架已经做完参数解析以及初步验证,还有就是告诉你如何返回结果. cmd 参数就是DebugLevelCmd结构体.处理完毕以后直接返回结果即可.

需要说明的是closeChan一般不用,如果你处理的是一个长时间不能返回的任务,那么这时候有可能客户端已经停止请求了,这时候处理函数可以通过closeChan检测到这种情况来停止任务,然后返回一个错误信息.
比如return nil, ErrClientQuit

3. 客户端使用

具体见btcctl.go

	cmd, err := btcjson.NewCmd(method, params...)
	marshalledJSON, err := btcjson.MarshalCmd(1, cmd)
	result, err := sendPostRequest(marshalledJSON, cfg)
	//result就是命令的执行结果,根据情况进行解析

4. 其他

rpcserver是提供了外部使用者如何调控一个正在运行的btcd全节点.

  • 提供的接口完全兼容bitcoind.
  • 没有钱包相关功能
  • 很多命令提供的功能可以在btcd.conf预置
    • 比如可以在btcd.conf中指定debuglevel
      ###