Update websocket clients with rescan progress.

This change periodically (about every 10 seconds) notifies the
connected websocket client of the height of the last processed block
as part of the rescan.  This enables clients to listen for the
notification and keep track of how much progress a rescan has made
even without any results being found.  If the websocket connection is
lost during the rescan, on reconnect, clients may safely start over at
the last notified height.
This commit is contained in:
Josh Rickmar 2014-03-24 13:29:50 -05:00
parent 5932cd5385
commit d702e37141

View file

@ -1675,10 +1675,15 @@ func handleRescan(wsc *wsClient, icmd btcjson.Cmd) (interface{}, *btcjson.Error)
minBlock := int64(cmd.BeginBlock) minBlock := int64(cmd.BeginBlock)
maxBlock := int64(cmd.EndBlock) maxBlock := int64(cmd.EndBlock)
// A ticker is created to wait at least 10 seconds before notifying the
// websocket client of the current progress completed by the rescan.
ticker := time.NewTicker(10 * time.Second)
defer ticker.Stop()
// FetchHeightRange may not return a complete list of block shas for // FetchHeightRange may not return a complete list of block shas for
// the given range, so fetch range as many times as necessary. // the given range, so fetch range as many times as necessary.
db := wsc.server.server.db db := wsc.server.server.db
for { for minBlock < maxBlock {
hashList, err := db.FetchHeightRange(minBlock, maxBlock) hashList, err := db.FetchHeightRange(minBlock, maxBlock)
if err != nil { if err != nil {
rpcsLog.Errorf("Error looking up block range: %v", err) rpcsLog.Errorf("Error looking up block range: %v", err)
@ -1699,19 +1704,39 @@ func handleRescan(wsc *wsClient, icmd btcjson.Cmd) (interface{}, *btcjson.Error)
// client requesting the rescan has disconnected. // client requesting the rescan has disconnected.
select { select {
case <-wsc.quit: case <-wsc.quit:
rpcsLog.Debugf("Stopped rescan at height %v for disconnected client", rpcsLog.Debugf("Stopped rescan at height %v "+
blk.Height()) "for disconnected client", blk.Height())
return nil, nil return nil, nil
default: default:
rescanBlock(wsc, &lookups, blk) rescanBlock(wsc, &lookups, blk)
} }
// Periodically notify the client of the progress
// completed. Continue with next block if no progress
// notification is needed yet.
select {
case <-ticker.C: // fallthrough
default:
continue
} }
if maxBlock-minBlock > int64(len(hashList)) { n := btcws.NewRescanProgressNtfn(int32(blk.Height()))
minBlock += int64(len(hashList)) mn, err := n.MarshalJSON()
} else { if err != nil {
break rpcsLog.Errorf("Failed to marshal rescan "+
"progress notification: %v", err)
continue
} }
if err = wsc.QueueNotification(mn); err == ErrClientQuit {
// Finished if the client disconnected.
rpcsLog.Debugf("Stopped rescan at height %v "+
"for disconnected client", blk.Height())
return nil, nil
}
}
minBlock += int64(len(hashList))
} }
rpcsLog.Info("Finished rescan") rpcsLog.Info("Finished rescan")