Repository: grpc/grpc-go
File: xds/internal/clients/grpctransport/grpc_transport.go (Go)

Code before:

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/encoding"
	"google.golang.org/grpc/keepalive"
	"google.golang.org/grpc/xds/internal/clients"
)

// ServerConfigExtension holds the settings for connecting to an xDS management server
// using gRPC.
type ServerConfigExtension struct {
	// Credentials is the credential bundle containing the gRPC credentials for
	// connecting to the xDS management server.
	Credentials credentials.Bundle
}

// Builder provides a way to build a gRPC-based transport to an xDS management
// server.
type Builder struct{}

func init() {
	encoding.RegisterCodec(&byteCodec{})
}

// Build creates a new gRPC-based transport to an xDS management server using
// the provided clients.ServerConfig. This involves creating a
// grpc.ClientConn to the server using the provided credentials and server URI,
// and byteCodec which is byte-based implementation of encoding.Codec to send
// and receive messages as bytes on the stream.
//
// If any of ServerURI or Extensions of `sc` are not present, Build() will return
// an error.
func (b *Builder) Build(sc clients.ServerConfig) (clients.Transport, error) {
	if sc.ServerURI == "" {
		return nil, fmt.Errorf("xds: ServerConfig's ServerURI field cannot be empty")
	}
	if sc.Extensions == nil {
		return nil, fmt.Errorf("xds: ServerConfig's Extensions field cannot be nil for gRPC transport")
	}
	gtsce, ok := sc.Extensions.(ServerConfigExtension)
	if !ok {
		return nil, fmt.Errorf("xds: ServerConfig's Extensions field cannot be anything other than grpctransport.ServerConfigExtension for gRPC transport")
	}
	if gtsce.Credentials == nil {
		return nil, fmt.Errorf("xsd: ServerConfigExtensions's Credentials field cannot be nil for gRPC transport")
	}

	// TODO: Incorporate reference count map for existing transports and
	// deduplicate transports based on server URI and credentials so that
	// transport channel to same server can be shared between xDS and LRS
	// client.

Review comment (suggestion):
ServerConfig is for any kind of server.  LRS is not necessarily the same as the xds management server.  We should be more careful about using this phrase in places where it doesn't apply.  Also in `ServerConfig` itself.

Code after:

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/keepalive"
	"google.golang.org/grpc/xds/internal/clients"
)

// ServerConfigExtension holds settings for connecting to a gRPC server,
// such as an xDS management or an LRS server.
type ServerConfigExtension struct {
	// Credentials will be used for all gRPC transports. If it is unset,
	// transport creation will fail.
	Credentials credentials.Bundle
}

// Builder creates gRPC-based Transports. It must be paired with ServerConfigs
// that contain an Extension field of type ServerConfigExtension.
type Builder struct{}

// Build returns a gRPC-based clients.Transport.
//
// The Extension field of the ServerConfig must be a ServerConfigExtension.
func (b *Builder) Build(sc clients.ServerConfig) (clients.Transport, error) {
	if sc.ServerURI == "" {
		return nil, fmt.Errorf("grpctransport: ServerURI is not set in ServerConfig")
	}
	if sc.Extensions == nil {
		return nil, fmt.Errorf("grpctransport: Extensions is not set in ServerConfig")
	}
	sce, ok := sc.Extensions.(ServerConfigExtension)
	if !ok {
		return nil, fmt.Errorf("grpctransport: Extensions field is %T, but must be %T in ServerConfig", sc.Extensions, ServerConfigExtension{})
	}
	if sce.Credentials == nil {
		return nil, fmt.Errorf("grptransport: Credentials field is not set in ServerConfigExtension")
	}

	// TODO: Incorporate reference count map for existing transports and
	// deduplicate transports based on the provided ServerConfig so that
	// transport channel to same server can be shared between xDS and LRS
	// client.

	// Create a new gRPC client/channel for the server with the provided
	// credentials, server URI, and a byte codec to send and receive messages.
	// Also set a static keepalive configuration that is common across gRPC
	// language implementations.
	kpCfg := grpc.WithKeepaliveParams(keepalive.ClientParameters{
		Time:    5 * time.Minute,
		Timeout: 20 * time.Second,
	})
	cc, err := grpc.NewClient(sc.ServerURI, kpCfg, grpc.WithCredentialsBundle(sce.Credentials), grpc.WithDefaultCallOptions(grpc.ForceCodec(&byteCodec{})))