refactor(server_media)_: pass a func to get the images instead of using the cache (#6127)

The community cache that the image server was using was not intended to be used for that. It can be invalidated at any moment. Also, it did not contain changes made by admins (admin events).
Using this new approach, we pass functions from the community manager to the media server so that it can have access to the correct community description.
This commit is contained in:
Jonathan Rainville 2024-11-29 13:54:10 -05:00 committed by GitHub
parent 732347cebf
commit 8a7f24b095
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 68 additions and 36 deletions

View File

@ -9,6 +9,7 @@ import (
"fmt"
"io/ioutil"
"os"
"reflect"
"strconv"
"strings"
"sync"
@ -477,9 +478,30 @@ func NewManager(
manager.forceMembersReevaluation = make(map[string]chan struct{}, 10)
}
if mediaServer != nil && !reflect.ValueOf(mediaServer).IsNil() {
manager.SetMediaServerProperties()
}
return manager, nil
}
func (m *Manager) SetMediaServerProperties() {
m.mediaServer.SetCommunityImageReader(func(communityID string) (map[string]*protobuf.IdentityImage, error) {
community, err := m.GetByIDString(communityID)
if err != nil {
return nil, err
}
return community.Images(), nil
})
m.mediaServer.SetCommunityTokensReader(func(communityID string) ([]*protobuf.CommunityTokenMetadata, error) {
community, err := m.GetByIDString(communityID)
if err != nil {
return nil, err
}
return community.CommunityTokensMetadata(), nil
})
}
type Subscription struct {
Community *Community
CreatingHistoryArchivesSignal *signal.CreatingHistoryArchivesSignal
@ -507,6 +529,7 @@ type CommunityResponse struct {
func (m *Manager) SetMediaServer(mediaServer server.MediaServerInterface) {
m.mediaServer = mediaServer
m.SetMediaServerProperties()
}
func (m *Manager) Subscribe() chan *Subscription {
@ -2238,6 +2261,9 @@ func (m *Manager) NewHashRatchetKeys(keys []*encryption.HashRatchetInfo) error {
return m.persistence.InvalidateDecryptedCommunityCacheForKeys(keys)
}
// NOTE: encrypted_community_description_cache is not a cache for the community description
// The purpose of this cache is tightly coupled with the hash ratchet,
// meaning the cache is invalidated whenever we receive a key that was previously missing for that community
func (m *Manager) preprocessDescription(id types.HexBytes, description *protobuf.CommunityDescription) ([]*CommunityPrivateDataFailedToDecrypt, *protobuf.CommunityDescription, error) {
decryptedCommunity, err := m.persistence.GetDecryptedCommunityDescription(id, description.Clock)
if err != nil {

View File

@ -14,9 +14,6 @@ import (
"strconv"
"time"
"github.com/golang/protobuf/proto"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/protocol/protobuf"
"go.uber.org/zap"
@ -1000,7 +997,7 @@ func handleCommunityTokenImages(db *sql.DB, logger *zap.Logger) http.HandlerFunc
}
}
func handleCommunityDescriptionImagesPath(db *sql.DB, logger *zap.Logger) http.HandlerFunc {
func handleCommunityDescriptionImagesPath(db *sql.DB, getCommunityImages func(communityID string) (map[string]*protobuf.IdentityImage, error), logger *zap.Logger) http.HandlerFunc {
if db == nil {
return handleRequestDBMissing(logger)
}
@ -1019,17 +1016,13 @@ func handleCommunityDescriptionImagesPath(db *sql.DB, logger *zap.Logger) http.H
name = params["name"][0]
}
err, communityDescription := getCommunityDescription(db, communityID, logger)
communityImages, err := getCommunityImages(communityID)
if err != nil {
return
}
if communityDescription.Identity == nil {
logger.Error("no identity in community description", zap.String("community id", communityID))
return
}
var imagePayload []byte
for t, i := range communityDescription.Identity.Images {
for t, i := range communityImages {
if t == name {
imagePayload = i.Payload
}
@ -1053,7 +1046,7 @@ func handleCommunityDescriptionImagesPath(db *sql.DB, logger *zap.Logger) http.H
}
}
func handleCommunityDescriptionTokenImagesPath(db *sql.DB, logger *zap.Logger) http.HandlerFunc {
func handleCommunityDescriptionTokenImagesPath(db *sql.DB, getCommunityTokens func(communityID string) ([]*protobuf.CommunityTokenMetadata, error), logger *zap.Logger) http.HandlerFunc {
if db == nil {
return handleRequestDBMissing(logger)
}
@ -1073,13 +1066,13 @@ func handleCommunityDescriptionTokenImagesPath(db *sql.DB, logger *zap.Logger) h
}
symbol := params["symbol"][0]
err, communityDescription := getCommunityDescription(db, communityID, logger)
communityTokens, err := getCommunityTokens(communityID)
if err != nil {
return
}
var foundToken *protobuf.CommunityTokenMetadata
for _, m := range communityDescription.CommunityTokensMetadata {
for _, m := range communityTokens {
if m.GetSymbol() == symbol {
foundToken = m
}
@ -1108,23 +1101,6 @@ func handleCommunityDescriptionTokenImagesPath(db *sql.DB, logger *zap.Logger) h
}
}
// getCommunityDescription returns the latest community description from the cache.
// NOTE: you should ensure preprocessDescription is called before this function.
func getCommunityDescription(db *sql.DB, communityID string, logger *zap.Logger) (error, *protobuf.CommunityDescription) {
var descriptionBytes []byte
err := db.QueryRow(`SELECT description FROM encrypted_community_description_cache WHERE community_id = ? ORDER BY clock DESC LIMIT 1`, types.Hex2Bytes(communityID)).Scan(&descriptionBytes)
if err != nil {
logger.Error("failed to find community description", zap.String("community id", communityID), zap.Error(err))
return err, nil
}
communityDescription := new(protobuf.CommunityDescription)
err = proto.Unmarshal(descriptionBytes, communityDescription)
if err != nil {
logger.Error("failed to unmarshal community description", zap.String("community id", communityID), zap.Error(err))
}
return err, communityDescription
}
func handleWalletCommunityImages(db *sql.DB, logger *zap.Logger) http.HandlerFunc {
if db == nil {
return handleRequestDBMissing(logger)

View File

@ -3,6 +3,7 @@ package server
import (
"crypto/tls"
"database/sql"
"errors"
"net/url"
"strconv"
@ -10,6 +11,7 @@ import (
"github.com/status-im/status-go/logutils"
"github.com/status-im/status-go/multiaccounts"
"github.com/status-im/status-go/protocol/common"
"github.com/status-im/status-go/protocol/protobuf"
"github.com/status-im/status-go/services/wallet/thirdparty"
"github.com/status-im/status-go/signal"
)
@ -25,10 +27,12 @@ func WithMediaServerDisableTLS(disableTLS bool) MediaServerOption {
type MediaServer struct {
Server
db *sql.DB
downloader *ipfs.Downloader
multiaccountsDB *multiaccounts.Database
walletDB *sql.DB
db *sql.DB
downloader *ipfs.Downloader
multiaccountsDB *multiaccounts.Database
walletDB *sql.DB
communityImagesReader func(communityID string) (map[string]*protobuf.IdentityImage, error)
communityTokenReader func(communityID string) ([]*protobuf.CommunityTokenMetadata, error)
// disableTLS controls whether the media server uses HTTP instead of HTTPS.
// Set to true to avoid TLS certificate issues with react-native-fast-image
@ -89,8 +93,8 @@ func NewMediaServer(db *sql.DB, downloader *ipfs.Downloader, multiaccountsDB *mu
LinkPreviewFaviconPath: handleLinkPreviewFavicon(s.db, s.logger),
StatusLinkPreviewThumbnailPath: handleStatusLinkPreviewThumbnail(s.db, s.logger),
communityTokenImagesPath: handleCommunityTokenImages(s.db, s.logger),
communityDescriptionImagesPath: handleCommunityDescriptionImagesPath(s.db, s.logger),
communityDescriptionTokenImagesPath: handleCommunityDescriptionTokenImagesPath(s.db, s.logger),
communityDescriptionImagesPath: handleCommunityDescriptionImagesPath(s.db, s.getCommunityImage, s.logger),
communityDescriptionTokenImagesPath: handleCommunityDescriptionTokenImagesPath(s.db, s.getCommunityTokens, s.logger),
walletCommunityImagesPath: handleWalletCommunityImages(s.walletDB, s.logger),
walletCollectionImagesPath: handleWalletCollectionImages(s.walletDB, s.logger),
walletCollectibleImagesPath: handleWalletCollectibleImages(s.walletDB, s.logger),
@ -106,6 +110,28 @@ func (s *MediaServer) MakeBaseURL() *url.URL {
}
}
func (s *MediaServer) SetCommunityImageReader(getFunc func(communityID string) (map[string]*protobuf.IdentityImage, error)) {
s.communityImagesReader = getFunc
}
func (s *MediaServer) getCommunityImage(communityID string) (map[string]*protobuf.IdentityImage, error) {
if s.communityImagesReader == nil {
return nil, errors.New("community image reader not set")
}
return s.communityImagesReader(communityID)
}
func (s *MediaServer) SetCommunityTokensReader(getFunc func(communityID string) ([]*protobuf.CommunityTokenMetadata, error)) {
s.communityTokenReader = getFunc
}
func (s *MediaServer) getCommunityTokens(communityID string) ([]*protobuf.CommunityTokenMetadata, error) {
if s.communityTokenReader == nil {
return nil, errors.New("community token reader not set")
}
return s.communityTokenReader(communityID)
}
func (s *MediaServer) MakeImageServerURL() string {
u := s.MakeBaseURL()
u.Path = basePath + "/"

View File

@ -1,6 +1,10 @@
package server
import "github.com/status-im/status-go/protocol/protobuf"
type MediaServerInterface interface {
MakeCommunityDescriptionTokenImageURL(communityID, symbol string) string
MakeCommunityImageURL(communityID, name string) string
SetCommunityImageReader(func(communityID string) (map[string]*protobuf.IdentityImage, error))
SetCommunityTokensReader(func(communityID string) ([]*protobuf.CommunityTokenMetadata, error))
}