go-micro.dev/v5@v5.12.0/transport/grpc/grpc.go (about) 1 // Package grpc provides a grpc transport 2 package grpc 3 4 import ( 5 "context" 6 "crypto/tls" 7 "net" 8 9 "go-micro.dev/v5/cmd" 10 "go-micro.dev/v5/transport" 11 maddr "go-micro.dev/v5/util/addr" 12 mnet "go-micro.dev/v5/util/net" 13 mls "go-micro.dev/v5/util/tls" 14 "google.golang.org/grpc" 15 "google.golang.org/grpc/credentials" 16 17 pb "go-micro.dev/v5/transport/grpc/proto" 18 ) 19 20 type grpcTransport struct { 21 opts transport.Options 22 } 23 24 type grpcTransportListener struct { 25 listener net.Listener 26 secure bool 27 tls *tls.Config 28 } 29 30 func init() { 31 cmd.DefaultTransports["grpc"] = NewTransport 32 } 33 34 func getTLSConfig(addr string) (*tls.Config, error) { 35 hosts := []string{addr} 36 37 // check if its a valid host:port 38 if host, _, err := net.SplitHostPort(addr); err == nil { 39 if len(host) == 0 { 40 hosts = maddr.IPs() 41 } else { 42 hosts = []string{host} 43 } 44 } 45 46 // generate a certificate 47 cert, err := mls.Certificate(hosts...) 48 if err != nil { 49 return nil, err 50 } 51 52 return &tls.Config{Certificates: []tls.Certificate{cert}}, nil 53 } 54 55 func (t *grpcTransportListener) Addr() string { 56 return t.listener.Addr().String() 57 } 58 59 func (t *grpcTransportListener) Close() error { 60 return t.listener.Close() 61 } 62 63 func (t *grpcTransportListener) Accept(fn func(transport.Socket)) error { 64 var opts []grpc.ServerOption 65 66 // setup tls if specified 67 if t.secure || t.tls != nil { 68 config := t.tls 69 if config == nil { 70 var err error 71 addr := t.listener.Addr().String() 72 config, err = getTLSConfig(addr) 73 if err != nil { 74 return err 75 } 76 } 77 78 creds := credentials.NewTLS(config) 79 opts = append(opts, grpc.Creds(creds)) 80 } 81 82 // new service 83 srv := grpc.NewServer(opts...) 84 85 // register service 86 pb.RegisterTransportServer(srv, µTransport{addr: t.listener.Addr().String(), fn: fn}) 87 88 // start serving 89 return srv.Serve(t.listener) 90 } 91 92 func (t *grpcTransport) Dial(addr string, opts ...transport.DialOption) (transport.Client, error) { 93 dopts := transport.DialOptions{ 94 Timeout: transport.DefaultDialTimeout, 95 } 96 97 for _, opt := range opts { 98 opt(&dopts) 99 } 100 101 options := []grpc.DialOption{ 102 grpc.WithTimeout(dopts.Timeout), 103 } 104 105 if t.opts.Secure || t.opts.TLSConfig != nil { 106 config := t.opts.TLSConfig 107 if config == nil { 108 config = &tls.Config{ 109 InsecureSkipVerify: true, 110 } 111 } 112 creds := credentials.NewTLS(config) 113 options = append(options, grpc.WithTransportCredentials(creds)) 114 } else { 115 options = append(options, grpc.WithInsecure()) 116 } 117 118 // dial the server 119 conn, err := grpc.Dial(addr, options...) 120 if err != nil { 121 return nil, err 122 } 123 124 // create stream 125 stream, err := pb.NewTransportClient(conn).Stream(context.Background()) 126 if err != nil { 127 return nil, err 128 } 129 130 // return a client 131 return &grpcTransportClient{ 132 conn: conn, 133 stream: stream, 134 local: "localhost", 135 remote: addr, 136 }, nil 137 } 138 139 func (t *grpcTransport) Listen(addr string, opts ...transport.ListenOption) (transport.Listener, error) { 140 var options transport.ListenOptions 141 for _, o := range opts { 142 o(&options) 143 } 144 145 ln, err := mnet.Listen(addr, func(addr string) (net.Listener, error) { 146 return net.Listen("tcp", addr) 147 }) 148 if err != nil { 149 return nil, err 150 } 151 152 return &grpcTransportListener{ 153 listener: ln, 154 tls: t.opts.TLSConfig, 155 secure: t.opts.Secure, 156 }, nil 157 } 158 159 func (t *grpcTransport) Init(opts ...transport.Option) error { 160 for _, o := range opts { 161 o(&t.opts) 162 } 163 return nil 164 } 165 166 func (t *grpcTransport) Options() transport.Options { 167 return t.opts 168 } 169 170 func (t *grpcTransport) String() string { 171 return "grpc" 172 } 173 174 func NewTransport(opts ...transport.Option) transport.Transport { 175 var options transport.Options 176 for _, o := range opts { 177 o(&options) 178 } 179 return &grpcTransport{opts: options} 180 }