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, &microTransport{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  }