作者: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已經處於等待接收使用者的請求。