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 }