github.com/MetalBlockchain/metalgo@v1.11.9/vms/rpcchainvm/grpcutils/client.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 "time" 9 10 "google.golang.org/grpc" 11 "google.golang.org/grpc/credentials/insecure" 12 "google.golang.org/grpc/keepalive" 13 ) 14 15 const ( 16 // After a duration of this time if the client doesn't see any activity it 17 // pings the server to see if the transport is still alive. 18 // If set below 10s, a minimum value of 10s will be used instead. 19 // grpc-go default infinity 20 defaultClientKeepAliveTime = 30 * time.Second 21 // After having pinged for keepalive check, the client waits for a duration 22 // of Timeout and if no activity is seen even after that the connection is 23 // closed. grpc-go default 20s 24 defaultClientKeepAliveTimeOut = 10 * time.Second 25 // If true, client sends keepalive pings even with no active RPCs. If false, 26 // when there are no active RPCs, Time and Timeout will be ignored and no 27 // keepalive pings will be sent. grpc-go default false 28 defaultPermitWithoutStream = true 29 // WaitForReady configures the action to take when an RPC is attempted on 30 // broken connections or unreachable servers. If waitForReady is false and 31 // the connection is in the TRANSIENT_FAILURE state, the RPC will fail 32 // immediately. Otherwise, the RPC client will block the call until a 33 // connection is available (or the call is canceled or times out) and will 34 // retry the call if it fails due to a transient error. gRPC will not retry 35 // if data was written to the wire unless the server indicates it did not 36 // process the data. Please refer to 37 // https://github.com/grpc/grpc/blob/master/doc/wait-for-ready.md. 38 // 39 // gRPC default behavior is to NOT "wait for ready". 40 defaultWaitForReady = true 41 ) 42 43 var DefaultDialOptions = []grpc.DialOption{ 44 grpc.WithDefaultCallOptions( 45 grpc.MaxCallRecvMsgSize(math.MaxInt), 46 grpc.MaxCallSendMsgSize(math.MaxInt), 47 grpc.WaitForReady(defaultWaitForReady), 48 ), 49 grpc.WithKeepaliveParams(keepalive.ClientParameters{ 50 Time: defaultClientKeepAliveTime, 51 Timeout: defaultClientKeepAliveTimeOut, 52 PermitWithoutStream: defaultPermitWithoutStream, 53 }), 54 grpc.WithTransportCredentials(insecure.NewCredentials()), 55 } 56 57 // gRPC clients created from this ClientConn will wait forever for the Server to 58 // become Ready. If you desire a dial timeout ensure context is properly plumbed 59 // to the client and use context.WithTimeout. 60 // 61 // Dial returns a gRPC ClientConn with the dial options as defined by 62 // DefaultDialOptions. DialOption can also optionally be passed. 63 func Dial(addr string, opts ...DialOption) (*grpc.ClientConn, error) { 64 return grpc.Dial("passthrough:///"+addr, newDialOpts(opts...)...) 65 } 66 67 // DialOptions are options which can be applied to a gRPC client in addition to 68 // the defaults set by DefaultDialOptions. 69 type DialOptions struct { 70 opts []grpc.DialOption 71 } 72 73 // append(DefaultDialOptions, ...) will always allocate a new slice and will 74 // not overwrite any potential data that may have previously been appended to 75 // DefaultServerOptions https://go.dev/ref/spec#Composite_literals 76 func newDialOpts(opts ...DialOption) []grpc.DialOption { 77 d := &DialOptions{opts: DefaultDialOptions} 78 d.applyOpts(opts) 79 return d.opts 80 } 81 82 func (d *DialOptions) applyOpts(opts []DialOption) { 83 for _, opt := range opts { 84 opt(d) 85 } 86 } 87 88 type DialOption func(*DialOptions) 89 90 // WithChainUnaryInterceptor takes a list of unary client interceptors which 91 // are added to the dial options. 92 func WithChainUnaryInterceptor(interceptors ...grpc.UnaryClientInterceptor) DialOption { 93 return func(d *DialOptions) { 94 d.opts = append(d.opts, grpc.WithChainUnaryInterceptor(interceptors...)) 95 } 96 } 97 98 // WithChainStreamInterceptor takes a list of stream client interceptors which 99 // are added to the dial options. 100 func WithChainStreamInterceptor(interceptors ...grpc.StreamClientInterceptor) DialOption { 101 return func(d *DialOptions) { 102 d.opts = append(d.opts, grpc.WithChainStreamInterceptor(interceptors...)) 103 } 104 }