From 849be69299e5a72675c8c4214ed5730f8ef6192e Mon Sep 17 00:00:00 2001 From: Dario Gabriel Lipicar Date: Mon, 10 Jul 2023 06:02:17 -0300 Subject: [PATCH] chore: use single opensea client instance --- protocol/communities/manager.go | 2 + services/wallet/collectibles/collectibles.go | 40 ++----- services/wallet/connection/status.go | 56 +++++++++ services/wallet/thirdparty/opensea/client.go | 114 ++++++------------- 4 files changed, 100 insertions(+), 112 deletions(-) create mode 100644 services/wallet/connection/status.go diff --git a/protocol/communities/manager.go b/protocol/communities/manager.go index 5f33928db..a981701cb 100644 --- a/protocol/communities/manager.go +++ b/protocol/communities/manager.go @@ -2189,6 +2189,8 @@ func (m *Manager) GetOwnedERC721Tokens(walletAddresses []gethcommon.Address, tok ownedERC721Tokens := make(CollectiblesByChain) + client := m.openseaClientBuilder.NewOpenseaClient(m.walletConfig.OpenseaAPIKey, nil) + for chainID, erc721Tokens := range tokenRequirements { skipChain := true diff --git a/services/wallet/collectibles/collectibles.go b/services/wallet/collectibles/collectibles.go index a10cc9455..d092fd6c7 100644 --- a/services/wallet/collectibles/collectibles.go +++ b/services/wallet/collectibles/collectibles.go @@ -38,10 +38,9 @@ type Manager struct { mainContractOwnershipProvider thirdparty.CollectibleContractOwnershipProvider fallbackContractOwnershipProvider thirdparty.CollectibleContractOwnershipProvider metadataProvider thirdparty.CollectibleMetadataProvider - openseaAPIKey string + opensea *opensea.Client nftCache map[uint64]map[string]opensea.Asset nftCacheLock sync.RWMutex - walletFeed *event.Feed } func NewManager(rpcClient *rpc.Client, mainContractOwnershipProvider thirdparty.CollectibleContractOwnershipProvider, fallbackContractOwnershipProvider thirdparty.CollectibleContractOwnershipProvider, openseaAPIKey string, walletFeed *event.Feed) *Manager { @@ -56,9 +55,8 @@ func NewManager(rpcClient *rpc.Client, mainContractOwnershipProvider thirdparty. rpcClient: rpcClient, mainContractOwnershipProvider: mainContractOwnershipProvider, fallbackContractOwnershipProvider: fallbackContractOwnershipProvider, - openseaAPIKey: openseaAPIKey, + opensea: opensea.NewClient(openseaAPIKey, walletFeed), nftCache: make(map[uint64]map[string]opensea.Asset), - walletFeed: walletFeed, } } @@ -97,20 +95,11 @@ func (o *Manager) SetMetadataProvider(metadataProvider thirdparty.CollectibleMet } func (o *Manager) FetchAllCollectionsByOwner(chainID uint64, owner common.Address) ([]opensea.OwnedCollection, error) { - client, err := opensea.NewOpenseaClient(chainID, o.openseaAPIKey, o.walletFeed) - if err != nil { - return nil, err - } - return client.FetchAllCollectionsByOwner(owner) + return o.opensea.FetchAllCollectionsByOwner(chainID, owner) } 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, o.walletFeed) - if err != nil { - return nil, err - } - - assetContainer, err := client.FetchAllAssetsByOwnerAndCollection(owner, collectionSlug, cursor, limit) + assetContainer, err := o.opensea.FetchAllAssetsByOwnerAndCollection(chainID, owner, collectionSlug, cursor, limit) if err != nil { return nil, err } @@ -166,12 +155,7 @@ func (o *Manager) FetchBalancesByOwnerAndContractAddress(chainID uint64, ownerAd } 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, o.walletFeed) - if err != nil { - return nil, err - } - - assetContainer, err := client.FetchAllAssetsByOwnerAndContractAddress(owner, contractAddresses, cursor, limit) + assetContainer, err := o.opensea.FetchAllAssetsByOwnerAndContractAddress(chainID, owner, contractAddresses, cursor, limit) if err != nil { return nil, err } @@ -185,12 +169,7 @@ func (o *Manager) FetchAllAssetsByOwnerAndContractAddress(chainID uint64, owner } func (o *Manager) FetchAllAssetsByOwner(chainID uint64, owner common.Address, cursor string, limit int) (*opensea.AssetContainer, error) { - client, err := opensea.NewOpenseaClient(chainID, o.openseaAPIKey, o.walletFeed) - if err != nil { - return nil, err - } - - assetContainer, err := client.FetchAllAssetsByOwner(owner, cursor, limit) + assetContainer, err := o.opensea.FetchAllAssetsByOwner(chainID, owner, cursor, limit) if err != nil { return nil, err } @@ -208,12 +187,7 @@ func (o *Manager) FetchAssetsByNFTUniqueID(chainID uint64, uniqueIDs []thirdpart idsToFetch := o.getIDsNotInCache(chainID, uniqueIDs) if len(idsToFetch) > 0 { - client, err := opensea.NewOpenseaClient(chainID, o.openseaAPIKey, o.walletFeed) - if err != nil { - return nil, err - } - - fetchedAssetContainer, err := client.FetchAssetsByNFTUniqueID(idsToFetch, limit) + fetchedAssetContainer, err := o.opensea.FetchAssetsByNFTUniqueID(chainID, idsToFetch, limit) if err != nil { return nil, err } diff --git a/services/wallet/connection/status.go b/services/wallet/connection/status.go new file mode 100644 index 000000000..035e326a8 --- /dev/null +++ b/services/wallet/connection/status.go @@ -0,0 +1,56 @@ +package connection + +import ( + "sync" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/event" + "github.com/status-im/status-go/services/wallet/walletevent" +) + +type Status struct { + eventType walletevent.EventType + feed *event.Feed + isConnected bool + lastCheckedAt int64 + isConnectedLock sync.RWMutex +} + +func NewStatus(eventType walletevent.EventType, feed *event.Feed) *Status { + return &Status{ + eventType: eventType, + feed: feed, + isConnected: true, + lastCheckedAt: time.Now().Unix(), + } +} + +func (c *Status) 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.feed != nil { + c.feed.Send(walletevent.Event{ + Type: c.eventType, + Accounts: []common.Address{}, + Message: message, + At: time.Now().Unix(), + }) + } + } + c.isConnected = value +} + +func (c *Status) IsConnected() bool { + c.isConnectedLock.RLock() + defer c.isConnectedLock.RUnlock() + + return c.isConnected +} diff --git a/services/wallet/thirdparty/opensea/client.go b/services/wallet/thirdparty/opensea/client.go index 3da91fb74..7e7bb8d22 100644 --- a/services/wallet/thirdparty/opensea/client.go +++ b/services/wallet/thirdparty/opensea/client.go @@ -18,6 +18,7 @@ import ( "github.com/status-im/status-go/services/wallet/bigint" walletCommon "github.com/status-im/status-go/services/wallet/common" + "github.com/status-im/status-go/services/wallet/connection" "github.com/status-im/status-go/services/wallet/thirdparty" "github.com/status-im/status-go/services/wallet/walletevent" ) @@ -50,10 +51,6 @@ func getbaseURL(chainID uint64) (string, error) { return "", ErrChainIDNotSupported } -var OpenseaClientInstances = make(map[uint64]*Client) -var OpenseaClientInstancesLock = sync.RWMutex{} -var OpenseaHTTPClient *HTTPClient = nil - type TraitValue string func (st *TraitValue) UnmarshalJSON(b []byte) error { @@ -242,81 +239,37 @@ func (o *HTTPClient) doContentTypeRequest(url string) (string, error) { } type Client struct { - client *HTTPClient - url string - apiKey string - IsConnected bool - LastCheckedAt int64 - IsConnectedLock sync.RWMutex - feed *event.Feed + client *HTTPClient + apiKey string + connectionStatus *connection.Status } // new opensea client. -func NewOpenseaClient(chainID uint64, apiKey string, feed *event.Feed) (*Client, error) { - OpenseaClientInstancesLock.Lock() - defer OpenseaClientInstancesLock.Unlock() +func NewClient(apiKey string, feed *event.Feed) *Client { + return &Client{ + client: newHTTPClient(), + apiKey: apiKey, + connectionStatus: connection.NewStatus(EventCollectibleStatusChanged, feed), + } +} - if OpenseaHTTPClient == nil { - OpenseaHTTPClient = newHTTPClient() - } - - var tmpAPIKey string = "" - if chainID == ChainIDRequiringAPIKey { - tmpAPIKey = apiKey - } - if client, ok := OpenseaClientInstances[chainID]; ok { - if client.apiKey == tmpAPIKey { - return client, nil - } - } +func (o *Client) FetchAllCollectionsByOwner(chainID uint64, owner common.Address) ([]OwnedCollection, error) { + offset := 0 + var collections []OwnedCollection baseURL, err := getbaseURL(chainID) if err != nil { return nil, err } - openseaClient := &Client{ - client: OpenseaHTTPClient, - url: baseURL, - apiKey: tmpAPIKey, - IsConnected: true, - LastCheckedAt: time.Now().Unix(), - feed: feed, - } - OpenseaClientInstances[chainID] = openseaClient - return openseaClient, nil -} - -func (o *Client) setIsConnected(value bool) { - o.IsConnectedLock.Lock() - defer o.IsConnectedLock.Unlock() - o.LastCheckedAt = time.Now().Unix() - if value != o.IsConnected { - message := "down" - if value { - message = "up" - } - if o.feed != nil { - 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) { - offset := 0 - var collections []OwnedCollection for { - 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", baseURL, owner, offset, CollectionLimit) body, err := o.client.doGetRequest(url, o.apiKey) if err != nil { - o.setIsConnected(false) + o.connectionStatus.SetIsConnected(false) return nil, err } + o.connectionStatus.SetIsConnected(true) // if Json is not returned there must be an error if !json.Valid(body) { @@ -326,7 +279,6 @@ func (o *Client) FetchAllCollectionsByOwner(owner common.Address) ([]OwnedCollec var tmp []OwnedCollection err = json.Unmarshal(body, &tmp) if err != nil { - o.setIsConnected(false) return nil, err } @@ -336,11 +288,10 @@ func (o *Client) FetchAllCollectionsByOwner(owner common.Address) ([]OwnedCollec break } } - o.setIsConnected(true) return collections, nil } -func (o *Client) FetchAllAssetsByOwnerAndCollection(owner common.Address, collectionSlug string, cursor string, limit int) (*AssetContainer, error) { +func (o *Client) FetchAllAssetsByOwnerAndCollection(chainID uint64, owner common.Address, collectionSlug string, cursor string, limit int) (*AssetContainer, error) { queryParams := url.Values{ "owner": {owner.String()}, "collection": {collectionSlug}, @@ -350,10 +301,10 @@ func (o *Client) FetchAllAssetsByOwnerAndCollection(owner common.Address, collec queryParams["cursor"] = []string{cursor} } - return o.fetchAssets(queryParams, limit) + return o.fetchAssets(chainID, queryParams, limit) } -func (o *Client) FetchAllAssetsByOwnerAndContractAddress(owner common.Address, contractAddresses []common.Address, cursor string, limit int) (*AssetContainer, error) { +func (o *Client) FetchAllAssetsByOwnerAndContractAddress(chainID uint64, owner common.Address, contractAddresses []common.Address, cursor string, limit int) (*AssetContainer, error) { queryParams := url.Values{ "owner": {owner.String()}, } @@ -366,10 +317,10 @@ func (o *Client) FetchAllAssetsByOwnerAndContractAddress(owner common.Address, c queryParams["cursor"] = []string{cursor} } - return o.fetchAssets(queryParams, limit) + return o.fetchAssets(chainID, queryParams, limit) } -func (o *Client) FetchAllAssetsByOwner(owner common.Address, cursor string, limit int) (*AssetContainer, error) { +func (o *Client) FetchAllAssetsByOwner(chainID uint64, owner common.Address, cursor string, limit int) (*AssetContainer, error) { queryParams := url.Values{ "owner": {owner.String()}, } @@ -378,10 +329,10 @@ func (o *Client) FetchAllAssetsByOwner(owner common.Address, cursor string, limi queryParams["cursor"] = []string{cursor} } - return o.fetchAssets(queryParams, limit) + return o.fetchAssets(chainID, queryParams, limit) } -func (o *Client) FetchAssetsByNFTUniqueID(uniqueIDs []thirdparty.CollectibleUniqueID, limit int) (*AssetContainer, error) { +func (o *Client) FetchAssetsByNFTUniqueID(chainID uint64, uniqueIDs []thirdparty.CollectibleUniqueID, limit int) (*AssetContainer, error) { queryParams := url.Values{} for _, uniqueID := range uniqueIDs { @@ -389,10 +340,10 @@ func (o *Client) FetchAssetsByNFTUniqueID(uniqueIDs []thirdparty.CollectibleUniq queryParams.Add("asset_contract_addresses", uniqueID.ContractAddress.String()) } - return o.fetchAssets(queryParams, limit) + return o.fetchAssets(chainID, queryParams, limit) } -func (o *Client) fetchAssets(queryParams url.Values, limit int) (*AssetContainer, error) { +func (o *Client) fetchAssets(chainID uint64, queryParams url.Values, limit int) (*AssetContainer, error) { assets := new(AssetContainer) if len(queryParams["cursor"]) > 0 { @@ -404,15 +355,22 @@ func (o *Client) fetchAssets(queryParams url.Values, limit int) (*AssetContainer tmpLimit = limit } + baseURL, err := getbaseURL(chainID) + + if err != nil { + return nil, err + } + queryParams["limit"] = []string{strconv.Itoa(tmpLimit)} for { - url := o.url + "/assets?" + queryParams.Encode() + url := baseURL + "/assets?" + queryParams.Encode() body, err := o.client.doGetRequest(url, o.apiKey) if err != nil { - o.setIsConnected(false) + o.connectionStatus.SetIsConnected(false) return nil, err } + o.connectionStatus.SetIsConnected(true) // if Json is not returned there must be an error if !json.Valid(body) { @@ -422,7 +380,6 @@ func (o *Client) fetchAssets(queryParams url.Values, limit int) (*AssetContainer container := AssetContainer{} err = json.Unmarshal(body, &container) if err != nil { - o.setIsConnected(false) return nil, err } @@ -452,6 +409,5 @@ func (o *Client) fetchAssets(queryParams url.Values, limit int) (*AssetContainer } } - o.setIsConnected(true) return assets, nil }