// Package quic provides a QUIC based transport package quic import ( "crypto/tls" "encoding/gob" "github.com/lucas-clemente/quic-go" "github.com/micro/go-micro/transport" utls "github.com/micro/util/go/lib/tls" ) type quicSocket struct { s quic.Session st quic.Stream enc *gob.Encoder dec *gob.Decoder } type quicTransport struct { opts transport.Options } type quicClient struct { *quicSocket t *quicTransport opts transport.DialOptions } type quicListener struct { l quic.Listener t *quicTransport opts transport.ListenOptions } func (q *quicClient) Close() error { return q.quicSocket.st.Close() } func (q *quicSocket) Recv(m *transport.Message) error { return q.dec.Decode(&m) } func (q *quicSocket) Send(m *transport.Message) error { return q.enc.Encode(m) } func (q *quicSocket) Close() error { return q.s.Close() } func (q *quicSocket) Local() string { return q.s.LocalAddr().String() } func (q *quicSocket) Remote() string { return q.s.RemoteAddr().String() } func (q *quicListener) Addr() string { return q.l.Addr().String() } func (q *quicListener) Close() error { return q.l.Close() } func (q *quicListener) Accept(fn func(transport.Socket)) error { for { s, err := q.l.Accept() if err != nil { return err } stream, err := s.AcceptStream() if err != nil { continue } go func() { fn(&quicSocket{ s: s, st: stream, enc: gob.NewEncoder(stream), dec: gob.NewDecoder(stream), }) }() } } func (q *quicTransport) Init(opts ...transport.Option) error { for _, o := range opts { o(&q.opts) } return nil } func (q *quicTransport) Options() transport.Options { return q.opts } func (q *quicTransport) Dial(addr string, opts ...transport.DialOption) (transport.Client, error) { var options transport.DialOptions for _, o := range opts { o(&options) } config := q.opts.TLSConfig if config == nil { config = &tls.Config{ InsecureSkipVerify: true, } } s, err := quic.DialAddr(addr, config, nil) if err != nil { return nil, err } st, err := s.OpenStreamSync() if err != nil { return nil, err } enc := gob.NewEncoder(st) dec := gob.NewDecoder(st) return &quicClient{ &quicSocket{ s: s, st: st, enc: enc, dec: dec, }, q, options, }, nil } func (q *quicTransport) Listen(addr string, opts ...transport.ListenOption) (transport.Listener, error) { var options transport.ListenOptions for _, o := range opts { o(&options) } config := q.opts.TLSConfig if config == nil { cfg, err := utls.Certificate(addr) if err != nil { return nil, err } config = &tls.Config{ Certificates: []tls.Certificate{cfg}, } } l, err := quic.ListenAddr(addr, config, nil) if err != nil { return nil, err } return &quicListener{ l: l, t: q, opts: options, }, nil } func (q *quicTransport) String() string { return "quic" } func NewTransport(opts ...transport.Option) transport.Transport { options := transport.Options{} for _, o := range opts { o(&options) } return &quicTransport{ opts: options, } }