github.com/status-im/status-go@v1.1.0/services/accounts/accountsevent/watcher.go (about)

     1  package accountsevent
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/ethereum/go-ethereum/common"
     7  	"github.com/ethereum/go-ethereum/event"
     8  	"github.com/ethereum/go-ethereum/log"
     9  	"github.com/status-im/status-go/multiaccounts/accounts"
    10  	"github.com/status-im/status-go/services/wallet/async"
    11  )
    12  
    13  type AccountsChangeCb func(changedAddresses []common.Address, eventType EventType, currentAddresses []common.Address)
    14  
    15  // Watcher executes a given callback whenever an account gets added/removed
    16  type Watcher struct {
    17  	accountsDB  *accounts.Database
    18  	accountFeed *event.Feed
    19  	group       *async.Group
    20  	callback    AccountsChangeCb
    21  }
    22  
    23  func NewWatcher(accountsDB *accounts.Database, accountFeed *event.Feed, callback AccountsChangeCb) *Watcher {
    24  	return &Watcher{
    25  		accountsDB:  accountsDB,
    26  		accountFeed: accountFeed,
    27  		callback:    callback,
    28  	}
    29  }
    30  
    31  func (w *Watcher) Start() {
    32  	if w.group != nil {
    33  		return
    34  	}
    35  
    36  	w.group = async.NewGroup(context.Background())
    37  	w.group.Add(func(ctx context.Context) error {
    38  		return watch(ctx, w.accountsDB, w.accountFeed, w.callback)
    39  	})
    40  }
    41  
    42  func (w *Watcher) Stop() {
    43  	if w.group != nil {
    44  		w.group.Stop()
    45  		w.group.Wait()
    46  		w.group = nil
    47  	}
    48  }
    49  
    50  func onAccountsChange(accountsDB *accounts.Database, callback AccountsChangeCb, changedAddresses []common.Address, eventType EventType) {
    51  	currentEthAddresses, err := accountsDB.GetWalletAddresses()
    52  
    53  	if err != nil {
    54  		log.Error("failed getting wallet addresses", "error", err)
    55  		return
    56  	}
    57  
    58  	currentAddresses := make([]common.Address, 0, len(currentEthAddresses))
    59  	for _, ethAddress := range currentEthAddresses {
    60  		currentAddresses = append(currentAddresses, common.Address(ethAddress))
    61  	}
    62  
    63  	if callback != nil {
    64  		callback(changedAddresses, eventType, currentAddresses)
    65  	}
    66  }
    67  
    68  func watch(ctx context.Context, accountsDB *accounts.Database, accountFeed *event.Feed, callback AccountsChangeCb) error {
    69  	ch := make(chan Event, 1)
    70  	sub := accountFeed.Subscribe(ch)
    71  	defer sub.Unsubscribe()
    72  
    73  	for {
    74  		select {
    75  		case <-ctx.Done():
    76  			return nil
    77  		case err := <-sub.Err():
    78  			if err != nil {
    79  				log.Error("accounts watcher subscription failed", "error", err)
    80  			}
    81  		case ev := <-ch:
    82  			onAccountsChange(accountsDB, callback, ev.Accounts, ev.Type)
    83  		}
    84  	}
    85  }