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 }