Skip to content

Commit 0242326

Browse files
committed
fix(efp): use single EFP provider, initialization test changes, etc
Refactored the following.Manager to accept a single EFP provider and logger instead of a slice of providers. Updated initialization in service.go and all related tests. Adjusted EFP client to require an HTTP client on construction, improving dependency injection and testability.
1 parent 286a3ab commit 0242326

File tree

5 files changed

+91
-72
lines changed

5 files changed

+91
-72
lines changed

services/wallet/following/manager.go

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,57 +2,55 @@ package following
22

33
import (
44
"context"
5+
"errors"
56
"time"
67

78
"go.uber.org/zap"
89

910
"github.com/ethereum/go-ethereum/common"
1011

11-
"github.com/status-im/status-go/logutils"
1212
"github.com/status-im/status-go/services/wallet/thirdparty/efp"
1313
)
1414

15-
// Manager handles following address operations using EFP providers
15+
// Manager handles following address operations using EFP provider
1616
type Manager struct {
17-
providers []efp.FollowingDataProvider
17+
provider efp.FollowingDataProvider
18+
logger *zap.Logger
1819
}
1920

20-
// NewManager creates a new following manager with the provided EFP providers
21-
func NewManager(providers []efp.FollowingDataProvider) *Manager {
21+
// NewManager creates a new following manager with the provided EFP provider
22+
func NewManager(provider efp.FollowingDataProvider, logger *zap.Logger) *Manager {
2223
return &Manager{
23-
providers: providers,
24+
provider: provider,
25+
logger: logger,
2426
}
2527
}
2628

2729
// FetchFollowingAddresses fetches the list of addresses that the given user is following
28-
// Uses the first available provider (can be enhanced later with fallback logic)
2930
func (m *Manager) FetchFollowingAddresses(ctx context.Context, userAddress common.Address, search string, limit, offset int) ([]efp.FollowingAddress, error) {
30-
logutils.ZapLogger().Debug("following.Manager.FetchFollowingAddresses",
31+
m.logger.Debug("following.Manager.FetchFollowingAddresses",
3132
zap.String("userAddress", userAddress.Hex()),
3233
zap.String("search", search),
3334
zap.Int("limit", limit),
3435
zap.Int("offset", offset),
35-
zap.Int("providers.len", len(m.providers)),
3636
)
3737

38-
if len(m.providers) == 0 {
39-
return []efp.FollowingAddress{}, nil
38+
if m.provider == nil {
39+
return nil, errors.New("EFP provider not initialized")
4040
}
4141

42-
// Use the first provider (EFP client)
43-
provider := m.providers[0]
44-
if !provider.IsConnected() {
45-
logutils.ZapLogger().Warn("EFP provider not connected", zap.String("providerID", provider.ID()))
42+
if !m.provider.IsConnected() {
43+
m.logger.Warn("EFP provider not connected", zap.String("providerID", m.provider.ID()))
4644
return []efp.FollowingAddress{}, nil
4745
}
4846

4947
startTime := time.Now()
50-
addresses, err := provider.FetchFollowingAddresses(ctx, userAddress, search, limit, offset)
48+
addresses, err := m.provider.FetchFollowingAddresses(ctx, userAddress, search, limit, offset)
5149
duration := time.Since(startTime)
5250

53-
logutils.ZapLogger().Debug("following.Manager.FetchFollowingAddresses completed",
51+
m.logger.Debug("following.Manager.FetchFollowingAddresses completed",
5452
zap.String("userAddress", userAddress.Hex()),
55-
zap.String("providerID", provider.ID()),
53+
zap.String("providerID", m.provider.ID()),
5654
zap.Int("addresses.len", len(addresses)),
5755
zap.Duration("duration", duration),
5856
zap.Error(err),
@@ -67,27 +65,26 @@ func (m *Manager) FetchFollowingAddresses(ctx context.Context, userAddress commo
6765

6866
// FetchFollowingStats fetches the stats (following count) for a user
6967
func (m *Manager) FetchFollowingStats(ctx context.Context, userAddress common.Address) (int, error) {
70-
logutils.ZapLogger().Debug("following.Manager.FetchFollowingStats",
68+
m.logger.Debug("following.Manager.FetchFollowingStats",
7169
zap.String("userAddress", userAddress.Hex()),
7270
)
7371

74-
if len(m.providers) == 0 {
75-
return 0, nil
72+
if m.provider == nil {
73+
return 0, errors.New("EFP provider not initialized")
7674
}
7775

78-
provider := m.providers[0]
79-
if !provider.IsConnected() {
80-
logutils.ZapLogger().Warn("EFP provider not connected", zap.String("providerID", provider.ID()))
76+
if !m.provider.IsConnected() {
77+
m.logger.Warn("EFP provider not connected", zap.String("providerID", m.provider.ID()))
8178
return 0, nil
8279
}
8380

84-
count, err := provider.FetchFollowingStats(ctx, userAddress)
81+
count, err := m.provider.FetchFollowingStats(ctx, userAddress)
8582
if err != nil {
86-
logutils.ZapLogger().Error("following.Manager.FetchFollowingStats error", zap.Error(err))
83+
m.logger.Error("following.Manager.FetchFollowingStats error", zap.Error(err))
8784
return 0, err
8885
}
8986

90-
logutils.ZapLogger().Debug("following.Manager.FetchFollowingStats completed",
87+
m.logger.Debug("following.Manager.FetchFollowingStats completed",
9188
zap.String("userAddress", userAddress.Hex()),
9289
zap.Int("count", count),
9390
)

services/wallet/following/manager_test.go

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/ethereum/go-ethereum/common"
99
"github.com/stretchr/testify/require"
1010
"go.uber.org/mock/gomock"
11+
"go.uber.org/zap"
1112

1213
"github.com/status-im/status-go/services/wallet/thirdparty/efp"
1314
mock_efp "github.com/status-im/status-go/services/wallet/thirdparty/efp/mock"
@@ -17,7 +18,7 @@ func TestFetchFollowingAddressesSuccess(t *testing.T) {
1718
mockCtrl := gomock.NewController(t)
1819
defer mockCtrl.Finish()
1920

20-
ctx := context.TODO()
21+
ctx := t.Context()
2122
userAddress := common.HexToAddress("0x742d35cc6cf4c7c7")
2223

2324
expected := []efp.FollowingAddress{
@@ -32,7 +33,7 @@ func TestFetchFollowingAddressesSuccess(t *testing.T) {
3233
mockProvider.EXPECT().IsConnected().Return(true)
3334
mockProvider.EXPECT().FetchFollowingAddresses(ctx, userAddress, "", 10, 0).Return(expected, nil)
3435

35-
manager := NewManager([]efp.FollowingDataProvider{mockProvider})
36+
manager := NewManager(mockProvider, zap.NewNop())
3637

3738
result, err := manager.FetchFollowingAddresses(ctx, userAddress, "", 10, 0)
3839

@@ -46,15 +47,15 @@ func TestFetchFollowingStatsSuccess(t *testing.T) {
4647
mockCtrl := gomock.NewController(t)
4748
defer mockCtrl.Finish()
4849

49-
ctx := context.TODO()
50+
ctx := t.Context()
5051
userAddress := common.HexToAddress("0x742d35cc6cf4c7c7")
5152
expectedCount := 150
5253

5354
mockProvider := mock_efp.NewMockFollowingDataProvider(mockCtrl)
5455
mockProvider.EXPECT().IsConnected().Return(true)
5556
mockProvider.EXPECT().FetchFollowingStats(ctx, userAddress).Return(expectedCount, nil)
5657

57-
manager := NewManager([]efp.FollowingDataProvider{mockProvider})
58+
manager := NewManager(mockProvider, zap.NewNop())
5859

5960
result, err := manager.FetchFollowingStats(ctx, userAddress)
6061

@@ -66,14 +67,14 @@ func TestFetchFollowingAddressesProviderNotConnected(t *testing.T) {
6667
mockCtrl := gomock.NewController(t)
6768
defer mockCtrl.Finish()
6869

69-
ctx := context.TODO()
70+
ctx := t.Context()
7071
userAddress := common.HexToAddress("0x742d35cc6cf4c7c7")
7172

7273
mockProvider := mock_efp.NewMockFollowingDataProvider(mockCtrl)
7374
mockProvider.EXPECT().IsConnected().Return(false)
7475
mockProvider.EXPECT().ID().Return("efp").AnyTimes()
7576

76-
manager := NewManager([]efp.FollowingDataProvider{mockProvider})
77+
manager := NewManager(mockProvider, zap.NewNop())
7778

7879
result, err := manager.FetchFollowingAddresses(ctx, userAddress, "", 10, 0)
7980

@@ -85,7 +86,7 @@ func TestFetchFollowingAddressesProviderError(t *testing.T) {
8586
mockCtrl := gomock.NewController(t)
8687
defer mockCtrl.Finish()
8788

88-
ctx := context.TODO()
89+
ctx := t.Context()
8990
userAddress := common.HexToAddress("0x742d35cc6cf4c7c7")
9091
expectedError := errors.New("provider error")
9192

@@ -94,7 +95,7 @@ func TestFetchFollowingAddressesProviderError(t *testing.T) {
9495
mockProvider.EXPECT().IsConnected().Return(true)
9596
mockProvider.EXPECT().FetchFollowingAddresses(ctx, userAddress, "", 10, 0).Return(nil, expectedError)
9697

97-
manager := NewManager([]efp.FollowingDataProvider{mockProvider})
98+
manager := NewManager(mockProvider, zap.NewNop())
9899

99100
result, err := manager.FetchFollowingAddresses(ctx, userAddress, "", 10, 0)
100101

@@ -103,14 +104,15 @@ func TestFetchFollowingAddressesProviderError(t *testing.T) {
103104
require.Equal(t, expectedError, err)
104105
}
105106

106-
func TestFetchFollowingAddressesNoProviders(t *testing.T) {
107-
ctx := context.TODO()
107+
func TestFetchFollowingAddressesNoProvider(t *testing.T) {
108+
ctx := t.Context()
108109
userAddress := common.HexToAddress("0x742d35cc6cf4c7c7")
109110

110-
manager := NewManager([]efp.FollowingDataProvider{})
111+
manager := NewManager(nil, zap.NewNop())
111112

112113
result, err := manager.FetchFollowingAddresses(ctx, userAddress, "", 10, 0)
113114

114-
require.NoError(t, err)
115-
require.Len(t, result, 0)
115+
require.Error(t, err)
116+
require.Nil(t, result)
117+
require.Contains(t, err.Error(), "EFP provider not initialized")
116118
}

services/wallet/service.go

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"encoding/json"
77
"errors"
88
"fmt"
9+
"time"
910

1011
"github.com/golang/protobuf/proto"
1112

@@ -117,6 +118,7 @@ func NewService(
117118
var collectibleProviders thirdparty.CollectibleProviders = thirdparty.CollectibleProviders{}
118119
var pathProcessors []pathprocessor.PathProcessor = []pathprocessor.PathProcessor{}
119120
var leaderboardConfig leaderboard.ServiceConfig = leaderboard.NewDefaultServiceConfig()
121+
var followingManager *following.Manager
120122

121123
if thirdpartyServicesEnabled {
122124

@@ -176,6 +178,24 @@ func NewService(
176178
pathProcessors = buildPathProcessors(rpcClient, transactor, tokenManager, ensResolver, featureFlags)
177179

178180
leaderboardConfig = leaderboard.NewLeaderboardConfig(config.WalletConfig.MarketDataProxyConfig)
181+
182+
// EFP (Ethereum Follow Protocol) provider
183+
efpHTTPClient := thirdparty.NewHTTPClient(
184+
thirdparty.WithDetailedTimeouts(
185+
5*time.Second, // dialTimeout
186+
5*time.Second, // tlsHandshakeTimeout
187+
5*time.Second, // responseHeaderTimeout
188+
20*time.Second, // requestTimeout
189+
),
190+
thirdparty.WithMaxRetries(5),
191+
)
192+
efpClient := efp.NewClient(efpHTTPClient)
193+
followingManager = following.NewManager(efpClient, logutils.ZapLogger().Named("FollowingManager"))
194+
}
195+
196+
// Initialize followingManager with nil provider if third-party services are disabled
197+
if followingManager == nil {
198+
followingManager = following.NewManager(nil, logutils.ZapLogger().Named("FollowingManager"))
179199
}
180200

181201
cryptoOnRampManager := onramp.NewManager(cryptoOnRampProviders)
@@ -248,13 +268,6 @@ func NewService(
248268
collectiblesOwnershipController,
249269
collectiblesPublisher)
250270

251-
// EFP (Ethereum Follow Protocol) providers
252-
efpClient := efp.NewClient()
253-
followingProviders := []efp.FollowingDataProvider{
254-
efpClient,
255-
}
256-
followingManager := following.NewManager(followingProviders)
257-
258271
activity := activity.NewService(db, accountsDB, tokenManager, collectiblesManager, feed)
259272

260273
router := router.NewRouter(rpcClient, transactor, tokenManager, tokenBalancesFetcher, marketManager, collectibles,

services/wallet/thirdparty/efp/client.go

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"encoding/json"
66
"fmt"
77
"net/url"
8-
"time"
98

109
"github.com/ethereum/go-ethereum/common"
1110

@@ -14,10 +13,6 @@ import (
1413

1514
const baseURL = "https://api.ethfollow.xyz/api/v1"
1615

17-
const (
18-
requestDelay = 100 * time.Millisecond
19-
)
20-
2116
// ENSData represents ENS information from the EFP API
2217
type ENSData struct {
2318
Name string `json:"name"`
@@ -61,17 +56,7 @@ type Client struct {
6156
baseURL string
6257
}
6358

64-
func NewClient() *Client {
65-
httpClient := thirdparty.NewHTTPClient(
66-
thirdparty.WithDetailedTimeouts(
67-
5*time.Second, // dialTimeout
68-
5*time.Second, // tlsHandshakeTimeout
69-
5*time.Second, // responseHeaderTimeout
70-
20*time.Second, // requestTimeout
71-
),
72-
thirdparty.WithMaxRetries(5),
73-
)
74-
59+
func NewClient(httpClient *thirdparty.HTTPClient) *Client {
7560
return &Client{
7661
httpClient: httpClient,
7762
baseURL: baseURL,

0 commit comments

Comments
 (0)