github.com/MetalBlockchain/metalgo@v1.11.9/vms/rpcchainvm/grpcutils/server.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package grpcutils
     5  
     6  import (
     7  	"math"
     8  	"net"
     9  	"time"
    10  
    11  	"google.golang.org/grpc"
    12  	"google.golang.org/grpc/keepalive"
    13  )
    14  
    15  const (
    16  	// MinTime is the minimum amount of time a client should wait before sending
    17  	// a keepalive ping. grpc-go default 5 mins
    18  	defaultServerKeepAliveMinTime = 5 * time.Second
    19  	// After a duration of this time if the server doesn't see any activity it
    20  	// pings the client to see if the transport is still alive.
    21  	// If set below 1s, a minimum value of 1s will be used instead.
    22  	// grpc-go default 2h
    23  	defaultServerKeepAliveInterval = 2 * time.Hour
    24  	// After having pinged for keepalive check, the server waits for a duration
    25  	// of Timeout and if no activity is seen even after that the connection is
    26  	// closed. grpc-go default 20s
    27  	defaultServerKeepAliveTimeout = 20 * time.Second
    28  )
    29  
    30  var DefaultServerOptions = []grpc.ServerOption{
    31  	grpc.MaxRecvMsgSize(math.MaxInt),
    32  	grpc.MaxSendMsgSize(math.MaxInt),
    33  	grpc.MaxConcurrentStreams(math.MaxUint32),
    34  	grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{
    35  		MinTime:             defaultServerKeepAliveMinTime,
    36  		PermitWithoutStream: defaultPermitWithoutStream,
    37  	}),
    38  	grpc.KeepaliveParams(keepalive.ServerParameters{
    39  		Time:    defaultServerKeepAliveInterval,
    40  		Timeout: defaultServerKeepAliveTimeout,
    41  	}),
    42  }
    43  
    44  // NewServer will return a gRPC server with server options as defined by
    45  // DefaultServerOptions. ServerOption can also optionally be passed.
    46  func NewServer(opts ...ServerOption) *grpc.Server {
    47  	return grpc.NewServer(newServerOpts(opts)...)
    48  }
    49  
    50  type ServerOptions struct {
    51  	opts []grpc.ServerOption
    52  }
    53  
    54  // append(DefaultServerOptions, ...) will always allocate a new slice and will
    55  // not overwrite any potential data that may have previously been appended to
    56  // DefaultServerOptions https://go.dev/ref/spec#Composite_literals
    57  func newServerOpts(opts []ServerOption) []grpc.ServerOption {
    58  	s := &ServerOptions{opts: DefaultServerOptions}
    59  	s.applyOpts(opts)
    60  	return s.opts
    61  }
    62  
    63  func (s *ServerOptions) applyOpts(opts []ServerOption) {
    64  	for _, opt := range opts {
    65  		opt(s)
    66  	}
    67  }
    68  
    69  // ServerOption are options which can be applied to a gRPC server in addition to
    70  // the defaults set by DefaultServerOPtions.
    71  type ServerOption func(*ServerOptions)
    72  
    73  // WithUnaryInterceptor adds a single unary interceptor to the gRPC server
    74  // options.
    75  func WithUnaryInterceptor(unaryInterceptor grpc.UnaryServerInterceptor) ServerOption {
    76  	return func(s *ServerOptions) {
    77  		s.opts = append(s.opts, grpc.UnaryInterceptor(unaryInterceptor))
    78  	}
    79  }
    80  
    81  // WithStreamInterceptor adds a single stream interceptor to the gRPC server
    82  // options.
    83  func WithStreamInterceptor(streamInterceptor grpc.StreamServerInterceptor) ServerOption {
    84  	return func(s *ServerOptions) {
    85  		s.opts = append(s.opts, grpc.StreamInterceptor(streamInterceptor))
    86  	}
    87  }
    88  
    89  // NewListener returns a TCP listener listening against the next available port
    90  // on the system bound to localhost.
    91  func NewListener() (net.Listener, error) {
    92  	return net.Listen("tcp", "127.0.0.1:")
    93  }
    94  
    95  // Serve will start a gRPC server and block until it errors or is shutdown.
    96  func Serve(listener net.Listener, grpcServer *grpc.Server) {
    97  	// TODO: While errors will be reported later, it could be useful to somehow
    98  	//       log this if it is the primary error.
    99  	//
   100  	// There is nothing to with the error returned by serve here. Later requests
   101  	// will propegate their error if they occur.
   102  	_ = grpcServer.Serve(listener)
   103  
   104  	// Similarly, there is nothing to with an error when the listener is closed.
   105  	_ = listener.Close()
   106  }