diff --git a/api/types.go b/api/types.go
index 901d466f..22d8d15c 100644
--- a/api/types.go
+++ b/api/types.go
@@ -4,8 +4,11 @@ import (
"blockbook/bchain"
"blockbook/db"
"math/big"
+ "time"
)
+const BlockbookAbout = "Blockbook - blockchain indexer for TREZOR wallet https://trezor.io/. Do not use for any other purpose."
+
type ApiError struct {
Text string
Public bool
@@ -100,3 +103,23 @@ type Blocks struct {
Paging
Blocks []db.BlockInfo `json:"blocks"`
}
+
+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"`
+}
+
+type SystemInfo struct {
+ Blockbook *BlockbookInfo `json:"blockbook"`
+ Backend *bchain.ChainInfo `json:"backend"`
+}
diff --git a/api/worker.go b/api/worker.go
index eb3b1a32..6c018d7a 100644
--- a/api/worker.go
+++ b/api/worker.go
@@ -465,3 +465,31 @@ func (w *Worker) GetBlocks(page int, blocksOnPage int) (*Blocks, error) {
glog.Info("GetBlocks page ", page, " finished in ", time.Since(start))
return r, nil
}
+
+// GetSystemInfo returns information about system
+func (w *Worker) GetSystemInfo() (*SystemInfo, error) {
+ start := time.Now()
+ ci, err := w.chain.GetChainInfo()
+ if err != nil {
+ return nil, errors.Annotatef(err, "GetChainInfo")
+ }
+ vi := common.GetVersionInfo()
+ ss, bh, st := w.is.GetSyncState()
+ ms, mt, _ := w.is.GetMempoolSyncState()
+ 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(),
+ }
+ glog.Info("GetSystemInfo finished in ", time.Since(start))
+ return &SystemInfo{bi, ci}, nil
+}
diff --git a/server/public.go b/server/public.go
index 3c67e9c2..dbcb420f 100644
--- a/server/public.go
+++ b/server/public.go
@@ -19,7 +19,6 @@ import (
"github.com/golang/glog"
)
-const blockbookAbout = "Blockbook - blockchain indexer for TREZOR wallet https://trezor.io/. Do not use for any other purpose."
const txsOnPage = 25
const blocksOnPage = 50
const txsInAPI = 1000
@@ -95,10 +94,11 @@ func NewPublicServer(binding string, certFiles string, db *db.RocksDB, chain bch
serveMux.HandleFunc(path+"api/block-index/", s.jsonHandler(s.apiBlockIndex))
serveMux.HandleFunc(path+"api/tx/", s.jsonHandler(s.apiTx))
serveMux.HandleFunc(path+"api/address/", s.jsonHandler(s.apiAddress))
+ serveMux.HandleFunc(path+"api/", s.jsonHandler(s.apiIndex))
// handle socket.io
serveMux.Handle(path+"socket.io/", socketio.GetHandler())
// default handler
- serveMux.HandleFunc(path, s.index)
+ serveMux.HandleFunc(path, s.htmlTemplateHandler(s.explorerIndex))
s.templates = parseTemplates()
@@ -277,6 +277,7 @@ type tpl int
const (
noTpl = tpl(iota)
errorTpl
+ indexTpl
txTpl
addressTpl
blocksTpl
@@ -292,6 +293,7 @@ type TemplateData struct {
Tx *api.Tx
Error *api.ApiError
Blocks *api.Blocks
+ Info *api.SystemInfo
Page int
PrevPage int
NextPage int
@@ -300,6 +302,7 @@ type TemplateData struct {
func parseTemplates() []*template.Template {
templateFuncMap := template.FuncMap{
+ "formatTime": formatTime,
"formatUnixTime": formatUnixTime,
"formatAmount": formatAmount,
"setTxToTemplateData": setTxToTemplateData,
@@ -307,6 +310,7 @@ func parseTemplates() []*template.Template {
}
t := make([]*template.Template, tplCount)
t[errorTpl] = template.Must(template.New("error").Funcs(templateFuncMap).ParseFiles("./static/templates/error.html", "./static/templates/base.html"))
+ t[indexTpl] = template.Must(template.New("index").Funcs(templateFuncMap).ParseFiles("./static/templates/index.html", "./static/templates/base.html"))
t[txTpl] = template.Must(template.New("tx").Funcs(templateFuncMap).ParseFiles("./static/templates/tx.html", "./static/templates/txdetail.html", "./static/templates/base.html"))
t[addressTpl] = template.Must(template.New("address").Funcs(templateFuncMap).ParseFiles("./static/templates/address.html", "./static/templates/txdetail.html", "./static/templates/paging.html", "./static/templates/base.html"))
t[blocksTpl] = template.Must(template.New("blocks").Funcs(templateFuncMap).ParseFiles("./static/templates/blocks.html", "./static/templates/paging.html", "./static/templates/base.html"))
@@ -314,7 +318,11 @@ func parseTemplates() []*template.Template {
}
func formatUnixTime(ut int64) string {
- return time.Unix(ut, 0).Format(time.RFC1123)
+ return formatTime(time.Unix(ut, 0))
+}
+
+func formatTime(t time.Time) string {
+ return t.Format(time.RFC1123)
}
// for now return the string as it is
@@ -388,6 +396,19 @@ func (s *PublicServer) explorerBlocks(w http.ResponseWriter, r *http.Request) (t
return blocksTpl, data, nil
}
+func (s *PublicServer) explorerIndex(w http.ResponseWriter, r *http.Request) (tpl, *TemplateData, error) {
+ var si *api.SystemInfo
+ var err error
+ s.metrics.ExplorerViews.With(common.Labels{"action": "index"}).Inc()
+ si, err = s.api.GetSystemInfo()
+ if err != nil {
+ return errorTpl, nil, err
+ }
+ data := s.newTemplateData()
+ data.Info = si
+ return indexTpl, data, nil
+}
+
func (s *PublicServer) explorerSearch(w http.ResponseWriter, r *http.Request) (tpl, *TemplateData, error) {
q := strings.TrimSpace(r.URL.Query().Get("q"))
var tx *api.Tx
@@ -471,50 +492,14 @@ func getPagingRange(page int, total int) ([]int, int, int) {
return r, pp, np
}
-type resAboutBlockbookPublic 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"`
- About string `json:"about"`
-}
-
-// TODO - this is temporary, return html status page
-func (s *PublicServer) index(w http.ResponseWriter, r *http.Request) {
- vi := common.GetVersionInfo()
- ss, bh, st := s.is.GetSyncState()
- ms, mt, _ := s.is.GetMempoolSyncState()
- a := resAboutBlockbookPublic{
- 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,
- About: blockbookAbout,
- }
- w.Header().Set("Content-Type", "application/json; charset=utf-8")
- buf, err := json.MarshalIndent(a, "", " ")
- if err != nil {
- glog.Error(err)
- }
- w.Write(buf)
+func (s *PublicServer) apiIndex(r *http.Request) (interface{}, error) {
+ s.metrics.ExplorerViews.With(common.Labels{"action": "api-index"}).Inc()
+ return s.api.GetSystemInfo()
}
func (s *PublicServer) apiBlockIndex(r *http.Request) (interface{}, error) {
type resBlockIndex struct {
BlockHash string `json:"blockHash"`
- About string `json:"about"`
}
var err error
var hash string
@@ -535,7 +520,6 @@ func (s *PublicServer) apiBlockIndex(r *http.Request) (interface{}, error) {
}
return resBlockIndex{
BlockHash: hash,
- About: blockbookAbout,
}, nil
}
diff --git a/server/socketio.go b/server/socketio.go
index 9d3dc5c4..2e931d1f 100644
--- a/server/socketio.go
+++ b/server/socketio.go
@@ -551,7 +551,7 @@ func (s *SocketIoServer) getInfo() (res resultGetInfo, err error) {
res.Result.Network = s.chain.GetNetworkName()
res.Result.Subversion = s.chain.GetSubversion()
res.Result.CoinName = s.chain.GetCoinName()
- res.Result.About = blockbookAbout
+ res.Result.About = api.BlockbookAbout
return
}
diff --git a/static/templates/index.html b/static/templates/index.html
new file mode 100644
index 00000000..fbc31bd8
--- /dev/null
+++ b/static/templates/index.html
@@ -0,0 +1,94 @@
+{{define "specific"}}{{$cs := .CoinShortcut}}{{$bb := .Info.Blockbook}}{{$be := .Info.Backend}}
+
Application status
+
+
+
Blockbook
+
+
+
+ | Coin |
+ {{$bb.Coin}} |
+
+
+ | Host |
+ {{$bb.Host}} |
+
+
+ | Version / Commit / Build |
+ {{$bb.Version}} / {{$bb.GitCommit}} / {{$bb.BuildTime}} |
+
+
+ | Synchronized |
+ {{$bb.InSync}} |
+
+
+ | Last Block |
+ {{$bb.BestHeight}} |
+
+
+ | Last Block Update |
+ {{formatTime $bb.LastBlockTime}} |
+
+
+ | Mempool in Sync |
+ {{$bb.InSyncMempool}} |
+
+
+ | Last Mempool Update |
+ {{formatTime $bb.LastMempoolTime}} |
+
+
+ | Size On Disk |
+ {{$bb.DbSize}} |
+
+
+
+
+
+
Backend
+
+
+
+ | Chain |
+ {{$be.Chain}} |
+
+
+ | Version |
+ {{$be.Version}} |
+
+
+ | Subversion |
+ {{$be.Subversion}} |
+
+
+ | Protocol Version |
+ {{$be.ProtocolVersion}} |
+
+
+ | Last Block |
+ {{$be.Blocks}} |
+
+
+ | Difficulty |
+ {{$be.Difficulty}} |
+
+
+ | Timeoffset |
+ {{$be.Timeoffset}} |
+
+
+ | Size On Disk |
+ {{$be.SizeOnDisk}} |
+
+ {{- if $be.Warnings -}}
+
+ | Warnings |
+ {{$be.Warnings}} |
+
+ {{- end -}}
+
+
+
+
+{{$bb.About}}
+{{end}}
\ No newline at end of file