feat: new configurable endpoint RequestCommunityInfoFromMailserverV2 (#4238)

* StatusUnfurler: use shard from url
This commit is contained in:
Igor Sirotin 2023-11-03 10:30:24 +00:00 committed by GitHub
parent 25f25e9853
commit c27384680a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 137 additions and 57 deletions

View File

@ -155,7 +155,12 @@ func main() {
}
}
community, err := messenger.RequestCommunityInfoFromMailserver(*communityID, shard, true)
community, err := messenger.FetchCommunity(&protocol.FetchCommunityRequest{
CommunityKey: *communityID,
Shard: shard,
TryDatabase: true,
WaitForResponse: true,
})
if err != nil {
logger.Error("community error", "error", err)

View File

@ -3331,11 +3331,11 @@ func (s *MessengerCommunitiesSuite) TestGetCommunityIdFromKey() {
privateKey := "0x3f932031cb5f94ba7eb8ab4c824c3677973ab01fde65d1b89e0b3f470003a2cd"
// Public key returns the same
communityID := s.bob.GetCommunityIDFromKey(publicKey)
communityID := GetCommunityIDFromKey(publicKey)
s.Require().Equal(communityID, publicKey)
// Private key returns the public key
communityID = s.bob.GetCommunityIDFromKey(privateKey)
communityID = GetCommunityIDFromKey(privateKey)
s.Require().Equal(communityID, publicKey)
}

View File

@ -92,9 +92,14 @@ func (u *StatusUnfurler) fillCommunityImages(community *communities.Community, i
return nil
}
func (u *StatusUnfurler) buildCommunityData(communityID string) (*communities.Community, *common.StatusCommunityLinkPreview, error) {
func (u *StatusUnfurler) buildCommunityData(communityID string, shard *common.Shard) (*communities.Community, *common.StatusCommunityLinkPreview, error) {
// This automatically checks the database
community, err := u.m.RequestCommunityInfoFromMailserver(communityID, nil, true)
community, err := u.m.FetchCommunity(&FetchCommunityRequest{
CommunityKey: communityID,
Shard: shard,
TryDatabase: true,
WaitForResponse: true,
})
if err != nil {
return nil, nil, fmt.Errorf("failed to get community info for communityID '%s': %w", communityID, err)
@ -120,8 +125,8 @@ func (u *StatusUnfurler) buildCommunityData(communityID string) (*communities.Co
return community, c, nil
}
func (u *StatusUnfurler) buildChannelData(channelUUID string, communityID string) (*common.StatusCommunityChannelLinkPreview, error) {
community, communityData, err := u.buildCommunityData(communityID)
func (u *StatusUnfurler) buildChannelData(channelUUID string, communityID string, communityShard *common.Shard) (*common.StatusCommunityChannelLinkPreview, error) {
community, communityData, err := u.buildCommunityData(communityID, communityShard)
if err != nil {
return nil, fmt.Errorf("failed to build channel community data: %w", err)
}
@ -169,7 +174,7 @@ func (u *StatusUnfurler) Unfurl() (*common.StatusLinkPreview, error) {
if resp.Community == nil {
return preview, fmt.Errorf("channel community can't be empty")
}
preview.Channel, err = u.buildChannelData(resp.Channel.ChannelUUID, resp.Community.CommunityID)
preview.Channel, err = u.buildChannelData(resp.Channel.ChannelUUID, resp.Community.CommunityID, resp.Shard)
if err != nil {
return nil, fmt.Errorf("error when building channel data: %w", err)
}
@ -177,7 +182,7 @@ func (u *StatusUnfurler) Unfurl() (*common.StatusLinkPreview, error) {
}
if resp.Community != nil {
_, preview.Community, err = u.buildCommunityData(resp.Community.CommunityID)
_, preview.Community, err = u.buildCommunityData(resp.Community.CommunityID, resp.Shard)
if err != nil {
return nil, fmt.Errorf("error when building community data: %w", err)
}

View File

@ -67,6 +67,36 @@ const (
maxChunkSizeBytes = 1500000
)
type FetchCommunityRequest struct {
// CommunityKey should be either a public or a private community key
CommunityKey string `json:"communityKey"`
Shard *common.Shard `json:"shard"`
TryDatabase bool `json:"tryDatabase"`
WaitForResponse bool `json:"waitForResponse"`
}
func (r *FetchCommunityRequest) Validate() error {
if len(r.CommunityKey) <= 2 {
return fmt.Errorf("community key is too short")
}
return nil
}
func (r *FetchCommunityRequest) getCommunityID() string {
return GetCommunityIDFromKey(r.CommunityKey)
}
func GetCommunityIDFromKey(communityKey string) string {
// Check if the key is a private key. strip the 0x at the start
if privateKey, err := crypto.HexToECDSA(communityKey[2:]); err == nil {
// It is a privateKey
return types.HexBytes(crypto.CompressPubkey(&privateKey.PublicKey)).String()
}
// Not a private key, use the public key
return communityKey
}
func (m *Messenger) publishOrg(org *communities.Community) error {
if org == nil {
return nil
@ -2326,7 +2356,12 @@ func (m *Messenger) ImportCommunity(ctx context.Context, key *ecdsa.PrivateKey)
return nil, err
}
_, err = m.RequestCommunityInfoFromMailserver(community.IDString(), community.Shard(), false)
_, err = m.FetchCommunity(&FetchCommunityRequest{
CommunityKey: community.IDString(),
Shard: community.Shard(),
TryDatabase: false,
WaitForResponse: true,
})
if err != nil {
// TODO In the future we should add a mechanism to re-apply next steps (adding owner, joining)
// if there is no connection with mailserver. Otherwise changes will be overwritten.
@ -2592,56 +2627,37 @@ func (m *Messenger) findCommunityInfoFromDB(communityID string) (*communities.Co
return community, nil
}
func (m *Messenger) GetCommunityIDFromKey(communityKey string) string {
// Check if the key is a private key. strip the 0x at the start
privateKey, err := crypto.HexToECDSA(communityKey[2:])
communityID := ""
if err != nil {
// Not a private key, use the public key
communityID = communityKey
} else {
// It is a privateKey
communityID = types.HexBytes(crypto.CompressPubkey(&privateKey.PublicKey)).String()
// FetchCommunity installs filter for community and requests its details
// from mailserver.
//
// If `request.TryDatabase` is true, it first looks for community in database,
// and requests from mailserver only if it wasn't found locally.
// If `request.WaitForResponse` is true, it waits until it has the community before returning it.
// If `request.WaitForResponse` is false, it installs filter for community and requests its details
// from mailserver. When response received it will be passed through signals handler.
func (m *Messenger) FetchCommunity(request *FetchCommunityRequest) (*communities.Community, error) {
if err := request.Validate(); err != nil {
return nil, fmt.Errorf("invalid request: %w", err)
}
return communityID
}
communityID := request.getCommunityID()
// RequestCommunityInfoFromMailserver installs filter for community and requests its details
// from mailserver. It waits until it has the community before returning it.
// If useDatabase is true, it searches for community in database and does not request mailserver.
func (m *Messenger) RequestCommunityInfoFromMailserver(privateOrPublicKey string, shard *common.Shard, useDatabase bool) (*communities.Community, error) {
communityID := m.GetCommunityIDFromKey(privateOrPublicKey)
if useDatabase {
if request.TryDatabase {
community, err := m.findCommunityInfoFromDB(communityID)
if err != nil {
return nil, err
}
if community != nil {
if !request.WaitForResponse {
m.config.messengerSignalsHandler.CommunityInfoFound(community)
}
return community, nil
}
}
return m.requestCommunityInfoFromMailserver(communityID, shard, true)
return m.requestCommunityInfoFromMailserver(communityID, request.Shard, request.WaitForResponse)
}
// RequestCommunityInfoFromMailserverAsync installs filter for community and requests its details
// from mailserver. When response received it will be passed through signals handler
func (m *Messenger) RequestCommunityInfoFromMailserverAsync(privateOrPublicKey string, shard *common.Shard) error {
communityID := m.GetCommunityIDFromKey(privateOrPublicKey)
community, err := m.findCommunityInfoFromDB(communityID)
if err != nil {
return err
}
if community != nil {
m.config.messengerSignalsHandler.CommunityInfoFound(community)
return nil
}
_, err = m.requestCommunityInfoFromMailserver(communityID, shard, false)
return err
}
// RequestCommunityInfoFromMailserver installs filter for community and requests its details
// requestCommunityInfoFromMailserver installs filter for community and requests its details
// from mailserver. When response received it will be passed through signals handler
func (m *Messenger) requestCommunityInfoFromMailserver(communityID string, shard *common.Shard, waitForResponse bool) (*communities.Community, error) {
@ -2696,6 +2712,11 @@ func (m *Messenger) requestCommunityInfoFromMailserver(communityID string, shard
return nil, err
}
m.logger.Info("mailserver request performed",
zap.String("communityID", communityID),
zap.Bool("waitForResponse", waitForResponse),
)
if !waitForResponse {
return nil, nil
}
@ -2712,6 +2733,9 @@ func (m *Messenger) requestCommunityInfoFromMailserver(communityID string, shard
return nil, err
}
if community != nil && community.Name() != "" && community.DescriptionText() != "" {
m.logger.Debug("community info found",
zap.String("communityID", communityID),
zap.String("displayName", community.Name()))
return community, nil
}
@ -2722,7 +2746,7 @@ func (m *Messenger) requestCommunityInfoFromMailserver(communityID string, shard
}
}
// RequestCommunityInfoFromMailserver installs filter for community and requests its details
// requestCommunitiesFromMailserver installs filter for community and requests its details
// from mailserver. When response received it will be passed through signals handler
func (m *Messenger) requestCommunitiesFromMailserver(communities []communities.CommunityShard) {
m.requestedCommunitiesLock.Lock()

View File

@ -463,7 +463,7 @@ func (api *PublicAPI) ImportCommunity(ctx context.Context, hexPrivateKey string)
// GetCommunityPublicKeyFromPrivateKey gets the community's public key from its private key
func (api *PublicAPI) GetCommunityPublicKeyFromPrivateKey(ctx context.Context, hexPrivateKey string) string {
publicKey := api.service.messenger.GetCommunityIDFromKey(hexPrivateKey)
publicKey := protocol.GetCommunityIDFromKey(hexPrivateKey)
return publicKey
}
@ -1205,22 +1205,58 @@ func (api *PublicAPI) EnsVerified(pk, ensName string) error {
return api.service.messenger.ENSVerified(pk, ensName)
}
// DEPRECATED
// Deprecated: RequestCommunityInfoFromMailserver is deprecated in favor of
// configurable FetchCommunity.
func (api *PublicAPI) RequestCommunityInfoFromMailserver(communityID string) (*communities.Community, error) {
return api.service.messenger.RequestCommunityInfoFromMailserver(communityID, nil, true)
request := &protocol.FetchCommunityRequest{
CommunityKey: communityID,
Shard: nil,
TryDatabase: true,
WaitForResponse: true,
}
return api.FetchCommunity(request)
}
// Deprecated: RequestCommunityInfoFromMailserverWithShard is deprecated in favor of
// configurable FetchCommunity.
func (api *PublicAPI) RequestCommunityInfoFromMailserverWithShard(communityID string, shard *common.Shard) (*communities.Community, error) {
return api.service.messenger.RequestCommunityInfoFromMailserver(communityID, shard, true)
request := &protocol.FetchCommunityRequest{
CommunityKey: communityID,
Shard: shard,
TryDatabase: true,
WaitForResponse: true,
}
return api.FetchCommunity(request)
}
// DEPRECATED
// Deprecated: RequestCommunityInfoFromMailserverAsync is deprecated in favor of
// configurable FetchCommunity.
func (api *PublicAPI) RequestCommunityInfoFromMailserverAsync(communityID string) error {
return api.service.messenger.RequestCommunityInfoFromMailserverAsync(communityID, nil)
request := &protocol.FetchCommunityRequest{
CommunityKey: communityID,
Shard: nil,
TryDatabase: true,
WaitForResponse: false,
}
_, err := api.FetchCommunity(request)
return err
}
// Deprecated: RequestCommunityInfoFromMailserverAsyncWithShard is deprecated in favor of
// configurable FetchCommunity.
func (api *PublicAPI) RequestCommunityInfoFromMailserverAsyncWithShard(communityID string, shard *common.Shard) error {
return api.service.messenger.RequestCommunityInfoFromMailserverAsync(communityID, shard)
request := &protocol.FetchCommunityRequest{
CommunityKey: communityID,
Shard: shard,
TryDatabase: true,
WaitForResponse: false,
}
_, err := api.FetchCommunity(request)
return err
}
func (api *PublicAPI) FetchCommunity(request *protocol.FetchCommunityRequest) (*communities.Community, error) {
return api.service.messenger.FetchCommunity(request)
}
func (api *PublicAPI) ActivityCenterNotifications(request protocol.ActivityCenterNotificationsRequest) (*protocol.ActivityCenterPaginationResponse, error) {

View File

@ -671,7 +671,12 @@ func (s *Service) fetchCommunity(communityID string) (*communities.Community, er
// communities that have specific shards
var shard *common.Shard = nil // TODO: build this with info from token
community, err := s.messenger.RequestCommunityInfoFromMailserver(communityID, shard, true)
community, err := s.messenger.FetchCommunity(&protocol.FetchCommunityRequest{
CommunityKey: communityID,
Shard: shard,
TryDatabase: true,
WaitForResponse: true,
})
if err != nil {
return nil, err

View File

@ -75,7 +75,12 @@ func (p *PublicAPI) CommunityInfo(communityID types.HexBytes, shard *common.Shar
return nil, ErrNotInitialized
}
community, err := p.service.messenger.RequestCommunityInfoFromMailserver(communityID.String(), shard, true)
community, err := p.service.messenger.FetchCommunity(&protocol.FetchCommunityRequest{
CommunityKey: communityID.String(),
Shard: shard,
TryDatabase: true,
WaitForResponse: true,
})
if err != nil {
return nil, err
}