Use a single handler (per wallet) for all tx notifications.

This commit is contained in:
Josh Rickmar 2013-09-05 11:19:48 -04:00
parent 897fa1448b
commit 019df772b1
2 changed files with 132 additions and 112 deletions

42
cmd.go
View file

@ -81,6 +81,7 @@ type BtcWallet struct {
*wallet.Wallet *wallet.Wallet
mtx sync.RWMutex mtx sync.RWMutex
dirty bool dirty bool
NewBlockTxSeqN uint64
UtxoStore struct { UtxoStore struct {
sync.RWMutex sync.RWMutex
dirty bool dirty bool
@ -183,13 +184,35 @@ func OpenWallet(cfg *config, account string) (*BtcWallet, error) {
} }
func (w *BtcWallet) Track() { func (w *BtcWallet) Track() {
seq.Lock()
n := seq.n
seq.n++
seq.Unlock()
// Use goroutines and a WaitGroup to prevent unnecessary waiting for
// released locks.
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
wallets.Lock() wallets.Lock()
name := w.Name() name := w.Name()
if wallets.m[name] == nil { if wallets.m[name] == nil {
wallets.m[name] = w wallets.m[name] = w
} }
wallets.Unlock() wallets.Unlock()
}()
go func() {
defer wg.Done()
w.mtx.Lock()
w.NewBlockTxSeqN = n
w.mtx.Unlock()
}()
wg.Wait()
replyHandlers.Lock()
replyHandlers.m[n] = w.NewBlockTxHandler
replyHandlers.Unlock()
for _, addr := range w.GetActiveAddresses() { for _, addr := range w.GetActiveAddresses() {
go w.ReqNewTxsForAddress(addr) go w.ReqNewTxsForAddress(addr)
} }
@ -231,10 +254,9 @@ func (w *BtcWallet) RescanForAddress(addr string, blocks ...int) {
} }
func (w *BtcWallet) ReqNewTxsForAddress(addr string) { func (w *BtcWallet) ReqNewTxsForAddress(addr string) {
seq.Lock() w.mtx.RLock()
n := seq.n n := w.NewBlockTxSeqN
seq.n++ w.mtx.RUnlock()
seq.Unlock()
m := &btcjson.Message{ m := &btcjson.Message{
Jsonrpc: "1.0", Jsonrpc: "1.0",
@ -244,8 +266,10 @@ func (w *BtcWallet) ReqNewTxsForAddress(addr string) {
} }
msg, _ := json.Marshal(m) msg, _ := json.Marshal(m)
replyHandlers.Lock() btcdMsgs <- msg
replyHandlers.m[n] = func(result interface{}) bool { }
func (w *BtcWallet) NewBlockTxHandler(result interface{}) bool {
// TODO(jrick): btcd also sends the block hash in the reply. // TODO(jrick): btcd also sends the block hash in the reply.
// Do we want it saved as well? // Do we want it saved as well?
v, ok := result.(map[string]interface{}) v, ok := result.(map[string]interface{})
@ -289,7 +313,7 @@ func (w *BtcWallet) ReqNewTxsForAddress(addr string) {
return false return false
} }
// btcd sends the tx hashe as a BE string. Convert to a // btcd sends the tx hash as a BE string. Convert to a
// LE ShaHash. // LE ShaHash.
txhash, err := btcwire.NewShaHashFromStr(txhashBE) txhash, err := btcwire.NewShaHashFromStr(txhashBE)
if err != nil { if err != nil {
@ -340,7 +364,3 @@ func (w *BtcWallet) ReqNewTxsForAddress(addr string) {
// Never remove this handler. // Never remove this handler.
return false return false
} }
replyHandlers.Unlock()
btcdMsgs <- msg
}

View file

@ -319,7 +319,7 @@ func ListenAndServe() error {
// requests for each channel in the set. // requests for each channel in the set.
go frontendListenerDuplicator() go frontendListenerDuplicator()
// XXX(jrick): We need some sort of authentication before websocket // TODO(jrick): We need some sort of authentication before websocket
// connections are allowed, and perhaps TLS on the server as well. // connections are allowed, and perhaps TLS on the server as well.
http.Handle("/frontend", websocket.Handler(frontendReqsNotifications)) http.Handle("/frontend", websocket.Handler(frontendReqsNotifications))
if err := http.ListenAndServe(fmt.Sprintf(":%d", cfg.SvrPort), nil); err != nil { if err := http.ListenAndServe(fmt.Sprintf(":%d", cfg.SvrPort), nil); err != nil {