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 }