feat: trigger collectibles fetch on new account

This commit is contained in:
Dario Gabriel Lipicar 2023-07-24 15:54:21 -03:00 committed by dlipicar
parent 5ba5611a8d
commit 85d8e83394
3 changed files with 149 additions and 12 deletions

View File

@ -0,0 +1,86 @@
package walletaccounts
import (
"context"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
"github.com/status-im/status-go/multiaccounts/accounts"
"github.com/status-im/status-go/services/accounts/accountsevent"
"github.com/status-im/status-go/services/wallet/async"
)
type AccountsChangeCb func(changedAddresses []common.Address, eventType accountsevent.EventType, currentAddresses []common.Address)
// Watcher executes a given callback whenever an account gets added/removed
type Watcher struct {
accountsDB *accounts.Database
accountFeed *event.Feed
group *async.Group
callback AccountsChangeCb
}
func NewWatcher(accountsDB *accounts.Database, accountFeed *event.Feed, callback AccountsChangeCb) *Watcher {
return &Watcher{
accountsDB: accountsDB,
accountFeed: accountFeed,
callback: callback,
}
}
func (w *Watcher) Start() {
if w.group != nil {
return
}
w.group = async.NewGroup(context.Background())
w.group.Add(func(ctx context.Context) error {
return watch(ctx, w.accountsDB, w.accountFeed, w.callback)
})
}
func (w *Watcher) Stop() {
if w.group != nil {
w.group.Stop()
w.group.Wait()
w.group = nil
}
}
func onAccountsChange(accountsDB *accounts.Database, callback AccountsChangeCb, changedAddresses []common.Address, eventType accountsevent.EventType) {
currentEthAddresses, err := accountsDB.GetWalletAddresses()
if err != nil {
log.Error("failed getting wallet addresses", "error", err)
return
}
currentAddresses := make([]common.Address, 0, len(currentEthAddresses))
for _, ethAddress := range currentEthAddresses {
currentAddresses = append(currentAddresses, common.Address(ethAddress))
}
if callback != nil {
callback(changedAddresses, eventType, currentAddresses)
}
}
func watch(ctx context.Context, accountsDB *accounts.Database, accountFeed *event.Feed, callback AccountsChangeCb) error {
ch := make(chan accountsevent.Event, 1)
sub := accountFeed.Subscribe(ch)
defer sub.Unsubscribe()
for {
select {
case <-ctx.Done():
return nil
case err := <-sub.Err():
if err != nil {
log.Error("accounts watcher subscription failed", "error", err)
}
case ev := <-ch:
onAccountsChange(accountsDB, callback, ev.Accounts, ev.Type)
}
}
}

View File

