feat: event on error

This commit is contained in:
Anthony Laibe 2023-03-20 14:02:09 +01:00 committed by Anthony Laibe
parent 4e222cc404
commit ba75bda39e
10 changed files with 141 additions and 124 deletions

View File

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"strings" "strings"
"sync"
"time" "time"
"github.com/afex/hystrix-go/hystrix" "github.com/afex/hystrix-go/hystrix"
@ -31,8 +32,11 @@ type ClientWithFallback struct {
mainRPC *rpc.Client mainRPC *rpc.Client
fallbackRPC *rpc.Client fallbackRPC *rpc.Client
IsConnected bool WalletNotifier func(chainId uint64, message string)
LastCheckedAt int64
IsConnected bool
IsConnectedLock sync.RWMutex
LastCheckedAt int64
} }
var vmErrors = []error{ var vmErrors = []error{
@ -118,6 +122,22 @@ func isVMError(err error) bool {
return false return false
} }
func (c *ClientWithFallback) setIsConnected(value bool) {
c.IsConnectedLock.Lock()
defer c.IsConnectedLock.Unlock()
c.LastCheckedAt = time.Now().Unix()
if value != c.IsConnected {
message := "down"
if value {
message = "up"
}
if c.WalletNotifier != nil {
c.WalletNotifier(c.ChainID, message)
}
}
c.IsConnected = value
}
func (c *ClientWithFallback) makeCallNoReturn(main func() error, fallback func() error) error { func (c *ClientWithFallback) makeCallNoReturn(main func() error, fallback func() error) error {
resultChan := make(chan CommandResult, 1) resultChan := make(chan CommandResult, 1)
c.LastCheckedAt = time.Now().Unix() c.LastCheckedAt = time.Now().Unix()
@ -130,7 +150,7 @@ func (c *ClientWithFallback) makeCallNoReturn(main func() error, fallback func()
} }
return err return err
} }
c.IsConnected = true c.setIsConnected(true)
resultChan <- CommandResult{} resultChan <- CommandResult{}
return nil return nil
}, func(err error) error { }, func(err error) error {
@ -144,10 +164,9 @@ func (c *ClientWithFallback) makeCallNoReturn(main func() error, fallback func()
resultChan <- CommandResult{vmError: err} resultChan <- CommandResult{vmError: err}
return nil return nil
} }
c.IsConnected = false c.setIsConnected(false)
return err return err
} }
c.IsConnected = true
resultChan <- CommandResult{} resultChan <- CommandResult{}
return nil return nil
}) })
@ -175,7 +194,7 @@ func (c *ClientWithFallback) makeCallSingleReturn(main func() (any, error), fall
} }
return err return err
} }
c.IsConnected = true c.setIsConnected(true)
resultChan <- CommandResult{res1: res} resultChan <- CommandResult{res1: res}
return nil return nil
}, func(err error) error { }, func(err error) error {
@ -189,10 +208,10 @@ func (c *ClientWithFallback) makeCallSingleReturn(main func() (any, error), fall
resultChan <- CommandResult{vmError: err} resultChan <- CommandResult{vmError: err}
return nil return nil
} }
c.IsConnected = false c.setIsConnected(false)
return err return err
} }
c.IsConnected = true c.setIsConnected(true)
resultChan <- CommandResult{res1: res} resultChan <- CommandResult{res1: res}
return nil return nil
}) })
@ -220,7 +239,7 @@ func (c *ClientWithFallback) makeCallDoubleReturn(main func() (any, any, error),
} }
return err return err
} }
c.IsConnected = true c.setIsConnected(true)
resultChan <- CommandResult{res1: a, res2: b} resultChan <- CommandResult{res1: a, res2: b}
return nil return nil
}, func(err error) error { }, func(err error) error {
@ -234,10 +253,10 @@ func (c *ClientWithFallback) makeCallDoubleReturn(main func() (any, any, error),
resultChan <- CommandResult{vmError: err} resultChan <- CommandResult{vmError: err}
return nil return nil
} }
c.IsConnected = false c.setIsConnected(false)
return err return err
} }
c.IsConnected = true c.setIsConnected(true)
resultChan <- CommandResult{res1: a, res2: b} resultChan <- CommandResult{res1: a, res2: b}
return nil return nil
}) })

