From 92f0479a0ce63af8cd53b3a0eba820edc09798e2 Mon Sep 17 00:00:00 2001 From: Igor Sirotin Date: Wed, 20 Dec 2023 12:49:12 +0000 Subject: [PATCH] chore: fetch contact with `StoreNodeRequestManager` (#4484) --- protocol/linkpreview_unfurler_status.go | 2 +- protocol/messenger.go | 32 +-- protocol/messenger_contacts.go | 91 +------ .../messenger_store_node_request_manager.go | 249 ++++++++++++------ protocol/messenger_storenode_request_test.go | 52 +++- services/ext/api.go | 2 +- wakuv2/config.go | 3 +- wakuv2/waku.go | 3 +- 8 files changed, 233 insertions(+), 201 deletions(-) diff --git a/protocol/linkpreview_unfurler_status.go b/protocol/linkpreview_unfurler_status.go index 57633038e..4b6285ff9 100644 --- a/protocol/linkpreview_unfurler_status.go +++ b/protocol/linkpreview_unfurler_status.go @@ -59,7 +59,7 @@ func (u *StatusUnfurler) buildContactData(publicKey string) (*common.StatusConta // If no contact found locally, fetch it from waku if contact == nil { - if contact, err = u.m.RequestContactInfoFromMailserver(contactID, true); err != nil { + if contact, err = u.m.FetchContact(contactID, true); err != nil { return nil, fmt.Errorf("failed to request contact info from mailserver for public key '%s': %w", publicKey, err) } } diff --git a/protocol/messenger.go b/protocol/messenger.go index 86450c50d..a2df64085 100644 --- a/protocol/messenger.go +++ b/protocol/messenger.go @@ -154,9 +154,6 @@ type Messenger struct { once sync.Once } - requestedContactsLock sync.RWMutex - requestedContacts map[string]*transport.Filter - connectionState connection.State telemetryClient *telemetry.Client contractMaker *contracts.ContractMaker @@ -531,16 +528,14 @@ func NewMessenger( peers: make(map[string]peerStatus), availabilitySubscriptions: make([]chan struct{}, 0), }, - mailserversDatabase: c.mailserversDatabase, - account: c.account, - quit: make(chan struct{}), - ctx: ctx, - cancel: cancel, - requestedContactsLock: sync.RWMutex{}, - requestedContacts: make(map[string]*transport.Filter), - importingCommunities: make(map[string]bool), - importingChannels: make(map[string]bool), - importRateLimiter: rate.NewLimiter(rate.Every(importSlowRate), 1), + mailserversDatabase: c.mailserversDatabase, + account: c.account, + quit: make(chan struct{}), + ctx: ctx, + cancel: cancel, + importingCommunities: make(map[string]bool), + importingChannels: make(map[string]bool), + importRateLimiter: rate.NewLimiter(rate.Every(importSlowRate), 1), importDelayer: struct { wait chan struct{} once sync.Once @@ -583,7 +578,7 @@ func NewMessenger( } messenger.mentionsManager = NewMentionManager(messenger) - messenger.storeNodeRequestsManager = NewCommunityRequestsManager(messenger) + messenger.storeNodeRequestsManager = NewStoreNodeRequestManager(messenger) if c.walletService != nil { messenger.walletAPI = walletAPI @@ -3745,11 +3740,9 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte contact, contactFound := messageState.AllContacts.Load(senderID) - if _, ok := m.requestedContacts[senderID]; !ok { - // Check for messages from blocked users - if contactFound && contact.Blocked { - continue - } + // Check for messages from blocked users + if contactFound && contact.Blocked { + continue } // Don't process duplicates @@ -3773,7 +3766,6 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte contact = c if msg.ApplicationLayer.Type != protobuf.ApplicationMetadataMessage_PUSH_NOTIFICATION_QUERY { messageState.AllContacts.Store(senderID, contact) - m.forgetContactInfoRequest(senderID) } } messageState.CurrentMessageState = &CurrentMessageState{ diff --git a/protocol/messenger_contacts.go b/protocol/messenger_contacts.go index bbbacb3b5..58fbd543c 100644 --- a/protocol/messenger_contacts.go +++ b/protocol/messenger_contacts.go @@ -5,7 +5,6 @@ import ( "crypto/ecdsa" "errors" "fmt" - "time" "github.com/golang/protobuf/proto" "go.uber.org/zap" @@ -1218,93 +1217,9 @@ func (m *Messenger) scheduleSyncFiltersForContact(publicKey *ecdsa.PublicKey) (* return filter, nil } -func (m *Messenger) RequestContactInfoFromMailserver(pubkey string, waitForResponse bool) (*Contact, error) { - - err := m.requestContactInfoFromMailserver(pubkey) - - if err != nil { - return nil, err - } - - if !waitForResponse { - return nil, nil - } - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - - defer func() { - cancel() - m.forgetContactInfoRequest(pubkey) - }() - - for { - select { - case <-time.After(200 * time.Millisecond): - contact, ok := m.allContacts.Load(pubkey) - if ok && contact != nil && contact.DisplayName != "" { - return contact, nil - } - - case <-ctx.Done(): - return nil, fmt.Errorf("failed to request contact info from mailserver: %w", ctx.Err()) - } - } -} - -func (m *Messenger) requestContactInfoFromMailserver(pubkey string) error { - - m.requestedContactsLock.Lock() - defer m.requestedContactsLock.Unlock() - - if _, ok := m.requestedContacts[pubkey]; ok { - return nil - } - - m.logger.Debug("requesting contact info from mailserver", zap.String("publicKey", pubkey)) - - c, err := buildContactFromPkString(pubkey) - - if err != nil { - return err - } - - publicKey, err := c.PublicKey() - - if err != nil { - return err - } - - var filter *transport.Filter - filter, err = m.scheduleSyncFiltersForContact(publicKey) - - if err != nil { - return err - } - - m.requestedContacts[pubkey] = filter - - return nil -} - -func (m *Messenger) forgetContactInfoRequest(publicKey string) { - - m.requestedContactsLock.Lock() - defer m.requestedContactsLock.Unlock() - - filter, ok := m.requestedContacts[publicKey] - if !ok { - return - } - - m.logger.Debug("forgetting contact info request", zap.String("publicKey", publicKey)) - - err := m.transport.RemoveFilters([]*transport.Filter{filter}) - - if err != nil { - m.logger.Warn("failed to remove filter", zap.Error(err)) - } - - delete(m.requestedContacts, publicKey) +func (m *Messenger) FetchContact(contactID string, waitForResponse bool) (*Contact, error) { + contact, _, err := m.storeNodeRequestsManager.FetchContact(contactID, waitForResponse) + return contact, err } func (m *Messenger) SubscribeToSelfContactChanges() chan *SelfContactChangeEvent { diff --git a/protocol/messenger_store_node_request_manager.go b/protocol/messenger_store_node_request_manager.go index d85d868e3..822fb2d22 100644 --- a/protocol/messenger_store_node_request_manager.go +++ b/protocol/messenger_store_node_request_manager.go @@ -6,6 +6,9 @@ import ( "sync" "time" + "github.com/status-im/status-go/eth-node/crypto" + "github.com/status-im/status-go/protocol/common/shard" + "go.uber.org/zap" "github.com/status-im/status-go/eth-node/types" @@ -17,20 +20,25 @@ const ( storeNodeAvailableTimeout = 30 * time.Second ) -// FetchCommunityStats is used in tests -type FetchCommunityStats struct { +// StoreNodeRequestStats is used in tests +type StoreNodeRequestStats struct { FetchedEnvelopesCount int FetchedPagesCount int } +type storeNodeRequestID struct { + RequestType storeNodeRequestType `json:"requestType"` + DataID string `json:"dataID"` +} + type StoreNodeRequestManager struct { messenger *Messenger logger *zap.Logger // activeRequests contain all ongoing store node requests. - // Map is indexed with `CommunityID`. - // Request might be duplicated in the map if the request is for multiple communities. - activeRequests map[string]*storeNodeRequest + // Map is indexed with `DataID`. + // Request might be duplicated in the map in case of contentType collisions. + activeRequests map[storeNodeRequestID]*storeNodeRequest // activeRequestsLock should be locked each time activeRequests is being accessed or changed. activeRequestsLock sync.RWMutex @@ -38,11 +46,11 @@ type StoreNodeRequestManager struct { onPerformingBatch func(MailserverBatch) } -func NewCommunityRequestsManager(m *Messenger) *StoreNodeRequestManager { +func NewStoreNodeRequestManager(m *Messenger) *StoreNodeRequestManager { return &StoreNodeRequestManager{ messenger: m, logger: m.logger.Named("StoreNodeRequestManager"), - activeRequests: map[string]*storeNodeRequest{}, + activeRequests: map[storeNodeRequestID]*storeNodeRequest{}, activeRequestsLock: sync.RWMutex{}, onPerformingBatch: nil, } @@ -53,18 +61,18 @@ func NewCommunityRequestsManager(m *Messenger) *StoreNodeRequestManager { // the function will also wait for the store node response and return the fetched community. // Automatically waits for an available store node. // When a `nil` community and `nil` error is returned, that means the community wasn't found at the store node. -func (m *StoreNodeRequestManager) FetchCommunity(community communities.CommunityShard, waitForResponse bool) (*communities.Community, FetchCommunityStats, error) { +func (m *StoreNodeRequestManager) FetchCommunity(community communities.CommunityShard, waitForResponse bool) (*communities.Community, StoreNodeRequestStats, error) { m.logger.Info("requesting community from store node", zap.Any("community", community), zap.Bool("waitForResponse", waitForResponse)) - channel, err := m.subscribeToCommunityRequest(community) + channel, err := m.subscribeToRequest(storeNodeCommunityRequest, community.CommunityID, community.Shard) if err != nil { - return nil, FetchCommunityStats{}, fmt.Errorf("failed to create a request for community: %w", err) + return nil, StoreNodeRequestStats{}, fmt.Errorf("failed to create a request for community: %w", err) } if !waitForResponse { - return nil, FetchCommunityStats{}, nil + return nil, StoreNodeRequestStats{}, nil } result := <-channel @@ -96,34 +104,64 @@ func (m *StoreNodeRequestManager) FetchCommunities(communities []communities.Com return outErr } -// subscribeToCommunityRequest checks if a request for given community is already in progress, creates and installs +func (m *StoreNodeRequestManager) FetchContact(contactID string, waitForResponse bool) (*Contact, StoreNodeRequestStats, error) { + m.logger.Info("requesting contact from store node", + zap.Any("contactID", contactID), + zap.Bool("waitForResponse", waitForResponse)) + + channel, err := m.subscribeToRequest(storeNodeContactRequest, contactID, nil) + if err != nil { + return nil, StoreNodeRequestStats{}, fmt.Errorf("failed to create a request for community: %w", err) + } + + if !waitForResponse { + return nil, StoreNodeRequestStats{}, nil + } + + result := <-channel + return result.contact, result.stats, result.err +} + +// subscribeToRequest checks if a request for given community/contact is already in progress, creates and installs // a new one if not found, and returns a subscription to the result of the found/started request. -// The subscription can then be used to get the result of the request, this could be either a community or an error. -func (m *StoreNodeRequestManager) subscribeToCommunityRequest(community communities.CommunityShard) (communitySubscriptionChannel, error) { +// The subscription can then be used to get the result of the request, this could be either a community/contact or an error. +func (m *StoreNodeRequestManager) subscribeToRequest(requestType storeNodeRequestType, dataID string, shard *shard.Shard) (storeNodeResponseSubscription, error) { // It's important to unlock only after getting the subscription channel. // We also lock `activeRequestsLock` during finalizing the requests. This ensures that the subscription // created in this function will get the result even if the requests proceeds faster than this function ends. m.activeRequestsLock.Lock() defer m.activeRequestsLock.Unlock() - request, requestFound := m.activeRequests[community.CommunityID] + requestID := storeNodeRequestID{ + RequestType: requestType, + DataID: dataID, + } + + request, requestFound := m.activeRequests[requestID] if !requestFound { // Create corresponding filter - filter, filterCreated, err := m.getFilter(community) + var err error + var filter *transport.Filter + filterCreated := false + + filter, filterCreated, err = m.getFilter(requestType, dataID, shard) if err != nil { + if filterCreated { + m.forgetFilter(filter) + } return nil, fmt.Errorf("failed to create community filter: %w", err) } request = m.newStoreNodeRequest() request.pubsubTopic = filter.PubsubTopic - request.communityID = community.CommunityID + request.requestID = requestID request.contentTopic = filter.ContentTopic if filterCreated { request.filterToForget = filter } - m.activeRequests[community.CommunityID] = request + m.activeRequests[requestID] = request request.start() } @@ -134,38 +172,62 @@ func (m *StoreNodeRequestManager) subscribeToCommunityRequest(community communit func (m *StoreNodeRequestManager) newStoreNodeRequest() *storeNodeRequest { return &storeNodeRequest{ manager: m, - subscriptions: make([]communitySubscriptionChannel, 0), + subscriptions: make([]storeNodeResponseSubscription, 0), } } // getFilter checks if a filter for a given community is already created and creates one of not found. // Returns the found/created filter, a flag if the filter was created by the function and an error. -func (m *StoreNodeRequestManager) getFilter(c communities.CommunityShard) (*transport.Filter, bool, error) { +func (m *StoreNodeRequestManager) getFilter(requestType storeNodeRequestType, dataID string, shard *shard.Shard) (*transport.Filter, bool, error) { // First check if such filter already exists. - filter := m.messenger.transport.FilterByChatID(c.CommunityID) + filter := m.messenger.transport.FilterByChatID(dataID) if filter != nil { //we don't remember filter id associated with community because it was already installed return filter, false, nil } - // If filter wasn't installed we create it and - // remember for uninstalling after response is received - filters, err := m.messenger.transport.InitPublicFilters([]transport.FiltersToInitialize{{ - ChatID: c.CommunityID, - PubsubTopic: c.Shard.PubsubTopic(), - }}) + switch requestType { + case storeNodeCommunityRequest: + // If filter wasn't installed we create it and + // remember for uninstalling after response is received + filters, err := m.messenger.transport.InitPublicFilters([]transport.FiltersToInitialize{{ + ChatID: dataID, + PubsubTopic: shard.PubsubTopic(), + }}) - if err != nil { - m.logger.Error("can't install filter for community", zap.Error(err)) - return nil, true, err + if err != nil { + m.logger.Error("failed to install filter for community", zap.Error(err)) + return nil, false, err + } + + if len(filters) != 1 { + m.logger.Error("Unexpected number of filters created") + return nil, true, fmt.Errorf("unexepcted number of filters created") + } + + filter = filters[0] + case storeNodeContactRequest: + publicKeyBytes, err := types.DecodeHex(dataID) + if err != nil { + return nil, false, fmt.Errorf("failed to decode contact id: %w", err) + } + + publicKey, err := crypto.UnmarshalPubkey(publicKeyBytes) + if err != nil { + return nil, false, fmt.Errorf("failed to unmarshal public key: %w", err) + } + + filter, err = m.messenger.transport.JoinPrivate(publicKey) + + if err != nil { + return nil, false, fmt.Errorf("failed to install filter for contact: %w", err) + } + + default: + return nil, false, fmt.Errorf("invalid store node request type: %d", requestType) } - if len(filters) != 1 { - m.logger.Error("Unexpected number of filters created") - return nil, true, fmt.Errorf("unexepcted number of filters created") - } - - return filters[0], true, nil + return filter, true, nil } // forgetFilter uninstalls the given filter @@ -176,38 +238,49 @@ func (m *StoreNodeRequestManager) forgetFilter(filter *transport.Filter) { } } +type storeNodeRequestType int + +const ( + storeNodeCommunityRequest storeNodeRequestType = iota + storeNodeContactRequest +) + // storeNodeRequest represents a single store node batch request. // For a valid storeNodeRequest to be performed, the user must set all the struct fields and call start method. type storeNodeRequest struct { + requestID storeNodeRequestID + // request parameters pubsubTopic string contentTopic types.TopicType // request corresponding metadata to be used in finalize filterToForget *transport.Filter - communityID string // internal fields manager *StoreNodeRequestManager - subscriptions []communitySubscriptionChannel - result fetchCommunityResult + subscriptions []storeNodeResponseSubscription + result storeNodeRequestResult } -// fetchCommunityResult contains result of a single storeNodeRequest +// storeNodeRequestResult contains result of a single storeNodeRequest +// Further by using `data` we mean community/contact, depending on request type. // If any error occurs during the request, err field will be set. -// If a community was successfully fetched, community field will contain the fetched information. -// If a community wasn't found in store node, then a community will be set to `nil`. +// If data was successfully fetched, data field will contain the fetched information. +// If data wasn't found in store node, then a data will be set to `nil`. // stats will contain information about the performed request that might be useful for testing. -type fetchCommunityResult struct { - err error +type storeNodeRequestResult struct { + err error + stats StoreNodeRequestStats + // One of data fields (community or contact) will be present depending on request type community *communities.Community - stats FetchCommunityStats + contact *Contact } -type communitySubscriptionChannel = chan fetchCommunityResult +type storeNodeResponseSubscription = chan storeNodeRequestResult -func (r *storeNodeRequest) subscribe() communitySubscriptionChannel { - channel := make(communitySubscriptionChannel, 100) +func (r *storeNodeRequest) subscribe() storeNodeResponseSubscription { + channel := make(storeNodeResponseSubscription, 100) r.subscriptions = append(r.subscriptions, channel) return channel } @@ -217,8 +290,9 @@ func (r *storeNodeRequest) finalize() { defer r.manager.activeRequestsLock.Unlock() r.manager.logger.Info("request finished", - zap.String("communityID", r.communityID), + zap.Any("requestID", r.requestID), zap.Bool("communityFound", r.result.community != nil), + zap.Bool("contactFound", r.result.contact != nil), zap.Error(r.result.err)) // Send the result to subscribers @@ -232,7 +306,7 @@ func (r *storeNodeRequest) finalize() { r.manager.messenger.passStoredCommunityInfoToSignalHandler(r.result.community) } - delete(r.manager.activeRequests, r.communityID) + delete(r.manager.activeRequests, r.requestID) if r.filterToForget != nil { r.manager.forgetFilter(r.filterToForget) @@ -241,7 +315,7 @@ func (r *storeNodeRequest) finalize() { func (r *storeNodeRequest) shouldFetchNextPage(envelopesCount int) (bool, uint32) { logger := r.manager.logger.With( - zap.String("communityID", r.communityID), + zap.Any("requestID", r.requestID), zap.Int("envelopesCount", envelopesCount)) r.result.stats.FetchedEnvelopesCount += envelopesCount @@ -251,45 +325,63 @@ func (r *storeNodeRequest) shouldFetchNextPage(envelopesCount int) (bool, uint32 r.manager.messenger.ProcessAllMessages() // Try to get community from database - community, err := r.manager.messenger.communitiesManager.GetByIDString(r.communityID) + switch r.requestID.RequestType { + case storeNodeCommunityRequest: + community, err := r.manager.messenger.communitiesManager.GetByIDString(r.requestID.DataID) - if err != nil { - logger.Error("failed to read from database", - zap.String("communityID", r.communityID), - zap.Error(err)) - r.result = fetchCommunityResult{ - community: nil, - err: fmt.Errorf("failed to read from database: %w", err), + if err != nil { + logger.Error("failed to read from database", + zap.String("communityID", r.requestID.DataID), + zap.Error(err)) + r.result = storeNodeRequestResult{ + community: nil, + err: fmt.Errorf("failed to read from database: %w", err), + } + return false, 0 // failed to read from database, no sense to continue the procedure } - return false, 0 // failed to read from database, no sense to continue the procedure + + if community == nil { + // community not found in the database, request next page + logger.Debug("community still not fetched") + return true, defaultStoreNodeRequestPageSize + } + + logger.Debug("community found", + zap.String("displayName", community.Name())) + + r.result.community = community + + case storeNodeContactRequest: + contact := r.manager.messenger.GetContactByID(r.requestID.DataID) + + if contact == nil { + // contact not found in the database, request next page + logger.Debug("contact still not fetched") + return true, defaultStoreNodeRequestPageSize + } + + logger.Debug("contact found", + zap.String("displayName", contact.DisplayName)) + + r.result.contact = contact } - if community == nil { - // community not found in the database, request next page - logger.Debug("community still not fetched") - return true, defaultStoreNodeRequestPageSize - } - - logger.Debug("community found", - zap.String("displayName", community.Name())) - - r.result.community = community - return false, 0 } func (r *storeNodeRequest) routine() { r.manager.logger.Info("starting store node request", - zap.String("communityID", r.communityID), + zap.Any("requestID", r.requestID), zap.String("pubsubTopic", r.pubsubTopic), zap.Any("contentTopic", r.contentTopic), ) // Return a nil community and no error when request was - // performed successfully, but no community found. - r.result = fetchCommunityResult{ - community: nil, + // performed successfully, but no community/contact found. + r.result = storeNodeRequestResult{ err: nil, + community: nil, + contact: nil, } defer func() { @@ -297,7 +389,6 @@ func (r *storeNodeRequest) routine() { }() if !r.manager.messenger.waitForAvailableStoreNode(storeNodeAvailableTimeout) { - r.result.community = nil r.result.err = fmt.Errorf("store node is not available") return } @@ -324,11 +415,5 @@ func (r *storeNodeRequest) routine() { } func (r *storeNodeRequest) start() { - r.manager.logger.Debug("starting new community request", - zap.Any("communities", r.communityID), - zap.String("pubsubTopic", r.pubsubTopic), - zap.Any("contentTopic", r.contentTopic), - ) - go r.routine() } diff --git a/protocol/messenger_storenode_request_test.go b/protocol/messenger_storenode_request_test.go index a262386ef..470716aef 100644 --- a/protocol/messenger_storenode_request_test.go +++ b/protocol/messenger_storenode_request_test.go @@ -6,6 +6,8 @@ import ( "testing" "time" + "github.com/status-im/status-go/multiaccounts/accounts" + gethbridge "github.com/status-im/status-go/eth-node/bridge/geth" "github.com/status-im/status-go/protocol/common" "github.com/status-im/status-go/protocol/communities" @@ -63,7 +65,7 @@ func (s *MessengerStoreNodeRequestSuite) SetupTest() { s.cancel = make(chan struct{}, 10) - storeNodeLogger := s.logger.With(zap.String("name", "store-node-waku")) + storeNodeLogger := s.logger.Named("store-node-waku") s.wakuStoreNode = NewWakuV2(&s.Suite, storeNodeLogger, true, true) storeNodeListenAddresses := s.wakuStoreNode.ListenAddresses() @@ -149,14 +151,20 @@ func (s *MessengerStoreNodeRequestSuite) createCommunity(m *Messenger) *communit return response.Communities()[0] } -func (s *MessengerStoreNodeRequestSuite) requireCommunitiesEqual(fetchedCommunity *communities.Community, expectedCommunityInfo *communities.Community) { - s.Require().Equal(expectedCommunityInfo.Name(), fetchedCommunity.Name()) - s.Require().Equal(expectedCommunityInfo.Identity().Description, fetchedCommunity.Identity().Description) - s.Require().Equal(expectedCommunityInfo.Color(), fetchedCommunity.Color()) - s.Require().Equal(expectedCommunityInfo.Tags(), fetchedCommunity.Tags()) +func (s *MessengerStoreNodeRequestSuite) requireCommunitiesEqual(c *communities.Community, expected *communities.Community) { + s.Require().Equal(expected.Name(), c.Name()) + s.Require().Equal(expected.Identity().Description, c.Identity().Description) + s.Require().Equal(expected.Color(), c.Color()) + s.Require().Equal(expected.Tags(), c.Tags()) } -func (s *MessengerStoreNodeRequestSuite) fetchCommunity(m *Messenger, communityShard communities.CommunityShard, expectedCommunityInfo *communities.Community) FetchCommunityStats { +func (s *MessengerStoreNodeRequestSuite) requireContactsEqual(c *Contact, expected *Contact) { + s.Require().Equal(expected.DisplayName, c.DisplayName) + s.Require().Equal(expected.Bio, c.Bio) + s.Require().Equal(expected.SocialLinks, c.SocialLinks) +} + +func (s *MessengerStoreNodeRequestSuite) fetchCommunity(m *Messenger, communityShard communities.CommunityShard, expectedCommunityInfo *communities.Community) StoreNodeRequestStats { fetchedCommunity, stats, err := m.storeNodeRequestsManager.FetchCommunity(communityShard, true) s.Require().NoError(err) @@ -170,6 +178,17 @@ func (s *MessengerStoreNodeRequestSuite) fetchCommunity(m *Messenger, communityS return stats } +func (s *MessengerStoreNodeRequestSuite) fetchProfile(m *Messenger, contactID string, expectedContact *Contact) { + fetchedContact, err := m.FetchContact(contactID, true) + s.Require().NoError(err) + s.Require().NotNil(fetchedContact) + s.Require().Equal(contactID, fetchedContact.ID) + + if expectedContact != nil { + s.requireContactsEqual(fetchedContact, expectedContact) + } +} + func (s *MessengerStoreNodeRequestSuite) waitForAvailableStoreNode(messenger *Messenger) { WaitForAvailableStoreNode(&s.Suite, messenger, storeNodeConnectTimeout) } @@ -438,3 +457,22 @@ func (s *MessengerStoreNodeRequestSuite) TestRequestWithoutWaitingResponse() { s.requireCommunitiesEqual(fetchedCommunities[community.IDString()], community) } + +func (s *MessengerStoreNodeRequestSuite) TestRequestProfileInfo() { + s.createOwner() + + // Set keypair (to be able to set displayName) + ownerProfileKp := accounts.GetProfileKeypairForTest(true, false, false) + ownerProfileKp.KeyUID = s.owner.account.KeyUID + ownerProfileKp.Accounts[0].KeyUID = s.owner.account.KeyUID + + err := s.owner.settings.SaveOrUpdateKeypair(ownerProfileKp) + s.Require().NoError(err) + + // Set display name, this will also publish contact code + err = s.owner.SetDisplayName("super-owner") + s.Require().NoError(err) + + s.createBob() + s.fetchProfile(s.bob, s.owner.selfContact.ID, s.owner.selfContact) +} diff --git a/services/ext/api.go b/services/ext/api.go index aaa1d99a4..d4d7cebda 100644 --- a/services/ext/api.go +++ b/services/ext/api.go @@ -353,7 +353,7 @@ func (api *PublicAPI) GetContactByID(parent context.Context, id string) *protoco } func (api *PublicAPI) RequestContactInfoFromMailserver(pubkey string) (*protocol.Contact, error) { - return api.service.messenger.RequestContactInfoFromMailserver(pubkey, true) + return api.service.messenger.FetchContact(pubkey, true) } func (api *PublicAPI) RemoveFilters(parent context.Context, chats []*transport.Filter) error { diff --git a/wakuv2/config.go b/wakuv2/config.go index 580f1a16d..931ce3b83 100644 --- a/wakuv2/config.go +++ b/wakuv2/config.go @@ -19,9 +19,10 @@ package wakuv2 import ( - ethdisc "github.com/ethereum/go-ethereum/p2p/dnsdisc" "github.com/waku-org/go-waku/waku/v2/protocol/relay" + ethdisc "github.com/ethereum/go-ethereum/p2p/dnsdisc" + "github.com/status-im/status-go/wakuv2/common" ) diff --git a/wakuv2/waku.go b/wakuv2/waku.go index 6660f8abc..08eec56db 100644 --- a/wakuv2/waku.go +++ b/wakuv2/waku.go @@ -54,7 +54,6 @@ import ( pubsub "github.com/libp2p/go-libp2p-pubsub" "github.com/libp2p/go-libp2p/core/metrics" - ethdisc "github.com/ethereum/go-ethereum/p2p/dnsdisc" "github.com/waku-org/go-waku/waku/v2/dnsdisc" wps "github.com/waku-org/go-waku/waku/v2/peerstore" "github.com/waku-org/go-waku/waku/v2/protocol" @@ -62,6 +61,8 @@ import ( "github.com/waku-org/go-waku/waku/v2/protocol/peer_exchange" "github.com/waku-org/go-waku/waku/v2/protocol/relay" + ethdisc "github.com/ethereum/go-ethereum/p2p/dnsdisc" + "github.com/status-im/status-go/connection" "github.com/status-im/status-go/eth-node/types" "github.com/status-im/status-go/timesource"