@ -10,8 +10,11 @@ import (
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/status-im/status-go/multiaccounts/accounts"
"github.com/status-im/status-go/rpc/network" "github.com/status-im/status-go/rpc/network"
"github.com/status-im/status-go/services/accounts/accountsevent"
walletaccounts "github.com/status-im/status-go/services/wallet/accounts"
"github.com/status-im/status-go/services/wallet/async" "github.com/status-im/status-go/services/wallet/async"
walletCommon "github.com/status-im/status-go/services/wallet/common" walletCommon "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/services/wallet/thirdparty" "github.com/status-im/status-go/services/wallet/thirdparty"
@ -40,21 +43,27 @@ var (
) )
type Service struct { type Service struct {
manager *Manager manager *Manager
db *sql.DB db *sql.DB
eventFeed *event.Feed walletFeed *event.Feed
accountsDB *accounts.Database
accountsFeed *event.Feed
networkManager *network.Manager networkManager *network.Manager
cancelFn context.CancelFunc cancelFn context.CancelFunc
group *async.Group group *async.Group
scheduler *async.Scheduler scheduler *async.Scheduler
accountsWatcher *walletaccounts.Watcher
} }
func NewService(db *sql.DB, eventFeed *event.Feed, networkManager *network.Manager, manager *Manager) *Service { func NewService(db *sql.DB, walletFeed *event.Feed, accountsDB *accounts.Database, accountsFeed *event.Feed, networkManager *network.Manager, manager *Manager) *Service {
return &Service{ return &Service{
manager: manager, manager: manager,
db: db, db: db,
eventFeed: eventFeed, walletFeed: walletFeed,
accountsDB: accountsDB,
accountsFeed: accountsFeed,
networkManager: networkManager, networkManager: networkManager,
scheduler: async.NewScheduler(), scheduler: async.NewScheduler(),
} }
@ -144,7 +153,8 @@ func (s *Service) GetCollectiblesDataAsync(ctx context.Context, uniqueIDs []thir
s.sendResponseEvent(EventGetCollectiblesDataDone, res, err) s.sendResponseEvent(EventGetCollectiblesDataDone, res, err)
}) })
} }
func (s *Service) Start() {
func (s *Service) startPeriodicalOwnershipFetch() {
if s.group != nil { if s.group != nil {
return return
} }
@ -156,14 +166,14 @@ func (s *Service) Start() {
command := newRefreshOwnedCollectiblesCommand( command := newRefreshOwnedCollectiblesCommand(
s.manager, s.manager,
s.db, s.db,
s.eventFeed, s.walletFeed,
s.networkManager, s.networkManager,
) )
s.group.Add(command.Command()) s.group.Add(command.Command())
} }
func (s *Service) Stop() { func (s *Service) stopPeriodicalOwnershipFetch() {
if s.cancelFn != nil { if s.cancelFn != nil {
s.cancelFn() s.cancelFn()
s.cancelFn = nil s.cancelFn = nil
@ -173,6 +183,47 @@ func (s *Service) Stop() {
s.group.Wait() s.group.Wait()
s.group = nil s.group = nil
} }
}
func (s *Service) startAccountsWatcher() {
if s.accountsWatcher != nil {
return
}
accountChangeCb := func(changedAddresses []common.Address, eventType accountsevent.EventType, currentAddresses []common.Address) {
// Whenever an account gets added, restart fetch
// TODO: Fetch only added accounts
if eventType == accountsevent.EventTypeAdded {
s.stopPeriodicalOwnershipFetch()
s.startPeriodicalOwnershipFetch()
}
}
s.accountsWatcher = walletaccounts.NewWatcher(s.accountsDB, s.accountsFeed, accountChangeCb)
s.accountsWatcher.Start()
}
func (s *Service) stopAccountsWatcher() {
if s.accountsWatcher != nil {
s.accountsWatcher.Stop()
s.accountsWatcher = nil
}
}
func (s *Service) Start() {
// Setup periodical collectibles refresh
s.startPeriodicalOwnershipFetch()
// Setup collectibles fetch when a new account gets added
s.startAccountsWatcher()
}
func (s *Service) Stop() {
s.stopAccountsWatcher()
s.stopPeriodicalOwnershipFetch()
s.scheduler.Stop() s.scheduler.Stop()
} }
@ -186,7 +237,7 @@ func (s *Service) sendResponseEvent(eventType walletevent.EventType, payloadObj
log.Debug("wallet.api.collectibles.Service RESPONSE", "eventType", eventType, "error", err, "payload.len", len(payload)) log.Debug("wallet.api.collectibles.Service RESPONSE", "eventType", eventType, "error", err, "payload.len", len(payload))
s.eventFeed.Send(walletevent.Event{ s.walletFeed.Send(walletevent.Event{
Type: eventType, Type: eventType,
Message: string(payload), Message: string(payload),
}) })

View File

@ -109,7 +109,7 @@ func NewService(
infuraClient := infura.NewClient(config.WalletConfig.InfuraAPIKey, config.WalletConfig.InfuraAPIKeySecret) infuraClient := infura.NewClient(config.WalletConfig.InfuraAPIKey, config.WalletConfig.InfuraAPIKeySecret)
openseaClient := opensea.NewClient(config.WalletConfig.OpenseaAPIKey, walletFeed) openseaClient := opensea.NewClient(config.WalletConfig.OpenseaAPIKey, walletFeed)
collectiblesManager := collectibles.NewManager(rpcClient, alchemyClient, infuraClient, openseaClient) collectiblesManager := collectibles.NewManager(rpcClient, alchemyClient, infuraClient, openseaClient)
collectibles := collectibles.NewService(db, walletFeed, rpcClient.NetworkManager, collectiblesManager) collectibles := collectibles.NewService(db, walletFeed, accountsDB, accountFeed, rpcClient.NetworkManager, collectiblesManager)
return &Service{ return &Service{
db: db, db: db,
accountsDB: accountsDB, accountsDB: accountsDB,