fix: fetch community only when assets metadata is missing

fixes: status-im/status-desktop#14296
This commit is contained in:
Patryk Osmaczko 2024-04-08 18:48:13 +02:00 committed by Jonathan Rainville
parent d3d155a5b2
commit 1ceb180e8a
5 changed files with 88 additions and 39 deletions

View File

@ -39,7 +39,6 @@ import (
"github.com/status-im/status-go/protocol"
"github.com/status-im/status-go/protocol/anonmetrics"
"github.com/status-im/status-go/protocol/common"
"github.com/status-im/status-go/protocol/common/shard"
"github.com/status-im/status-go/protocol/communities"
"github.com/status-im/status-go/protocol/communities/token"
"github.com/status-im/status-go/protocol/protobuf"
@ -550,17 +549,13 @@ func (s *Service) FillCollectibleMetadata(collectible *thirdparty.FullCollectibl
return fmt.Errorf("invalid communityID")
}
// FetchCommunityInfo should have been previously called once to ensure
// that the latest version of the CommunityDescription is available in the DB
community, err := s.fetchCommunity(communityID, false)
community, err := s.messenger.FindCommunityInfoFromDB(communityID)
if err != nil {
return err
}
if community == nil {
if err == communities.ErrOrgNotFound {
return nil
}
return err
}
tokenMetadata, err := s.fetchCommunityCollectibleMetadata(community, id.ContractID)
@ -637,48 +632,81 @@ func communityToInfo(community *communities.Community) *thirdparty.CommunityInfo
}
}
func (s *Service) FetchCommunityInfo(communityID string) (*thirdparty.CommunityInfo, error) {
community, err := s.fetchCommunity(communityID, true)
if err != nil {
return nil, err
}
return communityToInfo(community), nil
}
func (s *Service) fetchCommunity(communityID string, fetchLatest bool) (*communities.Community, error) {
if s.messenger == nil {
return nil, fmt.Errorf("messenger not ready")
}
// Try to fetch metadata from Messenger communities
// TODO: we need the shard information in the collectible to be able to retrieve info for
// communities that have specific shards
if fetchLatest {
// Try to fetch the latest version of the Community
var shard *shard.Shard = nil // TODO: build this with info from token
// NOTE: The community returned by this function will be nil if
// the version we have in the DB is the latest available.
_, err := s.messenger.FetchCommunity(&protocol.FetchCommunityRequest{
func (s *Service) fetchCommunityFromStoreNodes(communityID string) (*thirdparty.CommunityInfo, error) {
community, err := s.messenger.FetchCommunity(&protocol.FetchCommunityRequest{
CommunityKey: communityID,
Shard: shard,
TryDatabase: false,
WaitForResponse: true,
})
if err != nil {
return nil, err
}
return communityToInfo(community), nil
}
// Fetch latest community from store nodes.
func (s *Service) FetchCommunityInfo(communityID string) (*thirdparty.CommunityInfo, error) {
if s.messenger == nil {
return nil, fmt.Errorf("messenger not ready")
}
// Get the latest successfully fetched version of the Community
community, err := s.messenger.FindCommunityInfoFromDB(communityID)
if err != nil {
if err != nil && err != communities.ErrOrgNotFound {
return nil, err
}
return community, nil
// Fetch latest version from store nodes
if community == nil || !community.IsControlNode() {
return s.fetchCommunityFromStoreNodes(communityID)
}
return communityToInfo(community), nil
}
// Fetch latest community from store nodes only if any collectibles data is missing.
func (s *Service) FetchCommunityInfoForCollectibles(communityID string, ids []thirdparty.CollectibleUniqueID) (*thirdparty.CommunityInfo, error) {
if s.messenger == nil {
return nil, fmt.Errorf("messenger not ready")
}
community, err := s.messenger.FindCommunityInfoFromDB(communityID)
if err != nil && err != communities.ErrOrgNotFound {
return nil, err
}
if community == nil {
return s.fetchCommunityFromStoreNodes(communityID)
}
if community.IsControlNode() {
return communityToInfo(community), nil
}
contractIDs := func() map[string]thirdparty.ContractID {
result := map[string]thirdparty.ContractID{}
for _, id := range ids {
result[id.HashKey()] = id.ContractID
}
return result
}()
hasAllMetadata := true
for _, contractID := range contractIDs {
tokenMetadata, err := s.fetchCommunityCollectibleMetadata(community, contractID)
if err != nil {
return nil, err
}
if tokenMetadata == nil {
hasAllMetadata = false
break
}
}
if !hasAllMetadata {
return s.fetchCommunityFromStoreNodes(communityID)
}
return communityToInfo(community), nil
}
func (s *Service) fetchCommunityToken(communityID string, contractID thirdparty.ContractID) (*token.CommunityToken, error) {

View File

@ -728,7 +728,7 @@ func (o *Manager) fillCommunityID(asset *thirdparty.FullCollectibleData) error {
}
func (o *Manager) fetchCommunityAssets(communityID string, communityAssets []*thirdparty.FullCollectibleData) error {
communityInfo, err := o.communityManager.FetchCommunityInfo(communityID)
communityInfo, err := o.communityManager.FetchCommunityInfoForCollectibles(communityID, idsFromAssets(communityAssets))
// If the community is found, we update the DB.
// If the community is not found, we only insert new entries to the DB (don't replace what is already there).

View File

@ -204,3 +204,11 @@ func communityInfoToData(communityID string, community *thirdparty.CommunityInfo
return ret
}
func idsFromAssets(assets []*thirdparty.FullCollectibleData) []thirdparty.CollectibleUniqueID {
result := make([]thirdparty.CollectibleUniqueID, len(assets))
for i, asset := range assets {
result[i] = asset.CollectibleData.ID
}
return result
}

View File

@ -66,8 +66,8 @@ func (cm *Manager) setCommunityInfo(id string, c *thirdparty.CommunityInfo) (err
return cm.db.SetCommunityInfo(id, c)
}
func (cm *Manager) FetchCommunityInfo(communityID string) (*thirdparty.CommunityInfo, error) {
communityInfo, err := cm.communityInfoProvider.FetchCommunityInfo(communityID)
func (cm *Manager) fetchCommunityInfo(communityID string, fetcher func() (*thirdparty.CommunityInfo, error)) (*thirdparty.CommunityInfo, error) {
communityInfo, err := fetcher()
if err != nil {
dbErr := cm.setCommunityInfo(communityID, nil)
if dbErr != nil {
@ -79,6 +79,18 @@ func (cm *Manager) FetchCommunityInfo(communityID string) (*thirdparty.Community
return communityInfo, err
}
func (cm *Manager) FetchCommunityInfo(communityID string) (*thirdparty.CommunityInfo, error) {
return cm.fetchCommunityInfo(communityID, func() (*thirdparty.CommunityInfo, error) {
return cm.communityInfoProvider.FetchCommunityInfo(communityID)
})
}
func (cm *Manager) FetchCommunityInfoForCollectibles(communityID string, ids []thirdparty.CollectibleUniqueID) (*thirdparty.CommunityInfo, error) {
return cm.fetchCommunityInfo(communityID, func() (*thirdparty.CommunityInfo, error) {
return cm.communityInfoProvider.FetchCommunityInfoForCollectibles(communityID, ids)
})
}
func (cm *Manager) FetchCommunityMetadataAsync(communityID string) {
go func() {
communityInfo, err := cm.FetchCommunityMetadata(communityID)

View File

@ -14,4 +14,5 @@ type CommunityInfoProvider interface {
// Collectible-related methods
GetCommunityID(tokenURI string) string
FillCollectibleMetadata(collectible *FullCollectibleData) error
FetchCommunityInfoForCollectibles(communityID string, ids []CollectibleUniqueID) (*CommunityInfo, error)
}