From d702e371419e64c20e3d93326a84af4769edd675 Mon Sep 17 00:00:00 2001 From: Josh Rickmar Date: Mon, 24 Mar 2014 13:29:50 -0500 Subject: [PATCH] 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. --- rpcwebsocket.go | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/rpcwebsocket.go b/rpcwebsocket.go index 0a959b99..7e147f51 100644 --- a/rpcwebsocket.go +++ b/rpcwebsocket.go @@ -1675,10 +1675,15 @@ func handleRescan(wsc *wsClient, icmd btcjson.Cmd) (interface{}, *btcjson.Error) minBlock := int64(cmd.BeginBlock) 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 // the given range, so fetch range as many times as necessary. db := wsc.server.server.db - for { + for minBlock < maxBlock { hashList, err := db.FetchHeightRange(minBlock, maxBlock) if err != nil { 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. select { case <-wsc.quit: - rpcsLog.Debugf("Stopped rescan at height %v for disconnected client", - blk.Height()) + rpcsLog.Debugf("Stopped rescan at height %v "+ + "for disconnected client", blk.Height()) return nil, nil default: 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 + } + + n := btcws.NewRescanProgressNtfn(int32(blk.Height())) + mn, err := n.MarshalJSON() + if err != nil { + 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 + } } - if maxBlock-minBlock > int64(len(hashList)) { - minBlock += int64(len(hashList)) - } else { - break - } + minBlock += int64(len(hashList)) } rpcsLog.Info("Finished rescan")