Cleanup of internal http interface

This commit is contained in:
Martin Boehm 2018-09-19 15:59:49 +02:00
parent e260c11839
commit bb48f2d26e
4 changed files with 58 additions and 191 deletions

View File

@ -2,6 +2,7 @@ package api
import ( import (
"blockbook/bchain" "blockbook/bchain"
"blockbook/common"
"blockbook/db" "blockbook/db"
"math/big" "math/big"
"time" "time"
@ -112,18 +113,21 @@ type Block struct {
} }
type BlockbookInfo struct { type BlockbookInfo struct {
Coin string `json:"coin"` Coin string `json:"coin"`
Host string `json:"host"` Host string `json:"host"`
Version string `json:"version"` Version string `json:"version"`
GitCommit string `json:"gitcommit"` GitCommit string `json:"gitcommit"`
BuildTime string `json:"buildtime"` BuildTime string `json:"buildtime"`
InSync bool `json:"inSync"` InSync bool `json:"inSync"`
BestHeight uint32 `json:"bestHeight"` BestHeight uint32 `json:"bestHeight"`
LastBlockTime time.Time `json:"lastBlockTime"` LastBlockTime time.Time `json:"lastBlockTime"`
InSyncMempool bool `json:"inSyncMempool"` InSyncMempool bool `json:"inSyncMempool"`
LastMempoolTime time.Time `json:"lastMempoolTime"` LastMempoolTime time.Time `json:"lastMempoolTime"`
DbSize int64 `json:"dbSize"` MempoolSize int `json:"mempoolSize"`
About string `json:"about"` DbSize int64 `json:"dbSize"`
DbSizeFromColumns int64 `json:"dbSizeFromColumns,omitempty"`
DbColumns []common.InternalStateColumn `json:"dbColumns,omitempty"`
About string `json:"about"`
} }
type SystemInfo struct { type SystemInfo struct {

View File

@ -526,7 +526,7 @@ func (w *Worker) GetBlock(bid string, page int, txsOnPage int) (*Block, error) {
} }
// GetSystemInfo returns information about system // GetSystemInfo returns information about system
func (w *Worker) GetSystemInfo() (*SystemInfo, error) { func (w *Worker) GetSystemInfo(internal bool) (*SystemInfo, error) {
start := time.Now() start := time.Now()
ci, err := w.chain.GetChainInfo() ci, err := w.chain.GetChainInfo()
if err != nil { if err != nil {
@ -534,20 +534,29 @@ func (w *Worker) GetSystemInfo() (*SystemInfo, error) {
} }
vi := common.GetVersionInfo() vi := common.GetVersionInfo()
ss, bh, st := w.is.GetSyncState() ss, bh, st := w.is.GetSyncState()
ms, mt, _ := w.is.GetMempoolSyncState() ms, mt, msz := w.is.GetMempoolSyncState()
var dbc []common.InternalStateColumn
var dbs int64
if internal {
dbc = w.is.GetAllDBColumnStats()
dbs = w.is.DBSizeTotal()
}
bi := &BlockbookInfo{ bi := &BlockbookInfo{
Coin: w.is.Coin, Coin: w.is.Coin,
Host: w.is.Host, Host: w.is.Host,
Version: vi.Version, Version: vi.Version,
GitCommit: vi.GitCommit, GitCommit: vi.GitCommit,
BuildTime: vi.BuildTime, BuildTime: vi.BuildTime,
InSync: ss, InSync: ss,
BestHeight: bh, BestHeight: bh,
LastBlockTime: st, LastBlockTime: st,
InSyncMempool: ms, InSyncMempool: ms,
LastMempoolTime: mt, LastMempoolTime: mt,
About: BlockbookAbout, MempoolSize: msz,
DbSize: w.db.DatabaseSizeOnDisk(), DbSize: w.db.DatabaseSizeOnDisk(),
DbSizeFromColumns: dbs,
DbColumns: dbc,
About: BlockbookAbout,
} }
glog.Info("GetSystemInfo finished in ", time.Since(start)) glog.Info("GetSystemInfo finished in ", time.Since(start))
return &SystemInfo{bi, ci}, nil return &SystemInfo{bi, ci}, nil

View File

@ -1,20 +1,17 @@
package server package server
import ( import (
"blockbook/api"
"blockbook/bchain" "blockbook/bchain"
"blockbook/common" "blockbook/common"
"blockbook/db" "blockbook/db"
"context" "context"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"net/http" "net/http"
"strconv"
"time"
"github.com/golang/glog" "github.com/golang/glog"
"github.com/gorilla/mux"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
) )
@ -27,29 +24,21 @@ type InternalServer struct {
chain bchain.BlockChain chain bchain.BlockChain
chainParser bchain.BlockChainParser chainParser bchain.BlockChainParser
is *common.InternalState is *common.InternalState
} api *api.Worker
type resAboutBlockbookInternal struct {
Coin string `json:"coin"`
Host string `json:"host"`
Version string `json:"version"`
GitCommit string `json:"gitcommit"`
BuildTime string `json:"buildtime"`
InSync bool `json:"inSync"`
BestHeight uint32 `json:"bestHeight"`
LastBlockTime time.Time `json:"lastBlockTime"`
InSyncMempool bool `json:"inSyncMempool"`
LastMempoolTime time.Time `json:"lastMempoolTime"`
MempoolSize int `json:"mempoolSize"`
DbColumns []common.InternalStateColumn `json:"dbColumns"`
} }
// NewInternalServer creates new internal http interface to blockbook and returns its handle // NewInternalServer creates new internal http interface to blockbook and returns its handle
func NewInternalServer(httpServerBinding string, certFiles string, db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxCache, is *common.InternalState) (*InternalServer, error) { func NewInternalServer(binding, certFiles string, db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxCache, is *common.InternalState) (*InternalServer, error) {
r := mux.NewRouter() api, err := api.NewWorker(db, chain, txCache, is)
if err != nil {
return nil, err
}
addr, path := splitBinding(binding)
serveMux := http.NewServeMux()
https := &http.Server{ https := &http.Server{
Addr: httpServerBinding, Addr: addr,
Handler: r, Handler: serveMux,
} }
s := &InternalServer{ s := &InternalServer{
https: https, https: https,
@ -59,15 +48,11 @@ func NewInternalServer(httpServerBinding string, certFiles string, db *db.RocksD
chain: chain, chain: chain,
chainParser: chain.GetChainParser(), chainParser: chain.GetChainParser(),
is: is, is: is,
api: api,
} }
r.HandleFunc("/", s.index) serveMux.HandleFunc(path+"metrics", promhttp.Handler().ServeHTTP)
r.HandleFunc("/bestBlockHash", s.bestBlockHash) serveMux.HandleFunc(path, s.index)
r.HandleFunc("/blockHash/{height}", s.blockHash)
r.HandleFunc("/transactions/{address}/{lower}/{higher}", s.transactions)
r.HandleFunc("/confirmedTransactions/{address}/{lower}/{higher}", s.confirmedTransactions)
r.HandleFunc("/unconfirmedTransactions/{address}", s.unconfirmedTransactions)
r.HandleFunc("/metrics", promhttp.Handler().ServeHTTP)
return s, nil return s, nil
} }
@ -94,142 +79,11 @@ func (s *InternalServer) Shutdown(ctx context.Context) error {
return s.https.Shutdown(ctx) return s.https.Shutdown(ctx)
} }
func respondError(w http.ResponseWriter, err error, context string) {
w.WriteHeader(http.StatusBadRequest)
glog.Errorf("internal server: (context %s) error: %v", context, err)
}
func respondHashData(w http.ResponseWriter, hash string) {
type hashData struct {
Hash string `json:"hash"`
}
json.NewEncoder(w).Encode(hashData{
Hash: hash,
})
}
func (s *InternalServer) index(w http.ResponseWriter, r *http.Request) { func (s *InternalServer) index(w http.ResponseWriter, r *http.Request) {
vi := common.GetVersionInfo() si, err := s.api.GetSystemInfo(true)
ss, bh, st := s.is.GetSyncState() buf, err := json.MarshalIndent(si, "", " ")
ms, mt, msz := s.is.GetMempoolSyncState()
a := resAboutBlockbookInternal{
Coin: s.is.Coin,
Host: s.is.Host,
Version: vi.Version,
GitCommit: vi.GitCommit,
BuildTime: vi.BuildTime,
InSync: ss,
BestHeight: bh,
LastBlockTime: st,
InSyncMempool: ms,
LastMempoolTime: mt,
MempoolSize: msz,
DbColumns: s.is.GetAllDBColumnStats(),
}
buf, err := json.MarshalIndent(a, "", " ")
if err != nil { if err != nil {
glog.Error(err) glog.Error(err)
} }
w.Write(buf) w.Write(buf)
} }
func (s *InternalServer) bestBlockHash(w http.ResponseWriter, r *http.Request) {
_, hash, err := s.db.GetBestBlock()
if err != nil {
respondError(w, err, "bestBlockHash")
return
}
respondHashData(w, hash)
}
func (s *InternalServer) blockHash(w http.ResponseWriter, r *http.Request) {
heightString := mux.Vars(r)["height"]
var hash string
height, err := strconv.ParseUint(heightString, 10, 32)
if err == nil {
hash, err = s.db.GetBlockHash(uint32(height))
}
if err != nil {
respondError(w, err, fmt.Sprintf("blockHash %s", heightString))
} else {
respondHashData(w, hash)
}
}
func (s *InternalServer) getAddress(r *http.Request) (address string, err error) {
address, ok := mux.Vars(r)["address"]
if !ok {
err = errors.New("Empty address")
}
return
}
func (s *InternalServer) getAddressAndHeightRange(r *http.Request) (address string, lower, higher uint32, err error) {
address, err = s.getAddress(r)
if err != nil {
return
}
higher64, err := strconv.ParseUint(mux.Vars(r)["higher"], 10, 32)
if err != nil {
return
}
lower64, err := strconv.ParseUint(mux.Vars(r)["lower"], 10, 32)
if err != nil {
return
}
return address, uint32(lower64), uint32(higher64), err
}
type transactionList struct {
Txid []string `json:"txid"`
}
func (s *InternalServer) unconfirmedTransactions(w http.ResponseWriter, r *http.Request) {
address, err := s.getAddress(r)
if err != nil {
respondError(w, err, fmt.Sprint("unconfirmedTransactions for address", address))
}
txs, err := s.chain.GetMempoolTransactions(address)
if err != nil {
respondError(w, err, fmt.Sprint("unconfirmedTransactions for address", address))
}
txList := transactionList{Txid: txs}
json.NewEncoder(w).Encode(txList)
}
func (s *InternalServer) confirmedTransactions(w http.ResponseWriter, r *http.Request) {
address, lower, higher, err := s.getAddressAndHeightRange(r)
if err != nil {
respondError(w, err, fmt.Sprint("confirmedTransactions for address", address))
}
txList := transactionList{}
err = s.db.GetTransactions(address, lower, higher, func(txid string, vout uint32, isOutput bool) error {
txList.Txid = append(txList.Txid, txid)
return nil
})
if err != nil {
respondError(w, err, fmt.Sprint("confirmedTransactions for address", address))
}
json.NewEncoder(w).Encode(txList)
}
func (s *InternalServer) transactions(w http.ResponseWriter, r *http.Request) {
address, lower, higher, err := s.getAddressAndHeightRange(r)
if err != nil {
respondError(w, err, fmt.Sprint("transactions for address", address))
}
txList := transactionList{}
err = s.db.GetTransactions(address, lower, higher, func(txid string, vout uint32, isOutput bool) error {
txList.Txid = append(txList.Txid, txid)
return nil
})
if err != nil {
respondError(w, err, fmt.Sprint("transactions for address", address))
}
txs, err := s.chain.GetMempoolTransactions(address)
if err != nil {
respondError(w, err, fmt.Sprint("transactions for address", address))
}
txList.Txid = append(txList.Txid, txs...)
json.NewEncoder(w).Encode(txList)
}

View File

@ -426,7 +426,7 @@ func (s *PublicServer) explorerIndex(w http.ResponseWriter, r *http.Request) (tp
var si *api.SystemInfo var si *api.SystemInfo
var err error var err error
s.metrics.ExplorerViews.With(common.Labels{"action": "index"}).Inc() s.metrics.ExplorerViews.With(common.Labels{"action": "index"}).Inc()
si, err = s.api.GetSystemInfo() si, err = s.api.GetSystemInfo(false)
if err != nil { if err != nil {
return errorTpl, nil, err return errorTpl, nil, err
} }
@ -522,7 +522,7 @@ func getPagingRange(page int, total int) ([]int, int, int) {
func (s *PublicServer) apiIndex(r *http.Request) (interface{}, error) { func (s *PublicServer) apiIndex(r *http.Request) (interface{}, error) {
s.metrics.ExplorerViews.With(common.Labels{"action": "api-index"}).Inc() s.metrics.ExplorerViews.With(common.Labels{"action": "api-index"}).Inc()
return s.api.GetSystemInfo() return s.api.GetSystemInfo(false)
} }
func (s *PublicServer) apiBlockIndex(r *http.Request) (interface{}, error) { func (s *PublicServer) apiBlockIndex(r *http.Request) (interface{}, error) {