View File

@ -52,6 +52,8 @@ type Client struct {
handlersMx sync.RWMutex // mx guards handlers handlersMx sync.RWMutex // mx guards handlers
handlers map[string]Handler // locally registered handlers handlers map[string]Handler // locally registered handlers
log log.Logger log log.Logger
walletNotifier func(chainID uint64, message string)
} }
// NewClient initializes Client and tries to connect to both, // NewClient initializes Client and tries to connect to both,
@ -93,8 +95,15 @@ func NewClient(client *gethrpc.Client, upstreamChainID uint64, upstream params.U
return &c, nil return &c, nil
} }
func (c *Client) SetWalletNotifier(notifier func(chainID uint64, message string)) {
c.walletNotifier = notifier
}
func (c *Client) getClientUsingCache(chainID uint64) (*chain.ClientWithFallback, error) { func (c *Client) getClientUsingCache(chainID uint64) (*chain.ClientWithFallback, error) {
if rpcClient, ok := c.rpcClients[chainID]; ok { if rpcClient, ok := c.rpcClients[chainID]; ok {
if rpcClient.WalletNotifier == nil {
rpcClient.WalletNotifier = c.walletNotifier
}
return rpcClient, nil return rpcClient, nil
} }
@ -120,6 +129,7 @@ func (c *Client) getClientUsingCache(chainID uint64) (*chain.ClientWithFallback,
} }
client := chain.NewClient(rpcClient, rpcFallbackClient, chainID) client := chain.NewClient(rpcClient, rpcFallbackClient, chainID)
client.WalletNotifier = c.walletNotifier
c.rpcClients[chainID] = client c.rpcClients[chainID] = client
return client, nil return client, nil
} }

View File

@ -37,10 +37,6 @@ func (api *API) StartWallet(ctx context.Context) error {
return api.reader.Start() return api.reader.Start()
} }
func (api *API) CheckConnected(ctx context.Context) *ConnectedResult {
return api.s.CheckConnected(ctx)
}
func (api *API) StopWallet(ctx context.Context) error { func (api *API) StopWallet(ctx context.Context) error {
return api.s.Stop() return api.s.Stop()
} }

View File

