Start public interface in limited mode before initial sync #51

pull/56/head
Martin Boehm 2018-09-20 12:15:46 +02:00
parent 9a33c338dd
commit d6b9cd496b
7 changed files with 84 additions and 40 deletions

View File

@ -118,6 +118,8 @@ type BlockbookInfo struct {
Version string `json:"version"`
GitCommit string `json:"gitcommit"`
BuildTime string `json:"buildtime"`
SyncMode bool `json:"syncMode"`
InitialSync bool `json:"initialsync"`
InSync bool `json:"inSync"`
BestHeight uint32 `json:"bestHeight"`
LastBlockTime time.Time `json:"lastBlockTime"`

View File

@ -547,6 +547,8 @@ func (w *Worker) GetSystemInfo(internal bool) (*SystemInfo, error) {
Version: vi.Version,
GitCommit: vi.GitCommit,
BuildTime: vi.BuildTime,
SyncMode: w.is.SyncMode,
InitialSync: w.is.InitialSync,
InSync: ss,
BestHeight: bh,
LastBlockTime: st,

View File

@ -267,19 +267,9 @@ func main() {
}()
}
if *synchronize {
if err := syncWorker.ResyncIndex(nil); err != nil {
glog.Error("resyncIndex ", err)
return
}
if _, err = chain.ResyncMempool(nil); err != nil {
glog.Error("resyncMempool ", err)
return
}
}
var publicServer *server.PublicServer
if *publicBinding != "" {
// start public server in limited functionality, extend it after sync is finished by calling ConnectFullPublicInterface
publicServer, err = server.NewPublicServer(*publicBinding, *certFiles, index, chain, txCache, *explorerURL, metrics, internalState, *debugMode)
if err != nil {
glog.Error("socketio: ", err)
@ -301,10 +291,27 @@ func main() {
}
if *synchronize {
// start the synchronization loops after the server interfaces are started
internalState.SyncMode = true
internalState.InitialSync = true
if err := syncWorker.ResyncIndex(nil); err != nil {
glog.Error("resyncIndex ", err)
return
}
var mempoolCount int
if mempoolCount, err = chain.ResyncMempool(nil); err != nil {
glog.Error("resyncMempool ", err)
return
}
internalState.FinishedMempoolSync(mempoolCount)
go syncIndexLoop()
go syncMempoolLoop()
go storeInternalStateLoop()
internalState.InitialSync = false
}
go storeInternalStateLoop()
if *publicBinding != "" {
// start full public interface
publicServer.ConnectFullPublicInterface()
}
if *blockFrom >= 0 {

View File

@ -37,6 +37,10 @@ type InternalState struct {
LastStore time.Time `json:"lastStore"`
// true if application is with flag --sync
SyncMode bool `json:"syncMode"`
InitialSync bool `json:"initialSync"`
IsSynchronized bool `json:"isSynchronized"`
BestHeight uint32 `json:"bestHeight"`
LastSync time.Time `json:"lastSync"`
@ -64,6 +68,14 @@ func (is *InternalState) FinishedSync(bestHeight uint32) {
is.LastSync = time.Now()
}
// UpdateBestHeight sets new best height, without changing IsSynchronized flag
func (is *InternalState) UpdateBestHeight(bestHeight uint32) {
is.mux.Lock()
defer is.mux.Unlock()
is.BestHeight = bestHeight
is.LastSync = time.Now()
}
// FinishedSyncNoChange marks end of synchronization in case no index update was necessary, it does not update lastSync time
func (is *InternalState) FinishedSyncNoChange() {
is.mux.Lock()

View File

@ -988,8 +988,10 @@ func (d *RocksDB) writeHeight(wb *gorocksdb.WriteBatch, height uint32, bi *Block
return err
}
wb.PutCF(d.cfh[cfHeight], key, val)
d.is.UpdateBestHeight(height)
case opDelete:
wb.DeleteCF(d.cfh[cfHeight], key)
d.is.UpdateBestHeight(height - 1)
}
return nil
}
@ -1223,9 +1225,9 @@ func dirSize(path string) (int64, error) {
var size int64
err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error {
if err == nil {
if !info.IsDir() {
size += info.Size()
}
if !info.IsDir() {
size += info.Size()
}
}
return err
})
@ -1352,6 +1354,12 @@ func (d *RocksDB) LoadInternalState(rpcCoin string) (*common.InternalState, erro
}
}
is.DbColumns = nc
// after load, reset the synchronization data
is.IsSynchronized = false
is.IsMempoolSynchronized = false
var t time.Time
is.LastMempoolSync = t
is.SyncMode = false
return is, nil
}

View File

@ -42,6 +42,7 @@ type PublicServer struct {
}
// NewPublicServer creates new public server http interface to blockbook and returns its handle
// only basic functionality is mapped, to map all functions, call
func NewPublicServer(binding string, certFiles string, db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxCache, explorerURL string, metrics *common.Metrics, is *common.InternalState, debugMode bool) (*PublicServer, error) {
api, err := api.NewWorker(db, chain, txCache, is)
@ -76,33 +77,15 @@ func NewPublicServer(binding string, certFiles string, db *db.RocksDB, chain bch
is: is,
debug: debugMode,
}
s.templates = parseTemplates()
// favicon
// map only basic functions, the rest is enabled by method MapFullPublicInterface
serveMux.Handle(path+"favicon.ico", http.FileServer(http.Dir("./static/")))
// support for tests of socket.io interface
serveMux.Handle(path+"test.html", http.FileServer(http.Dir("./static/")))
// redirect to wallet requests for tx and address, possibly to external site
serveMux.HandleFunc(path+"tx/", s.txRedirect)
serveMux.HandleFunc(path+"address/", s.addressRedirect)
// explorer
serveMux.HandleFunc(path+"explorer/tx/", s.htmlTemplateHandler(s.explorerTx))
serveMux.HandleFunc(path+"explorer/address/", s.htmlTemplateHandler(s.explorerAddress))
serveMux.HandleFunc(path+"explorer/search/", s.htmlTemplateHandler(s.explorerSearch))
serveMux.HandleFunc(path+"explorer/blocks", s.htmlTemplateHandler(s.explorerBlocks))
serveMux.HandleFunc(path+"explorer/block/", s.htmlTemplateHandler(s.explorerBlock))
serveMux.Handle(path+"static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static/"))))
// API calls
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/block/", s.jsonHandler(s.apiBlock))
serveMux.HandleFunc(path+"api/", s.jsonHandler(s.apiIndex))
// handle socket.io
serveMux.Handle(path+"socket.io/", socketio.GetHandler())
// default handler
serveMux.HandleFunc(path, s.htmlTemplateHandler(s.explorerIndex))
s.templates = parseTemplates()
// default API handler
serveMux.HandleFunc(path+"api/", s.jsonHandler(s.apiIndex))
return s, nil
}
@ -117,6 +100,30 @@ func (s *PublicServer) Run() error {
return s.https.ListenAndServeTLS(fmt.Sprint(s.certFiles, ".crt"), fmt.Sprint(s.certFiles, ".key"))
}
// ConnectFullPublicInterface enables complete public functionality
func (s *PublicServer) ConnectFullPublicInterface() {
serveMux := s.https.Handler.(*http.ServeMux)
_, path := splitBinding(s.binding)
// support for tests of socket.io interface
serveMux.Handle(path+"test.html", http.FileServer(http.Dir("./static/")))
// redirect to wallet requests for tx and address, possibly to external site
serveMux.HandleFunc(path+"tx/", s.txRedirect)
serveMux.HandleFunc(path+"address/", s.addressRedirect)
// explorer
serveMux.HandleFunc(path+"explorer/tx/", s.htmlTemplateHandler(s.explorerTx))
serveMux.HandleFunc(path+"explorer/address/", s.htmlTemplateHandler(s.explorerAddress))
serveMux.HandleFunc(path+"explorer/search/", s.htmlTemplateHandler(s.explorerSearch))
serveMux.HandleFunc(path+"explorer/blocks", s.htmlTemplateHandler(s.explorerBlocks))
serveMux.HandleFunc(path+"explorer/block/", s.htmlTemplateHandler(s.explorerBlock))
// API calls
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/block/", s.jsonHandler(s.apiBlock))
// socket.io interface
serveMux.Handle(path+"socket.io/", s.socketio.GetHandler())
}
// Close closes the server
func (s *PublicServer) Close() error {
glog.Infof("public server: closing")

View File

@ -1,5 +1,11 @@
{{define "specific"}}{{$cs := .CoinShortcut}}{{$bb := .Info.Blockbook}}{{$be := .Info.Backend}}
<h1>Application status</h1>
{{- if $bb.InitialSync -}}
<h3 class="bg-danger text-white" style="padding: 20px;">Application is now in initial synchronization and does not provide any data.</h3>
{{- end -}}
{{- if not $bb.SyncMode -}}
<h3 class="bg-warning text-white" style="padding: 20px;">Synchronization with backend is disabled, the state of index is not up to date.</h3>
{{- end -}}
<div class="row">
<div class="col-md-6">
<h3>Blockbook</h3>
@ -19,7 +25,7 @@
</tr>
<tr>
<td>Synchronized</td>
<td class="data{{if not $bb.InSync}} text-danger{{end}}">{{$bb.InSync}}</td>
<td class="data {{if not $bb.InSync}}text-danger{{else}}text-success{{end}}">{{$bb.InSync}}</td>
</tr>
<tr>
<td>Last Block</td>
@ -31,7 +37,7 @@
</tr>
<tr>
<td>Mempool in Sync</td>
<td class="data{{if not $bb.InSyncMempool}} text-danger{{end}}">{{$bb.InSyncMempool}}</td>
<td class="data {{if not $bb.InSyncMempool}}text-danger{{else}}text-success{{end}}">{{$bb.InSyncMempool}}</td>
</tr>
<tr>
<td>Last Mempool Update</td>