Fabric-ca client端初始化过程源码分析
本文从Fabric-ca源码入手,以newRegisterCommand()函数为例,简单分析client启动时的过程。Fabric-ca源码可以从github.com下载,本文以v1.4.6为例进行简单分析。
与server相似,本文也是从main.go开始:
// fabric-ca/cmd/fabric-ca-client/main.go
package main
import (
...
)
// The fabric-ca client main
func main() {
if err := command.RunMain(os.Args); err != nil {
os.Exit(1)
}
}
main()函数只是调用了package command中的RunMain()函数,所以接下来我们以RunMain()函数为起点来简析client端的启动过程,其中包括client端的初始化以及跟server端的初次交互:
// fabric-ca/cmd/fabric-ca-client/command/root.go
package command
import "os"
// RunMain is the fabric-ca client main
func RunMain(args []string) error {
// Save the os.Args
saveOsArgs := os.Args
os.Args = args
// Execute the command
cmdName := ""
if len(args) > 1 {
cmdName = args[1]
}
ccmd := NewCommand(cmdName)
err := ccmd.Execute()
// Restore original os.Args
os.Args = saveOsArgs
return err
}
不难看出,与server类似,都是先通过NewCommand()函数来添加命令,之后再通过Execute()来执行操作:
// fabric-ca/cmd/fabric-ca-client/command/clientcmd.go
// ClientCmd encapsulates cobra command that provides command line interface
// for the Fabric CA client and the configuration used by the Fabric CA client
type ClientCmd struct {
// name of the sub command
name string
// rootCmd is the base command for the Hyerledger Fabric CA client
rootCmd *cobra.Command
// My viper instance
myViper *viper.Viper
// cfgFileName is the name of the configuration file
cfgFileName string
// homeDirectory is the location of the client's home directory
homeDirectory string
// clientCfg is the client's configuration
clientCfg *lib.ClientConfig
// cfgAttrs are the attributes specified via flags or env variables
// and translated to Attributes field in registration
cfgAttrs []string
// cfgAttrReqs are the attribute requests specified via flags or env variables
// and translated to the AttrReqs field in enrollment
cfgAttrReqs []string
// cfgCsrNames are the certificate signing request names specified via flags
// or env variables
cfgCsrNames []string
// csrCommonName is the certificate signing request common name specified via the flag
csrCommonName string
// gencrl command argument values
crlParams crlArgs
// revoke command argument values
revokeParams revokeArgs
// profileMode is the profiling mode, cpu or mem or empty
profileMode string
// profileInst is the profiling instance object
profileInst interface {
Stop()
}
// Dynamically configuring identities
dynamicIdentity identityArgs
// Dynamically configuring affiliations
dynamicAffiliation affiliationArgs
// Set to log level
logLevel string
}
// NewCommand returns new ClientCmd ready for running
func NewCommand(name string) *ClientCmd {
c := &ClientCmd{
myViper: viper.New(),
}
c.name = strings.ToLower(name)
c.init()
return c
}
...
// init initializes the ClientCmd instance
// It intializes the cobra root and sub commands and
// registers command flgs with viper
func (c *ClientCmd) init() {
...
c.rootCmd.AddCommand(c.newRegisterCommand(),
newEnrollCmd(c).getCommand(),
c.newReenrollCommand(),
c.newRevokeCommand(),
newGetCAInfoCmd(c).getCommand(),
c.newGenCsrCommand(),
c.newGenCRLCommand(),
c.newIdentityCommand(),
c.newAffiliationCommand(),
createCertificateCommand(c))
c.rootCmd.AddCommand(&cobra.Command{
Use: "version",
Short: "Prints Fabric CA Client version",
Run: func(cmd *cobra.Command, args []string) {
fmt.Print(metadata.GetVersionInfo(cmdName))
},
})
c.registerFlags()
...
}
在NewCommand()函数中,创建了一个*ClientCmd的对象,之后,调用该对象的init()方法。在init()方法中,首先实例化了*ClientCmd.rootCmd,其中会要执行checkAndEnableProfiling()来检查运行环境:
// checkAndEnableProfiling checks for the FABRIC_CA_CLIENT_PROFILE_MODE
// env variable, if it is set to "cpu", cpu profiling is enbled;
// if it is set to "heap", heap profiling is enabled
func (c *ClientCmd) checkAndEnableProfiling() error {
...
}
// registerFlags registers command flags with viper
func (c *ClientCmd) registerFlags() {
...
}
之后会调用AddCommand()函数来添加newRegisterCommand()、newEnrollCmd(c).getCommand()、newReenrollCommand()、newRevokeCommand()、newGetCAInfoCmd(c).getCommand()、newGenCsrCommand()、newGenCRLCommand()、newIdentityCommand()、newAffiliationCommand()、createCertificateCommand()和获取client版本的命令。随后执行c.registerFlags()操作。registerFlags()函数中主要是注册一些命令行参数,这里就不细究了。
newRegisterCommand()
// fabric-ca/cmd/fabric-ca-client/command/register.go
func (c *ClientCmd) newRegisterCommand() *cobra.Command {
...
}
// The client register main logic
func (c *ClientCmd) runRegister() error {
...
}
在newRegisterCommand()函数中,实例化了一个*cobra.Command命令对象,该对象中包含两个命令:ConfigInit()和runRegister()。ConfigInit()命令是为fabric-ca-client命令初始化一些配置,这里不做说明,而runRegister()中包含客户端注册的主要逻辑:首先实例化一个lib.Client结构体,之后导入client端的身份凭证client.LoadMyIdentity(),随后发起注册*Identity.Register()。
// fabric-ca/lib/client.go
// Client is the fabric-ca client object
type Client struct {
// The client's home directory
HomeDir string `json:"homeDir,omitempty"`
// The client's configuration
Config *ClientConfig
// Denotes if the client object is already initialized
initialized bool
// File and directory paths
keyFile, certFile, idemixCredFile, idemixCredsDir, ipkFile, caCertsDir string
// The crypto service provider (BCCSP)
csp bccsp.BCCSP
// HTTP client associated with this Fabric CA client
httpClient *http.Client
// Public key of Idemix issuer
issuerPublicKey *idemix.IssuerPublicKey
}
// LoadMyIdentity loads the client's identity from disk
func (c *Client) LoadMyIdentity() (*Identity, error) {
...
return c.LoadIdentity(c.keyFile, c.certFile, c.idemixCredFile)
}
// LoadIdentity loads an identity from disk
func (c *Client) LoadIdentity(keyFile, certFile, idemixCredFile string) (*Identity, error) {
...
return c.NewIdentity(creds)
}
// NewIdentity creates a new identity
func (c *Client) NewIdentity(creds []credential.Credential) (*Identity, error) {
...
return NewIdentity(c, name, creds), nil
}
如上,在LoadMyIdentity()中会先调用Init()来初始化client,然后再调用LoadIdentity()函数,从硬盘中导入身份凭证。在LoadIdentity()中同样会调用Init()来初始化client,之后会调用NewCredential()接口来导入x509和idemin格式的证书。证书读取完成后,调用NewIdentity()来创建新的身份认证。至此,身份导入过程就完成了,接下来就是注册了。
//fabric-ca/lib/identity.go
// Register registers a new identity
// @param req The registration request
func (i *Identity) Register(req *api.RegistrationRequest) (rr *api.RegistrationResponse, err error) {
...
}
在Register(),会将认证请求序列后,通过Post请求发送给服务端,并将服务端的应答返回给调用者。
// Post sends arbitrary request body (reqBody) to an endpoint.
// This adds an authorization header which contains the signature
// of this identity over the body and non-signature part of the authorization header.
// The return value is the body of the response.
func (i *Identity) Post(endpoint string, reqBody []byte, result interface{}, queryParam map[string]string) error {
...
}
至此,注册命令就结束了。
Fabric-ca client端初始化过程源码分析的更多相关文章
- Bootstrap初始化过程源码分析--netty客户端的启动
Bootstrap初始化过程 netty的客户端引导类是Bootstrap,我们看一下spark的rpc中客户端部分对Bootstrap的初始化过程 TransportClientFactory.cr ...
- A2dp初始化流程源码分析
蓝牙启动的时候,会涉及到各个profile 的启动.这篇文章分析一下,蓝牙中a2dp profile的初始化流程. 我们从AdapterState.java中对于USER_TURN_ON 消息的处理说 ...
- A2dp sink 初始化流程源码分析
A2dp sink的初始化流程和A2dp 的初始化流程,基本一样,这里做简单分析.这里分析的android的版本是Android O. 我们先从service的启动说起吧. 下面 是启动的时候的log ...
- Netty入门一:服务端应用搭建 & 启动过程源码分析
最近周末也没啥事就学学Netty,同时打算写一些博客记录一下(写的过程理解更加深刻了) 本文主要从三个方法来呈现:Netty核心组件简介.Netty服务端创建.Netty启动过程源码分析 如果你对Ne ...
- SpringSecurity 初始化流程源码
SpringSecurity 初始化流程源码 本篇主要讲解 SpringSecurity初始化流程的源码部分,包括核心的 springSecurityFilterChain 是如何创建的,以及在介绍哪 ...
- Spark(五十一):Spark On YARN(Yarn-Cluster模式)启动流程源码分析(二)
上篇<Spark(四十九):Spark On YARN启动流程源码分析(一)>我们讲到启动SparkContext初始化,ApplicationMaster启动资源中,讲解的内容明显不完整 ...
- Dubbo消费方服务调用过程源码分析
参考:dubbo消费方服务调用过程源码分析dubbo基于spring的构建分析Dubbo概述--调用过程dubbo 请求调用过程分析dubbo集群容错机制代码分析1dubbo集群容错策略的代码分析2d ...
- [Android]从Launcher开始启动App流程源码分析
以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5017056.html 从Launcher开始启动App流程源码 ...
- spark源码阅读--shuffle读过程源码分析
shuffle读过程源码分析 上一篇中,我们分析了shuffle在map阶段的写过程.简单回顾一下,主要是将ShuffleMapTask计算的结果数据在内存中按照分区和key进行排序,过程中由于内存限 ...
- Spark(四十九):Spark On YARN启动流程源码分析(一)
引导: 该篇章主要讲解执行spark-submit.sh提交到将任务提交给Yarn阶段代码分析. spark-submit的入口函数 一般提交一个spark作业的方式采用spark-submit来提交 ...
随机推荐
- 创元集团的数智化实践 这次选择了和火山引擎 VeDI 搭档
更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 近日,上海创元化妆品有限公司(以下简称"创元集团")与火山引擎数智平台 VeDI 达成合作,旨 ...
- ByteHouse:基于ClickHouse的实时数仓能力升级解读
更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 ByteHouse是火山引擎上的一款云原生数据仓库,为用户带来极速分析体验,能够支撑实时数据分析和海量数据离 ...
- 复旦大学2020考研机试题-编程能力摸底试题(A-E)
A.斗牛 给定五个0~9范围内的整数a1,a2,a3,a4,a5.如果能从五个整数中选出三个并且这三个整数的和为10的倍数(包括0),那么这五个整数的权值即为剩下两个没被选出来的整数的和对10取余的结 ...
- 图扑数字孪生智慧机场,助推民航"四型机场"建设
前言 民航局印发的<智慧民航建设路线图>文件中,明确提出智慧机场是智慧民航的四个核心抓手之一.并从机场全域协同运行.作业与服务智能化.智慧建造与运维方面,为智慧机场的发展绘制了清晰的蓝图. ...
- 使用 nacos 搭建注册中心及配置中心
本文为博主原创,转载请注明出处: 在分布式微服务框架中,现在都流行使用 nacos 作为分布式框架的注册中心与配置中心.当我们搭建一套spring boot 框架的时候,默认会将配置文件 放在 res ...
- 在线P图工具(基于minipaint开发)
在浏览github过程中,发现一个超级实用的仓库,viliulsle开发的minipaint,类似于photoshop的网页版.基于webpack开发的,打包非常简单,故自己搭建了一套. 在线预览 在 ...
- css - 编写 兼容到ie7的导航
1, index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset=& ...
- Java-Enum常量特定方法
OnJava8-Enum-常量特定方法 用枚举实现责任链模式 责任链(Chain Of Responsibility)设计模式先创建了一批用于解决目标问题的不同方法,然后将它们连成一条"链& ...
- Mongo-文档主键-ObjectId
文档主键 文档主键时 _id,如果插入文档时,没有传入则自动生产ObjectId 作为文档主键 文档主键要求在集合中唯一 文档主键可以时另一个文档,被当作字符串对象处理 ObjectId对象 获取文档 ...
- Mygin实现上下文
本篇是Mygin的第三篇 目的 将路由独立出来,方便后续扩展修改 上下文Context,对http.ResponseWriter和http.Request进行封装,实现对JSON.HTML等的支持 路 ...