@ -8,6 +8,7 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/event"
"github.com/status-im/status-go/contracts/collectibles" "github.com/status-im/status-go/contracts/collectibles"
"github.com/status-im/status-go/rpc" "github.com/status-im/status-go/rpc"
"github.com/status-im/status-go/services/wallet/thirdparty" "github.com/status-im/status-go/services/wallet/thirdparty"
@ -22,19 +23,21 @@ type Manager struct {
openseaAPIKey string openseaAPIKey string
nftCache map[uint64]map[string]opensea.Asset nftCache map[uint64]map[string]opensea.Asset
nftCacheLock sync.RWMutex nftCacheLock sync.RWMutex
walletFeed *event.Feed
} }
func NewManager(rpcClient *rpc.Client, metadataProvider thirdparty.NFTMetadataProvider, openseaAPIKey string) *Manager { func NewManager(rpcClient *rpc.Client, metadataProvider thirdparty.NFTMetadataProvider, openseaAPIKey string, walletFeed *event.Feed) *Manager {
return &Manager{ return &Manager{
rpcClient: rpcClient, rpcClient: rpcClient,
metadataProvider: metadataProvider, metadataProvider: metadataProvider,
openseaAPIKey: openseaAPIKey, openseaAPIKey: openseaAPIKey,
nftCache: make(map[uint64]map[string]opensea.Asset), nftCache: make(map[uint64]map[string]opensea.Asset),
walletFeed: walletFeed,
} }
} }
func (o *Manager) FetchAllCollectionsByOwner(chainID uint64, owner common.Address) ([]opensea.OwnedCollection, error) { func (o *Manager) FetchAllCollectionsByOwner(chainID uint64, owner common.Address) ([]opensea.OwnedCollection, error) {
client, err := opensea.NewOpenseaClient(chainID, o.openseaAPIKey) client, err := opensea.NewOpenseaClient(chainID, o.openseaAPIKey, o.walletFeed)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -42,7 +45,7 @@ func (o *Manager) FetchAllCollectionsByOwner(chainID uint64, owner common.Addres
} }
func (o *Manager) FetchAllAssetsByOwnerAndCollection(chainID uint64, owner common.Address, collectionSlug string, cursor string, limit int) (*opensea.AssetContainer, error) { func (o *Manager) FetchAllAssetsByOwnerAndCollection(chainID uint64, owner common.Address, collectionSlug string, cursor string, limit int) (*opensea.AssetContainer, error) {
client, err := opensea.NewOpenseaClient(chainID, o.openseaAPIKey) client, err := opensea.NewOpenseaClient(chainID, o.openseaAPIKey, o.walletFeed)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -61,7 +64,7 @@ func (o *Manager) FetchAllAssetsByOwnerAndCollection(chainID uint64, owner commo
} }
func (o *Manager) FetchAllAssetsByOwnerAndContractAddress(chainID uint64, owner common.Address, contractAddresses []common.Address, cursor string, limit int) (*opensea.AssetContainer, error) { func (o *Manager) FetchAllAssetsByOwnerAndContractAddress(chainID uint64, owner common.Address, contractAddresses []common.Address, cursor string, limit int) (*opensea.AssetContainer, error) {
client, err := opensea.NewOpenseaClient(chainID, o.openseaAPIKey) client, err := opensea.NewOpenseaClient(chainID, o.openseaAPIKey, o.walletFeed)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -80,7 +83,7 @@ func (o *Manager) FetchAllAssetsByOwnerAndContractAddress(chainID uint64, owner
} }
func (o *Manager) FetchAllAssetsByOwner(chainID uint64, owner common.Address, cursor string, limit int) (*opensea.AssetContainer, error) { func (o *Manager) FetchAllAssetsByOwner(chainID uint64, owner common.Address, cursor string, limit int) (*opensea.AssetContainer, error) {
client, err := opensea.NewOpenseaClient(chainID, o.openseaAPIKey) client, err := opensea.NewOpenseaClient(chainID, o.openseaAPIKey, o.walletFeed)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -103,7 +106,7 @@ func (o *Manager) FetchAssetsByNFTUniqueID(chainID uint64, uniqueIDs []thirdpart
idsToFetch := o.getIDsNotInCache(chainID, uniqueIDs) idsToFetch := o.getIDsNotInCache(chainID, uniqueIDs)
if len(idsToFetch) > 0 { if len(idsToFetch) > 0 {
client, err := opensea.NewOpenseaClient(chainID, o.openseaAPIKey) client, err := opensea.NewOpenseaClient(chainID, o.openseaAPIKey, o.walletFeed)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -5,8 +5,15 @@ import (
"time" "time"
"github.com/afex/hystrix-go/hystrix" "github.com/afex/hystrix-go/hystrix"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/event"
"github.com/status-im/status-go/services/wallet/thirdparty" "github.com/status-im/status-go/services/wallet/thirdparty"
"github.com/status-im/status-go/services/wallet/walletevent"
)
const (
EventMarketStatusChanged walletevent.EventType = "wallet-market-status-changed"
) )
type DataPoint struct { type DataPoint struct {
@ -17,15 +24,17 @@ type DataPoint struct {
type DataPerTokenAndCurrency = map[string]map[string]DataPoint type DataPerTokenAndCurrency = map[string]map[string]DataPoint
type Manager struct { type Manager struct {
main thirdparty.MarketDataProvider main thirdparty.MarketDataProvider
fallback thirdparty.MarketDataProvider fallback thirdparty.MarketDataProvider
priceCache DataPerTokenAndCurrency feed *event.Feed
IsConnected bool priceCache DataPerTokenAndCurrency
LastCheckedAt int64 priceCacheLock sync.RWMutex
priceCacheLock sync.RWMutex IsConnected bool
LastCheckedAt int64
IsConnectedLock sync.RWMutex
} }
func NewManager(main thirdparty.MarketDataProvider, fallback thirdparty.MarketDataProvider) *Manager { func NewManager(main thirdparty.MarketDataProvider, fallback thirdparty.MarketDataProvider, feed *event.Feed) *Manager {
hystrix.ConfigureCommand("marketClient", hystrix.CommandConfig{ hystrix.ConfigureCommand("marketClient", hystrix.CommandConfig{
Timeout: 10000, Timeout: 10000,
MaxConcurrentRequests: 100, MaxConcurrentRequests: 100,
@ -36,21 +45,40 @@ func NewManager(main thirdparty.MarketDataProvider, fallback thirdparty.MarketDa
return &Manager{ return &Manager{
main: main, main: main,
fallback: fallback, fallback: fallback,
feed: feed,
priceCache: make(DataPerTokenAndCurrency), priceCache: make(DataPerTokenAndCurrency),
IsConnected: true, IsConnected: true,
LastCheckedAt: time.Now().Unix(), LastCheckedAt: time.Now().Unix(),
} }
} }
func (pm *Manager) setIsConnected(value bool) {
pm.IsConnectedLock.Lock()
defer pm.IsConnectedLock.Unlock()
pm.LastCheckedAt = time.Now().Unix()
if value != pm.IsConnected {
message := "down"
if value {
message = "up"
}
pm.feed.Send(walletevent.Event{
Type: EventMarketStatusChanged,
Accounts: []common.Address{},
Message: message,
At: time.Now().Unix(),
})
}
pm.IsConnected = value
}
func (pm *Manager) makeCall(main func() (any, error), fallback func() (any, error)) (any, error) { func (pm *Manager) makeCall(main func() (any, error), fallback func() (any, error)) (any, error) {
resultChan := make(chan any, 1) resultChan := make(chan any, 1)
pm.LastCheckedAt = time.Now().Unix()
errChan := hystrix.Go("marketClient", func() error { errChan := hystrix.Go("marketClient", func() error {
res, err := main() res, err := main()
if err != nil { if err != nil {
return err return err
} }
pm.IsConnected = true pm.setIsConnected(true)
resultChan <- res resultChan <- res
return nil return nil
}, func(err error) error { }, func(err error) error {
@ -60,10 +88,10 @@ func (pm *Manager) makeCall(main func() (any, error), fallback func() (any, erro
res, err := fallback() res, err := fallback()
if err != nil { if err != nil {
pm.IsConnected = false pm.setIsConnected(false)
return err return err
} }
pm.IsConnected = true pm.setIsConnected(true)
resultChan <- res resultChan <- res
return nil return nil
}) })

View File

@ -110,21 +110,6 @@ func (r *Reader) Start() error {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
r.cancel = cancel r.cancel = cancel
go func() {
ticker := time.NewTicker(time.Minute)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
r.walletFeed.Send(walletevent.Event{
Type: EventWalletTickCheckConnected,
})
}
}
}()
go func() { go func() {
ticker := time.NewTicker(10 * time.Minute) ticker := time.NewTicker(10 * time.Minute)
defer ticker.Stop() defer ticker.Stop()

View File

@ -1,10 +1,10 @@
package wallet package wallet
import ( import (
"context"
"database/sql" "database/sql"
"time" "time"
"github.com/ethereum/go-ethereum/common"
"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/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
@ -23,23 +23,15 @@ import (
"github.com/status-im/status-go/services/wallet/thirdparty" "github.com/status-im/status-go/services/wallet/thirdparty"
"github.com/status-im/status-go/services/wallet/thirdparty/coingecko" "github.com/status-im/status-go/services/wallet/thirdparty/coingecko"
"github.com/status-im/status-go/services/wallet/thirdparty/cryptocompare" "github.com/status-im/status-go/services/wallet/thirdparty/cryptocompare"
"github.com/status-im/status-go/services/wallet/thirdparty/opensea"
"github.com/status-im/status-go/services/wallet/token" "github.com/status-im/status-go/services/wallet/token"
"github.com/status-im/status-go/services/wallet/transfer" "github.com/status-im/status-go/services/wallet/transfer"
"github.com/status-im/status-go/services/wallet/walletevent" "github.com/status-im/status-go/services/wallet/walletevent"
"github.com/status-im/status-go/transactions" "github.com/status-im/status-go/transactions"
) )
type Connection struct { const (
Up bool `json:"up"` EventBlockchainStatusChanged walletevent.EventType = "wallet-blockchain-status-changed"
LastCheckedAt int64 `json:"lastCheckedAt"` )
}
type ConnectedResult struct {
Blockchains map[uint64]Connection `json:"blockchains"`
Market Connection `json:"market"`
Collectibles map[uint64]Connection `json:"collectibles"`
}
// NewService initializes service instance. // NewService initializes service instance.
func NewService( func NewService(
@ -62,17 +54,26 @@ func NewService(
signals := &walletevent.SignalsTransmitter{ signals := &walletevent.SignalsTransmitter{
Publisher: walletFeed, Publisher: walletFeed,
} }
rpcClient.SetWalletNotifier(func(chainID uint64, message string) {
walletFeed.Send(walletevent.Event{
Type: EventBlockchainStatusChanged,
Accounts: []common.Address{},
Message: message,
At: time.Now().Unix(),
ChainID: chainID,
})
})
tokenManager := token.NewTokenManager(db, rpcClient, rpcClient.NetworkManager) tokenManager := token.NewTokenManager(db, rpcClient, rpcClient.NetworkManager)
savedAddressesManager := &SavedAddressesManager{db: db} savedAddressesManager := &SavedAddressesManager{db: db}
transactionManager := transfer.NewTransactionManager(db, gethManager, transactor, config, accountsDB) transactionManager := transfer.NewTransactionManager(db, gethManager, transactor, config, accountsDB)
transferController := transfer.NewTransferController(db, rpcClient, accountFeed, walletFeed, transactionManager) transferController := transfer.NewTransferController(db, rpcClient, accountFeed, walletFeed, transactionManager)
cryptoCompare := cryptocompare.NewClient() cryptoCompare := cryptocompare.NewClient()
coingecko := coingecko.NewClient() coingecko := coingecko.NewClient()
marketManager := market.NewManager(cryptoCompare, coingecko) marketManager := market.NewManager(cryptoCompare, coingecko, walletFeed)
reader := NewReader(rpcClient, tokenManager, marketManager, accountsDB, walletFeed) reader := NewReader(rpcClient, tokenManager, marketManager, accountsDB, walletFeed)
history := history.NewService(db, walletFeed, rpcClient, tokenManager, marketManager) history := history.NewService(db, walletFeed, rpcClient, tokenManager, marketManager)
currency := currency.NewService(db, walletFeed, tokenManager, marketManager) currency := currency.NewService(db, walletFeed, tokenManager, marketManager)
collectiblesManager := collectibles.NewManager(rpcClient, nftMetadataProvider, openseaAPIKey) collectiblesManager := collectibles.NewManager(rpcClient, nftMetadataProvider, openseaAPIKey, walletFeed)
return &Service{ return &Service{
db: db, db: db,
accountsDB: accountsDB, accountsDB: accountsDB,
@ -170,39 +171,3 @@ func (s *Service) Protocols() []p2p.Protocol {
func (s *Service) IsStarted() bool { func (s *Service) IsStarted() bool {
return s.started return s.started
} }
func (s *Service) CheckConnected(ctx context.Context) *ConnectedResult {
networks, err := s.rpcClient.NetworkManager.Get(false)
blockchains := make(map[uint64]Connection)
if err == nil {
for _, network := range networks {
ethClient, err := s.rpcClient.EthClient(network.ChainID)
if err != nil {
blockchains[network.ChainID] = Connection{
Up: true,
LastCheckedAt: time.Now().Unix(),
}
}
blockchains[network.ChainID] = Connection{
Up: ethClient.IsConnected,
LastCheckedAt: ethClient.LastCheckedAt,
}
}
}
collectibles := make(map[uint64]Connection)
for chainID, client := range opensea.OpenseaClientInstances {
collectibles[chainID] = Connection{
Up: client.IsConnected,
LastCheckedAt: client.LastCheckedAt,
}
}
return &ConnectedResult{
Blockchains: blockchains,
Collectibles: collectibles,
Market: Connection{
Up: s.marketManager.IsConnected,
LastCheckedAt: s.marketManager.LastCheckedAt,
},
}
}

View File

@ -5,7 +5,6 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/url"
"strings" "strings"
"sync" "sync"
"time" "time"
@ -111,7 +110,6 @@ func mapTokensToSymbols(tokens []GeckoToken, tokenMap map[string]GeckoToken) {
} }
func (c *Client) getTokens() (map[string]GeckoToken, error) { func (c *Client) getTokens() (map[string]GeckoToken, error) {
c.fetchTokensMutex.Lock() c.fetchTokensMutex.Lock()
defer c.fetchTokensMutex.Unlock() defer c.fetchTokensMutex.Unlock()
@ -226,16 +224,8 @@ func (c *Client) FetchTokenMarketValues(symbols []string, currency string) (map[
if err != nil { if err != nil {
return nil, err return nil, err
} }
queryParams := url.Values{ url := fmt.Sprintf("%scoins/markets?ids=%s&vs_currency=%s&order=market_cap_desc&per_page=250&page=1&sparkline=false&price_change_percentage=1h%2C24h", baseURL, strings.Join(ids, ","), currency)
"ids": {strings.Join(ids, ",")},
"vs_currency": {currency},
"order": {"market_cap_desc"},
"per_page": {"250"},
"page": {"1"},
"sparkline": {"false"},
"price_change_percentage": {"1h,24h"},
}
url := baseURL + "coins/markets" + queryParams.Encode()
resp, err := c.DoQuery(url) resp, err := c.DoQuery(url)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -12,10 +12,16 @@ import (
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/status-im/status-go/services/wallet/bigint" "github.com/status-im/status-go/services/wallet/bigint"
"github.com/status-im/status-go/services/wallet/thirdparty" "github.com/status-im/status-go/services/wallet/thirdparty"
"github.com/status-im/status-go/services/wallet/walletevent"
)
const (
EventCollectibleStatusChanged walletevent.EventType = "wallet-collectible-status-changed"
) )
const AssetLimit = 200 const AssetLimit = 200
@ -216,10 +222,11 @@ type Client struct {
IsConnected bool IsConnected bool
LastCheckedAt int64 LastCheckedAt int64
IsConnectedLock sync.RWMutex IsConnectedLock sync.RWMutex
feed *event.Feed
} }
// new opensea client. // new opensea client.
func NewOpenseaClient(chainID uint64, apiKey string) (*Client, error) { func NewOpenseaClient(chainID uint64, apiKey string, feed *event.Feed) (*Client, error) {
if OpenseaHTTPClient == nil { if OpenseaHTTPClient == nil {
OpenseaHTTPClient = newHTTPClient() OpenseaHTTPClient = newHTTPClient()
} }
@ -228,16 +235,16 @@ func NewOpenseaClient(chainID uint64, apiKey string) (*Client, error) {
if chainID == ChainIDRequiringAPIKey { if chainID == ChainIDRequiringAPIKey {
tmpAPIKey = apiKey tmpAPIKey = apiKey
} }
if client, ok := OpenseaClientInstances[chainID]; ok {
if client.apiKey == tmpAPIKey {
return client, nil
}
}
baseURL, err := getbaseURL(chainID) baseURL, err := getbaseURL(chainID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if client, ok := OpenseaClientInstances[chainID]; ok {
if client.apiKey == tmpAPIKey {
return client, nil
}
}
openseaClient := &Client{ openseaClient := &Client{
client: OpenseaHTTPClient, client: OpenseaHTTPClient,
@ -245,18 +252,30 @@ func NewOpenseaClient(chainID uint64, apiKey string) (*Client, error) {
apiKey: tmpAPIKey, apiKey: tmpAPIKey,
IsConnected: true, IsConnected: true,
LastCheckedAt: time.Now().Unix(), LastCheckedAt: time.Now().Unix(),
feed: feed,
} }
OpenseaClientInstances[chainID] = openseaClient OpenseaClientInstances[chainID] = openseaClient
return openseaClient, nil return openseaClient, nil
} }
func (o *Client) setConnected(value bool) { func (o *Client) setIsConnected(value bool) {
o.IsConnectedLock.Lock() o.IsConnectedLock.Lock()
defer o.IsConnectedLock.Unlock() defer o.IsConnectedLock.Unlock()
o.IsConnected = value
o.LastCheckedAt = time.Now().Unix() o.LastCheckedAt = time.Now().Unix()
if value != o.IsConnected {
message := "down"
if value {
message = "up"
}
o.feed.Send(walletevent.Event{
Type: EventCollectibleStatusChanged,
Accounts: []common.Address{},
Message: message,
At: time.Now().Unix(),
})
}
o.IsConnected = value
} }
func (o *Client) FetchAllCollectionsByOwner(owner common.Address) ([]OwnedCollection, error) { func (o *Client) FetchAllCollectionsByOwner(owner common.Address) ([]OwnedCollection, error) {
offset := 0 offset := 0
var collections []OwnedCollection var collections []OwnedCollection
@ -264,7 +283,7 @@ func (o *Client) FetchAllCollectionsByOwner(owner common.Address) ([]OwnedCollec
url := fmt.Sprintf("%s/collections?asset_owner=%s&offset=%d&limit=%d", o.url, owner, offset, CollectionLimit) url := fmt.Sprintf("%s/collections?asset_owner=%s&offset=%d&limit=%d", o.url, owner, offset, CollectionLimit)
body, err := o.client.doGetRequest(url, o.apiKey) body, err := o.client.doGetRequest(url, o.apiKey)
if err != nil { if err != nil {
o.setConnected(false) o.setIsConnected(false)
return nil, err return nil, err
} }
@ -276,7 +295,7 @@ func (o *Client) FetchAllCollectionsByOwner(owner common.Address) ([]OwnedCollec
var tmp []OwnedCollection var tmp []OwnedCollection
err = json.Unmarshal(body, &tmp) err = json.Unmarshal(body, &tmp)
if err != nil { if err != nil {
o.setConnected(false) o.setIsConnected(false)
return nil, err return nil, err
} }
@ -286,7 +305,7 @@ func (o *Client) FetchAllCollectionsByOwner(owner common.Address) ([]OwnedCollec
break break
} }
} }
o.setConnected(true) o.setIsConnected(true)
return collections, nil return collections, nil
} }
@ -360,7 +379,7 @@ func (o *Client) fetchAssets(queryParams url.Values, limit int) (*AssetContainer
body, err := o.client.doGetRequest(url, o.apiKey) body, err := o.client.doGetRequest(url, o.apiKey)
if err != nil { if err != nil {
o.setConnected(false) o.setIsConnected(false)
return nil, err return nil, err
} }
@ -372,7 +391,7 @@ func (o *Client) fetchAssets(queryParams url.Values, limit int) (*AssetContainer
container := AssetContainer{} container := AssetContainer{}
err = json.Unmarshal(body, &container) err = json.Unmarshal(body, &container)
if err != nil { if err != nil {
o.setConnected(false) o.setIsConnected(false)
return nil, err return nil, err
} }
@ -396,6 +415,6 @@ func (o *Client) fetchAssets(queryParams url.Values, limit int) (*AssetContainer
} }
} }
o.setConnected(true) o.setIsConnected(true)
return assets, nil return assets, nil
} }

View File

@ -15,4 +15,6 @@ type Event struct {
BlockNumber *big.Int `json:"blockNumber"` BlockNumber *big.Int `json:"blockNumber"`
Accounts []common.Address `json:"accounts"` Accounts []common.Address `json:"accounts"`
Message string `json:"message"` Message string `json:"message"`
At int64 `json:"at"`
ChainID uint64 `json:"chainId"`
} }