gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/transport/quic/quic.go (about)

     1  // Package quic provides a QUIC based transport
     2  package quic
     3  
     4  import (
     5  	"context"
     6  	"crypto/tls"
     7  	"encoding/gob"
     8  	"time"
     9  
    10  	quic "github.com/lucas-clemente/quic-go"
    11  	"gitee.com/liuxuezhan/go-micro-v1.18.0/transport"
    12  	utls "gitee.com/liuxuezhan/go-micro-v1.18.0/util/tls"
    13  )
    14  
    15  type quicSocket struct {
    16  	s   quic.Session
    17  	st  quic.Stream
    18  	enc *gob.Encoder
    19  	dec *gob.Decoder
    20  }
    21  
    22  type quicTransport struct {
    23  	opts transport.Options
    24  }
    25  
    26  type quicClient struct {
    27  	*quicSocket
    28  	t    *quicTransport
    29  	opts transport.DialOptions
    30  }
    31  
    32  type quicListener struct {
    33  	l    quic.Listener
    34  	t    *quicTransport
    35  	opts transport.ListenOptions
    36  }
    37  
    38  func (q *quicClient) Close() error {
    39  	return q.quicSocket.st.Close()
    40  }
    41  
    42  func (q *quicSocket) Recv(m *transport.Message) error {
    43  	return q.dec.Decode(&m)
    44  }
    45  
    46  func (q *quicSocket) Send(m *transport.Message) error {
    47  	// set the write deadline
    48  	q.st.SetWriteDeadline(time.Now().Add(time.Second * 10))
    49  	// send the data
    50  	return q.enc.Encode(m)
    51  }
    52  
    53  func (q *quicSocket) Close() error {
    54  	return q.s.Close()
    55  }
    56  
    57  func (q *quicSocket) Local() string {
    58  	return q.s.LocalAddr().String()
    59  }
    60  
    61  func (q *quicSocket) Remote() string {
    62  	return q.s.RemoteAddr().String()
    63  }
    64  
    65  func (q *quicListener) Addr() string {
    66  	return q.l.Addr().String()
    67  }
    68  
    69  func (q *quicListener) Close() error {
    70  	return q.l.Close()
    71  }
    72  
    73  func (q *quicListener) Accept(fn func(transport.Socket)) error {
    74  	for {
    75  		s, err := q.l.Accept(context.TODO())
    76  		if err != nil {
    77  			return err
    78  		}
    79  
    80  		stream, err := s.AcceptStream(context.TODO())
    81  		if err != nil {
    82  			continue
    83  		}
    84  
    85  		go func() {
    86  			fn(&quicSocket{
    87  				s:   s,
    88  				st:  stream,
    89  				enc: gob.NewEncoder(stream),
    90  				dec: gob.NewDecoder(stream),
    91  			})
    92  		}()
    93  	}
    94  }
    95  
    96  func (q *quicTransport) Init(opts ...transport.Option) error {
    97  	for _, o := range opts {
    98  		o(&q.opts)
    99  	}
   100  	return nil
   101  }
   102  
   103  func (q *quicTransport) Options() transport.Options {
   104  	return q.opts
   105  }
   106  
   107  func (q *quicTransport) Dial(addr string, opts ...transport.DialOption) (transport.Client, error) {
   108  	var options transport.DialOptions
   109  	for _, o := range opts {
   110  		o(&options)
   111  	}
   112  
   113  	config := q.opts.TLSConfig
   114  	if config == nil {
   115  		config = &tls.Config{
   116  			InsecureSkipVerify: true,
   117  			NextProtos:         []string{"http/1.1"},
   118  		}
   119  	}
   120  	s, err := quic.DialAddr(addr, config, &quic.Config{
   121  		IdleTimeout: time.Minute * 2,
   122  		KeepAlive:   true,
   123  	})
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  
   128  	st, err := s.OpenStreamSync(context.TODO())
   129  	if err != nil {
   130  		return nil, err
   131  	}
   132  
   133  	enc := gob.NewEncoder(st)
   134  	dec := gob.NewDecoder(st)
   135  
   136  	return &quicClient{
   137  		&quicSocket{
   138  			s:   s,
   139  			st:  st,
   140  			enc: enc,
   141  			dec: dec,
   142  		},
   143  		q,
   144  		options,
   145  	}, nil
   146  }
   147  
   148  func (q *quicTransport) Listen(addr string, opts ...transport.ListenOption) (transport.Listener, error) {
   149  	var options transport.ListenOptions
   150  	for _, o := range opts {
   151  		o(&options)
   152  	}
   153  
   154  	config := q.opts.TLSConfig
   155  	if config == nil {
   156  		cfg, err := utls.Certificate(addr)
   157  		if err != nil {
   158  			return nil, err
   159  		}
   160  		config = &tls.Config{
   161  			Certificates: []tls.Certificate{cfg},
   162  			NextProtos:   []string{"http/1.1"},
   163  		}
   164  	}
   165  
   166  	l, err := quic.ListenAddr(addr, config, &quic.Config{KeepAlive: true})
   167  	if err != nil {
   168  		return nil, err
   169  	}
   170  
   171  	return &quicListener{
   172  		l:    l,
   173  		t:    q,
   174  		opts: options,
   175  	}, nil
   176  }
   177  
   178  func (q *quicTransport) String() string {
   179  	return "quic"
   180  }
   181  
   182  func NewTransport(opts ...transport.Option) transport.Transport {
   183  	options := transport.Options{}
   184  
   185  	for _, o := range opts {
   186  		o(&options)
   187  	}
   188  
   189  	return &quicTransport{
   190  		opts: options,
   191  	}
   192  }