Derek解读Bytom源码-Api Server接口服务
作者: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函数我们看到有三个操作:
- 实例化api对象
- api.buildhandler添加router路由项
- 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已经处于等待接收用户的请求。