欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Derek解读Bytom源码-Api Server接口服务

程序员文章站 2022-10-04 21:38:42
作者:Derek 简介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockchain/bytom 本章介绍bytom代码Api Server接口服务 作者使用MacOS操作系统,其他平台也大同小异 ......

作者:derek

简介

github地址:https://github.com/bytom/bytom

gitee地址:https://gitee.com/bytomblockchain/bytom

本章介绍bytom代码api-server接口服务

作者使用macos操作系统,其他平台也大同小异

golang version: 1.8

api-server接口服务

api server是比原链中非常重要的一个功能,在比原链的架构中专门服务于bytomcli和dashboard,他的功能是接收并处理用户和矿池相关的请求。默认启动9888端口。总之主要功能如下:

  • 接收并处理用户或矿池发送的请求
  • 管理交易:打包、签名、提交等操作
  • 管理本地比原钱包
  • 管理本地p2p节点信息
  • 管理本地矿工挖矿操作等

在api server服务过程中,在监听地址listener上接收bytomcli或dashboard的请求访问。对每一个请求,api server均会创建一个新的goroutine来处理请求。首先api server读取请求内容,解析请求,接着匹配相应的路由项,随后调用路由项的handler回调函数来处理。最后handler处理完请求之后给bytomcli响应该请求。

api-server源码分析

在bytomd启动过程中,bytomd使用golang标准库http.newservemux()创建一个router路由器,提供请求的路由分发功能。创建api server主要有三部分组成:

  • 初始化http.newservemux()得到mux
  • 为mux.handle添加多个有效的router路由项。每一个路由项由http请求方法(get、post、put、delet)、url和handler回调函数组成
  • 将监听地址作为参数,最终执行serve(listener)开始服务于外部请求

创建api对象

node/node.go

func (n *node) initandstartapiserver() {
    n.api = api.newapi(n.syncmanager, n.wallet, n.txfeed, n.cpuminer, n.miningpool, n.chain, n.config, n.accesstokens)

    listenaddr := env.string("listen", n.config.apiaddress)
    env.parse()
    n.api.startserver(*listenaddr)
}

api/api.go

func newapi(sync *netsync.syncmanager, wallet *wallet.wallet, txfeeds *txfeed.tracker, cpuminer *cpuminer.cpuminer, miningpool *miningpool.miningpool, chain *protocol.chain, config *cfg.config, token *accesstoken.credentialstore) *api {
    api := &api{
        sync:          sync,
        wallet:        wallet,
        chain:         chain,
        accesstokens:  token,
        txfeedtracker: txfeeds,
        cpuminer:      cpuminer,
        miningpool:    miningpool,
    }
    api.buildhandler()
    api.initserver(config)

    return api
}

首先,实例化api对象。api-server管理的事情很多,所以参数也相对较多。
listenaddr本地端口,如果系统没有设置listen变量则使用config.apiaddress配置地址,默认为9888

newapi函数我们看到有三个操作:

  1. 实例化api对象
  2. api.buildhandler添加router路由项
  3. api.initserver实例化http.server,配置auth验证等

router路由项

func (a *api) buildhandler() {
    walletenable := false
    m := http.newservemux()
    if a.wallet != nil {
        walletenable = true

        m.handle("/create-account", jsonhandler(a.createaccount))
        m.handle("/list-accounts", jsonhandler(a.listaccounts))
        m.handle("/delete-account", jsonhandler(a.deleteaccount))
    // ...
    }
}

router路由项过多。这里只介绍关于账号相关的handler。其他的handler大同小异。

m.handle("/create-account", jsonhandler(a.createaccount))

我们可以看到一条router项由url和对应的handle回调函数组成。当我们请求的url匹配到/create-account时,api-server会执行a.createaccount函数,并将用户的传参也带过去。

启动api-server服务

api/api.go

func (a *api) startserver(address string) {
    log.withfield("api address:", address).info("rpc listen")
    listener, err := net.listen("tcp", address)
    if err != nil {
        cmn.exit(cmn.fmt("failed to register tcp port: %v", err))
    }

    go func() {
        if err := a.server.serve(listener); err != nil {
            log.withfield("error", errors.wrap(err, "serve")).error("rpc server")
        }
    }()
}

通过golang标准库net.listen方法,监听本地的地址端口。由于http服务是一个持久运行的服务,我们启动一个go程专门运行http服务。当运行a.server.serve没有任何报错时,我们可以看到服务器上启动的9888端口。此时api-server已经处于等待接收用户的请求。