forked from TrueCloudLab/frostfs-api-go
Evgenii Stratonikov
1473fa588f
gRPC client load-balancing API is ugly as f: 1. It is configured by pre-registering a balancer and the providing JSON configuration. 2. It doesn't allow different credentials for different endpoints (consider using "insecure" localhost and external endpoint). 3. To support frostfs usecase we also need to implement a resolver, which has its own difficulties. 4. https://github.com/grpc/grpc-go/issues/239#issuecomment-264548415 Using interface in place of grpc.ClientConn allows us to provide custom implentation for it (load-balancing, circuit breaker etc.). Refs TrueCloudLab/frostfs-node#1268 Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
130 lines
2.5 KiB
Go
130 lines
2.5 KiB
Go
package client
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"time"
|
|
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/credentials/insecure"
|
|
)
|
|
|
|
const (
|
|
grpcScheme = "grpc"
|
|
grpcTLSScheme = "grpcs"
|
|
)
|
|
|
|
// Option is a Client's option.
|
|
type Option func(*cfg)
|
|
|
|
type cfg struct {
|
|
addr string
|
|
|
|
dialTimeout time.Duration
|
|
rwTimeout time.Duration
|
|
|
|
tlsCfg *tls.Config
|
|
grpcDialOpts []grpc.DialOption
|
|
|
|
conn Conn
|
|
}
|
|
|
|
const (
|
|
defaultDialTimeout = 5 * time.Second
|
|
defaultRWTimeout = 1 * time.Minute
|
|
)
|
|
|
|
func (c *cfg) initDefault() {
|
|
c.dialTimeout = defaultDialTimeout
|
|
c.rwTimeout = defaultRWTimeout
|
|
c.grpcDialOpts = []grpc.DialOption{
|
|
grpc.WithBlock(),
|
|
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
|
}
|
|
}
|
|
|
|
// WithNetworkAddress returns option to specify
|
|
// network address of the remote server.
|
|
//
|
|
// Ignored if WithGRPCConn is provided.
|
|
func WithNetworkAddress(v string) Option {
|
|
return func(c *cfg) {
|
|
if v != "" {
|
|
c.addr = v
|
|
}
|
|
}
|
|
}
|
|
|
|
// WithNetworkURIAddress combines WithNetworkAddress and WithTLSCfg options
|
|
// based on arguments.
|
|
//
|
|
// Do not use along with WithNetworkAddress and WithTLSCfg.
|
|
//
|
|
// Ignored if WithGRPCConn is provided.
|
|
func WithNetworkURIAddress(addr string, tlsCfg *tls.Config) []Option {
|
|
host, isTLS, err := ParseURI(addr)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
opts := make([]Option, 2)
|
|
opts[0] = WithNetworkAddress(host)
|
|
if isTLS {
|
|
if tlsCfg == nil {
|
|
tlsCfg = &tls.Config{}
|
|
}
|
|
opts[1] = WithTLSCfg(tlsCfg)
|
|
} else {
|
|
opts[1] = WithTLSCfg(nil)
|
|
}
|
|
|
|
return opts
|
|
}
|
|
|
|
// WithDialTimeout returns option to specify
|
|
// dial timeout of the remote server connection.
|
|
//
|
|
// Ignored if WithGRPCConn is provided.
|
|
func WithDialTimeout(v time.Duration) Option {
|
|
return func(c *cfg) {
|
|
if v > 0 {
|
|
c.dialTimeout = v
|
|
}
|
|
}
|
|
}
|
|
|
|
// WithRWTimeout returns option to specify timeout
|
|
// for reading and writing single gRPC message.
|
|
func WithRWTimeout(v time.Duration) Option {
|
|
return func(c *cfg) {
|
|
if v > 0 {
|
|
c.rwTimeout = v
|
|
}
|
|
}
|
|
}
|
|
|
|
// WithTLSCfg returns option to specify
|
|
// TLS configuration.
|
|
//
|
|
// Ignored if WithGRPCConn is provided.
|
|
func WithTLSCfg(v *tls.Config) Option {
|
|
return func(c *cfg) {
|
|
c.tlsCfg = v
|
|
}
|
|
}
|
|
|
|
// WithGRPCConn returns option to specify
|
|
// gRPC virtual connection.
|
|
func WithGRPCConn(v Conn) Option {
|
|
return func(c *cfg) {
|
|
if v != nil {
|
|
c.conn = v
|
|
}
|
|
}
|
|
}
|
|
|
|
// WithGRPCDialOptions returns an option to specify grpc.DialOption.
|
|
func WithGRPCDialOptions(opts []grpc.DialOption) Option {
|
|
return func(c *cfg) {
|
|
c.grpcDialOpts = append(c.grpcDialOpts, opts...)
|
|
}
|
|
}
|