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 (
"blockbook/bchain"
"blockbook/common"
"blockbook/db"
"math/big"
"time"
@ -112,18 +113,21 @@ type Block struct {
}
type BlockbookInfo 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"`
DbSize int64 `json:"dbSize"`
About string `json:"about"`
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"`
DbSize int64 `json:"dbSize"`
DbSizeFromColumns int64 `json:"dbSizeFromColumns,omitempty"`
DbColumns []common.InternalStateColumn `json:"dbColumns,omitempty"`
About string `json:"about"`
}
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
func (w *Worker) GetSystemInfo() (*SystemInfo, error) {
func (w *Worker) GetSystemInfo(internal bool) (*SystemInfo, error) {
start := time.Now()
ci, err := w.chain.GetChainInfo()
if err != nil {
@ -534,20 +534,29 @@ func (w *Worker) GetSystemInfo() (*SystemInfo, error) {
}
vi := common.GetVersionInfo()
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{
Coin: w.is.Coin,
Host: w.is.Host,
Version: vi.Version,
GitCommit: vi.GitCommit,
BuildTime: vi.BuildTime,
InSync: ss,
BestHeight: bh,
LastBlockTime: st,
InSyncMempool: ms,
LastMempoolTime: mt,
About: BlockbookAbout,
DbSize: w.db.DatabaseSizeOnDisk(),
Coin: w.is.Coin,
Host: w.is.Host,
Version: vi.Version,
GitCommit: vi.GitCommit,
BuildTime: vi.BuildTime,
InSync: ss,
BestHeight: bh,
LastBlockTime: st,
InSyncMempool: ms,
LastMempoolTime: mt,
MempoolSize: msz,
DbSize: w.db.DatabaseSizeOnDisk(),
DbSizeFromColumns: dbs,
DbColumns: dbc,
About: BlockbookAbout,
}
glog.Info("GetSystemInfo finished in ", time.Since(start))
return &SystemInfo{bi, ci}, nil

View File

@ -1,20 +1,17 @@
package server
import (
"blockbook/api"
"blockbook/bchain"
"blockbook/common"
"blockbook/db"
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"strconv"
"time"
"github.com/golang/glog"
"github.com/gorilla/mux"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
@ -27,29 +24,21 @@ type InternalServer struct {
chain bchain.BlockChain
chainParser bchain.BlockChainParser
is *common.InternalState
}
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"`
api *api.Worker
}
// 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) {
r := mux.NewRouter()
func NewInternalServer(binding, certFiles string, db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxCache, is *common.InternalState) (*InternalServer, error) {
api, err := api.NewWorker(db, chain, txCache, is)
if err != nil {
return nil, err
}
addr, path := splitBinding(binding)
serveMux := http.NewServeMux()
https := &http.Server{
Addr: httpServerBinding,
Handler: r,
Addr: addr,
Handler: serveMux,
}
s := &InternalServer{
https: https,
@ -59,15 +48,11 @@ func NewInternalServer(httpServerBinding string, certFiles string, db *db.RocksD
chain: chain,
chainParser: chain.GetChainParser(),
is: is,
api: api,
}
r.HandleFunc("/", s.index)
r.HandleFunc("/bestBlockHash", s.bestBlockHash)
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)
serveMux.HandleFunc(path+"metrics", promhttp.Handler().ServeHTTP)
serveMux.HandleFunc(path, s.index)
return s, nil
}
@ -94,142 +79,11 @@ func (s *InternalServer) Shutdown(ctx context.Context) error {
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) {
vi := common.GetVersionInfo()
ss, bh, st := s.is.GetSyncState()
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, "", " ")
si, err := s.api.GetSystemInfo(true)
buf, err := json.MarshalIndent(si, "", " ")
if err != nil {
glog.Error(err)
}
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 err error
s.metrics.ExplorerViews.With(common.Labels{"action": "index"}).Inc()
si, err = s.api.GetSystemInfo()
si, err = s.api.GetSystemInfo(false)
if err != nil {
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) {
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) {