diff --git a/.travis.yml b/.travis.yml index f19b799..6ec19bf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: go go: - - 1.14.x - 1.15.x - 1.16.x diff --git a/AUTHORS b/AUTHORS index 04e10fe..0a7af39 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,2 +1,2 @@ -Roland Singer -Sebastian Borchers \ No newline at end of file +Roland Singer +Sebastian Borchers \ No newline at end of file diff --git a/TODO.md b/TODO.md index 4a7cfec..d383845 100644 --- a/TODO.md +++ b/TODO.md @@ -1,8 +1,8 @@ # TODO - write tests - complete full example -- finish documenting +- finish documentation - Include go report in readme (and fix issues that it reports beforehand) - add orbit fmt cmd for .orbit files - disconnect session after TTL? -- use tls.dialContext in yamux, once the new go version has come out \ No newline at end of file +- rework sample (it is more of a test right now, would be nicer if the simple one shows the minimal needed setup, and a full one almost all of the features available) diff --git a/cmd/orbit/gen.go b/cmd/orbit/gen.go index 7120e83..2b72815 100644 --- a/cmd/orbit/gen.go +++ b/cmd/orbit/gen.go @@ -28,24 +28,26 @@ package main import ( - "errors" - "github.com/desertbit/grumble" "github.com/desertbit/orbit/internal/codegen/gen" ) const ( flagForce = "force" + + argFiles = "files" ) var cmdGen = &grumble.Command{ - Name: "gen", - Help: "generate go code from .orbit file. Args: ", - AllowArgs: true, - Run: runGen, + Name: "gen", + Help: "generate go code from .orbit file", + Run: runGen, Flags: func(f *grumble.Flags) { f.Bool("f", flagForce, false, "generate all files, ignoring their last modification time") }, + Args: func(a *grumble.Args) { + a.StringList(argFiles, "The .orbit files the code should be generated for", grumble.Min(1)) + }, } func init() { @@ -53,12 +55,8 @@ func init() { } func runGen(ctx *grumble.Context) (err error) { - if len(ctx.Args) == 0 { - return errors.New("no file given") - } - // Iterate over each provided file path and generate the .orbit file. - for _, fp := range ctx.Args { + for _, fp := range ctx.Args.StringList(argFiles) { err = gen.Generate(fp, ctx.Flags.Bool(flagForce)) if err != nil { return diff --git a/examples/full/api/api_orbit_gen.go b/examples/full/api/api_orbit_gen.go index 8988726..661f64f 100644 --- a/examples/full/api/api_orbit_gen.go +++ b/examples/full/api/api_orbit_gen.go @@ -6,6 +6,7 @@ import ( errors "errors" fmt "fmt" closer "github.com/desertbit/closer/v3" + options "github.com/desertbit/options" oclient "github.com/desertbit/orbit/pkg/client" codec "github.com/desertbit/orbit/pkg/codec" packet "github.com/desertbit/orbit/pkg/packet" @@ -334,7 +335,11 @@ type client struct { maxRetSize int } -func NewClient(opts *oclient.Options) (c Client, err error) { +func NewClient(opts oclient.Options) (c Client, err error) { + err = options.SetDefaults(&opts, oclient.DefaultOptions()) + if err != nil { + return + } oc, err := oclient.New(opts) if err != nil { return @@ -512,7 +517,11 @@ type service struct { maxRetSize int } -func NewService(h ServiceHandler, opts *oservice.Options) (s Service, err error) { +func NewService(h ServiceHandler, opts oservice.Options) (s Service, err error) { + err = options.SetDefaults(&opts, oservice.DefaultOptions()) + if err != nil { + return + } os, err := oservice.New(opts) if err != nil { return diff --git a/examples/simple/client/main.go b/examples/simple/client/main.go index fbb2b5b..cb10bd3 100644 --- a/examples/simple/client/main.go +++ b/examples/simple/client/main.go @@ -36,13 +36,16 @@ import ( "time" "github.com/desertbit/orbit/examples/simple/hello" + "github.com/desertbit/orbit/examples/simple/world" "github.com/desertbit/orbit/pkg/client" olog "github.com/desertbit/orbit/pkg/hook/log" + "github.com/desertbit/orbit/pkg/transport/mux" "github.com/desertbit/orbit/pkg/transport/quic" ) func main() { - tr, err := quic.NewTransport(&quic.Options{ + qtr, err := quic.NewTransport(quic.Options{ + DialAddr: "127.0.0.1:1122", TLSConfig: &tls.Config{ InsecureSkipVerify: true, NextProtos: []string{"orbit-simple-example"}, @@ -52,9 +55,14 @@ func main() { log.Fatalln(err) } - c, err := hello.NewClient(&client.Options{ - Host: "127.0.0.1:1122", - Transport: tr, + // Multiplex transport to allow multiple services. + mtr, err := mux.New(qtr, mux.DefaultOptions()) + if err != nil { + return + } + + c, err := hello.NewClient(client.Options{ + Transport: mtr.Transport("hello"), Hooks: client.Hooks{ olog.ClientHook(), }, @@ -64,6 +72,17 @@ func main() { } defer c.Close() + wc, err := world.NewClient(client.Options{ + Transport: mtr.Transport("world"), + Hooks: client.Hooks{ + olog.ClientHook(), + }, + }) + if err != nil { + log.Fatalln(err) + } + defer wc.Close() + var wg sync.WaitGroup wg.Add(1) go func() { @@ -115,4 +134,9 @@ func main() { } bi.Close() wg.Wait() + + err = wc.YetAnotherCall(context.Background(), world.YetAnotherCallArg{S: "Finally done"}) + if err != nil { + return + } } diff --git a/examples/simple/hello/hello_orbit_gen.go b/examples/simple/hello/hello_orbit_gen.go index b9ac37b..38417b2 100644 --- a/examples/simple/hello/hello_orbit_gen.go +++ b/examples/simple/hello/hello_orbit_gen.go @@ -6,6 +6,7 @@ import ( errors "errors" fmt "fmt" closer "github.com/desertbit/closer/v3" + options "github.com/desertbit/options" oclient "github.com/desertbit/orbit/pkg/client" codec "github.com/desertbit/orbit/pkg/codec" packet "github.com/desertbit/orbit/pkg/packet" @@ -368,7 +369,11 @@ type client struct { maxRetSize int } -func NewClient(opts *oclient.Options) (c Client, err error) { +func NewClient(opts oclient.Options) (c Client, err error) { + err = options.SetDefaults(&opts, oclient.DefaultOptions()) + if err != nil { + return + } oc, err := oclient.New(opts) if err != nil { return @@ -479,7 +484,11 @@ type service struct { maxRetSize int } -func NewService(h ServiceHandler, opts *oservice.Options) (s Service, err error) { +func NewService(h ServiceHandler, opts oservice.Options) (s Service, err error) { + err = options.SetDefaults(&opts, oservice.DefaultOptions()) + if err != nil { + return + } os, err := oservice.New(opts) if err != nil { return diff --git a/examples/simple/service/main.go b/examples/simple/service/main.go index 6be8980..c03b0cb 100644 --- a/examples/simple/service/main.go +++ b/examples/simple/service/main.go @@ -39,24 +39,33 @@ import ( "time" "github.com/desertbit/orbit/examples/simple/hello" + "github.com/desertbit/orbit/examples/simple/world" olog "github.com/desertbit/orbit/pkg/hook/log" "github.com/desertbit/orbit/pkg/service" "github.com/desertbit/orbit/pkg/transport" + "github.com/desertbit/orbit/pkg/transport/mux" "github.com/desertbit/orbit/pkg/transport/quic" ) func main() { - tr, err := quic.NewTransport(&quic.Options{ - TLSConfig: generateTLSConfig(), + // Create quic transport. + qtr, err := quic.NewTransport(quic.Options{ + ListenAddr: "127.0.0.1:1122", + TLSConfig: generateTLSConfig(), }) if err != nil { log.Fatalln(err) } + // Multiplex transport to allow multiple services. + mtr, err := mux.New(qtr, mux.DefaultOptions()) + if err != nil { + return + } + s, err := hello.NewService(&ServiceHandler{}, - &service.Options{ - ListenAddr: ":1122", - Transport: tr, + service.Options{ + Transport: mtr.Transport("hello"), Hooks: service.Hooks{ olog.ServiceHook(), }, @@ -66,7 +75,26 @@ func main() { } defer s.Close() - err = s.Run() + go func() { + err = s.Run() + if err != nil { + log.Fatalln(err) + } + }() + + ws, err := world.NewService(&ServiceHandler{}, + service.Options{ + Transport: mtr.Transport("world"), + Hooks: service.Hooks{ + olog.ServiceHook(), + }, + }) + if err != nil { + log.Fatalln(err) + } + defer ws.Close() + + err = ws.Run() if err != nil { log.Fatalln(err) } @@ -99,6 +127,8 @@ func generateTLSConfig() *tls.Config { type ServiceHandler struct{} +// ### hello service + func (s *ServiceHandler) SayHi(ctx service.Context, arg hello.SayHiArg) (ret hello.SayHiRet, err error) { fmt.Printf("handler: SayHi, %s, %s\n", arg.Name, arg.Ts.String()) ret = hello.SayHiRet{Res: []int{1, 2, 3}} @@ -149,3 +179,10 @@ func (s *ServiceHandler) Bidirectional(ctx service.Context, stream *hello.Bidire } return nil } + +// ### world service + +func (s *ServiceHandler) YetAnotherCall(ctx service.Context, arg world.YetAnotherCallArg) (err error) { + fmt.Printf("world: YAC -> %s\n", arg.S) + return +} diff --git a/examples/simple/world/world.orbit b/examples/simple/world/world.orbit new file mode 100644 index 0000000..7ce0003 --- /dev/null +++ b/examples/simple/world/world.orbit @@ -0,0 +1,9 @@ +version 1 + +service { + call yetAnotherCall { + arg: { + s string + } + } +} diff --git a/examples/simple/world/world_msgp_gen.go b/examples/simple/world/world_msgp_gen.go new file mode 100644 index 0000000..f4d5ceb --- /dev/null +++ b/examples/simple/world/world_msgp_gen.go @@ -0,0 +1,110 @@ +package world + +// Code generated by github.com/tinylib/msgp DO NOT EDIT. + +import ( + "github.com/tinylib/msgp/msgp" +) + +// DecodeMsg implements msgp.Decodable +func (z *YetAnotherCallArg) DecodeMsg(dc *msgp.Reader) (err error) { + var field []byte + _ = field + var zb0001 uint32 + zb0001, err = dc.ReadMapHeader() + if err != nil { + err = msgp.WrapError(err) + return + } + for zb0001 > 0 { + zb0001-- + field, err = dc.ReadMapKeyPtr() + if err != nil { + err = msgp.WrapError(err) + return + } + switch msgp.UnsafeString(field) { + case "S": + z.S, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "S") + return + } + default: + err = dc.Skip() + if err != nil { + err = msgp.WrapError(err) + return + } + } + } + return +} + +// EncodeMsg implements msgp.Encodable +func (z YetAnotherCallArg) EncodeMsg(en *msgp.Writer) (err error) { + // map header, size 1 + // write "S" + err = en.Append(0x81, 0xa1, 0x53) + if err != nil { + return + } + err = en.WriteString(z.S) + if err != nil { + err = msgp.WrapError(err, "S") + return + } + return +} + +// MarshalMsg implements msgp.Marshaler +func (z YetAnotherCallArg) MarshalMsg(b []byte) (o []byte, err error) { + o = msgp.Require(b, z.Msgsize()) + // map header, size 1 + // string "S" + o = append(o, 0x81, 0xa1, 0x53) + o = msgp.AppendString(o, z.S) + return +} + +// UnmarshalMsg implements msgp.Unmarshaler +func (z *YetAnotherCallArg) UnmarshalMsg(bts []byte) (o []byte, err error) { + var field []byte + _ = field + var zb0001 uint32 + zb0001, bts, err = msgp.ReadMapHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + for zb0001 > 0 { + zb0001-- + field, bts, err = msgp.ReadMapKeyZC(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + switch msgp.UnsafeString(field) { + case "S": + z.S, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "S") + return + } + default: + bts, err = msgp.Skip(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + } + } + o = bts + return +} + +// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message +func (z YetAnotherCallArg) Msgsize() (s int) { + s = 1 + 2 + msgp.StringPrefixSize + len(z.S) + return +} diff --git a/examples/simple/world/world_msgp_gen_test.go b/examples/simple/world/world_msgp_gen_test.go new file mode 100644 index 0000000..df88fe6 --- /dev/null +++ b/examples/simple/world/world_msgp_gen_test.go @@ -0,0 +1,123 @@ +package world + +// Code generated by github.com/tinylib/msgp DO NOT EDIT. + +import ( + "bytes" + "testing" + + "github.com/tinylib/msgp/msgp" +) + +func TestMarshalUnmarshalYetAnotherCallArg(t *testing.T) { + v := YetAnotherCallArg{} + bts, err := v.MarshalMsg(nil) + if err != nil { + t.Fatal(err) + } + left, err := v.UnmarshalMsg(bts) + if err != nil { + t.Fatal(err) + } + if len(left) > 0 { + t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left) + } + + left, err = msgp.Skip(bts) + if err != nil { + t.Fatal(err) + } + if len(left) > 0 { + t.Errorf("%d bytes left over after Skip(): %q", len(left), left) + } +} + +func BenchmarkMarshalMsgYetAnotherCallArg(b *testing.B) { + v := YetAnotherCallArg{} + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + v.MarshalMsg(nil) + } +} + +func BenchmarkAppendMsgYetAnotherCallArg(b *testing.B) { + v := YetAnotherCallArg{} + bts := make([]byte, 0, v.Msgsize()) + bts, _ = v.MarshalMsg(bts[0:0]) + b.SetBytes(int64(len(bts))) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + bts, _ = v.MarshalMsg(bts[0:0]) + } +} + +func BenchmarkUnmarshalYetAnotherCallArg(b *testing.B) { + v := YetAnotherCallArg{} + bts, _ := v.MarshalMsg(nil) + b.ReportAllocs() + b.SetBytes(int64(len(bts))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := v.UnmarshalMsg(bts) + if err != nil { + b.Fatal(err) + } + } +} + +func TestEncodeDecodeYetAnotherCallArg(t *testing.T) { + v := YetAnotherCallArg{} + var buf bytes.Buffer + msgp.Encode(&buf, &v) + + m := v.Msgsize() + if buf.Len() > m { + t.Logf("WARNING: Msgsize() for %v is inaccurate", v) + } + + vn := YetAnotherCallArg{} + err := msgp.Decode(&buf, &vn) + if err != nil { + t.Error(err) + } + + buf.Reset() + msgp.Encode(&buf, &v) + err = msgp.NewReader(&buf).Skip() + if err != nil { + t.Error(err) + } +} + +func BenchmarkEncodeYetAnotherCallArg(b *testing.B) { + v := YetAnotherCallArg{} + var buf bytes.Buffer + msgp.Encode(&buf, &v) + b.SetBytes(int64(buf.Len())) + en := msgp.NewWriter(msgp.Nowhere) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + v.EncodeMsg(en) + } + en.Flush() +} + +func BenchmarkDecodeYetAnotherCallArg(b *testing.B) { + v := YetAnotherCallArg{} + var buf bytes.Buffer + msgp.Encode(&buf, &v) + b.SetBytes(int64(buf.Len())) + rd := msgp.NewEndlessReader(buf.Bytes(), b) + dc := msgp.NewReader(rd) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + err := v.DecodeMsg(dc) + if err != nil { + b.Fatal(err) + } + } +} diff --git a/examples/simple/world/world_orbit_gen.go b/examples/simple/world/world_orbit_gen.go new file mode 100644 index 0000000..7b71572 --- /dev/null +++ b/examples/simple/world/world_orbit_gen.go @@ -0,0 +1,182 @@ +/* code generated by orbit */ +package world + +import ( + context "context" + errors "errors" + fmt "fmt" + closer "github.com/desertbit/closer/v3" + options "github.com/desertbit/options" + oclient "github.com/desertbit/orbit/pkg/client" + codec "github.com/desertbit/orbit/pkg/codec" + packet "github.com/desertbit/orbit/pkg/packet" + oservice "github.com/desertbit/orbit/pkg/service" + transport "github.com/desertbit/orbit/pkg/transport" + validator "github.com/go-playground/validator/v10" + io "io" + net "net" + strings "strings" + sync "sync" + time "time" +) + +// Ensure that all imports are used. +var ( + _ context.Context + _ = errors.New("") + _ = fmt.Sprint() + _ io.Closer + _ net.Conn + _ time.Time + _ strings.Builder + _ sync.Locker + _ oclient.Client + _ closer.Closer + _ codec.Codec + _ = packet.MaxSize + _ oservice.Service + _ transport.Transport + _ validator.StructLevel +) + +//##############// +//### Errors ###// +//##############// + +var ErrClosed = errors.New("closed") + +func _clientErrorCheck(err error) error { + return err +} +func _serviceErrorCheck(err error) error { + return err +} +func _valErrCheck(err error) error { + if vErrs, ok := err.(validator.ValidationErrors); ok { + var errMsg strings.Builder + for _, err := range vErrs { + errMsg.WriteString(fmt.Sprintf("[name: '%s', value: '%s', tag: '%s']", err.StructNamespace(), err.Value(), err.Tag())) + } + return errors.New(errMsg.String()) + } + return err +} + +var validate = validator.New() + +//#############// +//### Types ###// +//#############// + +type YetAnotherCallArg struct { + S string +} + +//###############// +//### Service ###// +//###############// + +const ( + CallIDYetAnotherCall = "YetAnotherCall" +) + +type Client interface { + closer.Closer + StateChan() <-chan oclient.State + // Calls + YetAnotherCall(ctx context.Context, arg YetAnotherCallArg) (err error) +} + +type Service interface { + closer.Closer + Run() error +} + +type ServiceHandler interface { + // Calls + YetAnotherCall(ctx oservice.Context, arg YetAnotherCallArg) (err error) +} + +type client struct { + oclient.Client + codec codec.Codec + callTimeout time.Duration + streamInitTimeout time.Duration + maxArgSize int + maxRetSize int +} + +func NewClient(opts oclient.Options) (c Client, err error) { + err = options.SetDefaults(&opts, oclient.DefaultOptions()) + if err != nil { + return + } + oc, err := oclient.New(opts) + if err != nil { + return + } + c = &client{Client: oc, codec: opts.Codec, callTimeout: opts.CallTimeout, streamInitTimeout: opts.StreamInitTimeout, maxArgSize: opts.MaxArgSize, maxRetSize: opts.MaxRetSize} + return +} + +func (v1 *client) StateChan() <-chan oclient.State { + return v1.Client.StateChan() +} + +func (v1 *client) YetAnotherCall(ctx context.Context, arg YetAnotherCallArg) (err error) { + if v1.callTimeout > 0 { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, v1.callTimeout) + defer cancel() + } + err = v1.Call(ctx, CallIDYetAnotherCall, arg, nil) + if err != nil { + err = _clientErrorCheck(err) + return + } + return +} + +type service struct { + oservice.Service + h ServiceHandler + codec codec.Codec + maxArgSize int + maxRetSize int +} + +func NewService(h ServiceHandler, opts oservice.Options) (s Service, err error) { + err = options.SetDefaults(&opts, oservice.DefaultOptions()) + if err != nil { + return + } + os, err := oservice.New(opts) + if err != nil { + return + } + srvc := &service{Service: os, h: h, codec: opts.Codec, maxArgSize: opts.MaxArgSize, maxRetSize: opts.MaxRetSize} + // Ensure usage. + _ = srvc + os.RegisterCall(CallIDYetAnotherCall, srvc.yetAnotherCall, oservice.DefaultTimeout) + s = os + return +} + +func (v1 *service) yetAnotherCall(ctx oservice.Context, argData []byte) (retData interface{}, err error) { + var arg YetAnotherCallArg + err = v1.codec.Decode(argData, &arg) + if err != nil { + return + } + err = validate.Struct(arg) + if err != nil { + err = _valErrCheck(err) + return + } + err = v1.h.YetAnotherCall(ctx, arg) + if err != nil { + err = _serviceErrorCheck(err) + return + } + return +} diff --git a/go.mod b/go.mod index 282c15b..b049891 100644 --- a/go.mod +++ b/go.mod @@ -1,36 +1,31 @@ module github.com/desertbit/orbit -go 1.14 +go 1.15 require ( code.cloudfoundry.org/bytefmt v0.0.0-20200131002437-cf55d5288a48 github.com/cloudfoundry/bytefmt v0.0.0-20200131002437-cf55d5288a48 github.com/davecgh/go-spew v1.1.1 // indirect github.com/desertbit/closer/v3 v3.1.2 - github.com/desertbit/grumble v1.0.6 + github.com/desertbit/grumble v1.1.1 + github.com/desertbit/options v0.0.4 github.com/desertbit/yamux v1.0.1 - github.com/fatih/color v1.9.0 // indirect github.com/go-playground/validator/v10 v10.3.0 github.com/golang/protobuf v1.4.3 // indirect - github.com/hashicorp/go-multierror v1.1.0 // indirect github.com/kr/text v0.2.0 // indirect github.com/lucas-clemente/quic-go v0.19.3 - github.com/marten-seemann/qtls v0.10.0 // indirect - github.com/mattn/go-colorable v0.1.7 // indirect - github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect - github.com/onsi/ginkgo v1.14.0 // indirect github.com/philhofer/fwd v1.0.0 // indirect github.com/rs/zerolog v1.19.0 github.com/stretchr/testify v1.6.1 github.com/tinylib/msgp v1.1.2 github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect - golang.org/x/net v0.0.0-20200707034311-ab3426394381 // indirect golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect golang.org/x/text v0.3.3 // indirect google.golang.org/appengine v1.6.6 // indirect google.golang.org/protobuf v1.25.0 // indirect - gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/vmihailenco/msgpack.v3 v3.3.3 - gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b ) diff --git a/go.sum b/go.sum index a5239d5..3f34e0b 100644 --- a/go.sum +++ b/go.sum @@ -11,7 +11,6 @@ dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= -github.com/Netflix/go-expect v0.0.0-20190729225929-0e00d9168667 h1:l2RCK7mjLhjfZRIcCXTVHI34l67IRtKASBjusViLzQ0= github.com/Netflix/go-expect v0.0.0-20190729225929-0e00d9168667/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -29,40 +28,33 @@ github.com/cloudfoundry/bytefmt v0.0.0-20200131002437-cf55d5288a48 h1:PEwjDh+JW/ github.com/cloudfoundry/bytefmt v0.0.0-20200131002437-cf55d5288a48/go.mod h1:4oo6ExqTPaBVBwSm814h6UO5Fels1kN2KvpNscaCcS0= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/creack/pty v1.1.7 h1:6pwm8kMQKCmgUg0ZHTm5+/YvRK0s3THD/28+T6/kk4A= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/desertbit/closer/v3 v3.0.1/go.mod h1:AAC4KRd8DC40nwvV967J/kDFhujMEiuwIKQfN0IDxXw= github.com/desertbit/closer/v3 v3.1.2 h1:a6+2DmwIcNygW04XXWYq+Qp2X9uIk9QbZCP9//qEkb0= github.com/desertbit/closer/v3 v3.1.2/go.mod h1:AAC4KRd8DC40nwvV967J/kDFhujMEiuwIKQfN0IDxXw= github.com/desertbit/columnize v2.1.0+incompatible h1:h55rYmdrWoTj7w9aAnCkxzM3C2Eb8zuFa2W41t0o5j0= github.com/desertbit/columnize v2.1.0+incompatible/go.mod h1:5kPrzQwKbQ8E5D28nvTVPqIBJyj+8jvJzwt6HXZvXgI= -github.com/desertbit/go-shlex v0.1.0 h1:HapoSxMl/xT59s1Z+RR6ScBuH2H8vr4HcgERVjBTJ8s= -github.com/desertbit/go-shlex v0.1.0/go.mod h1:Qbb+mJNud5AypgHZ81EL8syOGaWlwvAOTqS7XmWI4pQ= -github.com/desertbit/grumble v1.0.6 h1:m/abmUuIs7I5V3zahlwqPezy2AMI754mRGF8sOL+M2w= -github.com/desertbit/grumble v1.0.6/go.mod h1:16pOXVF3OqcA4by1Cj44wr1eUe3t7rCxXllMc3N19n0= -github.com/desertbit/readline v0.0.0-20171208011716-f6d7a1f6fbf3 h1:PLbrJOpAtk8ros5avAt8am0GJvPuD08FVLV+ffmG0Jo= -github.com/desertbit/readline v0.0.0-20171208011716-f6d7a1f6fbf3/go.mod h1:AayRnEOr0ttSh4kgOlHBBtJufZMMW/1BVCdV5oFs8t0= -github.com/desertbit/yamux v1.0.0 h1:FHOGf0R827EMvYu2+LQi1Js8iWRkXKhX0isXR095fD4= -github.com/desertbit/yamux v1.0.0/go.mod h1:Q2KVuKXGwT6IuApVtaMA2y0OgnOFrNTQ1DTZ/WlMX7I= +github.com/desertbit/go-shlex v0.1.1 h1:c65HnbgX1QyC6kPL1dMzUpZ4puNUE6ai/eVucWNLNsk= +github.com/desertbit/go-shlex v0.1.1/go.mod h1:Qbb+mJNud5AypgHZ81EL8syOGaWlwvAOTqS7XmWI4pQ= +github.com/desertbit/grumble v1.1.1 h1:1wxy6ka1aqbtA3kZIHaPfB/DD91HSM2m4Kx2QIIGfpE= +github.com/desertbit/grumble v1.1.1/go.mod h1:r7j3ShNy5EmOsegRD2DzTutIaGiLiA3M5yBTXXeLwcs= +github.com/desertbit/options v0.0.4 h1:t8sP95Yc36v+pxeeMG+waAEmS0BqMuVUpEVuEvd90Vk= +github.com/desertbit/options v0.0.4/go.mod h1:Sn7JORR/i0yUZjOow9c/QwbKoYLdHtj0WrxRpse8SG4= +github.com/desertbit/readline v1.5.1 h1:/wOIZkWYl1s+IvJm/5bOknfUgs6MhS9svRNZpFM53Os= +github.com/desertbit/readline v1.5.1/go.mod h1:pHQgTsCFs9Cpfh5mlSUFi9Xa5kkL4d8L1Jo4UVWzPw0= github.com/desertbit/yamux v1.0.1 h1:4NBBiBQjoBgd3P4IKVUPZ/wLm7gZvbmMH4ojjmYRZIs= github.com/desertbit/yamux v1.0.1/go.mod h1:Q2KVuKXGwT6IuApVtaMA2y0OgnOFrNTQ1DTZ/WlMX7I= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= +github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -83,15 +75,11 @@ github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.4.0 h1:Rd1kQnQu0Hq3qvJppYSG0HtP+f5LPPUiDswTLiEegLg= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= @@ -100,7 +88,6 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= @@ -108,7 +95,6 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -121,92 +107,66 @@ github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE0 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= -github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A= -github.com/hinshun/vt10x v0.0.0-20180809195222-d55458df857c h1:kp3AxgXgDOmIJFR7bIwqFhwJ2qWar8tEQSE5XXhCfVk= github.com/hinshun/vt10x v0.0.0-20180809195222-d55458df857c/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8 h1:AkaSdXYQOWeaO3neb8EM634ahkXXe3jYbVh/F9lq+GI= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/lucas-clemente/quic-go v0.17.3 h1:jMX/MmDNCljfisgMmPGUcBJ+zUh9w3d3ia4YJjYS3TM= -github.com/lucas-clemente/quic-go v0.17.3/go.mod h1:I0+fcNTdb9eS1ZcjQZbDVPGchJ86chcIxPALn9lEJqE= github.com/lucas-clemente/quic-go v0.19.3 h1:eCDQqvGBB+kCTkA0XrAFtNe81FMa0/fn4QSoeAbmiF4= github.com/lucas-clemente/quic-go v0.19.3/go.mod h1:ADXpNbTQjq1hIzCpB+y/k5iz4n4z4IwqoLb94Kh5Hu8= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI= github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc= -github.com/marten-seemann/qtls v0.9.1/go.mod h1:T1MmAdDPyISzxlK6kjRr0pcZFBVd1OZbBb/j3cvzHhk= github.com/marten-seemann/qtls v0.10.0 h1:ECsuYUKalRL240rRD4Ri33ISb7kAQ3qGDlrrl55b2pc= github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs= github.com/marten-seemann/qtls-go1-15 v0.1.1 h1:LIH6K34bPVttyXnUWixk0bzH6/N07VxbSabxn5A5gZQ= github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw= -github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= -github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.8.1 h1:C5Dqfs/LeauYDX0jJXIe2SWmwCbGzx9yF8C8xy3Lh34= -github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -245,11 +205,9 @@ github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5k github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -270,10 +228,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 h1:DZhuSZLsGlFL4CmhA8BcRA0mnthyA/nZ00AqCUo7vHg= -golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -288,14 +243,11 @@ golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190228165749-92fc7df08ae7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= @@ -315,30 +267,25 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd h1:DBH9mDw0zluJT/R+nGuV3jWFWLFaHyYZWD4tOT+cjn0= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -352,7 +299,6 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190802003818-e9bb7d36c060/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= @@ -387,18 +333,15 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/AlecAivazis/survey.v1 v1.8.5/go.mod h1:iBNOmqKz/NUbZx3bA+4hAGLRC7fSK7tgtVDT4tB22XA= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= @@ -406,14 +349,14 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD gopkg.in/vmihailenco/msgpack.v3 v3.3.3 h1:ofZ+GtBfsZFb+np1DCzu9n//tnXGtrDhzu5nV3blbkE= gopkg.in/vmihailenco/msgpack.v3 v3.3.3/go.mod h1:OJZ1heoagDaTAJzkdu4QXATYlS0bONQeopugKgUPZLI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/grml.yaml b/grml.yaml index 1ef127d..7d1a605 100644 --- a/grml.yaml +++ b/grml.yaml @@ -13,9 +13,9 @@ commands: go test -race ./pkg/... ./internal/... ./cmd/... generate: - help: generate all internal msgp code + help: generate all msgp code exec: | - go generate ./internal/... + go generate ./internal/... ./pkg/... run: help: run commands @@ -57,7 +57,10 @@ commands: deps: - build.orbit exec: | - "${BINDIR}/orbit" gen --force "${ROOT}/examples/simple/hello/hello.orbit" + "${BINDIR}/orbit" gen \ + --force \ + "${ROOT}/examples/simple/hello/hello.orbit" \ + "${ROOT}/examples/simple/world/world.orbit" go build -o "${BINDIR}/simple-client" "${ROOT}/examples/simple/client" go build -o "${BINDIR}/simple-server" "${ROOT}/examples/simple/service" full: diff --git a/internal/api/api_gen.go b/internal/api/api_gen.go index eeab34f..3eaf1f4 100644 --- a/internal/api/api_gen.go +++ b/internal/api/api_gen.go @@ -1180,3 +1180,183 @@ func (z StreamType) Msgsize() (s int) { s = msgp.ByteSize return } + +// DecodeMsg implements msgp.Decodable +func (z *TypedStreamError) DecodeMsg(dc *msgp.Reader) (err error) { + var field []byte + _ = field + var zb0001 uint32 + zb0001, err = dc.ReadMapHeader() + if err != nil { + err = msgp.WrapError(err) + return + } + for zb0001 > 0 { + zb0001-- + field, err = dc.ReadMapKeyPtr() + if err != nil { + err = msgp.WrapError(err) + return + } + switch msgp.UnsafeString(field) { + case "Err": + z.Err, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Err") + return + } + case "Code": + z.Code, err = dc.ReadInt() + if err != nil { + err = msgp.WrapError(err, "Code") + return + } + default: + err = dc.Skip() + if err != nil { + err = msgp.WrapError(err) + return + } + } + } + return +} + +// EncodeMsg implements msgp.Encodable +func (z TypedStreamError) EncodeMsg(en *msgp.Writer) (err error) { + // map header, size 2 + // write "Err" + err = en.Append(0x82, 0xa3, 0x45, 0x72, 0x72) + if err != nil { + return + } + err = en.WriteString(z.Err) + if err != nil { + err = msgp.WrapError(err, "Err") + return + } + // write "Code" + err = en.Append(0xa4, 0x43, 0x6f, 0x64, 0x65) + if err != nil { + return + } + err = en.WriteInt(z.Code) + if err != nil { + err = msgp.WrapError(err, "Code") + return + } + return +} + +// MarshalMsg implements msgp.Marshaler +func (z TypedStreamError) MarshalMsg(b []byte) (o []byte, err error) { + o = msgp.Require(b, z.Msgsize()) + // map header, size 2 + // string "Err" + o = append(o, 0x82, 0xa3, 0x45, 0x72, 0x72) + o = msgp.AppendString(o, z.Err) + // string "Code" + o = append(o, 0xa4, 0x43, 0x6f, 0x64, 0x65) + o = msgp.AppendInt(o, z.Code) + return +} + +// UnmarshalMsg implements msgp.Unmarshaler +func (z *TypedStreamError) UnmarshalMsg(bts []byte) (o []byte, err error) { + var field []byte + _ = field + var zb0001 uint32 + zb0001, bts, err = msgp.ReadMapHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + for zb0001 > 0 { + zb0001-- + field, bts, err = msgp.ReadMapKeyZC(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + switch msgp.UnsafeString(field) { + case "Err": + z.Err, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Err") + return + } + case "Code": + z.Code, bts, err = msgp.ReadIntBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Code") + return + } + default: + bts, err = msgp.Skip(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + } + } + o = bts + return +} + +// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message +func (z TypedStreamError) Msgsize() (s int) { + s = 1 + 4 + msgp.StringPrefixSize + len(z.Err) + 5 + msgp.IntSize + return +} + +// DecodeMsg implements msgp.Decodable +func (z *TypedStreamType) DecodeMsg(dc *msgp.Reader) (err error) { + { + var zb0001 byte + zb0001, err = dc.ReadByte() + if err != nil { + err = msgp.WrapError(err) + return + } + (*z) = TypedStreamType(zb0001) + } + return +} + +// EncodeMsg implements msgp.Encodable +func (z TypedStreamType) EncodeMsg(en *msgp.Writer) (err error) { + err = en.WriteByte(byte(z)) + if err != nil { + err = msgp.WrapError(err) + return + } + return +} + +// MarshalMsg implements msgp.Marshaler +func (z TypedStreamType) MarshalMsg(b []byte) (o []byte, err error) { + o = msgp.Require(b, z.Msgsize()) + o = msgp.AppendByte(o, byte(z)) + return +} + +// UnmarshalMsg implements msgp.Unmarshaler +func (z *TypedStreamType) UnmarshalMsg(bts []byte) (o []byte, err error) { + { + var zb0001 byte + zb0001, bts, err = msgp.ReadByteBytes(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + (*z) = TypedStreamType(zb0001) + } + o = bts + return +} + +// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message +func (z TypedStreamType) Msgsize() (s int) { + s = msgp.ByteSize + return +} diff --git a/internal/api/api_gen_test.go b/internal/api/api_gen_test.go index 895407e..a15d6a9 100644 --- a/internal/api/api_gen_test.go +++ b/internal/api/api_gen_test.go @@ -799,3 +799,116 @@ func BenchmarkDecodeStreamRaw(b *testing.B) { } } } + +func TestMarshalUnmarshalTypedStreamError(t *testing.T) { + v := TypedStreamError{} + bts, err := v.MarshalMsg(nil) + if err != nil { + t.Fatal(err) + } + left, err := v.UnmarshalMsg(bts) + if err != nil { + t.Fatal(err) + } + if len(left) > 0 { + t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left) + } + + left, err = msgp.Skip(bts) + if err != nil { + t.Fatal(err) + } + if len(left) > 0 { + t.Errorf("%d bytes left over after Skip(): %q", len(left), left) + } +} + +func BenchmarkMarshalMsgTypedStreamError(b *testing.B) { + v := TypedStreamError{} + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + v.MarshalMsg(nil) + } +} + +func BenchmarkAppendMsgTypedStreamError(b *testing.B) { + v := TypedStreamError{} + bts := make([]byte, 0, v.Msgsize()) + bts, _ = v.MarshalMsg(bts[0:0]) + b.SetBytes(int64(len(bts))) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + bts, _ = v.MarshalMsg(bts[0:0]) + } +} + +func BenchmarkUnmarshalTypedStreamError(b *testing.B) { + v := TypedStreamError{} + bts, _ := v.MarshalMsg(nil) + b.ReportAllocs() + b.SetBytes(int64(len(bts))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := v.UnmarshalMsg(bts) + if err != nil { + b.Fatal(err) + } + } +} + +func TestEncodeDecodeTypedStreamError(t *testing.T) { + v := TypedStreamError{} + var buf bytes.Buffer + msgp.Encode(&buf, &v) + + m := v.Msgsize() + if buf.Len() > m { + t.Logf("WARNING: Msgsize() for %v is inaccurate", v) + } + + vn := TypedStreamError{} + err := msgp.Decode(&buf, &vn) + if err != nil { + t.Error(err) + } + + buf.Reset() + msgp.Encode(&buf, &v) + err = msgp.NewReader(&buf).Skip() + if err != nil { + t.Error(err) + } +} + +func BenchmarkEncodeTypedStreamError(b *testing.B) { + v := TypedStreamError{} + var buf bytes.Buffer + msgp.Encode(&buf, &v) + b.SetBytes(int64(buf.Len())) + en := msgp.NewWriter(msgp.Nowhere) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + v.EncodeMsg(en) + } + en.Flush() +} + +func BenchmarkDecodeTypedStreamError(b *testing.B) { + v := TypedStreamError{} + var buf bytes.Buffer + msgp.Encode(&buf, &v) + b.SetBytes(int64(buf.Len())) + rd := msgp.NewEndlessReader(buf.Bytes(), b) + dc := msgp.NewReader(rd) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + err := v.DecodeMsg(dc) + if err != nil { + b.Fatal(err) + } + } +} diff --git a/internal/codegen/gen/gen.go b/internal/codegen/gen/gen.go index 4a120cf..4025500 100644 --- a/internal/codegen/gen/gen.go +++ b/internal/codegen/gen/gen.go @@ -172,6 +172,7 @@ func generate(pkgName string, f *ast.File) string { {"oclient", "github.com/desertbit/orbit/pkg/client"}, {"closer", "github.com/desertbit/closer/v3"}, {"codec", "github.com/desertbit/orbit/pkg/codec"}, + {"options", "github.com/desertbit/options"}, {"packet", "github.com/desertbit/orbit/pkg/packet"}, {"oservice", "github.com/desertbit/orbit/pkg/service"}, {"transport", "github.com/desertbit/orbit/pkg/transport"}, diff --git a/internal/codegen/gen/gen_service.go b/internal/codegen/gen/gen_service.go index 7e9ef61..c95842b 100644 --- a/internal/codegen/gen/gen_service.go +++ b/internal/codegen/gen/gen_service.go @@ -121,7 +121,9 @@ func (g *generator) genClientStruct(calls []*ast.Call, streams []*ast.Stream, er g.writeLn("") // Generate the constructor. - g.writeLn("func NewClient(opts *oclient.Options) (c Client, err error) {") + g.writeLn("func NewClient(opts oclient.Options) (c Client, err error) {") + g.writeLn("err = options.SetDefaults(&opts, oclient.DefaultOptions())") + g.errIfNil() g.writeLn("oc, err := oclient.New(opts)") g.errIfNil() g.writeLn("c = &client{Client: oc, codec: opts.Codec, callTimeout: opts.CallTimeout, streamInitTimeout: opts.StreamInitTimeout, " + @@ -159,7 +161,9 @@ func (g *generator) genServiceStruct(calls []*ast.Call, streams []*ast.Stream, e g.writeLn("") // Generate the constructor. - g.writeLn("func NewService(h ServiceHandler, opts *oservice.Options) (s Service, err error) {") + g.writeLn("func NewService(h ServiceHandler, opts oservice.Options) (s Service, err error) {") + g.writeLn("err = options.SetDefaults(&opts, oservice.DefaultOptions())") + g.errIfNil() g.writeLn("os, err := oservice.New(opts)") g.errIfNil() g.writeLn("srvc := &service{Service: os, h: h, codec: opts.Codec, maxArgSize: opts.MaxArgSize, maxRetSize:opts.MaxRetSize}") diff --git a/pkg/client/client.go b/pkg/client/client.go index efd71d4..60ab748 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -33,6 +33,7 @@ import ( "sync" "github.com/desertbit/closer/v3" + "github.com/desertbit/options" "github.com/desertbit/orbit/pkg/transport" "github.com/rs/zerolog" ) @@ -94,7 +95,7 @@ type Client interface { type client struct { closer.Closer - opts *Options + opts Options log *zerolog.Logger hooks Hooks stateChan chan State @@ -104,9 +105,13 @@ type client struct { connectSessionChan chan chan interface{} } -func New(opts *Options) (Client, error) { - opts.setDefaults() - err := opts.validate() +func New(opts Options) (Client, error) { + err := options.SetDefaults(&opts, DefaultOptions()) + if err != nil { + return nil, err + } + + err = opts.validate() if err != nil { return nil, err } diff --git a/pkg/client/options.go b/pkg/client/options.go index 101ec57..829af9f 100644 --- a/pkg/client/options.go +++ b/pkg/client/options.go @@ -39,22 +39,7 @@ import ( "github.com/rs/zerolog" ) -const ( - defaultCallTimeout = 30 * time.Second - defaultConnectTimeout = 10 * time.Second - defaultConnectThrottleDuration = 2 * time.Second - defaultHandshakeTimeout = 7 * time.Second - defaultStreamInitTimeout = 10 * time.Second - - defaultMaxArgSize = 4 * 1024 * 1024 // 4 MB - defaultMaxRetSize = 4 * 1024 * 1024 // 4 MB - defaultMaxHeaderSize = 500 * 1024 // 500 KB -) - type Options struct { - // Host specifies the destination host address. This value must be set. - Host string - // Transport specifies the communication backend. This value must be set. Transport transport.Transport @@ -102,50 +87,32 @@ type Options struct { MaxHeaderSize int } -func (o *Options) setDefaults() { - if o.Closer == nil { - o.Closer = closer.New() - } - if o.Codec == nil { - o.Codec = msgpack.Codec - } - if o.Log == nil { - l := zerolog.New(zerolog.ConsoleWriter{ - Out: os.Stderr, - TimeFormat: time.RFC3339, - }).With().Timestamp().Str("component", "orbit").Logger() - o.Log = &l - } - if o.CallTimeout == 0 { - o.CallTimeout = defaultCallTimeout - } - if o.ConnectTimeout == 0 { - o.ConnectTimeout = defaultConnectTimeout - } - if o.ConnectThrottleDuration == 0 { - o.ConnectThrottleDuration = defaultConnectThrottleDuration - } - if o.HandshakeTimeout == 0 { - o.HandshakeTimeout = defaultHandshakeTimeout - } - if o.StreamInitTimeout == 0 { - o.StreamInitTimeout = defaultStreamInitTimeout - } - if o.MaxArgSize == 0 { - o.MaxArgSize = defaultMaxArgSize - } - if o.MaxRetSize == 0 { - o.MaxRetSize = defaultMaxRetSize - } - if o.MaxHeaderSize == 0 { - o.MaxHeaderSize = defaultMaxHeaderSize +func DefaultOptions() Options { + return Options{ + Closer: closer.New(), + Codec: msgpack.Codec, + Log: defaultLogger(), + CallTimeout: 30 * time.Second, + ConnectTimeout: 10 * time.Second, + ConnectThrottleDuration: 2 * time.Second, + HandshakeTimeout: 7 * time.Second, + StreamInitTimeout: 10 * time.Second, + MaxArgSize: 4 * 1024 * 1024, // 4 MB + MaxRetSize: 4 * 1024 * 1024, // 4 MB + MaxHeaderSize: 500 * 1024, // 500 KB } } +func defaultLogger() *zerolog.Logger { + l := zerolog.New(zerolog.ConsoleWriter{ + Out: os.Stderr, + TimeFormat: time.RFC3339, + }).With().Timestamp().Str("component", "orbit").Logger() + return &l +} + func (o *Options) validate() error { - if o.Host == "" { - return errors.New("empty host") - } else if o.Transport == nil { + if o.Transport == nil { return errors.New("no transport set") } return nil diff --git a/pkg/client/session.go b/pkg/client/session.go index 7f47078..bc4ac52 100644 --- a/pkg/client/session.go +++ b/pkg/client/session.go @@ -91,12 +91,12 @@ func (s *session) RemoteAddr() net.Addr { return s.conn.RemoteAddr() } -func connectSession(h clientHandler, opts *Options) (s *session, err error) { +func connectSession(h clientHandler, opts Options) (s *session, err error) { ctxConnect, cancelConnect := context.WithTimeout(context.Background(), opts.ConnectTimeout) defer cancelConnect() // Connect to the service. - conn, err := opts.Transport.Dial(opts.Closer.CloserOneWay(), ctxConnect, opts.Host) + conn, err := opts.Transport.Dial(opts.Closer.CloserOneWay(), ctxConnect) if err != nil { return } diff --git a/pkg/service/options.go b/pkg/service/options.go index 936efe2..3d66b84 100644 --- a/pkg/service/options.go +++ b/pkg/service/options.go @@ -39,21 +39,7 @@ import ( "github.com/rs/zerolog" ) -const ( - defaultCallTimeout = 30 * time.Second - defaultHandshakeTimeout = 7 * time.Second - defaultAcceptConnWorkers = 5 - defaultSessionIDLen = 32 - - defaultMaxArgSize = 4 * 1024 * 1024 // 4 MB - defaultMaxRetSize = 4 * 1024 * 1024 // 4 MB - defaultMaxHeaderSize = 500 * 1024 // 500 KB -) - type Options struct { - // ListenAddr specifies the listen address for the server. This value is passed to the transport backend. - ListenAddr string - // Transport specifies the communication backend. This value must be set. Transport transport.Transport @@ -101,47 +87,31 @@ type Options struct { MaxHeaderSize int } -func (o *Options) setDefaults() { - if o.Closer == nil { - o.Closer = closer.New() - } - if o.Codec == nil { - o.Codec = msgpack.Codec - } - if o.Log == nil { - l := zerolog.New(zerolog.ConsoleWriter{ - Out: os.Stderr, - TimeFormat: time.RFC3339, - }).With().Timestamp().Str("component", "orbit").Logger() - o.Log = &l - } - if o.CallTimeout == 0 { - o.CallTimeout = defaultCallTimeout - } - if o.HandshakeTimeout == 0 { - o.HandshakeTimeout = defaultHandshakeTimeout - } - if o.AcceptConnWorkers == 0 { - o.AcceptConnWorkers = defaultAcceptConnWorkers - } - if o.SessionIDLen == 0 { - o.SessionIDLen = defaultSessionIDLen - } - if o.MaxArgSize == 0 { - o.MaxArgSize = defaultMaxArgSize - } - if o.MaxRetSize == 0 { - o.MaxRetSize = defaultMaxRetSize - } - if o.MaxHeaderSize == 0 { - o.MaxHeaderSize = defaultMaxHeaderSize +func DefaultOptions() Options { + return Options{ + Closer: closer.New(), + Codec: msgpack.Codec, + Log: defaultLogger(), + CallTimeout: 30 * time.Second, + HandshakeTimeout: 7 * time.Second, + AcceptConnWorkers: 5, + SessionIDLen: 32, + MaxArgSize: 4 * 1024 * 1024, // 4 MB + MaxRetSize: 4 * 1024 * 1024, // 4 MB + MaxHeaderSize: 500 * 1024, // 500 KB } } +func defaultLogger() *zerolog.Logger { + l := zerolog.New(zerolog.ConsoleWriter{ + Out: os.Stderr, + TimeFormat: time.RFC3339, + }).With().Timestamp().Str("component", "orbit").Logger() + return &l +} + func (o *Options) validate() error { - if o.ListenAddr == "" { - return errors.New("empty listen address") - } else if o.Transport == nil { + if o.Transport == nil { return errors.New("no transport set") } return nil diff --git a/pkg/service/service.go b/pkg/service/service.go index 1f49e56..9eafa0e 100644 --- a/pkg/service/service.go +++ b/pkg/service/service.go @@ -32,6 +32,7 @@ import ( "time" "github.com/desertbit/closer/v3" + "github.com/desertbit/options" "github.com/desertbit/orbit/pkg/codec" "github.com/desertbit/orbit/pkg/transport" "github.com/rs/zerolog" @@ -128,7 +129,7 @@ type Service interface { type service struct { closer.Closer - opts *Options + opts Options codec codec.Codec log *zerolog.Logger hooks Hooks @@ -143,9 +144,14 @@ type service struct { asyncCallOpts map[string]asyncCallOptions // Key: callID } -func New(opts *Options) (Service, error) { - opts.setDefaults() - err := opts.validate() +func New(opts Options) (Service, error) { + // Set default values. + err := options.SetDefaults(&opts, DefaultOptions()) + if err != nil { + return nil, err + } + + err = opts.validate() if err != nil { return nil, err } @@ -173,12 +179,12 @@ func (s *service) Run() (err error) { defer s.Close_() // Open a listener with the transport. - ln, err := s.opts.Transport.Listen(s.CloserTwoWay(), s.opts.ListenAddr) + ln, err := s.opts.Transport.Listen(s.CloserTwoWay()) if err != nil { return } - s.log.Info().Str("listenAddr", s.opts.ListenAddr).Msg("service listening") + s.log.Info().Str("listenAddr", ln.Addr().String()).Msg("service listening") var ( conn transport.Conn diff --git a/pkg/service/session.go b/pkg/service/session.go index 1012529..c1d58d8 100644 --- a/pkg/service/session.go +++ b/pkg/service/session.go @@ -96,7 +96,7 @@ func initSession( conn transport.Conn, id string, h serviceHandler, - opts *Options, + opts Options, ) (s *session, err error) { // Close connection on error. defer func() { diff --git a/pkg/transport/mux/conn.go b/pkg/transport/mux/conn.go new file mode 100644 index 0000000..62f0212 --- /dev/null +++ b/pkg/transport/mux/conn.go @@ -0,0 +1,103 @@ +/* + * ORBIT - Interlink Remote Applications + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Roland Singer + * Copyright (c) 2020 Sebastian Borchers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package mux + +import ( + "context" + "errors" + "fmt" + "time" + + "github.com/desertbit/orbit/pkg/packet" + ot "github.com/desertbit/orbit/pkg/transport" +) + +// conn is a transport.Conn that takes care of sending the serviceID first, +// when opening a new stream. +type conn struct { + ot.Conn + + // Client + serviceID []byte + initTimeout time.Duration + // Server + streamChan <-chan ot.Stream +} + +func newConn(tc ot.Conn, serviceID string, initTimeout time.Duration, streamChan <-chan ot.Stream) *conn { + return &conn{ + Conn: tc, + serviceID: []byte(serviceID), + initTimeout: initTimeout, + streamChan: streamChan, + } +} + +// Implements the transport.Conn interface. +func (c *conn) OpenStream(ctx context.Context) (stream ot.Stream, err error) { + stream, err = c.Conn.OpenStream(ctx) + if err != nil { + err = fmt.Errorf("failed to open stream: %v", err) + return + } + + if c.initTimeout > 0 { + err = stream.SetWriteDeadline(time.Now().Add(c.initTimeout)) + if err != nil { + err = fmt.Errorf("failed to set read deadline: %v", err) + return + } + } + + // Send the service id first. + err = packet.Write(stream, c.serviceID, maxServiceIDSize) + if err != nil { + err = fmt.Errorf("failed to send service id: %v", err) + return + } + + // Reset deadline. + if c.initTimeout > 0 { + err = stream.SetWriteDeadline(time.Time{}) + if err != nil { + return + } + } + + return +} + +// Implements the transport.Conn interface. +func (c *conn) AcceptStream(ctx context.Context) (stream ot.Stream, err error) { + select { + case <-c.ClosingChan(): + err = errors.New("closed") + case stream = <-c.streamChan: + } + return +} diff --git a/pkg/transport/mux/listener.go b/pkg/transport/mux/listener.go new file mode 100644 index 0000000..ee59359 --- /dev/null +++ b/pkg/transport/mux/listener.go @@ -0,0 +1,69 @@ +/* + * ORBIT - Interlink Remote Applications + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Roland Singer + * Copyright (c) 2020 Sebastian Borchers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package mux + +import ( + "errors" + "net" + + "github.com/desertbit/closer/v3" + ot "github.com/desertbit/orbit/pkg/transport" +) + +// listener is a transport.Listener that accepts new connections via a +// go channel instead of listening on a socket itself. +type listener struct { + closer.Closer + + connChan chan ot.Conn + + addr net.Addr +} + +func newListener(cl closer.Closer, connChan chan ot.Conn, addr net.Addr) ot.Listener { + return &listener{ + Closer: cl, + connChan: connChan, + addr: addr, + } +} + +// Implements the transport.Listener interface. +func (ln *listener) Accept() (conn ot.Conn, err error) { + select { + case <-ln.ClosingChan(): + err = errors.New("closed") + case conn = <-ln.connChan: + } + return +} + +// Implements the transport.Listener interface. +func (ln *listener) Addr() net.Addr { + return ln.addr +} diff --git a/pkg/transport/mux/mux.go b/pkg/transport/mux/mux.go new file mode 100644 index 0000000..d8baa36 --- /dev/null +++ b/pkg/transport/mux/mux.go @@ -0,0 +1,258 @@ +/* + * ORBIT - Interlink Remote Applications + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Roland Singer + * Copyright (c) 2020 Sebastian Borchers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package mux + +import ( + "context" + "fmt" + "net" + "sync" + "time" + + "github.com/desertbit/closer/v3" + "github.com/desertbit/options" + "github.com/desertbit/orbit/pkg/packet" + ot "github.com/desertbit/orbit/pkg/transport" + "github.com/rs/zerolog/log" +) + +const ( + maxServiceIDSize = 128 +) + +// Mux is a wrapper around a transport.Transport and offers custom +// dial and listen methods, which allow to differentiate between +// multiple services, effectively enabling multiplexing multiple services +// over a single transport. +type Mux struct { + tr ot.Transport + + opts Options + + mx sync.Mutex + // Client + dialConn ot.Conn + // Server + isListening bool + listenAddr net.Addr + services map[string]*service +} + +// small helper struct representing a registered service. +type service struct { + connChan chan ot.Conn // listener channel. + streamChan chan ot.Stream // conn channel. +} + +// New creates a new multiplexer wrapping the given transport. +// In order to use the Mux as a transport.Transport, call Mux.Transport +// with a suitable serviceID. +func New(tr ot.Transport, opts Options) (*Mux, error) { + // Set default values, where needed. + err := options.SetDefaults(&opts, DefaultOptions()) + if err != nil { + return nil, err + } + + return &Mux{ + tr: tr, + opts: opts, + services: make(map[string]*service), + }, nil +} + +// Transport returns a small transport.Transport using m as its multiplexer. +func (m *Mux) Transport(serviceID string) ot.Transport { + return newTransport(m, serviceID) +} + +func (m *Mux) dial(cl closer.Closer, ctx context.Context, serviceID string) (conn ot.Conn, err error) { + // Establish a basic connection, if not yet done. + m.mx.Lock() + if m.dialConn == nil { + m.dialConn, err = m.tr.Dial(cl, ctx) + if err != nil { + m.mx.Unlock() + return + } + } + m.mx.Unlock() + + // Create a new mux.Conn with it. + conn = newConn(m.dialConn, serviceID, m.opts.InitTimeout, nil) + + return +} + +func (m *Mux) listen(cl closer.Closer, serviceID string) (ot.Listener, error) { + m.mx.Lock() + defer m.mx.Unlock() + + if !m.isListening { + // Create our listener. + ln, err := m.tr.Listen(cl) + if err != nil { + return nil, err + } + + go m.listenRoutine(ln) + + m.isListening = true + m.listenAddr = ln.Addr() + } + + // Check, if the service has been registered already. + if _, ok := m.services[serviceID]; ok { + return nil, fmt.Errorf("serviceID '%s' registered twice", serviceID) + } + + // Create a new service listener. + connChan := make(chan ot.Conn, 3) + ln := newListener(cl, connChan, m.listenAddr) + m.services[serviceID] = &service{connChan: connChan} + + return ln, nil +} + +func (m *Mux) listenRoutine(ln ot.Listener) { + var ( + conn ot.Conn + err error + ) + + ctx, cancel := ln.Context() + defer cancel() + + // Wait for incoming connections and pass them to our routine. + for { + conn, err = ln.Accept() + if err != nil { + if !ln.IsClosing() { + log.Error().Err(err).Msg("listenRoutine: accept") + } + return + } + + go m.acceptStreamRoutine(ctx, conn) + } +} + +func (m *Mux) acceptStreamRoutine(ctx context.Context, conn ot.Conn) { + defer conn.Close_() + + var ( + stream ot.Stream + err error + ) + + // Wait for incoming streams on the connection and handle them. + for { + stream, err = conn.AcceptStream(ctx) + if err != nil { + if !conn.IsClosing() && !conn.IsClosedError(err) { + log.Error().Err(err).Msg("mux.transport: failed to accept stream") + } + return + } + + go func() { + err = m.handleStream(conn, stream) + if err != nil { + log.Error().Err(err).Msg("mux.transport: failed to handle stream") + } + }() + } +} + +// handleStream reads the serviceID off of the given stream, before forwarding it to +// the respective service. +// If its the first stream of the given conn, a new mux conn is properly initialized +// and sent to the service's listener. +func (m *Mux) handleStream(conn ot.Conn, stream ot.Stream) (err error) { + defer func() { + if err != nil { + _ = stream.Close() + } + }() + + if m.opts.InitTimeout > 0 { + err = stream.SetReadDeadline(time.Now().Add(m.opts.InitTimeout)) + if err != nil { + return fmt.Errorf("failed to set read deadline: %v", err) + } + } + + // Read the service id. + idBuf := make([]byte, maxServiceIDSize) + data, err := packet.Read(stream, idBuf, maxServiceIDSize) + if err != nil { + return + } + serviceID := string(data) + + // Reset deadline. + if m.opts.InitTimeout > 0 { + err = stream.SetReadDeadline(time.Time{}) + if err != nil { + return + } + } + + var ( + srv *service + ok bool + ) + + m.mx.Lock() + defer m.mx.Unlock() + + // Check, if the service has been registered. + srv, ok = m.services[serviceID] + if !ok { + return fmt.Errorf("service '%s' has not been registered", serviceID) + } else if srv.streamChan == nil { + // Create the mux conn and send it to the service once. + srv.streamChan = make(chan ot.Stream, 3) + mc := newConn(conn, "", 0, srv.streamChan) + + select { + case <-conn.ClosingChan(): + return + case srv.connChan <- mc: + } + } + + // Pass the new stream to the service. + select { + case <-conn.ClosingChan(): + return + case srv.streamChan <- stream: + } + + return +} diff --git a/pkg/transport/mux/options.go b/pkg/transport/mux/options.go new file mode 100644 index 0000000..66ac142 --- /dev/null +++ b/pkg/transport/mux/options.go @@ -0,0 +1,46 @@ +/* + * ORBIT - Interlink Remote Applications + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Roland Singer + * Copyright (c) 2020 Sebastian Borchers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package mux + +import ( + "time" +) + +// Options allows to configure the transport. +type Options struct { + // InitTimeout specifies the duration the initial exchange of the transport value may take. + // 0 means a default timeout is used automatically, -1 disables it. + InitTimeout time.Duration +} + +// DefaultOptions returns an Options struct with default values set. +func DefaultOptions() Options { + return Options{ + InitTimeout: 15 * time.Second, + } +} diff --git a/pkg/transport/mux/transport.go b/pkg/transport/mux/transport.go new file mode 100644 index 0000000..ae07fc5 --- /dev/null +++ b/pkg/transport/mux/transport.go @@ -0,0 +1,60 @@ +/* + * ORBIT - Interlink Remote Applications + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Roland Singer + * Copyright (c) 2020 Sebastian Borchers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package mux + +import ( + "context" + + "github.com/desertbit/closer/v3" + ot "github.com/desertbit/orbit/pkg/transport" +) + +// transport is a tiny transport.Transport, which simply combines the given +// mux with the serviceID. +// This is the actual transport being used. +type transport struct { + mux *Mux + serviceID string +} + +func newTransport(m *Mux, serviceID string) ot.Transport { + return &transport{ + mux: m, + serviceID: serviceID, + } +} + +// Implements the transport.Transport interface. +func (t *transport) Dial(cl closer.Closer, ctx context.Context) (ot.Conn, error) { + return t.mux.dial(cl, ctx, t.serviceID) +} + +// Implements the transport.Transport interface. +func (t *transport) Listen(cl closer.Closer) (ot.Listener, error) { + return t.mux.listen(cl, t.serviceID) +} diff --git a/pkg/transport/quic/options.go b/pkg/transport/quic/options.go index ef5049e..a9df0aa 100644 --- a/pkg/transport/quic/options.go +++ b/pkg/transport/quic/options.go @@ -35,17 +35,14 @@ import ( quic "github.com/lucas-clemente/quic-go" ) -var ( - defaultConfig = &quic.Config{ - HandshakeTimeout: 10 * time.Second, - MaxIdleTimeout: 30 * time.Second, - MaxReceiveStreamFlowControlWindow: 6 * 1024 * 1024, // 6MB - MaxReceiveConnectionFlowControlWindow: 15 * 1024 * 1024, // 15MB - KeepAlive: true, - } -) - +// Options allows to configure the transport. type Options struct { + // TODO: + ListenAddr string + + // TODO: + DialAddr string + // TODO: Config *quic.Config @@ -53,13 +50,24 @@ type Options struct { TLSConfig *tls.Config } -func (o *Options) setDefaults() { - if o.Config == nil { - o.Config = defaultConfig +// DefaultOptions returns an Options struct with default values set. +func DefaultOptions() Options { + return Options{ + Config: &quic.Config{ + HandshakeTimeout: 10 * time.Second, + MaxIdleTimeout: 30 * time.Second, + MaxReceiveStreamFlowControlWindow: 6 * 1024 * 1024, // 6MB + MaxReceiveConnectionFlowControlWindow: 15 * 1024 * 1024, // 15MB + KeepAlive: true, + }, } } -func (o *Options) validate() (err error) { +// validate checks if o contains sane values. +func (o Options) validate() (err error) { + if o.ListenAddr == "" && o.DialAddr == "" { + return errors.New("listen and dial address not set") + } if o.TLSConfig == nil { return errors.New("tls config must not be nil") } diff --git a/pkg/transport/quic/transport.go b/pkg/transport/quic/transport.go index e4afa30..7dc9508 100644 --- a/pkg/transport/quic/transport.go +++ b/pkg/transport/quic/transport.go @@ -31,17 +31,22 @@ import ( "context" "github.com/desertbit/closer/v3" - "github.com/desertbit/orbit/pkg/transport" + "github.com/desertbit/options" + ot "github.com/desertbit/orbit/pkg/transport" quic "github.com/lucas-clemente/quic-go" ) type qTransport struct { - opts *Options + opts Options } -func NewTransport(opts *Options) (t transport.Transport, err error) { - // Set the default options. - opts.setDefaults() +// NewTransport returns a transport.Transport using the QUIC protocol. +func NewTransport(opts Options) (t ot.Transport, err error) { + // Set default values, where needed. + err = options.SetDefaults(&opts, DefaultOptions()) + if err != nil { + return + } // Validate the options. err = opts.validate() @@ -54,9 +59,10 @@ func NewTransport(opts *Options) (t transport.Transport, err error) { return } -func (q *qTransport) Dial(cl closer.Closer, ctx context.Context, addr string) (transport.Conn, error) { +// Implements the transport.Transport interface. +func (q *qTransport) Dial(cl closer.Closer, ctx context.Context) (ot.Conn, error) { // Create a quic connection. - qs, err := quic.DialAddrContext(ctx, addr, q.opts.TLSConfig, q.opts.Config) + qs, err := quic.DialAddrContext(ctx, q.opts.DialAddr, q.opts.TLSConfig, q.opts.Config) if err != nil { return nil, err } @@ -65,9 +71,10 @@ func (q *qTransport) Dial(cl closer.Closer, ctx context.Context, addr string) (t return newSession(cl, qs) } -func (q *qTransport) Listen(cl closer.Closer, addr string) (transport.Listener, error) { +// Implements the transport.Transport interface. +func (q *qTransport) Listen(cl closer.Closer) (ot.Listener, error) { // Create the quic listener. - ln, err := quic.ListenAddr(addr, q.opts.TLSConfig, q.opts.Config) + ln, err := quic.ListenAddr(q.opts.ListenAddr, q.opts.TLSConfig, q.opts.Config) if err != nil { return nil, err } diff --git a/pkg/transport/transport.go b/pkg/transport/transport.go index 8dbd042..2011424 100644 --- a/pkg/transport/transport.go +++ b/pkg/transport/transport.go @@ -35,8 +35,8 @@ import ( ) type Transport interface { - Dial(cl closer.Closer, ctx context.Context, addr string) (Conn, error) - Listen(cl closer.Closer, addr string) (Listener, error) + Dial(cl closer.Closer, ctx context.Context) (Conn, error) + Listen(cl closer.Closer) (Listener, error) } type Conn interface { diff --git a/pkg/transport/yamux/options.go b/pkg/transport/yamux/options.go index 4392694..f3c5fd5 100644 --- a/pkg/transport/yamux/options.go +++ b/pkg/transport/yamux/options.go @@ -29,6 +29,7 @@ package yamux import ( "crypto/tls" + "errors" "os" "time" @@ -36,18 +37,14 @@ import ( "github.com/rs/zerolog" ) -var ( - defaultConfig = &yamux.Config{ - AcceptBacklog: 256, - EnableKeepAlive: true, - KeepAliveInterval: 30 * time.Second, - ConnectionWriteTimeout: 10 * time.Second, - MaxStreamWindowSize: 256 * 1024, - LogOutput: defaultLogger(), - } -) - +// Options allows to configure the transport. type Options struct { + // TODO: + ListenAddr string + + // TODO: + DialAddr string + // TODO: Config *yamux.Config @@ -56,13 +53,24 @@ type Options struct { TLSConfig *tls.Config } -func (o *Options) setDefaults() { - if o.Config == nil { - o.Config = defaultConfig +// DefaultOptions returns an Options struct with default values set. +func DefaultOptions() Options { + return Options{ + Config: &yamux.Config{ + AcceptBacklog: 256, + EnableKeepAlive: true, + KeepAliveInterval: 30 * time.Second, + ConnectionWriteTimeout: 10 * time.Second, + MaxStreamWindowSize: 256 * 1024, + LogOutput: defaultLogger(), + }, } } -func (o *Options) validate() (err error) { +func (o Options) validate() (err error) { + if o.ListenAddr == "" && o.DialAddr == "" { + return errors.New("listen and dial address not set") + } err = yamux.VerifyConfig(o.Config) if err != nil { return diff --git a/pkg/transport/yamux/transport.go b/pkg/transport/yamux/transport.go index 7ca6e18..ba10e46 100644 --- a/pkg/transport/yamux/transport.go +++ b/pkg/transport/yamux/transport.go @@ -33,16 +33,21 @@ import ( "net" "github.com/desertbit/closer/v3" + "github.com/desertbit/options" "github.com/desertbit/orbit/pkg/transport" ) type yTransport struct { - opts *Options + opts Options } -func NewTransport(opts *Options) (t transport.Transport, err error) { - // Set the default options. - opts.setDefaults() +// NewTransport returns a transport.Transport using the yamux protocol. +func NewTransport(opts Options) (t transport.Transport, err error) { + // Set default values, where needed. + err = options.SetDefaults(&opts, DefaultOptions()) + if err != nil { + return + } // Validate the options. err = opts.validate() @@ -55,15 +60,14 @@ func NewTransport(opts *Options) (t transport.Transport, err error) { return } -func (t *yTransport) Dial(cl closer.Closer, ctx context.Context, addr string) (tc transport.Conn, err error) { +// Implements the transport.Transport interface. +func (t *yTransport) Dial(cl closer.Closer, ctx context.Context) (tc transport.Conn, err error) { // Open the connection. var conn net.Conn if t.opts.TLSConfig != nil { - // TODO: Cancel is deprecated, remove once https://github.com/golang/go/issues/18482 is merged and replace with DialContext. - dl := &net.Dialer{Cancel: ctx.Done()} - conn, err = tls.DialWithDialer(dl, "tcp", addr, t.opts.TLSConfig) + conn, err = (&tls.Dialer{Config: t.opts.TLSConfig}).DialContext(ctx, "tcp", t.opts.DialAddr) } else { - conn, err = (&net.Dialer{}).DialContext(ctx, "tcp", addr) + conn, err = (&net.Dialer{}).DialContext(ctx, "tcp", t.opts.DialAddr) } if err != nil { return @@ -72,13 +76,14 @@ func (t *yTransport) Dial(cl closer.Closer, ctx context.Context, addr string) (t return newSession(cl, conn, false, t.opts.Config) } -func (t *yTransport) Listen(cl closer.Closer, addr string) (tl transport.Listener, err error) { +// Implements the transport.Transport interface. +func (t *yTransport) Listen(cl closer.Closer) (tl transport.Listener, err error) { // Create the listener. var ln net.Listener if t.opts.TLSConfig != nil { - ln, err = tls.Listen("tcp", addr, t.opts.TLSConfig) + ln, err = tls.Listen("tcp", t.opts.ListenAddr, t.opts.TLSConfig) } else { - ln, err = net.Listen("tcp", addr) + ln, err = net.Listen("tcp", t.opts.ListenAddr) } if err != nil { return