Skip to content

Commit 3db72d4

Browse files
fix(go): connection factory
1 parent d47176e commit 3db72d4

File tree

2 files changed

+44
-54
lines changed

2 files changed

+44
-54
lines changed

openfeature-provider/go/confidence/local_resolver_factory.go

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919

2020
const (
2121
defaultPollIntervalSeconds = 10
22+
confidenceDomain = "edge-grpc.spotify.com"
2223
)
2324

2425
// StateProvider is an interface for providing resolver state
@@ -46,13 +47,11 @@ func NewLocalResolverFactory(
4647
ctx context.Context,
4748
runtime wazero.Runtime,
4849
wasmBytes []byte,
49-
resolverStateServiceAddr string,
50-
flagLoggerServiceAddr string,
51-
authServiceAddr string,
5250
apiClientID string,
5351
apiClientSecret string,
5452
customStateProvider StateProvider,
5553
accountId string,
54+
connFactory ConnFactory,
5655
) (*LocalResolverFactory, error) {
5756
logPollInterval := getPollIntervalSeconds()
5857

@@ -86,30 +85,35 @@ func NewLocalResolverFactory(
8685
// Create TLS credentials for secure connections
8786
tlsCreds := credentials.NewTLS(nil)
8887

88+
// Connection factory is provided by the builder
89+
factory := connFactory
90+
91+
// Base dial options with transport credentials
92+
baseOpts := []grpc.DialOption{
93+
grpc.WithTransportCredentials(tlsCreds),
94+
}
95+
8996
// Create auth service connection (no auth interceptor for this one)
90-
authConn, err := grpc.NewClient(authServiceAddr, grpc.WithTransportCredentials(tlsCreds))
97+
unauthConn, err := factory(ctx, confidenceDomain, baseOpts)
9198
if err != nil {
9299
return nil, err
93100
}
94-
authService := iamv1.NewAuthServiceClient(authConn)
101+
102+
authService := iamv1.NewAuthServiceClient(unauthConn)
95103

96104
// Create token holder
97105
tokenHolder := NewTokenHolder(apiClientID, apiClientSecret, authService)
98106

99107
// Create JWT auth interceptor
100108
authInterceptor := NewJwtAuthInterceptor(tokenHolder)
101109

102-
// Create gRPC connection for resolver state service with auth
103-
stateConn, err := grpc.NewClient(
104-
resolverStateServiceAddr,
105-
grpc.WithTransportCredentials(tlsCreds),
110+
authConnection, err := factory(ctx, confidenceDomain, append(
111+
append([]grpc.DialOption{}, baseOpts...),
106112
grpc.WithUnaryInterceptor(authInterceptor.UnaryClientInterceptor()),
107-
grpc.WithStreamInterceptor(authInterceptor.StreamClientInterceptor()),
108-
)
113+
))
109114
if err != nil {
110115
return nil, err
111116
}
112-
resolverStateService := adminv1.NewResolverStateServiceClient(stateConn)
113117

114118
// Get account name from token
115119
token, err := tokenHolder.GetToken(ctx)
@@ -123,6 +127,9 @@ func NewLocalResolverFactory(
123127
accountName = token.Account
124128
}
125129

130+
resolverStateService := adminv1.NewResolverStateServiceClient(authConnection)
131+
flagLoggerService := resolverv1.NewInternalFlagLoggerServiceClient(authConnection)
132+
126133
// Create state fetcher (which implements StateProvider)
127134
stateFetcher := NewFlagsAdminStateFetcher(resolverStateService, accountName)
128135
stateProvider = stateFetcher
@@ -143,18 +150,6 @@ func NewLocalResolverFactory(
143150
resolvedAccountId = "unknown"
144151
}
145152

146-
// Create gRPC connection for flag logger service with auth
147-
// Exposure logging is always enabled when using gRPC services
148-
loggerConn, err := grpc.NewClient(
149-
flagLoggerServiceAddr,
150-
grpc.WithTransportCredentials(tlsCreds),
151-
grpc.WithUnaryInterceptor(authInterceptor.UnaryClientInterceptor()),
152-
grpc.WithStreamInterceptor(authInterceptor.StreamClientInterceptor()),
153-
)
154-
if err != nil {
155-
return nil, err
156-
}
157-
flagLoggerService := resolverv1.NewInternalFlagLoggerServiceClient(loggerConn)
158153
flagLogger = NewGrpcWasmFlagLogger(flagLoggerService)
159154
}
160155

openfeature-provider/go/confidence/provider_builder.go

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,16 @@ import (
55
"fmt"
66

77
"github.com/tetratelabs/wazero"
8+
"google.golang.org/grpc"
89
)
910

10-
const (
11-
ConfidenceDomain = "edge-grpc.spotify.com"
12-
)
11+
// ConnFactory is an advanced/testing hook allowing callers to customize how
12+
// gRPC connections are created. The provider will pass the computed target and
13+
// its default DialOptions (TLS and required interceptors where applicable).
14+
// Implementations may modify options, change targets, or replace the dialing
15+
// mechanism entirely. Returning a connection with incompatible security/auth
16+
// can break functionality; use with care.
17+
type ConnFactory func(ctx context.Context, target string, defaultOpts []grpc.DialOption) (grpc.ClientConnInterface, error)
1318

1419
// ProviderConfig holds configuration for the Confidence provider
1520
type ProviderConfig struct {
@@ -18,11 +23,8 @@ type ProviderConfig struct {
1823
APIClientSecret string
1924
ClientSecret string
2025

21-
// Optional: Custom service addresses (for advanced use cases only)
22-
// If not provided, defaults to global region
23-
ResolverStateServiceAddr string
24-
FlagLoggerServiceAddr string
25-
AuthServiceAddr string
26+
// Advanced/testing: override connection creation
27+
ConnFactory ConnFactory
2628
}
2729

2830
// ProviderConfigWithStateProvider holds configuration for the Confidence provider with a custom StateProvider
@@ -61,40 +63,30 @@ func NewProvider(ctx context.Context, config ProviderConfig) (*LocalResolverProv
6163
return nil, fmt.Errorf("ClientSecret is required")
6264
}
6365

64-
// Set service addresses to defaults if not provided
65-
resolverStateServiceAddr := config.ResolverStateServiceAddr
66-
if resolverStateServiceAddr == "" {
67-
resolverStateServiceAddr = ConfidenceDomain
68-
}
69-
70-
flagLoggerServiceAddr := config.FlagLoggerServiceAddr
71-
if flagLoggerServiceAddr == "" {
72-
flagLoggerServiceAddr = ConfidenceDomain
73-
}
74-
75-
authServiceAddr := config.AuthServiceAddr
76-
if authServiceAddr == "" {
77-
authServiceAddr = ConfidenceDomain
78-
}
79-
8066
// Use embedded WASM module
8167
wasmBytes := defaultWasmBytes
8268

8369
runtimeConfig := wazero.NewRuntimeConfig()
8470
wasmRuntime := wazero.NewRuntimeWithConfig(ctx, runtimeConfig)
8571

72+
// Build connection factory (use default if none provided)
73+
connFactory := config.ConnFactory
74+
if connFactory == nil {
75+
connFactory = func(ctx context.Context, target string, defaultOpts []grpc.DialOption) (grpc.ClientConnInterface, error) {
76+
return grpc.NewClient(target, defaultOpts...)
77+
}
78+
}
79+
8680
// Create LocalResolverFactory (no custom StateProvider)
8781
factory, err := NewLocalResolverFactory(
8882
ctx,
8983
wasmRuntime,
9084
wasmBytes,
91-
resolverStateServiceAddr,
92-
flagLoggerServiceAddr,
93-
authServiceAddr,
9485
config.APIClientID,
9586
config.APIClientSecret,
9687
nil, // stateProvider
9788
"", // accountId (will be extracted from token)
89+
connFactory,
9890
)
9991
if err != nil {
10092
wasmRuntime.Close(ctx)
@@ -130,19 +122,22 @@ func NewProviderWithStateProvider(ctx context.Context, config ProviderConfigWith
130122
runtimeConfig := wazero.NewRuntimeConfig()
131123
wasmRuntime := wazero.NewRuntimeWithConfig(ctx, runtimeConfig)
132124

125+
// Build connection factory (use default)
126+
connFactory := func(ctx context.Context, target string, defaultOpts []grpc.DialOption) (grpc.ClientConnInterface, error) {
127+
return grpc.NewClient(target, defaultOpts...)
128+
}
129+
133130
// Create LocalResolverFactory with StateProvider
134131
// When using StateProvider, we don't need gRPC service addresses or API credentials
135132
factory, err := NewLocalResolverFactory(
136133
ctx,
137134
wasmRuntime,
138135
wasmBytes,
139-
"", // resolverStateServiceAddr - not used with StateProvider
140-
"", // flagLoggerServiceAddr - not used with StateProvider
141-
"", // authServiceAddr - not used with StateProvider
142136
"", // apiClientID - not used with StateProvider
143137
"", // apiClientSecret - not used with StateProvider
144138
config.StateProvider, // stateProvider
145139
config.AccountId, // accountId - required with StateProvider
140+
connFactory, // connFactory - unused here but passed for consistency
146141
)
147142
if err != nil {
148143
wasmRuntime.Close(ctx)

0 commit comments

Comments
 (0)