From f65694670e4c937af297e61eff798c623500c13e Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 17 Jun 2019 20:05:58 +0100 Subject: [PATCH 001/287] add cruft --- client/grpc/codec.go | 89 ++++++++++++++++++++++++++++++++++++++++++++ client/grpc/grpc.go | 13 ++++++- server/grpc/codec.go | 23 ++++++++++++ server/grpc/grpc.go | 4 +- 4 files changed, 126 insertions(+), 3 deletions(-) diff --git a/client/grpc/codec.go b/client/grpc/codec.go index 4994db70..b5e2a7bc 100644 --- a/client/grpc/codec.go +++ b/client/grpc/codec.go @@ -2,13 +2,16 @@ package grpc import ( "fmt" + "strings" "github.com/golang/protobuf/proto" "github.com/json-iterator/go" "github.com/micro/go-micro/codec" + "github.com/micro/go-micro/codec/bytes" "github.com/micro/go-micro/codec/jsonrpc" "github.com/micro/go-micro/codec/protorpc" "google.golang.org/grpc/encoding" + "google.golang.org/grpc" ) type jsonCodec struct{} @@ -52,7 +55,28 @@ func (w wrapCodec) String() string { return w.Codec.Name() } +func (w wrapCodec) Marshal(v interface{}) ([]byte, error) { + b, ok := v.(*bytes.Frame) + if ok { + return b.Data, nil + } + return w.Codec.Marshal(v) +} + +func (w wrapCodec) Unmarshal(data []byte, v interface{}) error { + b, ok := v.(*bytes.Frame) + if ok { + b.Data = data + return nil + } + return w.Codec.Unmarshal(data, v) +} + func (protoCodec) Marshal(v interface{}) ([]byte, error) { + b, ok := v.(*bytes.Frame) + if ok { + return b.Data, nil + } return proto.Marshal(v.(proto.Message)) } @@ -96,3 +120,68 @@ func (jsonCodec) Unmarshal(data []byte, v interface{}) error { func (jsonCodec) Name() string { return "json" } + +type grpcCodec struct { + // headers + id string + target string + method string + endpoint string + + s grpc.ClientStream + c encoding.Codec +} + +func (g *grpcCodec) ReadHeader(m *codec.Message, mt codec.MessageType) error { + md, err := g.s.Header() + if err != nil { + return err + } + if m == nil { + m = new(codec.Message) + } + if m.Header == nil { + m.Header = make(map[string]string) + } + for k, v := range md { + m.Header[k] = strings.Join(v, ",") + } + m.Id = g.id + m.Target = g.target + m.Method = g.method + m.Endpoint = g.endpoint + return nil +} + +func (g *grpcCodec) ReadBody(v interface{}) error { + frame := &bytes.Frame{} + if err := g.s.RecvMsg(frame); err != nil { + return err + } + return g.c.Unmarshal(frame.Data, v) +} + +func (g *grpcCodec) Write(m *codec.Message, v interface{}) error { + // if we don't have a body + if len(m.Body) == 0 { + b, err := g.c.Marshal(v) + if err != nil { + return err + } + m.Body = b + } + + // create an encoded frame + frame := &bytes.Frame{m.Body} + // write the body using the framing codec + return g.s.SendMsg(frame) +} + +func (g *grpcCodec) Close() error { + return g.s.CloseSend() +} + +func (g *grpcCodec) String() string { + return g.c.Name() +} + diff --git a/client/grpc/grpc.go b/client/grpc/grpc.go index 9ed206c6..ebdbed5a 100644 --- a/client/grpc/grpc.go +++ b/client/grpc/grpc.go @@ -177,7 +177,10 @@ func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client dialCtx, cancel = context.WithCancel(ctx) } defer cancel() - cc, err := grpc.DialContext(dialCtx, address, grpc.WithDefaultCallOptions(grpc.ForceCodec(cf)), g.secure()) + + wc := wrapCodec{cf} + + cc, err := grpc.DialContext(dialCtx, address, grpc.WithDefaultCallOptions(grpc.ForceCodec(wc)), g.secure()) if err != nil { return nil, errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err)) } @@ -193,6 +196,14 @@ func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client return nil, errors.InternalServerError("go.micro.client", fmt.Sprintf("Error creating stream: %v", err)) } + // set request codec + if r, ok := req.(*grpcRequest); ok { + r.codec = &grpcCodec{ + s: st, + c: wc, + } + } + rsp := &response{ conn: cc, stream: st, diff --git a/server/grpc/codec.go b/server/grpc/codec.go index 50a96ef4..681a104f 100644 --- a/server/grpc/codec.go +++ b/server/grpc/codec.go @@ -6,6 +6,7 @@ import ( "github.com/golang/protobuf/proto" "github.com/micro/go-micro/codec" + "github.com/micro/go-micro/codec/bytes" "github.com/micro/go-micro/codec/jsonrpc" "github.com/micro/go-micro/codec/protorpc" "google.golang.org/grpc/encoding" @@ -14,6 +15,7 @@ import ( type jsonCodec struct{} type bytesCodec struct{} type protoCodec struct{} +type wrapCodec struct { encoding.Codec } var ( defaultGRPCCodecs = map[string]encoding.Codec{ @@ -36,6 +38,27 @@ var ( } ) +func (w wrapCodec) String() string { + return w.Codec.Name() +} + +func (w wrapCodec) Marshal(v interface{}) ([]byte, error) { + b, ok := v.(*bytes.Frame) + if ok { + return b.Data, nil + } + return w.Codec.Marshal(v) +} + +func (w wrapCodec) Unmarshal(data []byte, v interface{}) error { + b, ok := v.(*bytes.Frame) + if ok { + b.Data = data + return nil + } + return w.Codec.Unmarshal(data, v) +} + func (protoCodec) Marshal(v interface{}) ([]byte, error) { return proto.Marshal(v.(proto.Message)) } diff --git a/server/grpc/grpc.go b/server/grpc/grpc.go index bde2e4c6..1b330812 100644 --- a/server/grpc/grpc.go +++ b/server/grpc/grpc.go @@ -56,8 +56,8 @@ type grpcServer struct { } func init() { - encoding.RegisterCodec(jsonCodec{}) - encoding.RegisterCodec(bytesCodec{}) + encoding.RegisterCodec(wrapCodec{jsonCodec{}}) + encoding.RegisterCodec(wrapCodec{bytesCodec{}}) } func newGRPCServer(opts ...server.Option) server.Server { From b754c335491a6d583f0c8324b488b35e8cd957aa Mon Sep 17 00:00:00 2001 From: johnson Date: Tue, 18 Jun 2019 17:07:31 +0800 Subject: [PATCH 002/287] grpc message should be able to set --- client/grpc/grpc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/grpc/grpc.go b/client/grpc/grpc.go index 9ed206c6..555fed0e 100644 --- a/client/grpc/grpc.go +++ b/client/grpc/grpc.go @@ -280,7 +280,7 @@ func (g *grpcClient) Options() client.Options { } func (g *grpcClient) NewMessage(topic string, msg interface{}, opts ...client.MessageOption) client.Message { - return newGRPCPublication(topic, msg, "application/octet-stream") + return newGRPCPublication(topic, msg, g.opts.ContentType, opts...) } func (g *grpcClient) NewRequest(service, method string, req interface{}, reqOpts ...client.RequestOption) client.Request { From 97cf2cd7c3b6a21a5201e7e6616847a966a617a8 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 18 Jun 2019 11:04:06 +0100 Subject: [PATCH 003/287] go fmt --- cmd/cmd.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/cmd.go b/cmd/cmd.go index 310aa431..37616312 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -14,8 +14,8 @@ import ( cgrpc "github.com/micro/go-micro/client/grpc" cmucp "github.com/micro/go-micro/client/mucp" "github.com/micro/go-micro/server" - smucp "github.com/micro/go-micro/server/mucp" sgrpc "github.com/micro/go-micro/server/grpc" + smucp "github.com/micro/go-micro/server/mucp" "github.com/micro/go-micro/util/log" // brokers @@ -180,7 +180,7 @@ var ( } DefaultClients = map[string]func(...client.Option) client.Client{ - "rpc": client.NewClient, + "rpc": client.NewClient, "mucp": cmucp.NewClient, "grpc": cgrpc.NewClient, } @@ -200,7 +200,7 @@ var ( } DefaultServers = map[string]func(...server.Option) server.Server{ - "rpc": server.NewServer, + "rpc": server.NewServer, "mucp": smucp.NewServer, "grpc": sgrpc.NewServer, } From 51560009d28187abc976052bed3716c3bf2a0c41 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 18 Jun 2019 11:04:36 +0100 Subject: [PATCH 004/287] go fmt --- proxy/http/http.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/http/http.go b/proxy/http/http.go index ebea885d..61a6fc06 100644 --- a/proxy/http/http.go +++ b/proxy/http/http.go @@ -10,8 +10,8 @@ import ( "net/url" "path" - "github.com/micro/go-micro/errors" "github.com/micro/go-micro/config/options" + "github.com/micro/go-micro/errors" "github.com/micro/go-micro/proxy" "github.com/micro/go-micro/server" ) From ed54384bf497c5c3fe96a27971281275fffa30a0 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 18 Jun 2019 11:56:11 +0100 Subject: [PATCH 005/287] Update network --- network/network.go | 40 ++++--- network/transport/transport.go | 203 --------------------------------- 2 files changed, 21 insertions(+), 222 deletions(-) delete mode 100644 network/transport/transport.go diff --git a/network/network.go b/network/network.go index adeb18cf..be83b8d0 100644 --- a/network/network.go +++ b/network/network.go @@ -1,26 +1,25 @@ -// Package network is an interface for defining a network overlay +// Package network is a package for defining a network overlay package network import ( "github.com/micro/go-micro/config/options" ) +// Network is an interface defining networks or graphs type Network interface { options.Options - // Id of this network - Id() string - // Connect to the network with id - Connect(id string) error + // Id of this node + Id() uint64 + // Connect to a node + Connect(id uint64) (Link, error) // Close the network connection Close() error - // Accept messages + // Accept messages on the network Accept() (*Message, error) - // Send a message + // Send a message to the network Send(*Message) error - // Advertise a service on this network - Advertise(service string) error - // Retrieve list of nodes for a service - Nodes(service string) ([]Node, error) + // Retrieve list of connections + Links() ([]Link, error) } // Node represents a network node @@ -29,16 +28,19 @@ type Node interface { Network } -// Message is a message sent over the network -type Message struct { - // Headers are the routing headers - // e.g Micro-Service, Micro-Endpoint, Micro-Network - // see https://github.com/micro/development/blob/master/protocol.md - Header map[string]string - // Body is the encaspulated payload - Body []byte +// Link is a connection to another node +type Link interface { + // remote node + Node + // length of link which dictates speed + Length() int + // weight of link which dictates curvature + Weight() int } +// Message is the base type for opaque data +type Message []byte + var ( // TODO: set default network DefaultNetwork Network diff --git a/network/transport/transport.go b/network/transport/transport.go deleted file mode 100644 index 60e6a957..00000000 --- a/network/transport/transport.go +++ /dev/null @@ -1,203 +0,0 @@ -// Package transport implements the network as a transport interface -package transport - -import ( - "context" - "time" - - "github.com/micro/go-micro/network" - "github.com/micro/go-micro/transport" - "github.com/micro/go-micro/util/backoff" -) - -type networkKey struct{} - -// Transport is a network transport -type Transport struct { - Network network.Network - options transport.Options -} - -// Socket is a transport socket -type Socket struct { - // The service - Service string - - // Send via Network.Send(Message) - Network network.Network - - // Remote/Local - remote, local string - - // the first message if its a listener - message *network.Message -} - -// Listener is a transport listener -type Listener struct { - // The local service - Service string - - // The network - Network network.Network -} - -func (s *Socket) Local() string { - return s.local -} - -func (s *Socket) Remote() string { - return s.remote -} - -func (s *Socket) Close() error { - // TODO: should it close the network? - return s.Network.Close() -} - -func (t *Transport) Init(opts ...transport.Option) error { - for _, o := range opts { - o(&t.options) - } - return nil -} - -func (t *Transport) Options() transport.Options { - return t.options -} - -func (t *Transport) Dial(service string, opts ...transport.DialOption) (transport.Client, error) { - // TODO: establish pseudo socket? - return &Socket{ - Service: service, - Network: t.Network, - remote: service, - // TODO: local - local: "local", - }, nil -} - -func (t *Transport) Listen(service string, opts ...transport.ListenOption) (transport.Listener, error) { - // TODO specify connect id - if err := t.Network.Connect("micro.mu"); err != nil { - return nil, err - } - - // advertise the service - if err := t.Network.Advertise(service); err != nil { - return nil, err - } - - return &Listener{ - Service: service, - Network: t.Network, - }, nil -} - -func (t *Transport) String() string { - return "network" -} - -func (s *Socket) Send(msg *transport.Message) error { - // TODO: set routing headers? - return s.Network.Send(&network.Message{ - Header: msg.Header, - Body: msg.Body, - }) -} - -func (s *Socket) Recv(msg *transport.Message) error { - if msg == nil { - msg = new(transport.Message) - } - - // return first message - if s.message != nil { - msg.Header = s.message.Header - msg.Body = s.message.Body - s.message = nil - return nil - } - - m, err := s.Network.Accept() - if err != nil { - return err - } - - msg.Header = m.Header - msg.Body = m.Body - return nil -} - -func (l *Listener) Addr() string { - return l.Service -} - -func (l *Listener) Close() error { - return l.Network.Close() -} - -func (l *Listener) Accept(fn func(transport.Socket)) error { - var i int - - for { - msg, err := l.Network.Accept() - if err != nil { - // increment error counter - i++ - - // break if lots of error - if i > 3 { - return err - } - - // otherwise continue - time.Sleep(backoff.Do(i)) - continue - } - - // reset - i = 0 - - // execute in go routine - go fn(&Socket{ - Service: l.Service, - Network: l.Network, - local: l.Service, - // TODO: remote - remote: "remote", - message: msg, - }) - } -} - -// NewTransport returns a new network transport. It assumes the network is already connected -func NewTransport(opts ...transport.Option) transport.Transport { - options := transport.Options{ - Context: context.Background(), - } - - for _, o := range opts { - o(&options) - } - - net, ok := options.Context.Value(networkKey{}).(network.Network) - if !ok { - net = network.DefaultNetwork - } - - return &Transport{ - options: options, - Network: net, - } -} - -// WithNetwork passes in the network -func WithNetwork(n network.Network) transport.Option { - return func(o *transport.Options) { - if o.Context == nil { - o.Context = context.Background() - } - o.Context = context.WithValue(o.Context, networkKey{}, n) - } -} From 6459cdfc21bda7a6385b7c4c0f38caafe08c3997 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 18 Jun 2019 14:42:56 +0100 Subject: [PATCH 006/287] propagate updates to local watchers --- registry/gossip/gossip.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/registry/gossip/gossip.go b/registry/gossip/gossip.go index c8ea457a..932a69e2 100644 --- a/registry/gossip/gossip.go +++ b/registry/gossip/gossip.go @@ -734,6 +734,12 @@ func (g *gossipRegistry) Register(s *registry.Service, opts ...registry.Register notify: nil, }) + // send update to local watchers + g.updates <- &update{ + Update: up, + Service: s, + } + // wait <-time.After(g.interval * 2) @@ -770,6 +776,13 @@ func (g *gossipRegistry) Deregister(s *registry.Service) error { notify: nil, }) + // send update to local watchers + // send update to local watchers + g.updates <- &update{ + Update: up, + Service: s, + } + // wait <-time.After(g.interval * 2) From 7266c62d098d0f927685c45768f97734d6d50db6 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 18 Jun 2019 15:33:31 +0100 Subject: [PATCH 007/287] remove comment --- registry/gossip/gossip.go | 1 - 1 file changed, 1 deletion(-) diff --git a/registry/gossip/gossip.go b/registry/gossip/gossip.go index 932a69e2..45506392 100644 --- a/registry/gossip/gossip.go +++ b/registry/gossip/gossip.go @@ -776,7 +776,6 @@ func (g *gossipRegistry) Deregister(s *registry.Service) error { notify: nil, }) - // send update to local watchers // send update to local watchers g.updates <- &update{ Update: up, From d3a6297b17cb78602875440b62d88971346a0f05 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 18 Jun 2019 18:51:52 +0100 Subject: [PATCH 008/287] Add working grpc proxy config --- client/grpc/codec.go | 29 +-- client/grpc/grpc.go | 20 +- client/grpc/request.go | 20 +- client/grpc/response.go | 10 +- client/proto/client.micro.go | 203 ++++++++++++++++++ client/proto/client.pb.go | 388 +++++++++++++++++++++++++++++++++++ client/proto/client.proto | 30 +++ cmd/cmd.go | 6 +- proxy/grpc/grpc.go | 9 +- proxy/http/http.go | 2 +- proxy/mucp/mucp.go | 2 + server/grpc/codec.go | 87 ++++++-- server/grpc/grpc.go | 29 ++- server/grpc/request.go | 7 +- server/grpc/response.go | 12 +- util/grpc/grpc.go | 17 ++ 16 files changed, 785 insertions(+), 86 deletions(-) create mode 100644 client/proto/client.micro.go create mode 100644 client/proto/client.pb.go create mode 100644 client/proto/client.proto diff --git a/client/grpc/codec.go b/client/grpc/codec.go index b5e2a7bc..62f30384 100644 --- a/client/grpc/codec.go +++ b/client/grpc/codec.go @@ -10,8 +10,8 @@ import ( "github.com/micro/go-micro/codec/bytes" "github.com/micro/go-micro/codec/jsonrpc" "github.com/micro/go-micro/codec/protorpc" - "google.golang.org/grpc/encoding" "google.golang.org/grpc" + "google.golang.org/grpc/encoding" ) type jsonCodec struct{} @@ -123,9 +123,9 @@ func (jsonCodec) Name() string { type grpcCodec struct { // headers - id string - target string - method string + id string + target string + method string endpoint string s grpc.ClientStream @@ -154,27 +154,19 @@ func (g *grpcCodec) ReadHeader(m *codec.Message, mt codec.MessageType) error { } func (g *grpcCodec) ReadBody(v interface{}) error { - frame := &bytes.Frame{} - if err := g.s.RecvMsg(frame); err != nil { - return err + if f, ok := v.(*bytes.Frame); ok { + return g.s.RecvMsg(f) } - return g.c.Unmarshal(frame.Data, v) + return g.s.RecvMsg(v) } func (g *grpcCodec) Write(m *codec.Message, v interface{}) error { // if we don't have a body - if len(m.Body) == 0 { - b, err := g.c.Marshal(v) - if err != nil { - return err - } - m.Body = b + if v != nil { + return g.s.SendMsg(v) } - - // create an encoded frame - frame := &bytes.Frame{m.Body} // write the body using the framing codec - return g.s.SendMsg(frame) + return g.s.SendMsg(&bytes.Frame{m.Body}) } func (g *grpcCodec) Close() error { @@ -184,4 +176,3 @@ func (g *grpcCodec) Close() error { func (g *grpcCodec) String() string { return g.c.Name() } - diff --git a/client/grpc/grpc.go b/client/grpc/grpc.go index ebdbed5a..30398b17 100644 --- a/client/grpc/grpc.go +++ b/client/grpc/grpc.go @@ -32,8 +32,9 @@ type grpcClient struct { } func init() { - encoding.RegisterCodec(jsonCodec{}) - encoding.RegisterCodec(bytesCodec{}) + encoding.RegisterCodec(wrapCodec{jsonCodec{}}) + encoding.RegisterCodec(wrapCodec{jsonCodec{}}) + encoding.RegisterCodec(wrapCodec{bytesCodec{}}) } // secure returns the dial option for whether its a secure or insecure connection @@ -129,7 +130,7 @@ func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.R ch := make(chan error, 1) go func() { - err := cc.Invoke(ctx, methodToGRPC(req.Endpoint(), req.Body()), req.Body(), rsp, grpc.ForceCodec(cf)) + err := cc.Invoke(ctx, methodToGRPC(req.Service(), req.Endpoint()), req.Body(), rsp, grpc.ForceCodec(cf)) ch <- microError(err) }() @@ -191,23 +192,26 @@ func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client ServerStreams: true, } - st, err := cc.NewStream(ctx, desc, methodToGRPC(req.Endpoint(), req.Body())) + st, err := cc.NewStream(ctx, desc, methodToGRPC(req.Service(), req.Endpoint())) if err != nil { return nil, errors.InternalServerError("go.micro.client", fmt.Sprintf("Error creating stream: %v", err)) } + codec := &grpcCodec{ + s: st, + c: wc, + } + // set request codec if r, ok := req.(*grpcRequest); ok { - r.codec = &grpcCodec{ - s: st, - c: wc, - } + r.codec = codec } rsp := &response{ conn: cc, stream: st, codec: cf, + gcodec: codec, } return &grpcStream{ diff --git a/client/grpc/request.go b/client/grpc/request.go index cb14a330..94b44da0 100644 --- a/client/grpc/request.go +++ b/client/grpc/request.go @@ -2,7 +2,6 @@ package grpc import ( "fmt" - "reflect" "strings" "github.com/micro/go-micro/client" @@ -18,30 +17,21 @@ type grpcRequest struct { codec codec.Codec } -func methodToGRPC(method string, request interface{}) string { +// service Struct.Method /service.Struct/Method +func methodToGRPC(service, method string) string { // no method or already grpc method if len(method) == 0 || method[0] == '/' { return method } - // can't operate on nil request - t := reflect.TypeOf(request) - if t == nil { - return method - } - // dereference - if t.Kind() == reflect.Ptr { - t = t.Elem() - } - // get package name - pParts := strings.Split(t.PkgPath(), "/") - pkg := pParts[len(pParts)-1] + // assume method is Foo.Bar mParts := strings.Split(method, ".") if len(mParts) != 2 { return method } + // return /pkg.Foo/Bar - return fmt.Sprintf("/%s.%s/%s", pkg, mParts[0], mParts[1]) + return fmt.Sprintf("/%s.%s/%s", service, mParts[0], mParts[1]) } func newGRPCRequest(service, method string, request interface{}, contentType string, reqOpts ...client.RequestOption) client.Request { diff --git a/client/grpc/response.go b/client/grpc/response.go index 7ef72241..c870fad9 100644 --- a/client/grpc/response.go +++ b/client/grpc/response.go @@ -4,6 +4,7 @@ import ( "strings" "github.com/micro/go-micro/codec" + "github.com/micro/go-micro/codec/bytes" "google.golang.org/grpc" "google.golang.org/grpc/encoding" ) @@ -12,11 +13,12 @@ type response struct { conn *grpc.ClientConn stream grpc.ClientStream codec encoding.Codec + gcodec codec.Codec } // Read the response func (r *response) Codec() codec.Reader { - return nil + return r.gcodec } // read the header @@ -34,5 +36,9 @@ func (r *response) Header() map[string]string { // Read the undecoded response func (r *response) Read() ([]byte, error) { - return nil, nil + f := &bytes.Frame{} + if err := r.gcodec.ReadBody(f); err != nil { + return nil, err + } + return f.Data, nil } diff --git a/client/proto/client.micro.go b/client/proto/client.micro.go new file mode 100644 index 00000000..d8c9ad88 --- /dev/null +++ b/client/proto/client.micro.go @@ -0,0 +1,203 @@ +// Code generated by protoc-gen-micro. DO NOT EDIT. +// source: micro/go-micro/client/proto/client.proto + +package go_micro_client + +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" +) + +import ( + context "context" + client "github.com/micro/go-micro/client" + server "github.com/micro/go-micro/server" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ client.Option +var _ server.Option + +// Client API for Micro service + +type MicroService interface { + // Call allows a single request to be made + Call(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) + // Stream is a bidirectional stream + Stream(ctx context.Context, opts ...client.CallOption) (Micro_StreamService, error) + // Publish publishes a message and returns an empty Message + Publish(ctx context.Context, in *Message, opts ...client.CallOption) (*Message, error) +} + +type microService struct { + c client.Client + name string +} + +func NewMicroService(name string, c client.Client) MicroService { + if c == nil { + c = client.NewClient() + } + if len(name) == 0 { + name = "go.micro.client" + } + return µService{ + c: c, + name: name, + } +} + +func (c *microService) Call(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) { + req := c.c.NewRequest(c.name, "Micro.Call", in) + out := new(Response) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *microService) Stream(ctx context.Context, opts ...client.CallOption) (Micro_StreamService, error) { + req := c.c.NewRequest(c.name, "Micro.Stream", &Request{}) + stream, err := c.c.Stream(ctx, req, opts...) + if err != nil { + return nil, err + } + return µServiceStream{stream}, nil +} + +type Micro_StreamService interface { + SendMsg(interface{}) error + RecvMsg(interface{}) error + Close() error + Send(*Request) error + Recv() (*Response, error) +} + +type microServiceStream struct { + stream client.Stream +} + +func (x *microServiceStream) Close() error { + return x.stream.Close() +} + +func (x *microServiceStream) SendMsg(m interface{}) error { + return x.stream.Send(m) +} + +func (x *microServiceStream) RecvMsg(m interface{}) error { + return x.stream.Recv(m) +} + +func (x *microServiceStream) Send(m *Request) error { + return x.stream.Send(m) +} + +func (x *microServiceStream) Recv() (*Response, error) { + m := new(Response) + err := x.stream.Recv(m) + if err != nil { + return nil, err + } + return m, nil +} + +func (c *microService) Publish(ctx context.Context, in *Message, opts ...client.CallOption) (*Message, error) { + req := c.c.NewRequest(c.name, "Micro.Publish", in) + out := new(Message) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for Micro service + +type MicroHandler interface { + // Call allows a single request to be made + Call(context.Context, *Request, *Response) error + // Stream is a bidirectional stream + Stream(context.Context, Micro_StreamStream) error + // Publish publishes a message and returns an empty Message + Publish(context.Context, *Message, *Message) error +} + +func RegisterMicroHandler(s server.Server, hdlr MicroHandler, opts ...server.HandlerOption) error { + type micro interface { + Call(ctx context.Context, in *Request, out *Response) error + Stream(ctx context.Context, stream server.Stream) error + Publish(ctx context.Context, in *Message, out *Message) error + } + type Micro struct { + micro + } + h := µHandler{hdlr} + return s.Handle(s.NewHandler(&Micro{h}, opts...)) +} + +type microHandler struct { + MicroHandler +} + +func (h *microHandler) Call(ctx context.Context, in *Request, out *Response) error { + return h.MicroHandler.Call(ctx, in, out) +} + +func (h *microHandler) Stream(ctx context.Context, stream server.Stream) error { + return h.MicroHandler.Stream(ctx, µStreamStream{stream}) +} + +type Micro_StreamStream interface { + SendMsg(interface{}) error + RecvMsg(interface{}) error + Close() error + Send(*Response) error + Recv() (*Request, error) +} + +type microStreamStream struct { + stream server.Stream +} + +func (x *microStreamStream) Close() error { + return x.stream.Close() +} + +func (x *microStreamStream) SendMsg(m interface{}) error { + return x.stream.Send(m) +} + +func (x *microStreamStream) RecvMsg(m interface{}) error { + return x.stream.Recv(m) +} + +func (x *microStreamStream) Send(m *Response) error { + return x.stream.Send(m) +} + +func (x *microStreamStream) Recv() (*Request, error) { + m := new(Request) + if err := x.stream.Recv(m); err != nil { + return nil, err + } + return m, nil +} + +func (h *microHandler) Publish(ctx context.Context, in *Message, out *Message) error { + return h.MicroHandler.Publish(ctx, in, out) +} diff --git a/client/proto/client.pb.go b/client/proto/client.pb.go new file mode 100644 index 00000000..2052f077 --- /dev/null +++ b/client/proto/client.pb.go @@ -0,0 +1,388 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: micro/go-micro/client/proto/client.proto + +package go_micro_client + +import ( + context "context" + fmt "fmt" + proto "github.com/golang/protobuf/proto" + grpc "google.golang.org/grpc" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +type Request struct { + Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` + Endpoint string `protobuf:"bytes,2,opt,name=endpoint,proto3" json:"endpoint,omitempty"` + ContentType string `protobuf:"bytes,3,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"` + Body []byte `protobuf:"bytes,4,opt,name=body,proto3" json:"body,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Request) Reset() { *m = Request{} } +func (m *Request) String() string { return proto.CompactTextString(m) } +func (*Request) ProtoMessage() {} +func (*Request) Descriptor() ([]byte, []int) { + return fileDescriptor_7d733ae29171347b, []int{0} +} + +func (m *Request) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Request.Unmarshal(m, b) +} +func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Request.Marshal(b, m, deterministic) +} +func (m *Request) XXX_Merge(src proto.Message) { + xxx_messageInfo_Request.Merge(m, src) +} +func (m *Request) XXX_Size() int { + return xxx_messageInfo_Request.Size(m) +} +func (m *Request) XXX_DiscardUnknown() { + xxx_messageInfo_Request.DiscardUnknown(m) +} + +var xxx_messageInfo_Request proto.InternalMessageInfo + +func (m *Request) GetService() string { + if m != nil { + return m.Service + } + return "" +} + +func (m *Request) GetEndpoint() string { + if m != nil { + return m.Endpoint + } + return "" +} + +func (m *Request) GetContentType() string { + if m != nil { + return m.ContentType + } + return "" +} + +func (m *Request) GetBody() []byte { + if m != nil { + return m.Body + } + return nil +} + +type Response struct { + Body []byte `protobuf:"bytes,1,opt,name=body,proto3" json:"body,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Response) Reset() { *m = Response{} } +func (m *Response) String() string { return proto.CompactTextString(m) } +func (*Response) ProtoMessage() {} +func (*Response) Descriptor() ([]byte, []int) { + return fileDescriptor_7d733ae29171347b, []int{1} +} + +func (m *Response) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Response.Unmarshal(m, b) +} +func (m *Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Response.Marshal(b, m, deterministic) +} +func (m *Response) XXX_Merge(src proto.Message) { + xxx_messageInfo_Response.Merge(m, src) +} +func (m *Response) XXX_Size() int { + return xxx_messageInfo_Response.Size(m) +} +func (m *Response) XXX_DiscardUnknown() { + xxx_messageInfo_Response.DiscardUnknown(m) +} + +var xxx_messageInfo_Response proto.InternalMessageInfo + +func (m *Response) GetBody() []byte { + if m != nil { + return m.Body + } + return nil +} + +type Message struct { + Topic string `protobuf:"bytes,1,opt,name=topic,proto3" json:"topic,omitempty"` + ContentType string `protobuf:"bytes,2,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"` + Body []byte `protobuf:"bytes,3,opt,name=body,proto3" json:"body,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Message) Reset() { *m = Message{} } +func (m *Message) String() string { return proto.CompactTextString(m) } +func (*Message) ProtoMessage() {} +func (*Message) Descriptor() ([]byte, []int) { + return fileDescriptor_7d733ae29171347b, []int{2} +} + +func (m *Message) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Message.Unmarshal(m, b) +} +func (m *Message) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Message.Marshal(b, m, deterministic) +} +func (m *Message) XXX_Merge(src proto.Message) { + xxx_messageInfo_Message.Merge(m, src) +} +func (m *Message) XXX_Size() int { + return xxx_messageInfo_Message.Size(m) +} +func (m *Message) XXX_DiscardUnknown() { + xxx_messageInfo_Message.DiscardUnknown(m) +} + +var xxx_messageInfo_Message proto.InternalMessageInfo + +func (m *Message) GetTopic() string { + if m != nil { + return m.Topic + } + return "" +} + +func (m *Message) GetContentType() string { + if m != nil { + return m.ContentType + } + return "" +} + +func (m *Message) GetBody() []byte { + if m != nil { + return m.Body + } + return nil +} + +func init() { + proto.RegisterType((*Request)(nil), "go.micro.client.Request") + proto.RegisterType((*Response)(nil), "go.micro.client.Response") + proto.RegisterType((*Message)(nil), "go.micro.client.Message") +} + +func init() { + proto.RegisterFile("micro/go-micro/client/proto/client.proto", fileDescriptor_7d733ae29171347b) +} + +var fileDescriptor_7d733ae29171347b = []byte{ + // 270 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x91, 0x3f, 0x4f, 0xc3, 0x30, + 0x10, 0xc5, 0xeb, 0xfe, 0x4b, 0x39, 0x2a, 0x21, 0x9d, 0x18, 0x4c, 0x06, 0x54, 0x32, 0x65, 0xc1, + 0x45, 0x30, 0x23, 0x86, 0xce, 0x95, 0x50, 0x40, 0xac, 0x28, 0x71, 0x4f, 0xc1, 0x52, 0x6a, 0x9b, + 0xd8, 0xad, 0x94, 0xef, 0xc8, 0x87, 0x42, 0x38, 0x29, 0x45, 0xd0, 0x2e, 0x6c, 0xf7, 0xee, 0x67, + 0xbd, 0x3b, 0xbf, 0x83, 0x74, 0xad, 0x64, 0x6d, 0xe6, 0xa5, 0xb9, 0x6e, 0x0b, 0x59, 0x29, 0xd2, + 0x7e, 0x6e, 0x6b, 0xe3, 0x77, 0x42, 0x04, 0x81, 0x67, 0xa5, 0x11, 0xe1, 0x8d, 0x68, 0xdb, 0xc9, + 0x16, 0xa2, 0x8c, 0xde, 0x37, 0xe4, 0x3c, 0x72, 0x88, 0x1c, 0xd5, 0x5b, 0x25, 0x89, 0xb3, 0x19, + 0x4b, 0x4f, 0xb2, 0x9d, 0xc4, 0x18, 0x26, 0xa4, 0x57, 0xd6, 0x28, 0xed, 0x79, 0x3f, 0xa0, 0x6f, + 0x8d, 0x57, 0x30, 0x95, 0x46, 0x7b, 0xd2, 0xfe, 0xd5, 0x37, 0x96, 0xf8, 0x20, 0xf0, 0xd3, 0xae, + 0xf7, 0xdc, 0x58, 0x42, 0x84, 0x61, 0x61, 0x56, 0x0d, 0x1f, 0xce, 0x58, 0x3a, 0xcd, 0x42, 0x9d, + 0x5c, 0xc2, 0x24, 0x23, 0x67, 0x8d, 0x76, 0x7b, 0xce, 0x7e, 0xf0, 0x17, 0x88, 0x96, 0xe4, 0x5c, + 0x5e, 0x12, 0x9e, 0xc3, 0xc8, 0x1b, 0xab, 0x64, 0xb7, 0x55, 0x2b, 0xfe, 0xcc, 0xed, 0x1f, 0x9f, + 0x3b, 0xd8, 0xfb, 0xde, 0x7e, 0x30, 0x18, 0x2d, 0xbf, 0x02, 0xc0, 0x7b, 0x18, 0x2e, 0xf2, 0xaa, + 0x42, 0x2e, 0x7e, 0x65, 0x22, 0xba, 0x40, 0xe2, 0x8b, 0x03, 0xa4, 0x5d, 0x39, 0xe9, 0xe1, 0x02, + 0xc6, 0x4f, 0xbe, 0xa6, 0x7c, 0xfd, 0x4f, 0x83, 0x94, 0xdd, 0x30, 0x7c, 0x80, 0xe8, 0x71, 0x53, + 0x54, 0xca, 0xbd, 0x1d, 0x70, 0xe9, 0xfe, 0x1f, 0x1f, 0x25, 0x49, 0xaf, 0x18, 0x87, 0xb3, 0xde, + 0x7d, 0x06, 0x00, 0x00, 0xff, 0xff, 0xd3, 0x63, 0x94, 0x1a, 0x02, 0x02, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MicroClient is the client API for Micro service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MicroClient interface { + // Call allows a single request to be made + Call(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) + // Stream is a bidirectional stream + Stream(ctx context.Context, opts ...grpc.CallOption) (Micro_StreamClient, error) + // Publish publishes a message and returns an empty Message + Publish(ctx context.Context, in *Message, opts ...grpc.CallOption) (*Message, error) +} + +type microClient struct { + cc *grpc.ClientConn +} + +func NewMicroClient(cc *grpc.ClientConn) MicroClient { + return µClient{cc} +} + +func (c *microClient) Call(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) { + out := new(Response) + err := c.cc.Invoke(ctx, "/go.micro.client.Micro/Call", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *microClient) Stream(ctx context.Context, opts ...grpc.CallOption) (Micro_StreamClient, error) { + stream, err := c.cc.NewStream(ctx, &_Micro_serviceDesc.Streams[0], "/go.micro.client.Micro/Stream", opts...) + if err != nil { + return nil, err + } + x := µStreamClient{stream} + return x, nil +} + +type Micro_StreamClient interface { + Send(*Request) error + Recv() (*Response, error) + grpc.ClientStream +} + +type microStreamClient struct { + grpc.ClientStream +} + +func (x *microStreamClient) Send(m *Request) error { + return x.ClientStream.SendMsg(m) +} + +func (x *microStreamClient) Recv() (*Response, error) { + m := new(Response) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *microClient) Publish(ctx context.Context, in *Message, opts ...grpc.CallOption) (*Message, error) { + out := new(Message) + err := c.cc.Invoke(ctx, "/go.micro.client.Micro/Publish", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MicroServer is the server API for Micro service. +type MicroServer interface { + // Call allows a single request to be made + Call(context.Context, *Request) (*Response, error) + // Stream is a bidirectional stream + Stream(Micro_StreamServer) error + // Publish publishes a message and returns an empty Message + Publish(context.Context, *Message) (*Message, error) +} + +func RegisterMicroServer(s *grpc.Server, srv MicroServer) { + s.RegisterService(&_Micro_serviceDesc, srv) +} + +func _Micro_Call_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MicroServer).Call(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/go.micro.client.Micro/Call", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MicroServer).Call(ctx, req.(*Request)) + } + return interceptor(ctx, in, info, handler) +} + +func _Micro_Stream_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(MicroServer).Stream(µStreamServer{stream}) +} + +type Micro_StreamServer interface { + Send(*Response) error + Recv() (*Request, error) + grpc.ServerStream +} + +type microStreamServer struct { + grpc.ServerStream +} + +func (x *microStreamServer) Send(m *Response) error { + return x.ServerStream.SendMsg(m) +} + +func (x *microStreamServer) Recv() (*Request, error) { + m := new(Request) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func _Micro_Publish_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Message) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MicroServer).Publish(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/go.micro.client.Micro/Publish", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MicroServer).Publish(ctx, req.(*Message)) + } + return interceptor(ctx, in, info, handler) +} + +var _Micro_serviceDesc = grpc.ServiceDesc{ + ServiceName: "go.micro.client.Micro", + HandlerType: (*MicroServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Call", + Handler: _Micro_Call_Handler, + }, + { + MethodName: "Publish", + Handler: _Micro_Publish_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "Stream", + Handler: _Micro_Stream_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, + Metadata: "micro/go-micro/client/proto/client.proto", +} diff --git a/client/proto/client.proto b/client/proto/client.proto new file mode 100644 index 00000000..b855fa22 --- /dev/null +++ b/client/proto/client.proto @@ -0,0 +1,30 @@ +syntax = "proto3"; + +package go.micro.client; + +// Micro is the micro client interface +service Micro { + // Call allows a single request to be made + rpc Call(Request) returns (Response) {}; + // Stream is a bidirectional stream + rpc Stream(stream Request) returns (stream Response) {}; + // Publish publishes a message and returns an empty Message + rpc Publish(Message) returns (Message) {}; +} + +message Request { + string service = 1; + string endpoint = 2; + string content_type = 3; + bytes body = 4; +} + +message Response { + bytes body = 1; +} + +message Message { + string topic = 1; + string content_type = 2; + bytes body = 3; +} diff --git a/cmd/cmd.go b/cmd/cmd.go index 310aa431..37616312 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -14,8 +14,8 @@ import ( cgrpc "github.com/micro/go-micro/client/grpc" cmucp "github.com/micro/go-micro/client/mucp" "github.com/micro/go-micro/server" - smucp "github.com/micro/go-micro/server/mucp" sgrpc "github.com/micro/go-micro/server/grpc" + smucp "github.com/micro/go-micro/server/mucp" "github.com/micro/go-micro/util/log" // brokers @@ -180,7 +180,7 @@ var ( } DefaultClients = map[string]func(...client.Option) client.Client{ - "rpc": client.NewClient, + "rpc": client.NewClient, "mucp": cmucp.NewClient, "grpc": cgrpc.NewClient, } @@ -200,7 +200,7 @@ var ( } DefaultServers = map[string]func(...server.Option) server.Server{ - "rpc": server.NewServer, + "rpc": server.NewServer, "mucp": smucp.NewServer, "grpc": sgrpc.NewServer, } diff --git a/proxy/grpc/grpc.go b/proxy/grpc/grpc.go index 89f71f8b..afb2453c 100644 --- a/proxy/grpc/grpc.go +++ b/proxy/grpc/grpc.go @@ -9,7 +9,6 @@ import ( "github.com/micro/go-micro/client" "github.com/micro/go-micro/client/grpc" "github.com/micro/go-micro/codec" - "github.com/micro/go-micro/codec/bytes" "github.com/micro/go-micro/config/options" "github.com/micro/go-micro/proxy" "github.com/micro/go-micro/server" @@ -86,14 +85,8 @@ func (p *Proxy) ServeRequest(ctx context.Context, req server.Request, rsp server } } - // read initial request - body, err := req.Read() - if err != nil { - return err - } - // create new request with raw bytes body - creq := p.Client.NewRequest(service, endpoint, &bytes.Frame{body}, client.WithContentType(req.ContentType())) + creq := p.Client.NewRequest(service, endpoint, nil, client.WithContentType(req.ContentType())) // create new stream stream, err := p.Client.Stream(ctx, creq, opts...) diff --git a/proxy/http/http.go b/proxy/http/http.go index ebea885d..61a6fc06 100644 --- a/proxy/http/http.go +++ b/proxy/http/http.go @@ -10,8 +10,8 @@ import ( "net/url" "path" - "github.com/micro/go-micro/errors" "github.com/micro/go-micro/config/options" + "github.com/micro/go-micro/errors" "github.com/micro/go-micro/proxy" "github.com/micro/go-micro/server" ) diff --git a/proxy/mucp/mucp.go b/proxy/mucp/mucp.go index ea239d45..cca97c90 100644 --- a/proxy/mucp/mucp.go +++ b/proxy/mucp/mucp.go @@ -39,6 +39,7 @@ func readLoop(r server.Request, s client.Stream) error { if err == io.EOF { return nil } + if err != nil { return err } @@ -50,6 +51,7 @@ func readLoop(r server.Request, s client.Stream) error { Header: hdr, Body: body, } + // write the raw request err = req.Codec().Write(msg, nil) if err == io.EOF { diff --git a/server/grpc/codec.go b/server/grpc/codec.go index 681a104f..cfa97f92 100644 --- a/server/grpc/codec.go +++ b/server/grpc/codec.go @@ -3,19 +3,22 @@ package grpc import ( "encoding/json" "fmt" + "strings" "github.com/golang/protobuf/proto" "github.com/micro/go-micro/codec" "github.com/micro/go-micro/codec/bytes" "github.com/micro/go-micro/codec/jsonrpc" "github.com/micro/go-micro/codec/protorpc" + "google.golang.org/grpc" "google.golang.org/grpc/encoding" + "google.golang.org/grpc/metadata" ) type jsonCodec struct{} type bytesCodec struct{} type protoCodec struct{} -type wrapCodec struct { encoding.Codec } +type wrapCodec struct{ encoding.Codec } var ( defaultGRPCCodecs = map[string]encoding.Codec{ @@ -39,24 +42,24 @@ var ( ) func (w wrapCodec) String() string { - return w.Codec.Name() + return w.Codec.Name() } func (w wrapCodec) Marshal(v interface{}) ([]byte, error) { - b, ok := v.(*bytes.Frame) - if ok { - return b.Data, nil - } - return w.Codec.Marshal(v) + b, ok := v.(*bytes.Frame) + if ok { + return b.Data, nil + } + return w.Codec.Marshal(v) } func (w wrapCodec) Unmarshal(data []byte, v interface{}) error { - b, ok := v.(*bytes.Frame) - if ok { - b.Data = data - return nil - } - return w.Codec.Unmarshal(data, v) + b, ok := v.(*bytes.Frame) + if ok { + b.Data = data + return nil + } + return w.Codec.Unmarshal(data, v) } func (protoCodec) Marshal(v interface{}) ([]byte, error) { @@ -103,3 +106,61 @@ func (bytesCodec) Unmarshal(data []byte, v interface{}) error { func (bytesCodec) Name() string { return "bytes" } + +type grpcCodec struct { + // headers + id string + target string + method string + endpoint string + + s grpc.ServerStream + c encoding.Codec +} + +func (g *grpcCodec) ReadHeader(m *codec.Message, mt codec.MessageType) error { + md, _ := metadata.FromIncomingContext(g.s.Context()) + if m == nil { + m = new(codec.Message) + } + if m.Header == nil { + m.Header = make(map[string]string) + } + for k, v := range md { + m.Header[k] = strings.Join(v, ",") + } + m.Id = g.id + m.Target = g.target + m.Method = g.method + m.Endpoint = g.endpoint + return nil +} + +func (g *grpcCodec) ReadBody(v interface{}) error { + // caller has requested a frame + if f, ok := v.(*bytes.Frame); ok { + return g.s.RecvMsg(f) + } + return g.s.RecvMsg(v) +} + +func (g *grpcCodec) Write(m *codec.Message, v interface{}) error { + // if we don't have a body + if v != nil { + b, err := g.c.Marshal(v) + if err != nil { + return err + } + m.Body = b + } + // write the body using the framing codec + return g.s.SendMsg(&bytes.Frame{m.Body}) +} + +func (g *grpcCodec) Close() error { + return nil +} + +func (g *grpcCodec) String() string { + return g.c.Name() +} diff --git a/server/grpc/grpc.go b/server/grpc/grpc.go index 1b330812..2f6e1d40 100644 --- a/server/grpc/grpc.go +++ b/server/grpc/grpc.go @@ -56,6 +56,7 @@ type grpcServer struct { } func init() { + encoding.RegisterCodec(wrapCodec{protoCodec{}}) encoding.RegisterCodec(wrapCodec{jsonCodec{}}) encoding.RegisterCodec(wrapCodec{bytesCodec{}}) } @@ -211,14 +212,30 @@ func (g *grpcServer) handler(srv interface{}, stream grpc.ServerStream) error { // process via router if g.opts.Router != nil { - // create a client.Request - request := &rpcRequest{ - service: g.opts.Name, - contentType: ct, - method: fmt.Sprintf("%s.%s", serviceName, methodName), + cc, err := g.newGRPCCodec(ct) + if err != nil { + return errors.InternalServerError("go.micro.server", err.Error()) + } + codec := &grpcCodec{ + method: fmt.Sprintf("%s.%s", serviceName, methodName), + endpoint: fmt.Sprintf("%s.%s", serviceName, methodName), + target: g.opts.Name, + s: stream, + c: cc, } - response := &rpcResponse{} + // create a client.Request + request := &rpcRequest{ + service: mgrpc.ServiceFromMethod(fullMethod), + contentType: ct, + method: fmt.Sprintf("%s.%s", serviceName, methodName), + codec: codec, + } + + response := &rpcResponse{ + header: make(map[string]string), + codec: codec, + } // create a wrapped function handler := func(ctx context.Context, req server.Request, rsp interface{}) error { diff --git a/server/grpc/request.go b/server/grpc/request.go index 951c1a19..617b9a7d 100644 --- a/server/grpc/request.go +++ b/server/grpc/request.go @@ -2,6 +2,7 @@ package grpc import ( "github.com/micro/go-micro/codec" + "github.com/micro/go-micro/codec/bytes" ) type rpcRequest struct { @@ -46,7 +47,11 @@ func (r *rpcRequest) Header() map[string]string { } func (r *rpcRequest) Read() ([]byte, error) { - return r.body, nil + f := &bytes.Frame{} + if err := r.codec.ReadBody(f); err != nil { + return nil, err + } + return f.Data, nil } func (r *rpcRequest) Stream() bool { diff --git a/server/grpc/response.go b/server/grpc/response.go index 451b1f4e..f13ad89c 100644 --- a/server/grpc/response.go +++ b/server/grpc/response.go @@ -1,15 +1,11 @@ package grpc import ( - "net/http" - "github.com/micro/go-micro/codec" - "github.com/micro/go-micro/transport" ) type rpcResponse struct { header map[string]string - socket transport.Socket codec codec.Codec } @@ -24,12 +20,8 @@ func (r *rpcResponse) WriteHeader(hdr map[string]string) { } func (r *rpcResponse) Write(b []byte) error { - if _, ok := r.header["Content-Type"]; !ok { - r.header["Content-Type"] = http.DetectContentType(b) - } - - return r.socket.Send(&transport.Message{ + return r.codec.Write(&codec.Message{ Header: r.header, Body: b, - }) + }, nil) } diff --git a/util/grpc/grpc.go b/util/grpc/grpc.go index b06a0673..59c5a969 100644 --- a/util/grpc/grpc.go +++ b/util/grpc/grpc.go @@ -38,3 +38,20 @@ func ServiceMethod(m string) (string, string, error) { return parts[0], parts[1], nil } + +// ServiceFromMethod returns the service +// /service.Foo/Bar => service +func ServiceFromMethod(m string) string { + if len(m) == 0 { + return m + } + if m[0] != '/' { + return m + } + parts := strings.Split(m, "/") + if len(parts) < 3 { + return m + } + parts = strings.Split(parts[1], ".") + return strings.Join(parts[:len(parts)-1], ".") +} From c0a628d65b024d1c1a95f9e6a0419d356da1e973 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Tue, 18 Jun 2019 21:39:00 +0100 Subject: [PATCH 009/287] Simplified delService code; properly delete service nodes --- registry/gossip/util.go | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/registry/gossip/util.go b/registry/gossip/util.go index 0fa8116d..75fb2dbf 100644 --- a/registry/gossip/util.go +++ b/registry/gossip/util.go @@ -115,27 +115,20 @@ func delNodes(old, del []*registry.Node) []*registry.Node { func delServices(old, del []*registry.Service) []*registry.Service { var services []*registry.Service - for _, o := range old { - srv := new(registry.Service) - *srv = *o - var rem bool - for _, s := range del { - if srv.Version == s.Version { - srv.Nodes = delNodes(srv.Nodes, s.Nodes) - - if len(srv.Nodes) == 0 { + if o.Version == s.Version { + s.Nodes = delNodes(s.Nodes, o.Nodes) + if len(s.Nodes) == 0 { rem = true + break } } } - if !rem { - services = append(services, srv) + services = append(services, o) } } - return services } From 606b1ff7cf6812877313ce11a1ec25f5483d16d1 Mon Sep 17 00:00:00 2001 From: magodo Date: Wed, 19 Jun 2019 14:42:09 +0800 Subject: [PATCH 010/287] `prefix` in consul api starts with no leading slash When `consul.StripPrefix(true)` is set, current impl. will pass the specified prefix (or default prefix) when calling consul api. However, `prefix` in consul api starts with no leading slash, so the default prefix (`/micro/config`) doesn't actually work. I avoid code changes (esp. the one in `util.go`) to eliminate impact on users who already notice it. --- config/source/consul/README.md | 6 +++--- config/source/consul/consul.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/source/consul/README.md b/config/source/consul/README.md index 2ba45e5b..061c0a3f 100644 --- a/config/source/consul/README.md +++ b/config/source/consul/README.md @@ -4,7 +4,7 @@ The consul source reads config from consul key/values ## Consul Format -The consul source expects keys under the default prefix `/micro/config` +The consul source expects keys under the default prefix `micro/config` Values are expected to be json @@ -29,8 +29,8 @@ Specify source with data consulSource := consul.NewSource( // optionally specify consul address; default to localhost:8500 consul.WithAddress("10.0.0.10:8500"), - // optionally specify prefix; defaults to /micro/config - consul.WithPrefix("/my/prefix"), + // optionally specify prefix; defaults to micro/config + consul.WithPrefix("my/prefix"), // optionally strip the provided prefix from the keys, defaults to false consul.StripPrefix(true), ) diff --git a/config/source/consul/consul.go b/config/source/consul/consul.go index 16e85332..785f20f7 100644 --- a/config/source/consul/consul.go +++ b/config/source/consul/consul.go @@ -21,7 +21,7 @@ type consul struct { var ( // DefaultPrefix is the prefix that consul keys will be assumed to have if you // haven't specified one - DefaultPrefix = "/micro/config/" + DefaultPrefix = "micro/config/" ) func (c *consul) Read() (*source.ChangeSet, error) { From 1c1dae0642951e11dae4e85bd900ab2ca5035b6e Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 19 Jun 2019 12:34:45 +0100 Subject: [PATCH 011/287] Fix the grpc test --- client/grpc/grpc_test.go | 4 ++-- client/grpc/request.go | 4 ++++ client/grpc/request_test.go | 29 +++++++++++------------------ 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/client/grpc/grpc_test.go b/client/grpc/grpc_test.go index 574058cb..074d8931 100644 --- a/client/grpc/grpc_test.go +++ b/client/grpc/grpc_test.go @@ -45,7 +45,7 @@ func TestGRPCClient(t *testing.T) { // register service r.Register(®istry.Service{ - Name: "test", + Name: "helloworld", Version: "test", Nodes: []*registry.Node{ ®istry.Node{ @@ -73,7 +73,7 @@ func TestGRPCClient(t *testing.T) { } for _, method := range testMethods { - req := c.NewRequest("test", method, &pb.HelloRequest{ + req := c.NewRequest("helloworld", method, &pb.HelloRequest{ Name: "John", }) diff --git a/client/grpc/request.go b/client/grpc/request.go index 94b44da0..066577ce 100644 --- a/client/grpc/request.go +++ b/client/grpc/request.go @@ -30,6 +30,10 @@ func methodToGRPC(service, method string) string { return method } + if len(service) == 0 { + return fmt.Sprintf("/%s/%s", mParts[0], mParts[1]) + } + // return /pkg.Foo/Bar return fmt.Sprintf("/%s.%s/%s", service, mParts[0], mParts[1]) } diff --git a/client/grpc/request_test.go b/client/grpc/request_test.go index eab3a3a1..c73d675b 100644 --- a/client/grpc/request_test.go +++ b/client/grpc/request_test.go @@ -2,45 +2,38 @@ package grpc import ( "testing" - - pb "google.golang.org/grpc/examples/helloworld/helloworld" ) func TestMethodToGRPC(t *testing.T) { testData := []struct { + service string method string expect string - request interface{} }{ { + "helloworld", "Greeter.SayHello", "/helloworld.Greeter/SayHello", - new(pb.HelloRequest), }, { + "helloworld", "/helloworld.Greeter/SayHello", "/helloworld.Greeter/SayHello", - new(pb.HelloRequest), }, { + "", + "/helloworld.Greeter/SayHello", + "/helloworld.Greeter/SayHello", + }, + { + "", "Greeter.SayHello", - "/helloworld.Greeter/SayHello", - pb.HelloRequest{}, - }, - { - "/helloworld.Greeter/SayHello", - "/helloworld.Greeter/SayHello", - pb.HelloRequest{}, - }, - { - "Greeter.SayHello", - "Greeter.SayHello", - nil, + "/Greeter/SayHello", }, } for _, d := range testData { - method := methodToGRPC(d.method, d.request) + method := methodToGRPC(d.service, d.method) if method != d.expect { t.Fatalf("expected %s got %s", d.expect, method) } From 08da7c128367db9884fadd914a34e1f88b5d7414 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Thu, 6 Jun 2019 16:37:40 +0100 Subject: [PATCH 012/287] First commit: Outline of Router interface --- router/default.go | 57 +++++++++++++++++++++++++++++++++++++++++++++++ router/options.go | 31 ++++++++++++++++++++++++++ router/route.go | 7 ++++++ router/router.go | 50 +++++++++++++++++++++++++++++++++++++++++ router/service.go | 7 ++++++ 5 files changed, 152 insertions(+) create mode 100644 router/default.go create mode 100644 router/options.go create mode 100644 router/route.go create mode 100644 router/router.go create mode 100644 router/service.go diff --git a/router/default.go b/router/default.go new file mode 100644 index 00000000..4f5b1a77 --- /dev/null +++ b/router/default.go @@ -0,0 +1,57 @@ +package router + +import ( + "github.com/micro/go-micro/registry" + "github.com/micro/go-micro/registry/gossip" +) + +type router struct { + opts Options + goss registry.Registry +} + +func newRouter(opts ...Option) Router { + // TODO: for now default options + goss := gossip.NewRegistry() + + r := &router{ + goss: goss, + } + + for _, o := range opts { + o(&r.opts) + } + + return r +} + +func (r *router) Init(opts ...Option) error { + for _, o := range opts { + o(&r.opts) + } + return nil +} + +func (r *router) Options() Options { + return r.opts +} + +func (r *router) AddRoute(route *Route, opts ...RouteOption) error { + return nil +} + +func (r *router) RemoveRoute(route *Route) error { + return nil +} + +func (r *router) GetRoute(s *Service) ([]*Route, error) { + return nil, nil +} + +func (r *router) List() ([]*Route, error) { + return nil, nil +} + +func (r *router) String() string { + return "" +} diff --git a/router/options.go b/router/options.go new file mode 100644 index 00000000..5cfbcd13 --- /dev/null +++ b/router/options.go @@ -0,0 +1,31 @@ +package router + +import ( + "context" + "time" + + "github.com/micro/go-micro/registry" +) + +// Options allows to set Router options +type Options struct { + // Registry is route source registry i.e. local registry + Registry registry.Registry + // Context stores arbitrary options + Context context.Context +} + +// RouteOption allows to soecify routing table options +type RouteOption struct { + // TTL defines route entry lifetime + TTL time.Duration + // COntext allows to specify other arbitrary options + Context context.Context +} + +// Registry is local registry +func Registry(r registry.Registry) Option { + return func(o *Options) { + o.Registry = r + } +} diff --git a/router/route.go b/router/route.go new file mode 100644 index 00000000..d9b80ce1 --- /dev/null +++ b/router/route.go @@ -0,0 +1,7 @@ +package router + +// Route is micro network route +type Route struct { + // Hop is the next route hop + Hop Router +} diff --git a/router/router.go b/router/router.go new file mode 100644 index 00000000..9142ea81 --- /dev/null +++ b/router/router.go @@ -0,0 +1,50 @@ +// Package router provides an interface for micro network routers +package router + +import ( + "errors" + + "github.com/micro/go-micro/registry" +) + +// Router is micro network router +type Router interface { + // Initi initializes Router with options + Init(...Option) error + // Options returns Router options + Options() Options + // AddRoute adds new service route + AddRoute(*Route, ...RouteOption) error + // RemoveRoute removes service route + RemoveRoute(*Route) error + // GetRoute returns list of routes for service + GetRoute(*Service) ([]*Route, error) + // List returns all routes + List() ([]*Route, error) + // String implemens fmt.Stringer interface + String() string +} + +// Option used by the Router +type Option func(*Options) + +var ( + DefaultRouter = NewRouter() + + // Not found error when Get is called + ErrNotFound = errors.New("route not found") +) + +// NewRouter creates new Router and returns it +func NewRouter(opts ...Option) Router { + // set Registry to DefaultRegistry + opt := Options{ + Registry: registry.DefaultRegistry, + } + + for _, o := range opts { + o(&opt) + } + + return newRouter(opts...) +} diff --git a/router/service.go b/router/service.go new file mode 100644 index 00000000..3d944c4a --- /dev/null +++ b/router/service.go @@ -0,0 +1,7 @@ +package router + +// Service is a service to route to +type Service struct { + // Name is service name + Name string +} From ee8b6b3114a4e6e1941b33156906eb7df72b22ce Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Thu, 6 Jun 2019 23:29:24 +0100 Subject: [PATCH 013/287] Redefeind interfaces; Added better modelled data strauctures Router interface has been redefined which fits better with what we are looking for. Routing table now offers a comprehensive set of information about its entries which will make up for rich queries in the future Query interface has been defined to enable current basic and more advanced queries in the future. --- router/default.go | 38 +++++++++++++++++++------ router/options.go | 35 +++++++++++++++++------- router/query.go | 70 +++++++++++++++++++++++++++++++++++++++++++++++ router/route.go | 7 ----- router/router.go | 42 ++++++++++++++++------------ router/service.go | 7 ----- router/table.go | 58 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 206 insertions(+), 51 deletions(-) create mode 100644 router/query.go delete mode 100644 router/route.go delete mode 100644 router/service.go create mode 100644 router/table.go diff --git a/router/default.go b/router/default.go index 4f5b1a77..07ccba2b 100644 --- a/router/default.go +++ b/router/default.go @@ -8,14 +8,14 @@ import ( type router struct { opts Options goss registry.Registry + t *Table } func newRouter(opts ...Option) Router { - // TODO: for now default options - goss := gossip.NewRegistry() - + // TODO: figure out how to supply gossip registry options r := &router{ - goss: goss, + goss: gossip.NewRegistry(), + t: NewTable(), } for _, o := range opts { @@ -25,6 +25,7 @@ func newRouter(opts ...Option) Router { return r } +// Init initializes router with given options func (r *router) Init(opts ...Option) error { for _, o := range opts { o(&r.opts) @@ -32,26 +33,45 @@ func (r *router) Init(opts ...Option) error { return nil } +// Options returns router options func (r *router) Options() Options { return r.opts } -func (r *router) AddRoute(route *Route, opts ...RouteOption) error { +// Add adds new entry into routing table with given options. +// It returns error if the entry could not be added. +func (r *router) Add(e *Entry, opts ...RouteOption) error { return nil } -func (r *router) RemoveRoute(route *Route) error { +// Remove removes entry from the routing table. +// It returns error if either the entry could not be removed or it does not exist. +func (r *router) Remove(e *Entry) error { return nil } -func (r *router) GetRoute(s *Service) ([]*Route, error) { +// Update updates an entry in the router's routing table +// It returns error if the entry was not found or it failed to be updated. +func (r *router) Update(e *Entry) error { + return nil +} + +// Lookup makes a query lookup and returns all matching entries +func (r *router) Lookup(q Query) ([]*Entry, error) { return nil, nil } -func (r *router) List() ([]*Route, error) { - return nil, nil +// Table returns routing table +func (r *router) Table() *Table { + return nil } +// Address returns router's network address +func (r *router) Address() string { + return "" +} + +// String prints debugging information about router func (r *router) String() string { return "" } diff --git a/router/options.go b/router/options.go index 5cfbcd13..3eeaf548 100644 --- a/router/options.go +++ b/router/options.go @@ -2,7 +2,6 @@ package router import ( "context" - "time" "github.com/micro/go-micro/registry" ) @@ -15,17 +14,33 @@ type Options struct { Context context.Context } -// RouteOption allows to soecify routing table options -type RouteOption struct { - // TTL defines route entry lifetime - TTL time.Duration - // COntext allows to specify other arbitrary options - Context context.Context -} - -// Registry is local registry +// Registry allows to set local service registry func Registry(r registry.Registry) Option { return func(o *Options) { o.Registry = r } } + +// RouteOptions allows to specify routing table options +type RouteOptions struct { + // NetID is network ID + NetID string + // Metric is route metric + Metric int + // COntext allows to specify other arbitrary options + Context context.Context +} + +// NetID allows to set micro network ID +func NetID(id string) RouteOption { + return func(o *RouteOptions) { + o.NetID = id + } +} + +// Metric allows to set route cost metric +func Metric(m int) RouteOption { + return func(o *RouteOptions) { + o.Metric = m + } +} diff --git a/router/query.go b/router/query.go new file mode 100644 index 00000000..05679600 --- /dev/null +++ b/router/query.go @@ -0,0 +1,70 @@ +package router + +// Policy defines query policy +type QueryPolicy int + +const ( + // DiscardNoRoute discards query when no rout is found + DiscardNoRoute QueryPolicy = iota + // ClosestMatch returns closest match to query + ClosestMatch +) + +// QueryOptions allow to define routing table query options +type QueryOptions struct { + // Route allows to set route options + Route *RouteOptions + // Service is micro service name + Service string + // Policy defines query lookup policy + Policy QueryPolicy +} + +// Route allows to set the route query options +func Route(r *RouteOptions) QueryOption { + return func(o *QueryOptions) { + o.Route = r + } +} + +// Service allows to set the service name in routing query +func Service(s string) QueryOption { + return func(o *QueryOptions) { + o.Service = s + } +} + +// Policy allows to define query lookup policy +func Policy(p QueryPolicy) QueryOption { + return func(o *QueryOptions) { + o.Policy = p + } +} + +// Query defines routing table query +type Query interface { + // Options returns query options + Options() QueryOptions +} + +type query struct { + opts QueryOptions +} + +// NewQuery creates new query and returns it +func NewQuery(opts ...QueryOption) Query { + qopts := QueryOptions{} + + for _, o := range opts { + o(&qopts) + } + + return &query{ + opts: qopts, + } +} + +// Options returns query options +func (q *query) Options() QueryOptions { + return q.opts +} diff --git a/router/route.go b/router/route.go deleted file mode 100644 index d9b80ce1..00000000 --- a/router/route.go +++ /dev/null @@ -1,7 +0,0 @@ -package router - -// Route is micro network route -type Route struct { - // Hop is the next route hop - Hop Router -} diff --git a/router/router.go b/router/router.go index 9142ea81..a98fba09 100644 --- a/router/router.go +++ b/router/router.go @@ -2,25 +2,32 @@ package router import ( - "errors" - "github.com/micro/go-micro/registry" ) +var ( + // DefaultRouter returns default micro router + DefaultRouter = NewRouter() +) + // Router is micro network router type Router interface { // Initi initializes Router with options Init(...Option) error // Options returns Router options Options() Options - // AddRoute adds new service route - AddRoute(*Route, ...RouteOption) error - // RemoveRoute removes service route - RemoveRoute(*Route) error - // GetRoute returns list of routes for service - GetRoute(*Service) ([]*Route, error) - // List returns all routes - List() ([]*Route, error) + // Add adds new entry into routing table + Add(*Entry, ...RouteOption) error + // Remove removes entry from the routing table + Remove(*Entry) error + // Update updates entry in the routing table + Update(*Entry) error + // Lookup queries the routing table and returns matching entries + Lookup(Query) ([]*Entry, error) + // Table returns routing table + Table() *Table + // Address is Router adddress + Address() string // String implemens fmt.Stringer interface String() string } @@ -28,22 +35,21 @@ type Router interface { // Option used by the Router type Option func(*Options) -var ( - DefaultRouter = NewRouter() +// RouteOption is used by Router for adding routing table entries +type RouteOption func(*RouteOptions) - // Not found error when Get is called - ErrNotFound = errors.New("route not found") -) +// QueryOption is used to defined routing table lookup query +type QueryOption func(*QueryOptions) // NewRouter creates new Router and returns it func NewRouter(opts ...Option) Router { - // set Registry to DefaultRegistry - opt := Options{ + // router registry to DefaultRegistry + ropts := Options{ Registry: registry.DefaultRegistry, } for _, o := range opts { - o(&opt) + o(&ropts) } return newRouter(opts...) diff --git a/router/service.go b/router/service.go deleted file mode 100644 index 3d944c4a..00000000 --- a/router/service.go +++ /dev/null @@ -1,7 +0,0 @@ -package router - -// Service is a service to route to -type Service struct { - // Name is service name - Name string -} diff --git a/router/table.go b/router/table.go new file mode 100644 index 00000000..e06f66e7 --- /dev/null +++ b/router/table.go @@ -0,0 +1,58 @@ +package router + +import "errors" + +var ( + // ErrRouteNotFound is returned when no rout was found + ErrRouteNotFound = errors.New("route not found") +) + +// Entry is micro network routing table entry +type Entry struct { + // NetID is micro network ID + NetID string + // Hop is the next route hop + Hop Router + // Metric is route cost metric + Metric int +} + +// Table is routing table +// It maps service name to routes +type Table struct { + // m stores routing table map + m map[string][]Entry +} + +// NewTable creates new routing table and returns it +func NewTable() *Table { + return &Table{ + m: make(map[string][]Entry), + } +} + +// TODO: Define lookup query interface +// Lookup looks up entry in the routing table +func (t *Table) Lookup() (*Entry, error) { + return nil, nil +} + +// Remove removes entry from the routing table +func (t *Table) Remove(e *Entry) error { + return nil +} + +// Update updates routin entry +func (t *Table) Update(e *Entry) error { + return nil +} + +// Size returns the size of the routing table +func (t *Table) Size() int { + return 0 +} + +// String returns text representation of routing table +func (t *Table) String() string { + return "" +} From e4311c3a10fe03ea0cfedf3db71de81ab8e5e7fa Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Fri, 7 Jun 2019 13:29:09 +0100 Subject: [PATCH 014/287] Redefined and polished some interfaces and data structures. --- router/default.go | 6 +++--- router/options.go | 30 ++++++++++++++++++++------ router/router.go | 16 ++++++++------ router/table.go | 54 +++++++++++++++++++++++++++++++++++------------ 4 files changed, 75 insertions(+), 31 deletions(-) diff --git a/router/default.go b/router/default.go index 07ccba2b..53c65618 100644 --- a/router/default.go +++ b/router/default.go @@ -8,7 +8,7 @@ import ( type router struct { opts Options goss registry.Registry - t *Table + t Table } func newRouter(opts ...Option) Router { @@ -62,13 +62,13 @@ func (r *router) Lookup(q Query) ([]*Entry, error) { } // Table returns routing table -func (r *router) Table() *Table { +func (r *router) Table() Table { return nil } // Address returns router's network address func (r *router) Address() string { - return "" + return r.opts.Address } // String prints debugging information about router diff --git a/router/options.go b/router/options.go index 3eeaf548..4db04ab7 100644 --- a/router/options.go +++ b/router/options.go @@ -2,22 +2,38 @@ package router import ( "context" - - "github.com/micro/go-micro/registry" ) // Options allows to set Router options type Options struct { - // Registry is route source registry i.e. local registry - Registry registry.Registry + // Address is router address + Address string + // RIB is Routing Information Base + RIB RIB + // Table is routing table + Table Table // Context stores arbitrary options Context context.Context } -// Registry allows to set local service registry -func Registry(r registry.Registry) Option { +// RIBase allows to configure RIB +func RIBase(r RIB) Option { return func(o *Options) { - o.Registry = r + o.RIB = r + } +} + +// Address allows to set router address +func Address(a string) Option { + return func(o *Options) { + o.Address = a + } +} + +// RoutingTable allows to specify custom routing table +func RoutingTable(t Table) Option { + return func(o *Options) { + o.Table = t } } diff --git a/router/router.go b/router/router.go index a98fba09..f8f94cce 100644 --- a/router/router.go +++ b/router/router.go @@ -1,10 +1,6 @@ // Package router provides an interface for micro network routers package router -import ( - "github.com/micro/go-micro/registry" -) - var ( // DefaultRouter returns default micro router DefaultRouter = NewRouter() @@ -25,13 +21,19 @@ type Router interface { // Lookup queries the routing table and returns matching entries Lookup(Query) ([]*Entry, error) // Table returns routing table - Table() *Table + Table() Table // Address is Router adddress Address() string // String implemens fmt.Stringer interface String() string } +// RIB is Routing Information Base +type RIB interface { + // String returns debug info + String() string +} + // Option used by the Router type Option func(*Options) @@ -43,9 +45,9 @@ type QueryOption func(*QueryOptions) // NewRouter creates new Router and returns it func NewRouter(opts ...Option) Router { - // router registry to DefaultRegistry + // set default options ropts := Options{ - Registry: registry.DefaultRegistry, + Table: DefaultTable, } for _, o := range opts { diff --git a/router/table.go b/router/table.go index e06f66e7..15933e8e 100644 --- a/router/table.go +++ b/router/table.go @@ -3,12 +3,34 @@ package router import "errors" var ( - // ErrRouteNotFound is returned when no rout was found + // DefaultRouter returns default micro router + DefaultTable = NewTable() + // ErrRouteNotFound is returned when no route was found ErrRouteNotFound = errors.New("route not found") + // ErrDuplicateRoute is return when route already exists + ErrDuplicateRoute = errors.New("duplicate route") ) +// Table is routing table +type Table interface { + // Add adds new route to the table + Add(*Entry) error + // Remove removes route from the table + Remove(*Entry) error + // Update updates route in the table + Update(*Entry) error + // Lookup looks up routes in the table + Lookup(Query) ([]*Entry, error) + // Size returns the size of the table + Size() int + // String prints the routing table + String() string +} + // Entry is micro network routing table entry type Entry struct { + // DestAddr is destination address + DestAddr string // NetID is micro network ID NetID string // Hop is the next route hop @@ -17,42 +39,46 @@ type Entry struct { Metric int } -// Table is routing table +// table is routing table // It maps service name to routes -type Table struct { +type table struct { // m stores routing table map m map[string][]Entry } // NewTable creates new routing table and returns it -func NewTable() *Table { - return &Table{ +func NewTable() Table { + return &table{ m: make(map[string][]Entry), } } -// TODO: Define lookup query interface -// Lookup looks up entry in the routing table -func (t *Table) Lookup() (*Entry, error) { - return nil, nil +// Add adds new routing entry +func (t *table) Add(e *Entry) error { + return nil } // Remove removes entry from the routing table -func (t *Table) Remove(e *Entry) error { +func (t *table) Remove(e *Entry) error { return nil } // Update updates routin entry -func (t *Table) Update(e *Entry) error { +func (t *table) Update(e *Entry) error { return nil } +// Lookup looks up entry in the routing table +func (t *table) Lookup(q Query) ([]*Entry, error) { + return nil, nil +} + // Size returns the size of the routing table -func (t *Table) Size() int { - return 0 +func (t *table) Size() int { + return len(t.m) } // String returns text representation of routing table -func (t *Table) String() string { +func (t *table) String() string { return "" } From d7f0db04ec2b438d38fc4abf2c233796937d0418 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Fri, 7 Jun 2019 17:20:22 +0100 Subject: [PATCH 015/287] Added network ID option. Added mutex to routing table. --- router/default.go | 24 +++++++++++++++++------- router/options.go | 23 ++++++++++++++++------- router/router.go | 2 ++ router/table.go | 10 +++++++--- 4 files changed, 42 insertions(+), 17 deletions(-) diff --git a/router/default.go b/router/default.go index 53c65618..1eefd644 100644 --- a/router/default.go +++ b/router/default.go @@ -1,27 +1,32 @@ package router import ( + "github.com/google/uuid" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/registry/gossip" ) type router struct { - opts Options - goss registry.Registry - t Table + opts Options + goss registry.Registry + table Table + id uuid.UUID } func newRouter(opts ...Option) Router { // TODO: figure out how to supply gossip registry options r := &router{ - goss: gossip.NewRegistry(), - t: NewTable(), + goss: gossip.NewRegistry(), + table: NewTable(), + id: uuid.New(), } for _, o := range opts { o(&r.opts) } + // TODO: need to start some gossip.Registry watch here + return r } @@ -63,10 +68,15 @@ func (r *router) Lookup(q Query) ([]*Entry, error) { // Table returns routing table func (r *router) Table() Table { - return nil + return r.table } -// Address returns router's network address +// Network returns router's micro network +func (r *router) Network() string { + return r.opts.Network +} + +// Address returns router's bind address func (r *router) Address() string { return r.opts.Address } diff --git a/router/options.go b/router/options.go index 4db04ab7..277e1a30 100644 --- a/router/options.go +++ b/router/options.go @@ -8,6 +8,8 @@ import ( type Options struct { // Address is router address Address string + // Network defines micro network address + Network string // RIB is Routing Information Base RIB RIB // Table is routing table @@ -16,13 +18,6 @@ type Options struct { Context context.Context } -// RIBase allows to configure RIB -func RIBase(r RIB) Option { - return func(o *Options) { - o.RIB = r - } -} - // Address allows to set router address func Address(a string) Option { return func(o *Options) { @@ -30,6 +25,20 @@ func Address(a string) Option { } } +// Network allows to set router network +func Network(n string) Option { + return func(o *Options) { + o.Network = n + } +} + +// RIBase allows to configure RIB +func RIBase(r RIB) Option { + return func(o *Options) { + o.RIB = r + } +} + // RoutingTable allows to specify custom routing table func RoutingTable(t Table) Option { return func(o *Options) { diff --git a/router/router.go b/router/router.go index f8f94cce..72af0979 100644 --- a/router/router.go +++ b/router/router.go @@ -24,6 +24,8 @@ type Router interface { Table() Table // Address is Router adddress Address() string + // Network defines network router is in + Network() string // String implemens fmt.Stringer interface String() string } diff --git a/router/table.go b/router/table.go index 15933e8e..1f2de4d3 100644 --- a/router/table.go +++ b/router/table.go @@ -1,6 +1,9 @@ package router -import "errors" +import ( + "errors" + "sync" +) var ( // DefaultRouter returns default micro router @@ -29,8 +32,8 @@ type Table interface { // Entry is micro network routing table entry type Entry struct { - // DestAddr is destination address - DestAddr string + // Addr is destination address + Addr string // NetID is micro network ID NetID string // Hop is the next route hop @@ -44,6 +47,7 @@ type Entry struct { type table struct { // m stores routing table map m map[string][]Entry + sync.RWMutex } // NewTable creates new routing table and returns it From ad92e6821eea5a67f1603e3e123a250ac841e307 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Fri, 7 Jun 2019 18:04:48 +0100 Subject: [PATCH 016/287] Removed DefaultTable() from global vars We will not initialize DefaultTable as global var unless the users asks for it explicitly. --- router/router.go | 8 ++------ router/table.go | 2 -- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/router/router.go b/router/router.go index 72af0979..319b296a 100644 --- a/router/router.go +++ b/router/router.go @@ -1,11 +1,6 @@ // Package router provides an interface for micro network routers package router -var ( - // DefaultRouter returns default micro router - DefaultRouter = NewRouter() -) - // Router is micro network router type Router interface { // Initi initializes Router with options @@ -49,7 +44,8 @@ type QueryOption func(*QueryOptions) func NewRouter(opts ...Option) Router { // set default options ropts := Options{ - Table: DefaultTable, + // Default table + Table: NewTable(), } for _, o := range opts { diff --git a/router/table.go b/router/table.go index 1f2de4d3..931ee9a2 100644 --- a/router/table.go +++ b/router/table.go @@ -6,8 +6,6 @@ import ( ) var ( - // DefaultRouter returns default micro router - DefaultTable = NewTable() // ErrRouteNotFound is returned when no route was found ErrRouteNotFound = errors.New("route not found") // ErrDuplicateRoute is return when route already exists From 9c57f32f5836f865b5d6e44a711f7ac533b8819c Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Sun, 9 Jun 2019 23:09:38 +0100 Subject: [PATCH 017/287] Added Entry type. Basic implementation of Router and Table --- router/default.go | 30 ++++++++--- router/entry.go | 89 +++++++++++++++++++++++++++++++ router/options.go | 24 --------- router/query.go | 22 ++++---- router/router.go | 18 +++---- router/table.go | 133 ++++++++++++++++++++++++++++++++++++---------- 6 files changed, 237 insertions(+), 79 deletions(-) create mode 100644 router/entry.go diff --git a/router/default.go b/router/default.go index 1eefd644..64770ce9 100644 --- a/router/default.go +++ b/router/default.go @@ -1,6 +1,9 @@ package router import ( + "fmt" + "strings" + "github.com/google/uuid" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/registry/gossip" @@ -45,25 +48,25 @@ func (r *router) Options() Options { // Add adds new entry into routing table with given options. // It returns error if the entry could not be added. -func (r *router) Add(e *Entry, opts ...RouteOption) error { - return nil +func (r *router) Add(e Entry) error { + return r.table.Add(e) } // Remove removes entry from the routing table. // It returns error if either the entry could not be removed or it does not exist. -func (r *router) Remove(e *Entry) error { - return nil +func (r *router) Remove(e Entry) error { + return r.table.Remove(e) } // Update updates an entry in the router's routing table // It returns error if the entry was not found or it failed to be updated. -func (r *router) Update(e *Entry) error { - return nil +func (r *router) Update(opts ...EntryOption) error { + return r.table.Update(opts...) } // Lookup makes a query lookup and returns all matching entries func (r *router) Lookup(q Query) ([]*Entry, error) { - return nil, nil + return nil, ErrNotImplemented } // Table returns routing table @@ -83,5 +86,16 @@ func (r *router) Address() string { // String prints debugging information about router func (r *router) String() string { - return "" + sb := &strings.Builder{} + + s := fmt.Sprintf("Router Local Address: %s\n", r.opts.Address) + sb.WriteString(s) + + s = fmt.Sprintf("Router Network Address: %s\n", r.opts.Network) + sb.WriteString(s) + + s = fmt.Sprintf("Routing table size: %d\n", r.opts.Table.Size()) + sb.WriteString(s) + + return sb.String() } diff --git a/router/entry.go b/router/entry.go new file mode 100644 index 00000000..1aee4d65 --- /dev/null +++ b/router/entry.go @@ -0,0 +1,89 @@ +package router + +// AddPolicy defines routing table addition policy +type AddPolicy int + +const ( + // Override overrides existing routing table entry + OverrideIfExists AddPolicy = iota + // ErrIfExists returns error if the entry already exists + ErrIfExists +) + +// EntryOptions defines micro network routing table entry options +type EntryOptions struct { + // DestAddr is destination address + DestAddr string + // Hop is the next route hop + Hop Router + // SrcAddr defines local routing address + // On local networkss, this will be the address of local router + SrcAddr string + // Metric is route cost metric + Metric int + // Policy defines entry addition policy + Policy AddPolicy +} + +// DestAddr sets destination address +func DestAddr(a string) EntryOption { + return func(o *EntryOptions) { + o.DestAddr = a + } +} + +// Hop allows to set the route entry options +func Hop(r Router) EntryOption { + return func(o *EntryOptions) { + o.Hop = r + } +} + +// SrcAddr sets source address +func SrcAddr(a string) EntryOption { + return func(o *EntryOptions) { + o.SrcAddr = a + } +} + +// Metric sets entry metric +func Metric(m int) EntryOption { + return func(o *EntryOptions) { + o.Metric = m + } +} + +// AddEntryPolicy sets add entry policy +func AddEntryPolicy(p AddPolicy) EntryOption { + return func(o *EntryOptions) { + o.Policy = p + } +} + +// Entry is routing table entry +type Entry interface { + // Options returns entry options + Options() EntryOptions +} + +type entry struct { + opts EntryOptions +} + +// NewEntry returns new routing table entry +func NewEntry(opts ...EntryOption) Entry { + eopts := EntryOptions{} + + for _, o := range opts { + o(&eopts) + } + + return &entry{ + opts: eopts, + } +} + +// Options returns entry options +func (e *entry) Options() EntryOptions { + return e.opts +} diff --git a/router/options.go b/router/options.go index 277e1a30..8e1077c1 100644 --- a/router/options.go +++ b/router/options.go @@ -45,27 +45,3 @@ func RoutingTable(t Table) Option { o.Table = t } } - -// RouteOptions allows to specify routing table options -type RouteOptions struct { - // NetID is network ID - NetID string - // Metric is route metric - Metric int - // COntext allows to specify other arbitrary options - Context context.Context -} - -// NetID allows to set micro network ID -func NetID(id string) RouteOption { - return func(o *RouteOptions) { - o.NetID = id - } -} - -// Metric allows to set route cost metric -func Metric(m int) RouteOption { - return func(o *RouteOptions) { - o.Metric = m - } -} diff --git a/router/query.go b/router/query.go index 05679600..9632e062 100644 --- a/router/query.go +++ b/router/query.go @@ -1,27 +1,27 @@ package router -// Policy defines query policy -type QueryPolicy int +// LookupPolicy defines query policy +type LookupPolicy int const ( - // DiscardNoRoute discards query when no rout is found - DiscardNoRoute QueryPolicy = iota - // ClosestMatch returns closest match to query + // DiscardNoRoute discards query when no route is found + DiscardNoRoute LookupPolicy = iota + // ClosestMatch returns closest match to supplied query ClosestMatch ) // QueryOptions allow to define routing table query options type QueryOptions struct { // Route allows to set route options - Route *RouteOptions + Route *EntryOptions // Service is micro service name Service string // Policy defines query lookup policy - Policy QueryPolicy + Policy LookupPolicy } -// Route allows to set the route query options -func Route(r *RouteOptions) QueryOption { +// EntryOpts allows to set the route query options +func EntryOpts(r *EntryOptions) QueryOption { return func(o *QueryOptions) { o.Route = r } @@ -34,8 +34,8 @@ func Service(s string) QueryOption { } } -// Policy allows to define query lookup policy -func Policy(p QueryPolicy) QueryOption { +// QueryLookupPolicy allows to define query lookup policy +func QueryLookupPolicy(p LookupPolicy) QueryOption { return func(o *QueryOptions) { o.Policy = p } diff --git a/router/router.go b/router/router.go index 319b296a..ef3b8117 100644 --- a/router/router.go +++ b/router/router.go @@ -8,18 +8,18 @@ type Router interface { // Options returns Router options Options() Options // Add adds new entry into routing table - Add(*Entry, ...RouteOption) error + Add(Entry) error // Remove removes entry from the routing table - Remove(*Entry) error + Remove(Entry) error // Update updates entry in the routing table - Update(*Entry) error + Update(...EntryOption) error // Lookup queries the routing table and returns matching entries Lookup(Query) ([]*Entry, error) // Table returns routing table Table() Table - // Address is Router adddress + // Address returns the router bind adddress Address() string - // Network defines network router is in + // Network returns router's micro network bind address Network() string // String implemens fmt.Stringer interface String() string @@ -31,13 +31,13 @@ type RIB interface { String() string } -// Option used by the Router +// Option used by the router type Option func(*Options) -// RouteOption is used by Router for adding routing table entries -type RouteOption func(*RouteOptions) +// EntryOption is used to define routing entry options +type EntryOption func(*EntryOptions) -// QueryOption is used to defined routing table lookup query +// QueryOption is used to define query options type QueryOption func(*QueryOptions) // NewRouter creates new Router and returns it diff --git a/router/table.go b/router/table.go index 931ee9a2..9039bb1e 100644 --- a/router/table.go +++ b/router/table.go @@ -2,7 +2,12 @@ package router import ( "errors" + "fmt" + "hash/fnv" + "strings" "sync" + + "github.com/olekukonko/tablewriter" ) var ( @@ -10,77 +15,151 @@ var ( ErrRouteNotFound = errors.New("route not found") // ErrDuplicateRoute is return when route already exists ErrDuplicateRoute = errors.New("duplicate route") + // ErrNotImplemented is returned when some functionality has not been implemented + ErrNotImplemented = errors.New("not implemented") ) // Table is routing table type Table interface { // Add adds new route to the table - Add(*Entry) error + Add(Entry) error // Remove removes route from the table - Remove(*Entry) error + Remove(Entry) error // Update updates route in the table - Update(*Entry) error + Update(...EntryOption) error // Lookup looks up routes in the table - Lookup(Query) ([]*Entry, error) + Lookup(Query) ([]Entry, error) // Size returns the size of the table Size() int // String prints the routing table String() string } -// Entry is micro network routing table entry -type Entry struct { - // Addr is destination address - Addr string - // NetID is micro network ID - NetID string - // Hop is the next route hop - Hop Router - // Metric is route cost metric - Metric int -} - // table is routing table // It maps service name to routes type table struct { // m stores routing table map - m map[string][]Entry + m map[string]map[uint64]Entry sync.RWMutex } // NewTable creates new routing table and returns it func NewTable() Table { return &table{ - m: make(map[string][]Entry), + m: make(map[string]map[uint64]Entry), } } // Add adds new routing entry -func (t *table) Add(e *Entry) error { - return nil +func (t *table) Add(e Entry) error { + t.Lock() + defer t.Unlock() + + destAddr := e.Options().DestAddr + h := fnv.New64() + h.Write([]byte(e.Options().DestAddr + e.Options().Hop.Address())) + + if _, ok := t.m[destAddr]; !ok { + // create new map for DestAddr routes + t.m[destAddr] = make(map[uint64]Entry) + t.m[destAddr][h.Sum64()] = e + return nil + } + + if _, ok := t.m[destAddr][h.Sum64()]; ok && e.Options().Policy == OverrideIfExists { + t.m[destAddr][h.Sum64()] = e + return nil + } + + return ErrDuplicateRoute } // Remove removes entry from the routing table -func (t *table) Remove(e *Entry) error { +func (t *table) Remove(e Entry) error { + t.Lock() + defer t.Unlock() + + destAddr := e.Options().DestAddr + h := fnv.New64() + h.Write([]byte(e.Options().DestAddr + e.Options().Hop.Address())) + + if _, ok := t.m[destAddr]; !ok { + return ErrRouteNotFound + } else { + delete(t.m[destAddr], h.Sum64()) + return nil + } + return nil } -// Update updates routin entry -func (t *table) Update(e *Entry) error { - return nil +// Update updates routing entry +func (t *table) Update(opts ...EntryOption) error { + t.Lock() + defer t.Unlock() + + e := NewEntry(opts...) + + destAddr := e.Options().DestAddr + h := fnv.New64() + h.Write([]byte(e.Options().DestAddr + e.Options().Hop.Address())) + + if _, ok := t.m[destAddr]; !ok { + return ErrRouteNotFound + } + + if _, ok := t.m[destAddr][h.Sum64()]; ok { + t.m[destAddr][h.Sum64()] = e + return nil + } + + return ErrRouteNotFound } // Lookup looks up entry in the routing table -func (t *table) Lookup(q Query) ([]*Entry, error) { - return nil, nil +func (t *table) Lookup(q Query) ([]Entry, error) { + return nil, ErrNotImplemented } // Size returns the size of the routing table func (t *table) Size() int { + t.RLock() + defer t.RUnlock() + return len(t.m) } // String returns text representation of routing table func (t *table) String() string { - return "" + t.RLock() + defer t.RUnlock() + + // this will help us build routing table string + sb := &strings.Builder{} + + // create nice table printing structure + table := tablewriter.NewWriter(sb) + table.SetHeader([]string{"Dest", "Hop", "Src", "Metric"}) + + var destAddr, prevAddr string + + for _, entries := range t.m { + for _, entry := range entries { + destAddr = entry.Options().DestAddr + // we want to avoid printing the same dest address + if prevAddr == destAddr { + destAddr = "" + } + strEntry := []string{ + destAddr, + entry.Options().Hop.Address(), + fmt.Sprintf("%d", entry.Options().SrcAddr), + fmt.Sprintf("%d", entry.Options().Metric), + } + table.Append(strEntry) + prevAddr = destAddr + } + } + + return sb.String() } From 459f4c83872d6be1c8a792f22f0f8aa8340888ae Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Sun, 9 Jun 2019 23:19:56 +0100 Subject: [PATCH 018/287] Added Router ID and query options to limit number of results --- router/default.go | 5 ++++- router/query.go | 9 +++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/router/default.go b/router/default.go index 64770ce9..8e1b1e94 100644 --- a/router/default.go +++ b/router/default.go @@ -88,7 +88,10 @@ func (r *router) Address() string { func (r *router) String() string { sb := &strings.Builder{} - s := fmt.Sprintf("Router Local Address: %s\n", r.opts.Address) + s := fmt.Sprintf("Router ID: %s\n", r.id.String()) + sb.WriteString(s) + + s = fmt.Sprintf("Router Local Address: %s\n", r.opts.Address) sb.WriteString(s) s = fmt.Sprintf("Router Network Address: %s\n", r.opts.Network) diff --git a/router/query.go b/router/query.go index 9632e062..677e2575 100644 --- a/router/query.go +++ b/router/query.go @@ -18,6 +18,8 @@ type QueryOptions struct { Service string // Policy defines query lookup policy Policy LookupPolicy + // Count defines max number of results to return + Count int } // EntryOpts allows to set the route query options @@ -41,6 +43,13 @@ func QueryLookupPolicy(p LookupPolicy) QueryOption { } } +// ResultCount allows to set max results to return +func ResultCount(c int) QueryOption { + return func(o *QueryOptions) { + o.Count = c + } +} + // Query defines routing table query type Query interface { // Options returns query options From da18ea4ab54267ecd57c2963303add9faa17789c Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Mon, 10 Jun 2019 13:34:23 +0100 Subject: [PATCH 019/287] Changed default router table modifications. Entry is now Route. --- router/default.go | 8 ++-- router/entry.go | 62 ++++++++++++++--------------- router/query.go | 10 ++--- router/router.go | 12 +++--- router/table.go | 99 +++++++++++++++++++++++------------------------ 5 files changed, 95 insertions(+), 96 deletions(-) diff --git a/router/default.go b/router/default.go index 8e1b1e94..2b525570 100644 --- a/router/default.go +++ b/router/default.go @@ -48,24 +48,24 @@ func (r *router) Options() Options { // Add adds new entry into routing table with given options. // It returns error if the entry could not be added. -func (r *router) Add(e Entry) error { +func (r *router) Add(e Route) error { return r.table.Add(e) } // Remove removes entry from the routing table. // It returns error if either the entry could not be removed or it does not exist. -func (r *router) Remove(e Entry) error { +func (r *router) Remove(e Route) error { return r.table.Remove(e) } // Update updates an entry in the router's routing table // It returns error if the entry was not found or it failed to be updated. -func (r *router) Update(opts ...EntryOption) error { +func (r *router) Update(opts ...RouteOption) error { return r.table.Update(opts...) } // Lookup makes a query lookup and returns all matching entries -func (r *router) Lookup(q Query) ([]*Entry, error) { +func (r *router) Lookup(q Query) ([]*Route, error) { return nil, ErrNotImplemented } diff --git a/router/entry.go b/router/entry.go index 1aee4d65..e37bbfd3 100644 --- a/router/entry.go +++ b/router/entry.go @@ -4,14 +4,14 @@ package router type AddPolicy int const ( - // Override overrides existing routing table entry + // Override overrides existing routing table route OverrideIfExists AddPolicy = iota - // ErrIfExists returns error if the entry already exists + // ErrIfExists returns error if the route already exists ErrIfExists ) -// EntryOptions defines micro network routing table entry options -type EntryOptions struct { +// RouteOptions defines micro network routing table route options +type RouteOptions struct { // DestAddr is destination address DestAddr string // Hop is the next route hop @@ -21,69 +21,69 @@ type EntryOptions struct { SrcAddr string // Metric is route cost metric Metric int - // Policy defines entry addition policy + // Policy defines route addition policy Policy AddPolicy } // DestAddr sets destination address -func DestAddr(a string) EntryOption { - return func(o *EntryOptions) { +func DestAddr(a string) RouteOption { + return func(o *RouteOptions) { o.DestAddr = a } } -// Hop allows to set the route entry options -func Hop(r Router) EntryOption { - return func(o *EntryOptions) { +// Hop allows to set the route route options +func Hop(r Router) RouteOption { + return func(o *RouteOptions) { o.Hop = r } } // SrcAddr sets source address -func SrcAddr(a string) EntryOption { - return func(o *EntryOptions) { +func SrcAddr(a string) RouteOption { + return func(o *RouteOptions) { o.SrcAddr = a } } -// Metric sets entry metric -func Metric(m int) EntryOption { - return func(o *EntryOptions) { +// Metric sets route metric +func Metric(m int) RouteOption { + return func(o *RouteOptions) { o.Metric = m } } -// AddEntryPolicy sets add entry policy -func AddEntryPolicy(p AddPolicy) EntryOption { - return func(o *EntryOptions) { +// RoutePolicy sets add route policy +func RoutePolicy(p AddPolicy) RouteOption { + return func(o *RouteOptions) { o.Policy = p } } -// Entry is routing table entry -type Entry interface { - // Options returns entry options - Options() EntryOptions +// Route is routing table route +type Route interface { + // Options returns route options + Options() RouteOptions } -type entry struct { - opts EntryOptions +type route struct { + opts RouteOptions } -// NewEntry returns new routing table entry -func NewEntry(opts ...EntryOption) Entry { - eopts := EntryOptions{} +// NewRoute returns new routing table route +func NewRoute(opts ...RouteOption) Route { + eopts := RouteOptions{} for _, o := range opts { o(&eopts) } - return &entry{ + return &route{ opts: eopts, } } -// Options returns entry options -func (e *entry) Options() EntryOptions { - return e.opts +// Options returns route options +func (r *route) Options() RouteOptions { + return r.opts } diff --git a/router/query.go b/router/query.go index 677e2575..68298740 100644 --- a/router/query.go +++ b/router/query.go @@ -13,7 +13,7 @@ const ( // QueryOptions allow to define routing table query options type QueryOptions struct { // Route allows to set route options - Route *EntryOptions + Route *RouteOptions // Service is micro service name Service string // Policy defines query lookup policy @@ -22,8 +22,8 @@ type QueryOptions struct { Count int } -// EntryOpts allows to set the route query options -func EntryOpts(r *EntryOptions) QueryOption { +// RouteOpts allows to set the route query options +func RouteOpts(r *RouteOptions) QueryOption { return func(o *QueryOptions) { o.Route = r } @@ -36,8 +36,8 @@ func Service(s string) QueryOption { } } -// QueryLookupPolicy allows to define query lookup policy -func QueryLookupPolicy(p LookupPolicy) QueryOption { +// QueryPolicy allows to define query lookup policy +func QueryPolicy(p LookupPolicy) QueryOption { return func(o *QueryOptions) { o.Policy = p } diff --git a/router/router.go b/router/router.go index ef3b8117..17b6324e 100644 --- a/router/router.go +++ b/router/router.go @@ -8,13 +8,13 @@ type Router interface { // Options returns Router options Options() Options // Add adds new entry into routing table - Add(Entry) error + Add(Route) error // Remove removes entry from the routing table - Remove(Entry) error + Remove(Route) error // Update updates entry in the routing table - Update(...EntryOption) error + Update(...RouteOption) error // Lookup queries the routing table and returns matching entries - Lookup(Query) ([]*Entry, error) + Lookup(Query) ([]*Route, error) // Table returns routing table Table() Table // Address returns the router bind adddress @@ -34,8 +34,8 @@ type RIB interface { // Option used by the router type Option func(*Options) -// EntryOption is used to define routing entry options -type EntryOption func(*EntryOptions) +// RouteOption is used to define routing table entry options +type RouteOption func(*RouteOptions) // QueryOption is used to define query options type QueryOption func(*QueryOptions) diff --git a/router/table.go b/router/table.go index 9039bb1e..b674797b 100644 --- a/router/table.go +++ b/router/table.go @@ -3,6 +3,7 @@ package router import ( "errors" "fmt" + "hash" "hash/fnv" "strings" "sync" @@ -22,13 +23,13 @@ var ( // Table is routing table type Table interface { // Add adds new route to the table - Add(Entry) error + Add(Route) error // Remove removes route from the table - Remove(Entry) error + Remove(Route) error // Update updates route in the table - Update(...EntryOption) error + Update(...RouteOption) error // Lookup looks up routes in the table - Lookup(Query) ([]Entry, error) + Lookup(Query) ([]Route, error) // Size returns the size of the table Size() int // String prints the routing table @@ -39,35 +40,37 @@ type Table interface { // It maps service name to routes type table struct { // m stores routing table map - m map[string]map[uint64]Entry + m map[uint64]Route + // h is a hasher hashes route entries + h hash.Hash64 sync.RWMutex } // NewTable creates new routing table and returns it func NewTable() Table { + h := fnv.New64() + h.Reset() + return &table{ - m: make(map[string]map[uint64]Entry), + m: make(map[uint64]Route), + h: h, } } // Add adds new routing entry -func (t *table) Add(e Entry) error { +func (t *table) Add(r Route) error { t.Lock() defer t.Unlock() - destAddr := e.Options().DestAddr - h := fnv.New64() - h.Write([]byte(e.Options().DestAddr + e.Options().Hop.Address())) + sum := t.hash(r) - if _, ok := t.m[destAddr]; !ok { - // create new map for DestAddr routes - t.m[destAddr] = make(map[uint64]Entry) - t.m[destAddr][h.Sum64()] = e + if _, ok := t.m[sum]; !ok { + t.m[sum] = r return nil } - if _, ok := t.m[destAddr][h.Sum64()]; ok && e.Options().Policy == OverrideIfExists { - t.m[destAddr][h.Sum64()] = e + if _, ok := t.m[sum]; ok && r.Options().Policy == OverrideIfExists { + t.m[sum] = r return nil } @@ -75,41 +78,36 @@ func (t *table) Add(e Entry) error { } // Remove removes entry from the routing table -func (t *table) Remove(e Entry) error { +func (t *table) Remove(r Route) error { t.Lock() defer t.Unlock() - destAddr := e.Options().DestAddr - h := fnv.New64() - h.Write([]byte(e.Options().DestAddr + e.Options().Hop.Address())) + sum := t.hash(r) - if _, ok := t.m[destAddr]; !ok { + if _, ok := t.m[sum]; !ok { return ErrRouteNotFound - } else { - delete(t.m[destAddr], h.Sum64()) - return nil } + delete(t.m, sum) + return nil } // Update updates routing entry -func (t *table) Update(opts ...EntryOption) error { +func (t *table) Update(opts ...RouteOption) error { t.Lock() defer t.Unlock() - e := NewEntry(opts...) + r := NewRoute(opts...) - destAddr := e.Options().DestAddr - h := fnv.New64() - h.Write([]byte(e.Options().DestAddr + e.Options().Hop.Address())) + sum := t.hash(r) - if _, ok := t.m[destAddr]; !ok { + if _, ok := t.m[sum]; !ok { return ErrRouteNotFound } - if _, ok := t.m[destAddr][h.Sum64()]; ok { - t.m[destAddr][h.Sum64()] = e + if _, ok := t.m[sum]; ok { + t.m[sum] = r return nil } @@ -117,7 +115,7 @@ func (t *table) Update(opts ...EntryOption) error { } // Lookup looks up entry in the routing table -func (t *table) Lookup(q Query) ([]Entry, error) { +func (t *table) Lookup(q Query) ([]Route, error) { return nil, ErrNotImplemented } @@ -141,25 +139,26 @@ func (t *table) String() string { table := tablewriter.NewWriter(sb) table.SetHeader([]string{"Dest", "Hop", "Src", "Metric"}) - var destAddr, prevAddr string - - for _, entries := range t.m { - for _, entry := range entries { - destAddr = entry.Options().DestAddr - // we want to avoid printing the same dest address - if prevAddr == destAddr { - destAddr = "" - } - strEntry := []string{ - destAddr, - entry.Options().Hop.Address(), - fmt.Sprintf("%d", entry.Options().SrcAddr), - fmt.Sprintf("%d", entry.Options().Metric), - } - table.Append(strEntry) - prevAddr = destAddr + for _, route := range t.m { + strRoute := []string{ + route.Options().DestAddr, + route.Options().Hop.Address(), + fmt.Sprintf("%d", route.Options().SrcAddr), + fmt.Sprintf("%d", route.Options().Metric), } + table.Append(strRoute) } return sb.String() } + +func (t *table) hash(r Route) uint64 { + srcAddr := r.Options().SrcAddr + destAddr := r.Options().DestAddr + routerAddr := r.Options().Hop.Address() + + t.h.Reset() + t.h.Write([]byte(srcAddr + destAddr + routerAddr)) + + return t.h.Sum64() +} From 5899134b66989e7e4cd3025f7d0a47297bb3beaf Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Mon, 10 Jun 2019 19:50:54 +0100 Subject: [PATCH 020/287] Simplified API. Correct Router initialization. Debug printing. --- router/default.go | 85 +++++++++++++++++++---------------------------- router/entry.go | 11 +++--- router/options.go | 28 +++++++++++++--- router/router.go | 22 ++---------- router/table.go | 11 +++--- 5 files changed, 72 insertions(+), 85 deletions(-) diff --git a/router/default.go b/router/default.go index 2b525570..e5971228 100644 --- a/router/default.go +++ b/router/default.go @@ -4,31 +4,36 @@ import ( "fmt" "strings" - "github.com/google/uuid" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/registry/gossip" + "github.com/olekukonko/tablewriter" ) type router struct { - opts Options - goss registry.Registry - table Table - id uuid.UUID + opts Options + goss registry.Registry } func newRouter(opts ...Option) Router { - // TODO: figure out how to supply gossip registry options - r := &router{ - goss: gossip.NewRegistry(), - table: NewTable(), - id: uuid.New(), + // set default options + options := Options{ + Table: NewTable(), } for _, o := range opts { - o(&r.opts) + o(&options) } - // TODO: need to start some gossip.Registry watch here + goss := gossip.NewRegistry( + gossip.Address(options.GossipAddr), + ) + + r := &router{ + opts: options, + goss: goss, + } + + // TODO: start gossip.Registry watch here return r } @@ -46,37 +51,9 @@ func (r *router) Options() Options { return r.opts } -// Add adds new entry into routing table with given options. -// It returns error if the entry could not be added. -func (r *router) Add(e Route) error { - return r.table.Add(e) -} - -// Remove removes entry from the routing table. -// It returns error if either the entry could not be removed or it does not exist. -func (r *router) Remove(e Route) error { - return r.table.Remove(e) -} - -// Update updates an entry in the router's routing table -// It returns error if the entry was not found or it failed to be updated. -func (r *router) Update(opts ...RouteOption) error { - return r.table.Update(opts...) -} - -// Lookup makes a query lookup and returns all matching entries -func (r *router) Lookup(q Query) ([]*Route, error) { - return nil, ErrNotImplemented -} - // Table returns routing table func (r *router) Table() Table { - return r.table -} - -// Network returns router's micro network -func (r *router) Network() string { - return r.opts.Network + return r.opts.Table } // Address returns router's bind address @@ -84,21 +61,29 @@ func (r *router) Address() string { return r.opts.Address } +// Network returns router's micro network +func (r *router) Network() string { + return r.opts.NetworkAddr +} + // String prints debugging information about router func (r *router) String() string { sb := &strings.Builder{} - s := fmt.Sprintf("Router ID: %s\n", r.id.String()) - sb.WriteString(s) + table := tablewriter.NewWriter(sb) + table.SetHeader([]string{"ID", "Address", "Gossip", "Network", "Table"}) - s = fmt.Sprintf("Router Local Address: %s\n", r.opts.Address) - sb.WriteString(s) + data := []string{ + r.opts.ID, + r.opts.Address, + r.opts.GossipAddr, + r.opts.NetworkAddr, + fmt.Sprintf("%d", r.opts.Table.Size()), + } + table.Append(data) - s = fmt.Sprintf("Router Network Address: %s\n", r.opts.Network) - sb.WriteString(s) - - s = fmt.Sprintf("Routing table size: %d\n", r.opts.Table.Size()) - sb.WriteString(s) + // render table into sb + table.Render() return sb.String() } diff --git a/router/entry.go b/router/entry.go index e37bbfd3..7d4a8d88 100644 --- a/router/entry.go +++ b/router/entry.go @@ -16,9 +16,8 @@ type RouteOptions struct { DestAddr string // Hop is the next route hop Hop Router - // SrcAddr defines local routing address - // On local networkss, this will be the address of local router - SrcAddr string + // Network defines micro network + Network string // Metric is route cost metric Metric int // Policy defines route addition policy @@ -39,10 +38,10 @@ func Hop(r Router) RouteOption { } } -// SrcAddr sets source address -func SrcAddr(a string) RouteOption { +// Network sets micro network +func Network(n string) RouteOption { return func(o *RouteOptions) { - o.SrcAddr = a + o.Network = n } } diff --git a/router/options.go b/router/options.go index 8e1077c1..066bf5ab 100644 --- a/router/options.go +++ b/router/options.go @@ -6,10 +6,14 @@ import ( // Options allows to set Router options type Options struct { + // ID is router ID + ID string // Address is router address Address string - // Network defines micro network address - Network string + // GossipAddr is router gossip address + GossipAddr string + // NetworkAddr defines micro network address + NetworkAddr string // RIB is Routing Information Base RIB RIB // Table is routing table @@ -18,6 +22,13 @@ type Options struct { Context context.Context } +// ID sets Router ID +func ID(id string) Option { + return func(o *Options) { + o.ID = id + } +} + // Address allows to set router address func Address(a string) Option { return func(o *Options) { @@ -25,10 +36,17 @@ func Address(a string) Option { } } -// Network allows to set router network -func Network(n string) Option { +// GossipAddress allows to set router address +func GossipAddress(a string) Option { return func(o *Options) { - o.Network = n + o.GossipAddr = a + } +} + +// NetworkAddr allows to set router network +func NetworkAddr(n string) Option { + return func(o *Options) { + o.NetworkAddr = n } } diff --git a/router/router.go b/router/router.go index 17b6324e..fffd1752 100644 --- a/router/router.go +++ b/router/router.go @@ -7,19 +7,11 @@ type Router interface { Init(...Option) error // Options returns Router options Options() Options - // Add adds new entry into routing table - Add(Route) error - // Remove removes entry from the routing table - Remove(Route) error - // Update updates entry in the routing table - Update(...RouteOption) error - // Lookup queries the routing table and returns matching entries - Lookup(Query) ([]*Route, error) // Table returns routing table Table() Table - // Address returns the router bind adddress + // Address returns router gossip adddress Address() string - // Network returns router's micro network bind address + // Network returns micro network address Network() string // String implemens fmt.Stringer interface String() string @@ -42,15 +34,5 @@ type QueryOption func(*QueryOptions) // NewRouter creates new Router and returns it func NewRouter(opts ...Option) Router { - // set default options - ropts := Options{ - // Default table - Table: NewTable(), - } - - for _, o := range opts { - o(&ropts) - } - return newRouter(opts...) } diff --git a/router/table.go b/router/table.go index b674797b..618b69ee 100644 --- a/router/table.go +++ b/router/table.go @@ -137,28 +137,31 @@ func (t *table) String() string { // create nice table printing structure table := tablewriter.NewWriter(sb) - table.SetHeader([]string{"Dest", "Hop", "Src", "Metric"}) + table.SetHeader([]string{"Service", "Gateway", "Network", "Metric"}) for _, route := range t.m { strRoute := []string{ route.Options().DestAddr, route.Options().Hop.Address(), - fmt.Sprintf("%d", route.Options().SrcAddr), + route.Options().Network, fmt.Sprintf("%d", route.Options().Metric), } table.Append(strRoute) } + // render table into sb + table.Render() + return sb.String() } func (t *table) hash(r Route) uint64 { - srcAddr := r.Options().SrcAddr destAddr := r.Options().DestAddr routerAddr := r.Options().Hop.Address() + network := r.Options().Network t.h.Reset() - t.h.Write([]byte(srcAddr + destAddr + routerAddr)) + t.h.Write([]byte(destAddr + routerAddr + network)) return t.h.Sum64() } From 338e0fdf181e3427d9b1829b466803c6c08b34f1 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Tue, 11 Jun 2019 23:59:25 +0100 Subject: [PATCH 021/287] Lots of refactoring. We now have basic routing table watcher. --- router/default.go | 126 ++++++++++++++++++++++++++++++++++++++-- router/entry.go | 10 ++-- router/options.go | 8 +-- router/query.go | 21 ++----- router/router.go | 15 +++-- router/table.go | 115 ++++++++++++++++++++++++++---------- router/table_watcher.go | 89 ++++++++++++++++++++++++++++ 7 files changed, 320 insertions(+), 64 deletions(-) create mode 100644 router/table_watcher.go diff --git a/router/default.go b/router/default.go index e5971228..5d2ffc29 100644 --- a/router/default.go +++ b/router/default.go @@ -3,7 +3,9 @@ package router import ( "fmt" "strings" + "sync" + "github.com/micro/go-log" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/registry/gossip" "github.com/olekukonko/tablewriter" @@ -12,6 +14,8 @@ import ( type router struct { opts Options goss registry.Registry + exit chan struct{} + wg *sync.WaitGroup } func newRouter(opts ...Option) Router { @@ -20,22 +24,22 @@ func newRouter(opts ...Option) Router { Table: NewTable(), } + // apply requested options for _, o := range opts { o(&options) } + // bind to gossip address to join gossip registry goss := gossip.NewRegistry( gossip.Address(options.GossipAddr), ) - r := &router{ + return &router{ opts: options, goss: goss, + exit: make(chan struct{}), + wg: &sync.WaitGroup{}, } - - // TODO: start gossip.Registry watch here - - return r } // Init initializes router with given options @@ -66,6 +70,118 @@ func (r *router) Network() string { return r.opts.NetworkAddr } +// Start starts the router +func (r *router) Start() error { + // TODO: + // - list all remote services and populate routing table + // - list all local services and populate remote registry + + gWatcher, err := r.goss.Watch() + if err != nil { + return fmt.Errorf("failed to create router gossip registry watcher: %v", err) + } + + tWatcher, err := r.opts.Table.Watch() + if err != nil { + return fmt.Errorf("failed to create routing table watcher: %v", err) + } + + r.wg.Add(1) + go r.watchGossip(gWatcher) + + r.wg.Add(1) + go r.watchTable(tWatcher) + + return nil +} + +// watch gossip registry +func (r *router) watchGossip(w registry.Watcher) error { + defer r.wg.Done() + + r.wg.Add(1) + go func() { + defer r.wg.Done() + <-r.exit + // stop gossip registry watcher + w.Stop() + }() + + var watchErr error + + // watch for changes to services + for { + res, err := w.Next() + if err == registry.ErrWatcherStopped { + break + } + + if err != nil { + watchErr = err + break + } + + switch res.Action { + case "create": + if len(res.Service.Nodes) > 0 { + log.Logf("Action: %s, Service: %v", res.Action, res.Service.Name) + } + case "delete": + log.Logf("Action: %s, Service: %v", res.Action, res.Service.Name) + } + } + + return watchErr +} + +// watch gossip registry +func (r *router) watchTable(w Watcher) error { + defer r.wg.Done() + + r.wg.Add(1) + go func() { + defer r.wg.Done() + <-r.exit + // stop gossip registry watcher + w.Stop() + }() + + var watchErr error + + // watch for changes to services + for { + res, err := w.Next() + if err == ErrWatcherStopped { + break + } + + if err != nil { + watchErr = err + break + } + + switch res.Action { + case "add": + log.Logf("Action: %s, Route: %v", res.Action, res.Route) + case "remove": + log.Logf("Action: %s, Route: %v", res.Action, res.Route) + } + } + + return watchErr +} + +// Stop stops the router +func (r *router) Stop() error { + // notify all goroutines to finish + close(r.exit) + + // wait for all goroutines to finish + r.wg.Wait() + + return nil +} + // String prints debugging information about router func (r *router) String() string { sb := &strings.Builder{} diff --git a/router/entry.go b/router/entry.go index 7d4a8d88..d446a3d9 100644 --- a/router/entry.go +++ b/router/entry.go @@ -14,8 +14,8 @@ const ( type RouteOptions struct { // DestAddr is destination address DestAddr string - // Hop is the next route hop - Hop Router + // Gateway is the next route hop + Gateway Router // Network defines micro network Network string // Metric is route cost metric @@ -31,10 +31,10 @@ func DestAddr(a string) RouteOption { } } -// Hop allows to set the route route options -func Hop(r Router) RouteOption { +// Gateway sets the route gateway +func Gateway(r Router) RouteOption { return func(o *RouteOptions) { - o.Hop = r + o.Gateway = r } } diff --git a/router/options.go b/router/options.go index 066bf5ab..f8c34091 100644 --- a/router/options.go +++ b/router/options.go @@ -29,21 +29,21 @@ func ID(id string) Option { } } -// Address allows to set router address +// Address sets router address func Address(a string) Option { return func(o *Options) { o.Address = a } } -// GossipAddress allows to set router address -func GossipAddress(a string) Option { +// GossipAddr sets router gossip address +func GossipAddr(a string) Option { return func(o *Options) { o.GossipAddr = a } } -// NetworkAddr allows to set router network +// NetworkAddr sets router network address func NetworkAddr(n string) Option { return func(o *Options) { o.NetworkAddr = n diff --git a/router/query.go b/router/query.go index 68298740..a022eda2 100644 --- a/router/query.go +++ b/router/query.go @@ -13,26 +13,17 @@ const ( // QueryOptions allow to define routing table query options type QueryOptions struct { // Route allows to set route options - Route *RouteOptions - // Service is micro service name - Service string + RouteOptions *RouteOptions // Policy defines query lookup policy Policy LookupPolicy // Count defines max number of results to return Count int } -// RouteOpts allows to set the route query options -func RouteOpts(r *RouteOptions) QueryOption { +// QueryRouteOpts allows to set the route query options +func QueryRouteOptons(r *RouteOptions) QueryOption { return func(o *QueryOptions) { - o.Route = r - } -} - -// Service allows to set the service name in routing query -func Service(s string) QueryOption { - return func(o *QueryOptions) { - o.Service = s + o.RouteOptions = r } } @@ -43,8 +34,8 @@ func QueryPolicy(p LookupPolicy) QueryOption { } } -// ResultCount allows to set max results to return -func ResultCount(c int) QueryOption { +// QueryCount allows to set max results to return +func QueryCount(c int) QueryOption { return func(o *QueryOptions) { o.Count = c } diff --git a/router/router.go b/router/router.go index fffd1752..40b49bc5 100644 --- a/router/router.go +++ b/router/router.go @@ -1,4 +1,4 @@ -// Package router provides an interface for micro network routers +// Package router provides an interface for micro network router package router // Router is micro network router @@ -9,11 +9,15 @@ type Router interface { Options() Options // Table returns routing table Table() Table - // Address returns router gossip adddress + // Address returns router adddress Address() string - // Network returns micro network address + // Network returns router network address Network() string - // String implemens fmt.Stringer interface + // Start starts router + Start() error + // Stop stops router + Stop() error + // String returns router debug info String() string } @@ -32,6 +36,9 @@ type RouteOption func(*RouteOptions) // QueryOption is used to define query options type QueryOption func(*QueryOptions) +// WatchOption is used to define what routes to watch in the table +type WatchOption func(*WatchOptions) + // NewRouter creates new Router and returns it func NewRouter(opts ...Option) Router { return newRouter(opts...) diff --git a/router/table.go b/router/table.go index 618b69ee..9611bf65 100644 --- a/router/table.go +++ b/router/table.go @@ -8,6 +8,7 @@ import ( "strings" "sync" + "github.com/google/uuid" "github.com/olekukonko/tablewriter" ) @@ -24,12 +25,14 @@ var ( type Table interface { // Add adds new route to the table Add(Route) error - // Remove removes route from the table + // Remove removes existing route from the table Remove(Route) error // Update updates route in the table Update(...RouteOption) error // Lookup looks up routes in the table Lookup(Query) ([]Route, error) + // Watch returns a watcher which allows you to track updates to the table + Watch(opts ...WatchOption) (Watcher, error) // Size returns the size of the table Size() int // String prints the routing table @@ -37,12 +40,13 @@ type Table interface { } // table is routing table -// It maps service name to routes type table struct { // m stores routing table map - m map[uint64]Route - // h is a hasher hashes route entries + m map[string]map[uint64]Route + // h hashes route entries h hash.Hash64 + // w is a list of table watchers + w map[string]*tableWatcher sync.RWMutex } @@ -52,73 +56,120 @@ func NewTable() Table { h.Reset() return &table{ - m: make(map[uint64]Route), + m: make(map[string]map[uint64]Route), + w: make(map[string]*tableWatcher), h: h, } } -// Add adds new routing entry +// Add adds a route to the routing table func (t *table) Add(r Route) error { t.Lock() defer t.Unlock() + destAddr := r.Options().DestAddr sum := t.hash(r) - if _, ok := t.m[sum]; !ok { - t.m[sum] = r + if _, ok := t.m[destAddr]; !ok { + t.m[destAddr] = make(map[uint64]Route) + t.m[destAddr][sum] = r + go t.sendResult(&Result{Action: "add", Route: r}) return nil } - if _, ok := t.m[sum]; ok && r.Options().Policy == OverrideIfExists { - t.m[sum] = r + if _, ok := t.m[destAddr][sum]; ok && r.Options().Policy == OverrideIfExists { + t.m[destAddr][sum] = r + go t.sendResult(&Result{Action: "update", Route: r}) return nil } return ErrDuplicateRoute } -// Remove removes entry from the routing table +// Remove removes the route from the routing table func (t *table) Remove(r Route) error { t.Lock() defer t.Unlock() + destAddr := r.Options().DestAddr sum := t.hash(r) - if _, ok := t.m[sum]; !ok { + if _, ok := t.m[destAddr]; !ok { return ErrRouteNotFound } - delete(t.m, sum) + delete(t.m[destAddr], sum) + go t.sendResult(&Result{Action: "remove", Route: r}) return nil } -// Update updates routing entry +// Update updates routing table using propvided options func (t *table) Update(opts ...RouteOption) error { t.Lock() defer t.Unlock() r := NewRoute(opts...) + destAddr := r.Options().DestAddr sum := t.hash(r) - if _, ok := t.m[sum]; !ok { + if _, ok := t.m[destAddr]; !ok { return ErrRouteNotFound } - if _, ok := t.m[sum]; ok { - t.m[sum] = r + if _, ok := t.m[destAddr][sum]; ok { + t.m[destAddr][sum] = r + go t.sendResult(&Result{Action: "update", Route: r}) return nil } return ErrRouteNotFound } -// Lookup looks up entry in the routing table +// Lookup queries routing table and returns all routes that match it func (t *table) Lookup(q Query) ([]Route, error) { return nil, ErrNotImplemented } +// Watch returns routing table entry watcher +func (t *table) Watch(opts ...WatchOption) (Watcher, error) { + // by default watch everything + wopts := WatchOptions{ + DestAddr: "*", + Network: "*", + } + + for _, o := range opts { + o(&wopts) + } + + watcher := &tableWatcher{ + opts: wopts, + resChan: make(chan *Result, 10), + done: make(chan struct{}), + } + + t.Lock() + t.w[uuid.New().String()] = watcher + t.Unlock() + + return watcher, nil +} + +// sendResult sends rules to all subscribe watchers +func (t *table) sendResult(r *Result) { + t.RLock() + defer t.RUnlock() + + for _, w := range t.w { + select { + case w.resChan <- r: + case <-w.done: + } + } +} + // Size returns the size of the routing table func (t *table) Size() int { t.RLock() @@ -127,7 +178,7 @@ func (t *table) Size() int { return len(t.m) } -// String returns text representation of routing table +// String returns debug information func (t *table) String() string { t.RLock() defer t.RUnlock() @@ -137,16 +188,18 @@ func (t *table) String() string { // create nice table printing structure table := tablewriter.NewWriter(sb) - table.SetHeader([]string{"Service", "Gateway", "Network", "Metric"}) + table.SetHeader([]string{"Destination", "Gateway", "Network", "Metric"}) - for _, route := range t.m { - strRoute := []string{ - route.Options().DestAddr, - route.Options().Hop.Address(), - route.Options().Network, - fmt.Sprintf("%d", route.Options().Metric), + for _, destRoute := range t.m { + for _, route := range destRoute { + strRoute := []string{ + route.Options().DestAddr, + route.Options().Gateway.Address(), + route.Options().Gateway.Network(), + fmt.Sprintf("%d", route.Options().Metric), + } + table.Append(strRoute) } - table.Append(strRoute) } // render table into sb @@ -155,13 +208,13 @@ func (t *table) String() string { return sb.String() } +// hash hashes the route using router gateway and network address func (t *table) hash(r Route) uint64 { - destAddr := r.Options().DestAddr - routerAddr := r.Options().Hop.Address() - network := r.Options().Network + gwAddr := r.Options().Gateway.Address() + netAddr := r.Options().Network t.h.Reset() - t.h.Write([]byte(destAddr + routerAddr + network)) + t.h.Write([]byte(gwAddr + netAddr)) return t.h.Sum64() } diff --git a/router/table_watcher.go b/router/table_watcher.go new file mode 100644 index 00000000..c246100b --- /dev/null +++ b/router/table_watcher.go @@ -0,0 +1,89 @@ +package router + +import ( + "errors" +) + +var ( + // ErrWatcherStopped is returned when routing table watcher has been stopped + ErrWatcherStopped = errors.New("routing table watcher stopped") +) + +// Watcher is an interface that returns updates to the routing table +type Watcher interface { + // Next is a blocking call that returns watch result + Next() (*Result, error) + // Stop stops watcher + Stop() +} + +// Result is returned by a call to Next on the watcher. +type Result struct { + // Action is routing table action which is either of add, remove or update + Action string + // Route is table rout + Route Route +} + +// Watcher options +type WatchOptions struct { + // Specify destination address to watch + DestAddr string + // Specify network to watch + Network string +} + +// WatchDestAddr sets what destination to watch +// Destination is usually microservice name +func WatchDestAddr(a string) WatchOption { + return func(o *WatchOptions) { + o.DestAddr = a + } +} + +// WatchNetwork sets what network to watch +func WatchNetwork(n string) WatchOption { + return func(o *WatchOptions) { + o.Network = n + } +} + +type tableWatcher struct { + opts WatchOptions + resChan chan *Result + done chan struct{} +} + +// TODO: We might simply use Query here once QueryLookup is figured out +// Next returns the next noticed action taken on table +func (w *tableWatcher) Next() (*Result, error) { + for { + select { + case res := <-w.resChan: + switch w.opts.DestAddr { + case "*": + if w.opts.Network == "*" || w.opts.Network == res.Route.Options().Network { + return res, nil + } + case res.Route.Options().DestAddr: + if w.opts.Network == "*" || w.opts.Network == res.Route.Options().Network { + return res, nil + } + } + // ignore if no match is found + continue + case <-w.done: + return nil, ErrWatcherStopped + } + } +} + +// Stop stops routing table watcher +func (w *tableWatcher) Stop() { + select { + case <-w.done: + return + default: + close(w.done) + } +} From 95fc625e998894afe4f91f1459667f3168cdfda9 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Wed, 12 Jun 2019 22:30:42 +0100 Subject: [PATCH 022/287] Big refactor. New Registry watchers. New options. New names. --- router/default.go | 218 +++++++++++++++++++++++++++++++++------- router/entry.go | 6 ++ router/options.go | 84 +++++++++++----- router/query.go | 35 ++++--- router/rib.go | 26 +++++ router/router.go | 19 ++-- router/table.go | 44 ++++++-- router/table_watcher.go | 4 +- 8 files changed, 346 insertions(+), 90 deletions(-) create mode 100644 router/rib.go diff --git a/router/default.go b/router/default.go index 5d2ffc29..7ae8a718 100644 --- a/router/default.go +++ b/router/default.go @@ -2,41 +2,33 @@ package router import ( "fmt" + "strconv" "strings" "sync" + "time" "github.com/micro/go-log" "github.com/micro/go-micro/registry" - "github.com/micro/go-micro/registry/gossip" "github.com/olekukonko/tablewriter" ) type router struct { opts Options - goss registry.Registry exit chan struct{} wg *sync.WaitGroup } func newRouter(opts ...Option) Router { - // set default options - options := Options{ - Table: NewTable(), - } + // get default options + options := DefaultOptions() // apply requested options for _, o := range opts { o(&options) } - // bind to gossip address to join gossip registry - goss := gossip.NewRegistry( - gossip.Address(options.GossipAddr), - ) - return &router{ opts: options, - goss: goss, exit: make(chan struct{}), wg: &sync.WaitGroup{}, } @@ -65,29 +57,78 @@ func (r *router) Address() string { return r.opts.Address } +// Gossip returns gossip bind address +func (r *router) Gossip() string { + return r.opts.GossipAddress +} + // Network returns router's micro network func (r *router) Network() string { - return r.opts.NetworkAddr + return r.opts.NetworkAddress } // Start starts the router func (r *router) Start() error { - // TODO: - // - list all remote services and populate routing table - // - list all local services and populate remote registry - - gWatcher, err := r.goss.Watch() - if err != nil { - return fmt.Errorf("failed to create router gossip registry watcher: %v", err) + // add local service routes into routing table + if err := r.addServiceRoutes(r.opts.LocalRegistry, "local", 1); err != nil { + return fmt.Errorf("failed to add service routes for local services: %v", err) } - tWatcher, err := r.opts.Table.Watch() + // add network service routes into routing table + if err := r.addServiceRoutes(r.opts.NetworkRegistry, r.opts.NetworkAddress, 10); err != nil { + return fmt.Errorf("failed to add service routes for network services: %v", err) + } + + // lookup local service routes and advertise them in network registry + query := NewQuery(QueryNetwork("local")) + localRoutes, err := r.opts.Table.Lookup(query) + if err != nil && err != ErrRouteNotFound { + return fmt.Errorf("failed to lookup local service routes: %v", err) + } + + addr := strings.Split(r.opts.Address, ":") + port, err := strconv.Atoi(addr[1]) + if err != nil { + fmt.Errorf("could not parse router address from %s: %v", r.opts.Address, err) + } + + for _, route := range localRoutes { + node := ®istry.Node{ + Id: r.opts.ID, + Address: addr[0], + Port: port, + } + + service := ®istry.Service{ + Name: route.Options().DestAddr, + Nodes: []*registry.Node{node}, + } + if err := r.opts.NetworkRegistry.Register(service, registry.RegisterTTL(10*time.Second)); err != nil { + return fmt.Errorf("failed to register service %s in network registry: %v", service.Name, err) + } + } + + lWatcher, err := r.opts.LocalRegistry.Watch() + if err != nil { + return fmt.Errorf("failed to create local registry watcher: %v", err) + } + + rWatcher, err := r.opts.NetworkRegistry.Watch() + if err != nil { + return fmt.Errorf("failed to create network registry watcher: %v", err) + } + + // we only watch local entries which we resend to network registry + tWatcher, err := r.opts.Table.Watch(WatchNetwork("local")) if err != nil { return fmt.Errorf("failed to create routing table watcher: %v", err) } r.wg.Add(1) - go r.watchGossip(gWatcher) + go r.watchLocal(lWatcher) + + r.wg.Add(1) + go r.watchRemote(rWatcher) r.wg.Add(1) go r.watchTable(tWatcher) @@ -95,15 +136,39 @@ func (r *router) Start() error { return nil } -// watch gossip registry -func (r *router) watchGossip(w registry.Watcher) error { +func (r *router) addServiceRoutes(reg registry.Registry, network string, metric int) error { + // list all local services + services, err := reg.ListServices() + if err != nil { + return fmt.Errorf("failed to list services: %v", err) + } + + // add services to routing table + for _, service := range services { + // create new micro network route + route := NewRoute( + DestAddr(service.Name), + Gateway(r), + Network(network), + Metric(metric), + ) + // add new route to routing table + if err := r.opts.Table.Add(route); err != nil { + return fmt.Errorf("failed to add route for service: %s", service.Name) + } + } + + return nil +} + +// watch local registry +func (r *router) watchLocal(w registry.Watcher) error { defer r.wg.Done() r.wg.Add(1) go func() { defer r.wg.Done() <-r.exit - // stop gossip registry watcher w.Stop() }() @@ -121,20 +186,83 @@ func (r *router) watchGossip(w registry.Watcher) error { break } + // create new route + route := NewRoute( + DestAddr(res.Service.Name), + Gateway(r), + Network("local"), + Metric(1), + ) + switch res.Action { case "create": if len(res.Service.Nodes) > 0 { - log.Logf("Action: %s, Service: %v", res.Action, res.Service.Name) + if err := r.opts.Table.Add(route); err != nil { + log.Logf("[router] failed to add route for local service: %v", res.Service.Name) + } } case "delete": - log.Logf("Action: %s, Service: %v", res.Action, res.Service.Name) + if err := r.opts.Table.Remove(route); err != nil { + log.Logf("[router] failed to remove route for local service: %v", res.Service.Name) + } } } return watchErr } -// watch gossip registry +// watch remote registry +func (r *router) watchRemote(w registry.Watcher) error { + defer r.wg.Done() + + r.wg.Add(1) + go func() { + defer r.wg.Done() + <-r.exit + w.Stop() + }() + + var watchErr error + + // watch for changes to services + for { + res, err := w.Next() + if err == registry.ErrWatcherStopped { + break + } + + if err != nil { + watchErr = err + break + } + + // create new route + route := NewRoute( + DestAddr(res.Service.Name), + Gateway(r), + Network(r.opts.NetworkAddress), + Metric(10), + RoutePolicy(IgnoreIfExists), + ) + + switch res.Action { + case "create": + if len(res.Service.Nodes) > 0 { + if err := r.opts.Table.Add(route); err != nil { + log.Logf("[router] failed to add route for network service: %v", res.Service.Name) + } + } + case "delete": + if err := r.opts.Table.Remove(route); err != nil { + log.Logf("[router] failed to remove route for network service: %v", res.Service.Name) + } + } + } + + return watchErr +} + +// watch routing table changes func (r *router) watchTable(w Watcher) error { defer r.wg.Done() @@ -142,7 +270,6 @@ func (r *router) watchTable(w Watcher) error { go func() { defer r.wg.Done() <-r.exit - // stop gossip registry watcher w.Stop() }() @@ -160,11 +287,35 @@ func (r *router) watchTable(w Watcher) error { break } + addr := strings.Split(r.opts.Address, ":") + port, err := strconv.Atoi(addr[1]) + if err != nil { + log.Logf("[router] could not parse router address from %s: %v", r.opts.Address, err) + continue + } + + node := ®istry.Node{ + Id: r.opts.ID, + Address: addr[0], + Port: port, + } + + service := ®istry.Service{ + Name: res.Route.Options().DestAddr, + Nodes: []*registry.Node{node}, + } + switch res.Action { case "add": - log.Logf("Action: %s, Route: %v", res.Action, res.Route) + log.Logf("[router] routing table action: %s, route: %v", res.Action, res.Route) + if err := r.opts.NetworkRegistry.Register(service, registry.RegisterTTL(10*time.Second)); err != nil { + log.Logf("[router] failed to register service %s in network registry: %v", service.Name, err) + } case "remove": - log.Logf("Action: %s, Route: %v", res.Action, res.Route) + log.Logf("[router] routing table action: %s, route: %v", res.Action, res.Route) + if err := r.opts.NetworkRegistry.Register(service); err != nil { + log.Logf("[router] failed to deregister service %s from network registry: %v", service.Name, err) + } } } @@ -187,13 +338,12 @@ func (r *router) String() string { sb := &strings.Builder{} table := tablewriter.NewWriter(sb) - table.SetHeader([]string{"ID", "Address", "Gossip", "Network", "Table"}) + table.SetHeader([]string{"ID", "Address", "Network", "Table"}) data := []string{ r.opts.ID, r.opts.Address, - r.opts.GossipAddr, - r.opts.NetworkAddr, + r.opts.NetworkAddress, fmt.Sprintf("%d", r.opts.Table.Size()), } table.Append(data) diff --git a/router/entry.go b/router/entry.go index d446a3d9..3b94a562 100644 --- a/router/entry.go +++ b/router/entry.go @@ -1,11 +1,15 @@ package router +import "context" + // AddPolicy defines routing table addition policy type AddPolicy int const ( // Override overrides existing routing table route OverrideIfExists AddPolicy = iota + // IgnoreIfExists does not add new route + IgnoreIfExists // ErrIfExists returns error if the route already exists ErrIfExists ) @@ -22,6 +26,8 @@ type RouteOptions struct { Metric int // Policy defines route addition policy Policy AddPolicy + // Context stores other arbitrary options + Context context.Context } // DestAddr sets destination address diff --git a/router/options.go b/router/options.go index f8c34091..9774f237 100644 --- a/router/options.go +++ b/router/options.go @@ -1,25 +1,35 @@ package router import ( - "context" + "github.com/google/uuid" + "github.com/micro/go-micro/registry" ) -// Options allows to set Router options +var ( + // DefaultAddress is default router bind address + DefaultAddress = ":9093" + // DefaultNetworkAddress is default micro network bind address + DefaultNetworkAddress = ":9094" +) + +// Options allows to set router options type Options struct { // ID is router ID ID string // Address is router address Address string - // GossipAddr is router gossip address - GossipAddr string - // NetworkAddr defines micro network address - NetworkAddr string - // RIB is Routing Information Base - RIB RIB + // GossipAddress is router gossip address + GossipAddress string + // NetworkAddress is micro network address + NetworkAddress string + // LocalRegistry is router local registry + LocalRegistry registry.Registry + // NetworkRegistry is router remote registry + NetworkRegistry registry.Registry // Table is routing table Table Table - // Context stores arbitrary options - Context context.Context + // RIB is Routing Information Base + RIB RIB } // ID sets Router ID @@ -36,24 +46,17 @@ func Address(a string) Option { } } -// GossipAddr sets router gossip address -func GossipAddr(a string) Option { +// GossipAddress sets router gossip address +func GossipAddress(a string) Option { return func(o *Options) { - o.GossipAddr = a + o.GossipAddress = a } } -// NetworkAddr sets router network address -func NetworkAddr(n string) Option { +// NetworkAddress sets router network address +func NetworkAddress(n string) Option { return func(o *Options) { - o.NetworkAddr = n - } -} - -// RIBase allows to configure RIB -func RIBase(r RIB) Option { - return func(o *Options) { - o.RIB = r + o.NetworkAddress = n } } @@ -63,3 +66,38 @@ func RoutingTable(t Table) Option { o.Table = t } } + +// LocalRegistry allows to specify local registry +func LocalRegistry(r registry.Registry) Option { + return func(o *Options) { + o.LocalRegistry = r + } +} + +// NetworkRegistry allows to specify remote registry +func NetworkRegistry(r registry.Registry) Option { + return func(o *Options) { + o.NetworkRegistry = r + } +} + +// RouterIB allows to configure RIB +func RouterIB(r RIB) Option { + return func(o *Options) { + o.RIB = r + } +} + +// DefaultOptions returns router default options +func DefaultOptions() Options { + // NOTE: by default both local and network registies use default registry i.e. mdns + // TODO: DefaultRIB needs to be added once it's properly figured out + return Options{ + ID: uuid.New().String(), + Address: DefaultAddress, + NetworkAddress: DefaultNetworkAddress, + LocalRegistry: registry.DefaultRegistry, + NetworkRegistry: registry.DefaultRegistry, + Table: NewTable(), + } +} diff --git a/router/query.go b/router/query.go index a022eda2..2cc0bf24 100644 --- a/router/query.go +++ b/router/query.go @@ -12,18 +12,25 @@ const ( // QueryOptions allow to define routing table query options type QueryOptions struct { - // Route allows to set route options - RouteOptions *RouteOptions + // DestAddr defines destination address + DestAddr string + // NetworkAddress defines network address + Network string // Policy defines query lookup policy Policy LookupPolicy - // Count defines max number of results to return - Count int } -// QueryRouteOpts allows to set the route query options -func QueryRouteOptons(r *RouteOptions) QueryOption { +// QueryDestAddr sets query destination address +func QueryDestAddr(a string) QueryOption { return func(o *QueryOptions) { - o.RouteOptions = r + o.DestAddr = a + } +} + +// QueryNetwork sets query network address +func QueryNetwork(a string) QueryOption { + return func(o *QueryOptions) { + o.Network = a } } @@ -34,13 +41,6 @@ func QueryPolicy(p LookupPolicy) QueryOption { } } -// QueryCount allows to set max results to return -func QueryCount(c int) QueryOption { - return func(o *QueryOptions) { - o.Count = c - } -} - // Query defines routing table query type Query interface { // Options returns query options @@ -53,7 +53,12 @@ type query struct { // NewQuery creates new query and returns it func NewQuery(opts ...QueryOption) Query { - qopts := QueryOptions{} + // default options + qopts := QueryOptions{ + DestAddr: "*", + Network: "*", + Policy: DiscardNoRoute, + } for _, o := range opts { o(&qopts) diff --git a/router/rib.go b/router/rib.go new file mode 100644 index 00000000..1c6f538e --- /dev/null +++ b/router/rib.go @@ -0,0 +1,26 @@ +package router + +// RIB is Routing Information Base +type RIB interface { + // Initi initializes RIB + Init(...RIBOption) error + // Options returns RIB options + Options() RIBOptions + // Routes returns routes in RIB + Routes() []Route + // String returns debug info + String() string +} + +// RIBOptions allow to set RIB sources. +type RIBOptions struct { + // Source defines RIB source URL + Source string +} + +// Source sets RIB source +func Source(s string) RIBOption { + return func(o *RIBOptions) { + o.Source = s + } +} diff --git a/router/router.go b/router/router.go index 40b49bc5..419b62d3 100644 --- a/router/router.go +++ b/router/router.go @@ -3,26 +3,22 @@ package router // Router is micro network router type Router interface { - // Initi initializes Router with options + // Init initializes the router with options Init(...Option) error - // Options returns Router options + // Options returns the router options Options() Options // Table returns routing table Table() Table // Address returns router adddress Address() string + // Gossip returns router gossip address + Gossip() string // Network returns router network address Network() string - // Start starts router + // Start starts the router Start() error - // Stop stops router + // Stop stops the router Stop() error - // String returns router debug info - String() string -} - -// RIB is Routing Information Base -type RIB interface { // String returns debug info String() string } @@ -30,6 +26,9 @@ type RIB interface { // Option used by the router type Option func(*Options) +// RIBOptopn is used to configure RIB +type RIBOption func(*RIBOptions) + // RouteOption is used to define routing table entry options type RouteOption func(*RouteOptions) diff --git a/router/table.go b/router/table.go index 9611bf65..d246e177 100644 --- a/router/table.go +++ b/router/table.go @@ -28,7 +28,7 @@ type Table interface { // Remove removes existing route from the table Remove(Route) error // Update updates route in the table - Update(...RouteOption) error + Update(Route) error // Lookup looks up routes in the table Lookup(Query) ([]Route, error) // Watch returns a watcher which allows you to track updates to the table @@ -83,6 +83,10 @@ func (t *table) Add(r Route) error { return nil } + if r.Options().Policy == IgnoreIfExists { + return nil + } + return ErrDuplicateRoute } @@ -104,13 +108,11 @@ func (t *table) Remove(r Route) error { return nil } -// Update updates routing table using propvided options -func (t *table) Update(opts ...RouteOption) error { +// Update updates routing table with new route +func (t *table) Update(r Route) error { t.Lock() defer t.Unlock() - r := NewRoute(opts...) - destAddr := r.Options().DestAddr sum := t.hash(r) @@ -129,7 +131,37 @@ func (t *table) Update(opts ...RouteOption) error { // Lookup queries routing table and returns all routes that match it func (t *table) Lookup(q Query) ([]Route, error) { - return nil, ErrNotImplemented + t.RLock() + defer t.RUnlock() + + var results []Route + + for destAddr, routes := range t.m { + if q.Options().DestAddr != "*" { + if q.Options().DestAddr != destAddr { + continue + } + for _, route := range routes { + if q.Options().Network == "*" || q.Options().Network == route.Options().Network { + results = append(results, route) + } + } + } + + if q.Options().DestAddr == "*" { + for _, route := range routes { + if q.Options().Network == "*" || q.Options().Network == route.Options().Network { + results = append(results, route) + } + } + } + } + + if len(results) == 0 && q.Options().Policy != DiscardNoRoute { + return nil, ErrRouteNotFound + } + + return results, nil } // Watch returns routing table entry watcher diff --git a/router/table_watcher.go b/router/table_watcher.go index c246100b..79aa7c46 100644 --- a/router/table_watcher.go +++ b/router/table_watcher.go @@ -54,14 +54,14 @@ type tableWatcher struct { done chan struct{} } -// TODO: We might simply use Query here once QueryLookup is figured out +// TODO: this needs to be thought through properly // Next returns the next noticed action taken on table func (w *tableWatcher) Next() (*Result, error) { for { select { case res := <-w.resChan: switch w.opts.DestAddr { - case "*": + case "*", "": if w.opts.Network == "*" || w.opts.Network == res.Route.Options().Network { return res, nil } From 6e669d4611be43b12f5e7469ac7c2e72fceb0bbd Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Thu, 13 Jun 2019 12:09:49 +0100 Subject: [PATCH 023/287] Reorganised source. Renamed files. No Code change. --- router/{default.go => default_router.go} | 0 router/default_table.go | 251 +++++++++++++++++++++++ router/options.go | 4 +- router/query.go | 3 + router/rib.go | 3 + router/{entry.go => route.go} | 3 + router/router.go | 27 +-- router/table.go | 244 ++-------------------- router/table_watcher.go | 6 +- 9 files changed, 295 insertions(+), 246 deletions(-) rename router/{default.go => default_router.go} (100%) create mode 100644 router/default_table.go rename router/{entry.go => route.go} (94%) diff --git a/router/default.go b/router/default_router.go similarity index 100% rename from router/default.go rename to router/default_router.go diff --git a/router/default_table.go b/router/default_table.go new file mode 100644 index 00000000..b5d6dd8f --- /dev/null +++ b/router/default_table.go @@ -0,0 +1,251 @@ +package router + +import ( + "fmt" + "hash" + "hash/fnv" + "strings" + "sync" + + "github.com/google/uuid" + "github.com/olekukonko/tablewriter" +) + +// TableOptions are routing table options +type TableOptions struct{} + +// table is in memory routing table +type table struct { + // opts are table options + opts TableOptions + // m stores routing table map + m map[string]map[uint64]Route + // h hashes route entries + h hash.Hash64 + // w is a list of table watchers + w map[string]*tableWatcher + sync.RWMutex +} + +// newTable creates default routing table and returns it +func newTable(opts ...TableOption) Table { + // default options + var options TableOptions + + // apply requested options + for _, o := range opts { + o(&options) + } + + h := fnv.New64() + h.Reset() + + return &table{ + opts: options, + m: make(map[string]map[uint64]Route), + w: make(map[string]*tableWatcher), + h: h, + } +} + +// Init initializes routing table with options +func (t *table) Init(opts ...TableOption) error { + for _, o := range opts { + o(&t.opts) + } + return nil +} + +// Options returns routing table options +func (t *table) Options() TableOptions { + return t.opts +} + +// Add adds a route to the routing table +func (t *table) Add(r Route) error { + t.Lock() + defer t.Unlock() + + destAddr := r.Options().DestAddr + sum := t.hash(r) + + if _, ok := t.m[destAddr]; !ok { + t.m[destAddr] = make(map[uint64]Route) + t.m[destAddr][sum] = r + go t.sendResult(&Result{Action: "add", Route: r}) + return nil + } + + if _, ok := t.m[destAddr][sum]; ok && r.Options().Policy == OverrideIfExists { + t.m[destAddr][sum] = r + go t.sendResult(&Result{Action: "update", Route: r}) + return nil + } + + if r.Options().Policy == IgnoreIfExists { + return nil + } + + return ErrDuplicateRoute +} + +// Remove removes the route from the routing table +func (t *table) Remove(r Route) error { + t.Lock() + defer t.Unlock() + + destAddr := r.Options().DestAddr + sum := t.hash(r) + + if _, ok := t.m[destAddr]; !ok { + return ErrRouteNotFound + } + + delete(t.m[destAddr], sum) + go t.sendResult(&Result{Action: "remove", Route: r}) + + return nil +} + +// Update updates routing table with new route +func (t *table) Update(r Route) error { + t.Lock() + defer t.Unlock() + + destAddr := r.Options().DestAddr + sum := t.hash(r) + + if _, ok := t.m[destAddr]; !ok { + return ErrRouteNotFound + } + + if _, ok := t.m[destAddr][sum]; ok { + t.m[destAddr][sum] = r + go t.sendResult(&Result{Action: "update", Route: r}) + return nil + } + + return ErrRouteNotFound +} + +// Lookup queries routing table and returns all routes that match it +func (t *table) Lookup(q Query) ([]Route, error) { + t.RLock() + defer t.RUnlock() + + var results []Route + + for destAddr, routes := range t.m { + if q.Options().DestAddr != "*" { + if q.Options().DestAddr != destAddr { + continue + } + for _, route := range routes { + if q.Options().Network == "*" || q.Options().Network == route.Options().Network { + results = append(results, route) + } + } + } + + if q.Options().DestAddr == "*" { + for _, route := range routes { + if q.Options().Network == "*" || q.Options().Network == route.Options().Network { + results = append(results, route) + } + } + } + } + + if len(results) == 0 && q.Options().Policy != DiscardNoRoute { + return nil, ErrRouteNotFound + } + + return results, nil +} + +// Watch returns routing table entry watcher +func (t *table) Watch(opts ...WatchOption) (Watcher, error) { + // by default watch everything + wopts := WatchOptions{ + DestAddr: "*", + Network: "*", + } + + for _, o := range opts { + o(&wopts) + } + + watcher := &tableWatcher{ + opts: wopts, + resChan: make(chan *Result, 10), + done: make(chan struct{}), + } + + t.Lock() + t.w[uuid.New().String()] = watcher + t.Unlock() + + return watcher, nil +} + +// sendResult sends rules to all subscribe watchers +func (t *table) sendResult(r *Result) { + t.RLock() + defer t.RUnlock() + + for _, w := range t.w { + select { + case w.resChan <- r: + case <-w.done: + } + } +} + +// Size returns the size of the routing table +func (t *table) Size() int { + t.RLock() + defer t.RUnlock() + + return len(t.m) +} + +// String returns debug information +func (t *table) String() string { + t.RLock() + defer t.RUnlock() + + // this will help us build routing table string + sb := &strings.Builder{} + + // create nice table printing structure + table := tablewriter.NewWriter(sb) + table.SetHeader([]string{"Destination", "Gateway", "Network", "Metric"}) + + for _, destRoute := range t.m { + for _, route := range destRoute { + strRoute := []string{ + route.Options().DestAddr, + route.Options().Gateway.Address(), + route.Options().Gateway.Network(), + fmt.Sprintf("%d", route.Options().Metric), + } + table.Append(strRoute) + } + } + + // render table into sb + table.Render() + + return sb.String() +} + +// hash hashes the route using router gateway and network address +func (t *table) hash(r Route) uint64 { + gwAddr := r.Options().Gateway.Address() + netAddr := r.Options().Network + + t.h.Reset() + t.h.Write([]byte(gwAddr + netAddr)) + + return t.h.Sum64() +} diff --git a/router/options.go b/router/options.go index 9774f237..c3b858a0 100644 --- a/router/options.go +++ b/router/options.go @@ -12,7 +12,7 @@ var ( DefaultNetworkAddress = ":9094" ) -// Options allows to set router options +// Options are router options type Options struct { // ID is router ID ID string @@ -82,7 +82,7 @@ func NetworkRegistry(r registry.Registry) Option { } // RouterIB allows to configure RIB -func RouterIB(r RIB) Option { +func RouterRIB(r RIB) Option { return func(o *Options) { o.RIB = r } diff --git a/router/query.go b/router/query.go index 2cc0bf24..313278d0 100644 --- a/router/query.go +++ b/router/query.go @@ -10,6 +10,9 @@ const ( ClosestMatch ) +// QueryOption is used to define query options +type QueryOption func(*QueryOptions) + // QueryOptions allow to define routing table query options type QueryOptions struct { // DestAddr defines destination address diff --git a/router/rib.go b/router/rib.go index 1c6f538e..2e1f7cfe 100644 --- a/router/rib.go +++ b/router/rib.go @@ -12,6 +12,9 @@ type RIB interface { String() string } +// RIBOptopn is used to configure RIB +type RIBOption func(*RIBOptions) + // RIBOptions allow to set RIB sources. type RIBOptions struct { // Source defines RIB source URL diff --git a/router/entry.go b/router/route.go similarity index 94% rename from router/entry.go rename to router/route.go index 3b94a562..9ef5b19d 100644 --- a/router/entry.go +++ b/router/route.go @@ -14,6 +14,9 @@ const ( ErrIfExists ) +// RouteOption is used to define routing table entry options +type RouteOption func(*RouteOptions) + // RouteOptions defines micro network routing table route options type RouteOptions struct { // DestAddr is destination address diff --git a/router/router.go b/router/router.go index 419b62d3..5e100c6b 100644 --- a/router/router.go +++ b/router/router.go @@ -1,19 +1,26 @@ // Package router provides an interface for micro network router package router +import "errors" + +var ( + // ErrNotImplemented is returned when some functionality has not been implemented + ErrNotImplemented = errors.New("not implemented") +) + // Router is micro network router type Router interface { // Init initializes the router with options Init(...Option) error // Options returns the router options Options() Options - // Table returns routing table + // Table returns the router routing table Table() Table - // Address returns router adddress + // Address returns the router adddress Address() string - // Gossip returns router gossip address + // Gossip returns the router gossip address Gossip() string - // Network returns router network address + // Network returns the router network address Network() string // Start starts the router Start() error @@ -26,18 +33,6 @@ type Router interface { // Option used by the router type Option func(*Options) -// RIBOptopn is used to configure RIB -type RIBOption func(*RIBOptions) - -// RouteOption is used to define routing table entry options -type RouteOption func(*RouteOptions) - -// QueryOption is used to define query options -type QueryOption func(*QueryOptions) - -// WatchOption is used to define what routes to watch in the table -type WatchOption func(*WatchOptions) - // NewRouter creates new Router and returns it func NewRouter(opts ...Option) Router { return newRouter(opts...) diff --git a/router/table.go b/router/table.go index d246e177..e1361380 100644 --- a/router/table.go +++ b/router/table.go @@ -2,251 +2,41 @@ package router import ( "errors" - "fmt" - "hash" - "hash/fnv" - "strings" - "sync" - - "github.com/google/uuid" - "github.com/olekukonko/tablewriter" ) var ( - // ErrRouteNotFound is returned when no route was found + // ErrRouteNotFound is returned when no route was found in the routing table ErrRouteNotFound = errors.New("route not found") - // ErrDuplicateRoute is return when route already exists + // ErrDuplicateRoute is returned when the route already exists ErrDuplicateRoute = errors.New("duplicate route") - // ErrNotImplemented is returned when some functionality has not been implemented - ErrNotImplemented = errors.New("not implemented") ) -// Table is routing table +// Table defines routing table interface type Table interface { - // Add adds new route to the table + // Init initializes the router with options + Init(...TableOption) error + // Options returns the router options + Options() TableOptions + // Add adds new route to the routing table Add(Route) error - // Remove removes existing route from the table + // Remove removes existing route from the routing table Remove(Route) error - // Update updates route in the table + // Update updates route in the routing table Update(Route) error - // Lookup looks up routes in the table + // Lookup looks up routes in the routing table and returns them Lookup(Query) ([]Route, error) - // Watch returns a watcher which allows you to track updates to the table + // Watch returns a watcher which allows to track updates to the routing table Watch(opts ...WatchOption) (Watcher, error) - // Size returns the size of the table + // Size returns the size of the routing table Size() int // String prints the routing table String() string } -// table is routing table -type table struct { - // m stores routing table map - m map[string]map[uint64]Route - // h hashes route entries - h hash.Hash64 - // w is a list of table watchers - w map[string]*tableWatcher - sync.RWMutex -} +// TableOption used by the routing table +type TableOption func(*TableOptions) // NewTable creates new routing table and returns it -func NewTable() Table { - h := fnv.New64() - h.Reset() - - return &table{ - m: make(map[string]map[uint64]Route), - w: make(map[string]*tableWatcher), - h: h, - } -} - -// Add adds a route to the routing table -func (t *table) Add(r Route) error { - t.Lock() - defer t.Unlock() - - destAddr := r.Options().DestAddr - sum := t.hash(r) - - if _, ok := t.m[destAddr]; !ok { - t.m[destAddr] = make(map[uint64]Route) - t.m[destAddr][sum] = r - go t.sendResult(&Result{Action: "add", Route: r}) - return nil - } - - if _, ok := t.m[destAddr][sum]; ok && r.Options().Policy == OverrideIfExists { - t.m[destAddr][sum] = r - go t.sendResult(&Result{Action: "update", Route: r}) - return nil - } - - if r.Options().Policy == IgnoreIfExists { - return nil - } - - return ErrDuplicateRoute -} - -// Remove removes the route from the routing table -func (t *table) Remove(r Route) error { - t.Lock() - defer t.Unlock() - - destAddr := r.Options().DestAddr - sum := t.hash(r) - - if _, ok := t.m[destAddr]; !ok { - return ErrRouteNotFound - } - - delete(t.m[destAddr], sum) - go t.sendResult(&Result{Action: "remove", Route: r}) - - return nil -} - -// Update updates routing table with new route -func (t *table) Update(r Route) error { - t.Lock() - defer t.Unlock() - - destAddr := r.Options().DestAddr - sum := t.hash(r) - - if _, ok := t.m[destAddr]; !ok { - return ErrRouteNotFound - } - - if _, ok := t.m[destAddr][sum]; ok { - t.m[destAddr][sum] = r - go t.sendResult(&Result{Action: "update", Route: r}) - return nil - } - - return ErrRouteNotFound -} - -// Lookup queries routing table and returns all routes that match it -func (t *table) Lookup(q Query) ([]Route, error) { - t.RLock() - defer t.RUnlock() - - var results []Route - - for destAddr, routes := range t.m { - if q.Options().DestAddr != "*" { - if q.Options().DestAddr != destAddr { - continue - } - for _, route := range routes { - if q.Options().Network == "*" || q.Options().Network == route.Options().Network { - results = append(results, route) - } - } - } - - if q.Options().DestAddr == "*" { - for _, route := range routes { - if q.Options().Network == "*" || q.Options().Network == route.Options().Network { - results = append(results, route) - } - } - } - } - - if len(results) == 0 && q.Options().Policy != DiscardNoRoute { - return nil, ErrRouteNotFound - } - - return results, nil -} - -// Watch returns routing table entry watcher -func (t *table) Watch(opts ...WatchOption) (Watcher, error) { - // by default watch everything - wopts := WatchOptions{ - DestAddr: "*", - Network: "*", - } - - for _, o := range opts { - o(&wopts) - } - - watcher := &tableWatcher{ - opts: wopts, - resChan: make(chan *Result, 10), - done: make(chan struct{}), - } - - t.Lock() - t.w[uuid.New().String()] = watcher - t.Unlock() - - return watcher, nil -} - -// sendResult sends rules to all subscribe watchers -func (t *table) sendResult(r *Result) { - t.RLock() - defer t.RUnlock() - - for _, w := range t.w { - select { - case w.resChan <- r: - case <-w.done: - } - } -} - -// Size returns the size of the routing table -func (t *table) Size() int { - t.RLock() - defer t.RUnlock() - - return len(t.m) -} - -// String returns debug information -func (t *table) String() string { - t.RLock() - defer t.RUnlock() - - // this will help us build routing table string - sb := &strings.Builder{} - - // create nice table printing structure - table := tablewriter.NewWriter(sb) - table.SetHeader([]string{"Destination", "Gateway", "Network", "Metric"}) - - for _, destRoute := range t.m { - for _, route := range destRoute { - strRoute := []string{ - route.Options().DestAddr, - route.Options().Gateway.Address(), - route.Options().Gateway.Network(), - fmt.Sprintf("%d", route.Options().Metric), - } - table.Append(strRoute) - } - } - - // render table into sb - table.Render() - - return sb.String() -} - -// hash hashes the route using router gateway and network address -func (t *table) hash(r Route) uint64 { - gwAddr := r.Options().Gateway.Address() - netAddr := r.Options().Network - - t.h.Reset() - t.h.Write([]byte(gwAddr + netAddr)) - - return t.h.Sum64() +func NewTable(opts ...TableOption) Table { + return newTable(opts...) } diff --git a/router/table_watcher.go b/router/table_watcher.go index 79aa7c46..78a87c96 100644 --- a/router/table_watcher.go +++ b/router/table_watcher.go @@ -9,7 +9,11 @@ var ( ErrWatcherStopped = errors.New("routing table watcher stopped") ) -// Watcher is an interface that returns updates to the routing table +// WatchOption is used to define what routes to watch in the table +type WatchOption func(*WatchOptions) + +// Watcher defines routing table watcher interface +// Watcher returns updates to the routing table type Watcher interface { // Next is a blocking call that returns watch result Next() (*Result, error) From 6a33b7576b313ee64831de301c781d8b95640313 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Thu, 13 Jun 2019 15:12:07 +0100 Subject: [PATCH 024/287] Removed router watcher code duplication. Small code refactor. --- router/default_router.go | 95 +++++++++------------------------------- router/default_table.go | 1 + router/options.go | 15 ++++--- router/rib.go | 9 ++-- router/route.go | 9 +++- router/router.go | 7 --- 6 files changed, 42 insertions(+), 94 deletions(-) diff --git a/router/default_router.go b/router/default_router.go index 7ae8a718..24bce98e 100644 --- a/router/default_router.go +++ b/router/default_router.go @@ -7,7 +7,6 @@ import ( "sync" "time" - "github.com/micro/go-log" "github.com/micro/go-micro/registry" "github.com/olekukonko/tablewriter" ) @@ -18,6 +17,7 @@ type router struct { wg *sync.WaitGroup } +// newRouter creates new router and returns it func newRouter(opts ...Option) Router { // get default options options := DefaultOptions() @@ -69,14 +69,14 @@ func (r *router) Network() string { // Start starts the router func (r *router) Start() error { - // add local service routes into routing table + // add local service routes into the routing table if err := r.addServiceRoutes(r.opts.LocalRegistry, "local", 1); err != nil { - return fmt.Errorf("failed to add service routes for local services: %v", err) + return fmt.Errorf("failed adding routes for local services: %v", err) } - // add network service routes into routing table + // add network service routes into the routing table if err := r.addServiceRoutes(r.opts.NetworkRegistry, r.opts.NetworkAddress, 10); err != nil { - return fmt.Errorf("failed to add service routes for network services: %v", err) + return fmt.Errorf("failed adding routes for network services: %v", err) } // lookup local service routes and advertise them in network registry @@ -125,10 +125,10 @@ func (r *router) Start() error { } r.wg.Add(1) - go r.watchLocal(lWatcher) + go r.manageServiceRoutes(lWatcher, "local", DefaultLocalMetric) r.wg.Add(1) - go r.watchRemote(rWatcher) + go r.manageServiceRoutes(rWatcher, r.opts.NetworkAddress, DefaultNetworkMetric) r.wg.Add(1) go r.watchTable(tWatcher) @@ -136,23 +136,22 @@ func (r *router) Start() error { return nil } +// addServiceRouteslists all available services in given registry and adds them to the routing table. +// NOTE: this is a one-off operation done to bootstrap the rouing table of the new router when it starts. +// It returns error if the route could not be added to the routing table. func (r *router) addServiceRoutes(reg registry.Registry, network string, metric int) error { - // list all local services services, err := reg.ListServices() if err != nil { return fmt.Errorf("failed to list services: %v", err) } - // add services to routing table for _, service := range services { - // create new micro network route route := NewRoute( DestAddr(service.Name), Gateway(r), Network(network), Metric(metric), ) - // add new route to routing table if err := r.opts.Table.Add(route); err != nil { return fmt.Errorf("failed to add route for service: %s", service.Name) } @@ -161,10 +160,13 @@ func (r *router) addServiceRoutes(reg registry.Registry, network string, metric return nil } -// watch local registry -func (r *router) watchLocal(w registry.Watcher) error { +// manageServiceRoutes watches services in given registry and updates the routing table accordingly. +// It returns error if the service registry watcher has stopped or if the routing table failed to be updated. +func (r *router) manageServiceRoutes(w registry.Watcher, network string, metric int) error { defer r.wg.Done() + // wait in the background for the router to stop + // when the router stops, stop the watcher and exit r.wg.Add(1) go func() { defer r.wg.Done() @@ -186,75 +188,23 @@ func (r *router) watchLocal(w registry.Watcher) error { break } - // create new route route := NewRoute( DestAddr(res.Service.Name), Gateway(r), - Network("local"), - Metric(1), + Network(network), + Metric(metric), ) switch res.Action { case "create": if len(res.Service.Nodes) > 0 { if err := r.opts.Table.Add(route); err != nil { - log.Logf("[router] failed to add route for local service: %v", res.Service.Name) + return fmt.Errorf("failed to add route for service: %v", res.Service.Name) } } case "delete": if err := r.opts.Table.Remove(route); err != nil { - log.Logf("[router] failed to remove route for local service: %v", res.Service.Name) - } - } - } - - return watchErr -} - -// watch remote registry -func (r *router) watchRemote(w registry.Watcher) error { - defer r.wg.Done() - - r.wg.Add(1) - go func() { - defer r.wg.Done() - <-r.exit - w.Stop() - }() - - var watchErr error - - // watch for changes to services - for { - res, err := w.Next() - if err == registry.ErrWatcherStopped { - break - } - - if err != nil { - watchErr = err - break - } - - // create new route - route := NewRoute( - DestAddr(res.Service.Name), - Gateway(r), - Network(r.opts.NetworkAddress), - Metric(10), - RoutePolicy(IgnoreIfExists), - ) - - switch res.Action { - case "create": - if len(res.Service.Nodes) > 0 { - if err := r.opts.Table.Add(route); err != nil { - log.Logf("[router] failed to add route for network service: %v", res.Service.Name) - } - } - case "delete": - if err := r.opts.Table.Remove(route); err != nil { - log.Logf("[router] failed to remove route for network service: %v", res.Service.Name) + return fmt.Errorf("failed to remove route for service: %v", res.Service.Name) } } } @@ -290,7 +240,6 @@ func (r *router) watchTable(w Watcher) error { addr := strings.Split(r.opts.Address, ":") port, err := strconv.Atoi(addr[1]) if err != nil { - log.Logf("[router] could not parse router address from %s: %v", r.opts.Address, err) continue } @@ -307,14 +256,12 @@ func (r *router) watchTable(w Watcher) error { switch res.Action { case "add": - log.Logf("[router] routing table action: %s, route: %v", res.Action, res.Route) if err := r.opts.NetworkRegistry.Register(service, registry.RegisterTTL(10*time.Second)); err != nil { - log.Logf("[router] failed to register service %s in network registry: %v", service.Name, err) + return fmt.Errorf("failed to register service %s in network registry: %v", service.Name, err) } case "remove": - log.Logf("[router] routing table action: %s, route: %v", res.Action, res.Route) if err := r.opts.NetworkRegistry.Register(service); err != nil { - log.Logf("[router] failed to deregister service %s from network registry: %v", service.Name, err) + return fmt.Errorf("failed to deregister service %s from network registry: %v", service.Name, err) } } } diff --git a/router/default_table.go b/router/default_table.go index b5d6dd8f..ce7ac967 100644 --- a/router/default_table.go +++ b/router/default_table.go @@ -11,6 +11,7 @@ import ( "github.com/olekukonko/tablewriter" ) +// TODO: This will allow for arbitrary routing table config. // TableOptions are routing table options type TableOptions struct{} diff --git a/router/options.go b/router/options.go index c3b858a0..0467c7ee 100644 --- a/router/options.go +++ b/router/options.go @@ -6,17 +6,17 @@ import ( ) var ( - // DefaultAddress is default router bind address - DefaultAddress = ":9093" - // DefaultNetworkAddress is default micro network bind address + // DefaultGossipAddress is default gossip bind address + DefaultGossipAddress = ":9093" + // DefaultNetworkAddress is default network bind address DefaultNetworkAddress = ":9094" ) // Options are router options type Options struct { - // ID is router ID + // ID is router id ID string - // Address is router address + // Address is router micro service address Address string // GossipAddress is router gossip address GossipAddress string @@ -39,7 +39,7 @@ func ID(id string) Option { } } -// Address sets router address +// Address sets router service address func Address(a string) Option { return func(o *Options) { o.Address = a @@ -94,7 +94,8 @@ func DefaultOptions() Options { // TODO: DefaultRIB needs to be added once it's properly figured out return Options{ ID: uuid.New().String(), - Address: DefaultAddress, + Address: ":8083", + GossipAddress: DefaultGossipAddress, NetworkAddress: DefaultNetworkAddress, LocalRegistry: registry.DefaultRegistry, NetworkRegistry: registry.DefaultRegistry, diff --git a/router/rib.go b/router/rib.go index 2e1f7cfe..684fe765 100644 --- a/router/rib.go +++ b/router/rib.go @@ -1,21 +1,22 @@ package router -// RIB is Routing Information Base +// RIB is Routing Information Base. +// RIB is used to source the base routing table. type RIB interface { // Initi initializes RIB Init(...RIBOption) error // Options returns RIB options Options() RIBOptions - // Routes returns routes in RIB + // Routes returns routes Routes() []Route // String returns debug info String() string } -// RIBOptopn is used to configure RIB +// RIBOptopn sets RIB options type RIBOption func(*RIBOptions) -// RIBOptions allow to set RIB sources. +// RIBOptions configures various RIB options type RIBOptions struct { // Source defines RIB source URL Source string diff --git a/router/route.go b/router/route.go index 9ef5b19d..ea913668 100644 --- a/router/route.go +++ b/router/route.go @@ -2,6 +2,13 @@ package router import "context" +var ( + // DefaultLocalMetric is default route cost for local network + DefaultLocalMetric = 1 + // DefaultNetworkMetric is default route cost for micro network + DefaultNetworkMetric = 10 +) + // AddPolicy defines routing table addition policy type AddPolicy int @@ -10,8 +17,6 @@ const ( OverrideIfExists AddPolicy = iota // IgnoreIfExists does not add new route IgnoreIfExists - // ErrIfExists returns error if the route already exists - ErrIfExists ) // RouteOption is used to define routing table entry options diff --git a/router/router.go b/router/router.go index 5e100c6b..080abbe9 100644 --- a/router/router.go +++ b/router/router.go @@ -1,13 +1,6 @@ // Package router provides an interface for micro network router package router -import "errors" - -var ( - // ErrNotImplemented is returned when some functionality has not been implemented - ErrNotImplemented = errors.New("not implemented") -) - // Router is micro network router type Router interface { // Init initializes the router with options From 322eaae52978a9e33ad35a3c8f1b524dd07742ea Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Thu, 13 Jun 2019 23:28:47 +0200 Subject: [PATCH 025/287] Small code refactoring. Added more comments and parseToNode func --- router/default_router.go | 69 +++++++++++++++++++++++----------------- router/default_table.go | 15 +++++---- router/options.go | 3 +- router/query.go | 15 +++++---- router/rib.go | 4 +-- router/route.go | 8 ++--- router/table_watcher.go | 2 +- 7 files changed, 64 insertions(+), 52 deletions(-) diff --git a/router/default_router.go b/router/default_router.go index 24bce98e..949afa98 100644 --- a/router/default_router.go +++ b/router/default_router.go @@ -70,35 +70,30 @@ func (r *router) Network() string { // Start starts the router func (r *router) Start() error { // add local service routes into the routing table - if err := r.addServiceRoutes(r.opts.LocalRegistry, "local", 1); err != nil { + if err := r.addServiceRoutes(r.opts.LocalRegistry, "local", DefaultLocalMetric); err != nil { return fmt.Errorf("failed adding routes for local services: %v", err) } // add network service routes into the routing table - if err := r.addServiceRoutes(r.opts.NetworkRegistry, r.opts.NetworkAddress, 10); err != nil { + if err := r.addServiceRoutes(r.opts.NetworkRegistry, r.opts.NetworkAddress, DefaultNetworkMetric); err != nil { return fmt.Errorf("failed adding routes for network services: %v", err) } - // lookup local service routes and advertise them in network registry + // routing table has been bootstrapped; + // NOTE: we only need to advertise local services upstream + // lookup local service routes and advertise them upstream query := NewQuery(QueryNetwork("local")) localRoutes, err := r.opts.Table.Lookup(query) if err != nil && err != ErrRouteNotFound { return fmt.Errorf("failed to lookup local service routes: %v", err) } - addr := strings.Split(r.opts.Address, ":") - port, err := strconv.Atoi(addr[1]) + node, err := r.parseToNode() if err != nil { - fmt.Errorf("could not parse router address from %s: %v", r.opts.Address, err) + return fmt.Errorf("failed to parse router into node: %v", err) } for _, route := range localRoutes { - node := ®istry.Node{ - Id: r.opts.ID, - Address: addr[0], - Port: port, - } - service := ®istry.Service{ Name: route.Options().DestAddr, Nodes: []*registry.Node{node}, @@ -108,37 +103,37 @@ func (r *router) Start() error { } } - lWatcher, err := r.opts.LocalRegistry.Watch() + localWatcher, err := r.opts.LocalRegistry.Watch() if err != nil { return fmt.Errorf("failed to create local registry watcher: %v", err) } - rWatcher, err := r.opts.NetworkRegistry.Watch() + networkWatcher, err := r.opts.NetworkRegistry.Watch() if err != nil { return fmt.Errorf("failed to create network registry watcher: %v", err) } - // we only watch local entries which we resend to network registry - tWatcher, err := r.opts.Table.Watch(WatchNetwork("local")) + // we only watch local netwrork entries which we then propagate upstream to network + tableWatcher, err := r.opts.Table.Watch(WatchNetwork("local")) if err != nil { return fmt.Errorf("failed to create routing table watcher: %v", err) } r.wg.Add(1) - go r.manageServiceRoutes(lWatcher, "local", DefaultLocalMetric) + go r.manageServiceRoutes(localWatcher, "local", DefaultLocalMetric) r.wg.Add(1) - go r.manageServiceRoutes(rWatcher, r.opts.NetworkAddress, DefaultNetworkMetric) + go r.manageServiceRoutes(networkWatcher, r.opts.NetworkAddress, DefaultNetworkMetric) r.wg.Add(1) - go r.watchTable(tWatcher) + go r.watchTable(tableWatcher) return nil } // addServiceRouteslists all available services in given registry and adds them to the routing table. // NOTE: this is a one-off operation done to bootstrap the rouing table of the new router when it starts. -// It returns error if the route could not be added to the routing table. +// It returns error if any of the routes could not be added to the routing table. func (r *router) addServiceRoutes(reg registry.Registry, network string, metric int) error { services, err := reg.ListServices() if err != nil { @@ -153,13 +148,34 @@ func (r *router) addServiceRoutes(reg registry.Registry, network string, metric Metric(metric), ) if err := r.opts.Table.Add(route); err != nil { - return fmt.Errorf("failed to add route for service: %s", service.Name) + return fmt.Errorf("error adding route for service: %s", service.Name) } } return nil } +// parseToNode parses router address into registryNode. +// It retuns error if the router network address could not be parsed into service host and port. +// NOTE: We use ":" as a default delimiter we split the network address on and then attempt to parse port into int. +func (r *router) parseToNode() (*registry.Node, error) { + // split on ":" as a standard host:port delimiter + addr := strings.Split(r.opts.NetworkAddress, ":") + // try to parse network port into integer + port, err := strconv.Atoi(addr[1]) + if err != nil { + return nil, fmt.Errorf("could not parse router network address from %s: %v", r.opts.NetworkAddress, err) + } + + node := ®istry.Node{ + Id: r.opts.ID, + Address: addr[0], + Port: port, + } + + return node, nil +} + // manageServiceRoutes watches services in given registry and updates the routing table accordingly. // It returns error if the service registry watcher has stopped or if the routing table failed to be updated. func (r *router) manageServiceRoutes(w registry.Watcher, network string, metric int) error { @@ -237,16 +253,9 @@ func (r *router) watchTable(w Watcher) error { break } - addr := strings.Split(r.opts.Address, ":") - port, err := strconv.Atoi(addr[1]) + node, err := r.parseToNode() if err != nil { - continue - } - - node := ®istry.Node{ - Id: r.opts.ID, - Address: addr[0], - Port: port, + return fmt.Errorf("failed to parse router into node: %v", err) } service := ®istry.Service{ diff --git a/router/default_table.go b/router/default_table.go index ce7ac967..4fd77b93 100644 --- a/router/default_table.go +++ b/router/default_table.go @@ -11,8 +11,8 @@ import ( "github.com/olekukonko/tablewriter" ) -// TODO: This will allow for arbitrary routing table config. // TableOptions are routing table options +// TODO: This will allow for arbitrary routing table options in the future type TableOptions struct{} // table is in memory routing table @@ -28,7 +28,7 @@ type table struct { sync.RWMutex } -// newTable creates default routing table and returns it +// newTable creates in memory routing table and returns it func newTable(opts ...TableOption) Table { // default options var options TableOptions @@ -64,12 +64,13 @@ func (t *table) Options() TableOptions { // Add adds a route to the routing table func (t *table) Add(r Route) error { - t.Lock() - defer t.Unlock() destAddr := r.Options().DestAddr sum := t.hash(r) + t.Lock() + defer t.Unlock() + if _, ok := t.m[destAddr]; !ok { t.m[destAddr] = make(map[uint64]Route) t.m[destAddr][sum] = r @@ -110,12 +111,12 @@ func (t *table) Remove(r Route) error { // Update updates routing table with new route func (t *table) Update(r Route) error { - t.Lock() - defer t.Unlock() - destAddr := r.Options().DestAddr sum := t.hash(r) + t.Lock() + defer t.Unlock() + if _, ok := t.m[destAddr]; !ok { return ErrRouteNotFound } diff --git a/router/options.go b/router/options.go index 0467c7ee..b3da5a2d 100644 --- a/router/options.go +++ b/router/options.go @@ -25,6 +25,7 @@ type Options struct { // LocalRegistry is router local registry LocalRegistry registry.Registry // NetworkRegistry is router remote registry + // NOTE: we need some abstraction on top of gossip.Registry NetworkRegistry registry.Registry // Table is routing table Table Table @@ -81,7 +82,7 @@ func NetworkRegistry(r registry.Registry) Option { } } -// RouterIB allows to configure RIB +// RouterRIB allows to configure RIB func RouterRIB(r RIB) Option { return func(o *Options) { o.RIB = r diff --git a/router/query.go b/router/query.go index 313278d0..339003db 100644 --- a/router/query.go +++ b/router/query.go @@ -10,16 +10,16 @@ const ( ClosestMatch ) -// QueryOption is used to define query options +// QueryOption sets routing table query options type QueryOption func(*QueryOptions) -// QueryOptions allow to define routing table query options +// QueryOptions are routing table query options type QueryOptions struct { - // DestAddr defines destination address + // DestAddr is destination address DestAddr string - // NetworkAddress defines network address + // NetworkAddress is network address Network string - // Policy defines query lookup policy + // Policy is query lookup policy Policy LookupPolicy } @@ -37,19 +37,20 @@ func QueryNetwork(a string) QueryOption { } } -// QueryPolicy allows to define query lookup policy +// QueryPolicy sets query policy func QueryPolicy(p LookupPolicy) QueryOption { return func(o *QueryOptions) { o.Policy = p } } -// Query defines routing table query +// Query is routing table query type Query interface { // Options returns query options Options() QueryOptions } +// query is a basic implementation of Query type query struct { opts QueryOptions } diff --git a/router/rib.go b/router/rib.go index 684fe765..8f2795c6 100644 --- a/router/rib.go +++ b/router/rib.go @@ -13,10 +13,10 @@ type RIB interface { String() string } -// RIBOptopn sets RIB options +// RIBOption sets RIB options type RIBOption func(*RIBOptions) -// RIBOptions configures various RIB options +// RIBOptions are RIB options type RIBOptions struct { // Source defines RIB source URL Source string diff --git a/router/route.go b/router/route.go index ea913668..b0e120df 100644 --- a/router/route.go +++ b/router/route.go @@ -13,16 +13,16 @@ var ( type AddPolicy int const ( - // Override overrides existing routing table route + // OverrideIfExists overrides route if it already exists OverrideIfExists AddPolicy = iota - // IgnoreIfExists does not add new route + // IgnoreIfExists does not modify existing route IgnoreIfExists ) -// RouteOption is used to define routing table entry options +// RouteOption is used to set routing table entry options type RouteOption func(*RouteOptions) -// RouteOptions defines micro network routing table route options +// RouteOptions are route options type RouteOptions struct { // DestAddr is destination address DestAddr string diff --git a/router/table_watcher.go b/router/table_watcher.go index 78a87c96..4afe85d0 100644 --- a/router/table_watcher.go +++ b/router/table_watcher.go @@ -29,7 +29,7 @@ type Result struct { Route Route } -// Watcher options +// WatchOptions are table watcher options type WatchOptions struct { // Specify destination address to watch DestAddr string From f62fcaad768c8aaee0f8d6f69e7b5dbd5e5f0a84 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Sun, 16 Jun 2019 23:09:59 +0100 Subject: [PATCH 026/287] Added router ID. Deregister remote services when router is stopped. Added ID function to router interface. Network registry addresses are deregistered when the router is stopped. Query has been updated to search for particular GW in lookups. --- router/default_router.go | 36 ++++++++++++++++++++++++++++++++---- router/default_table.go | 9 ++++++--- router/query.go | 13 +++++++++++++ router/router.go | 2 ++ 4 files changed, 53 insertions(+), 7 deletions(-) diff --git a/router/default_router.go b/router/default_router.go index 949afa98..6e949e68 100644 --- a/router/default_router.go +++ b/router/default_router.go @@ -47,6 +47,11 @@ func (r *router) Options() Options { return r.opts } +// ID returns router ID +func (r *router) ID() string { + return r.opts.ID +} + // Table returns routing table func (r *router) Table() Table { return r.opts.Table @@ -90,7 +95,7 @@ func (r *router) Start() error { node, err := r.parseToNode() if err != nil { - return fmt.Errorf("failed to parse router into node: %v", err) + return fmt.Errorf("failed to parse router into service node: %v", err) } for _, route := range localRoutes { @@ -147,7 +152,7 @@ func (r *router) addServiceRoutes(reg registry.Registry, network string, metric Network(network), Metric(metric), ) - if err := r.opts.Table.Add(route); err != nil { + if err := r.opts.Table.Add(route); err != nil && err != ErrDuplicateRoute { return fmt.Errorf("error adding route for service: %s", service.Name) } } @@ -214,12 +219,12 @@ func (r *router) manageServiceRoutes(w registry.Watcher, network string, metric switch res.Action { case "create": if len(res.Service.Nodes) > 0 { - if err := r.opts.Table.Add(route); err != nil { + if err := r.opts.Table.Add(route); err != nil && err != ErrDuplicateRoute { return fmt.Errorf("failed to add route for service: %v", res.Service.Name) } } case "delete": - if err := r.opts.Table.Remove(route); err != nil { + if err := r.opts.Table.Remove(route); err != nil && err != ErrRouteNotFound { return fmt.Errorf("failed to remove route for service: %v", res.Service.Name) } } @@ -280,6 +285,29 @@ func (r *router) watchTable(w Watcher) error { // Stop stops the router func (r *router) Stop() error { + // NOTE: we need a more efficient way of doing this e.g. network routes should be autoremoved when router stops gossiping + // deregister all services advertised by this router from remote registry + query := NewQuery(QueryGateway(r), QueryNetwork(r.opts.NetworkAddress)) + routes, err := r.opts.Table.Lookup(query) + if err != nil && err != ErrRouteNotFound { + return fmt.Errorf("failed to lookup routes for router %s: %v", r.opts.ID, err) + } + + node, err := r.parseToNode() + if err != nil { + return fmt.Errorf("failed to parse router into service node: %v", err) + } + + for _, route := range routes { + service := ®istry.Service{ + Name: route.Options().DestAddr, + Nodes: []*registry.Node{node}, + } + if err := r.opts.NetworkRegistry.Deregister(service); err != nil { + return fmt.Errorf("failed to deregister service %s from network registry: %v", service.Name, err) + } + } + // notify all goroutines to finish close(r.exit) diff --git a/router/default_table.go b/router/default_table.go index 4fd77b93..78b451ae 100644 --- a/router/default_table.go +++ b/router/default_table.go @@ -64,7 +64,6 @@ func (t *table) Options() TableOptions { // Add adds a route to the routing table func (t *table) Add(r Route) error { - destAddr := r.Options().DestAddr sum := t.hash(r) @@ -144,7 +143,9 @@ func (t *table) Lookup(q Query) ([]Route, error) { } for _, route := range routes { if q.Options().Network == "*" || q.Options().Network == route.Options().Network { - results = append(results, route) + if q.Options().Gateway.ID() == "*" || q.Options().Gateway.ID() == route.Options().Gateway.ID() { + results = append(results, route) + } } } } @@ -152,7 +153,9 @@ func (t *table) Lookup(q Query) ([]Route, error) { if q.Options().DestAddr == "*" { for _, route := range routes { if q.Options().Network == "*" || q.Options().Network == route.Options().Network { - results = append(results, route) + if q.Options().Gateway.ID() == "*" || q.Options().Gateway.ID() == route.Options().Gateway.ID() { + results = append(results, route) + } } } } diff --git a/router/query.go b/router/query.go index 339003db..fe767856 100644 --- a/router/query.go +++ b/router/query.go @@ -19,6 +19,8 @@ type QueryOptions struct { DestAddr string // NetworkAddress is network address Network string + // Gateway is gateway address + Gateway Router // Policy is query lookup policy Policy LookupPolicy } @@ -37,6 +39,13 @@ func QueryNetwork(a string) QueryOption { } } +// QueryGateway sets query gateway address +func QueryGateway(r Router) QueryOption { + return func(o *QueryOptions) { + o.Gateway = r + } +} + // QueryPolicy sets query policy func QueryPolicy(p LookupPolicy) QueryOption { return func(o *QueryOptions) { @@ -57,10 +66,14 @@ type query struct { // NewQuery creates new query and returns it func NewQuery(opts ...QueryOption) Query { + // default gateway for wildcard router + r := newRouter(ID("*")) + // default options qopts := QueryOptions{ DestAddr: "*", Network: "*", + Gateway: r, Policy: DiscardNoRoute, } diff --git a/router/router.go b/router/router.go index 080abbe9..0c70ecc7 100644 --- a/router/router.go +++ b/router/router.go @@ -7,6 +7,8 @@ type Router interface { Init(...Option) error // Options returns the router options Options() Options + // ID returns id of the router + ID() string // Table returns the router routing table Table() Table // Address returns the router adddress From 5088c9d9168523e84aa35ceb941992470c202599 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Mon, 17 Jun 2019 19:51:13 +0100 Subject: [PATCH 027/287] Increased Network registry TTL. Routing Table remove is now delete. Remove has been renamed to Delete to be more in line with the framework. A bunch of comments have been added/updated for the future generations We have increased the Network Registry TTL to 2 minutes. --- router/default_router.go | 44 +++++++++++++++++++++++++--------------- router/default_table.go | 12 ++++++++--- router/table.go | 4 ++-- router/table_watcher.go | 7 +++---- 4 files changed, 42 insertions(+), 25 deletions(-) diff --git a/router/default_router.go b/router/default_router.go index 6e949e68..89b28623 100644 --- a/router/default_router.go +++ b/router/default_router.go @@ -103,7 +103,7 @@ func (r *router) Start() error { Name: route.Options().DestAddr, Nodes: []*registry.Node{node}, } - if err := r.opts.NetworkRegistry.Register(service, registry.RegisterTTL(10*time.Second)); err != nil { + if err := r.opts.NetworkRegistry.Register(service, registry.RegisterTTL(120*time.Second)); err != nil { return fmt.Errorf("failed to register service %s in network registry: %v", service.Name, err) } } @@ -137,8 +137,8 @@ func (r *router) Start() error { } // addServiceRouteslists all available services in given registry and adds them to the routing table. -// NOTE: this is a one-off operation done to bootstrap the rouing table of the new router when it starts. -// It returns error if any of the routes could not be added to the routing table. +// NOTE: this is a one-off operation done when bootstrapping the routing table of the new router. +// It returns error if either the services could not be listed or if the routes could not be added to the routing table. func (r *router) addServiceRoutes(reg registry.Registry, network string, metric int) error { services, err := reg.ListServices() if err != nil { @@ -160,11 +160,11 @@ func (r *router) addServiceRoutes(reg registry.Registry, network string, metric return nil } -// parseToNode parses router address into registryNode. -// It retuns error if the router network address could not be parsed into service host and port. -// NOTE: We use ":" as a default delimiter we split the network address on and then attempt to parse port into int. +// parseToNode parses router into registry.Node and returns the result. +// It returns error if the router network address could not be parsed into service host and port. +// NOTE: We use ":" as the default delimiter when we split the network address. func (r *router) parseToNode() (*registry.Node, error) { - // split on ":" as a standard host:port delimiter + // split on ":" as a standard host/port delimiter addr := strings.Split(r.opts.NetworkAddress, ":") // try to parse network port into integer port, err := strconv.Atoi(addr[1]) @@ -219,13 +219,17 @@ func (r *router) manageServiceRoutes(w registry.Watcher, network string, metric switch res.Action { case "create": if len(res.Service.Nodes) > 0 { + /// only return error if the route is not duplicate, but something else has failed if err := r.opts.Table.Add(route); err != nil && err != ErrDuplicateRoute { return fmt.Errorf("failed to add route for service: %v", res.Service.Name) } } case "delete": - if err := r.opts.Table.Remove(route); err != nil && err != ErrRouteNotFound { - return fmt.Errorf("failed to remove route for service: %v", res.Service.Name) + if len(res.Service.Nodes) <= 1 { + // only return error if the route is present in the table, but something else has failed + if err := r.opts.Table.Delete(route); err != nil && err != ErrRouteNotFound { + return fmt.Errorf("failed to delete route for service: %v", res.Service.Name) + } } } } @@ -233,7 +237,8 @@ func (r *router) manageServiceRoutes(w registry.Watcher, network string, metric return watchErr } -// watch routing table changes +// watchTable watches routing table entries and either adds or deletes locally registered service to/from network registry +// It returns error if the locally registered services either fails to be added/deleted to/from network registry. func (r *router) watchTable(w Watcher) error { defer r.wg.Done() @@ -270,12 +275,18 @@ func (r *router) watchTable(w Watcher) error { switch res.Action { case "add": - if err := r.opts.NetworkRegistry.Register(service, registry.RegisterTTL(10*time.Second)); err != nil { - return fmt.Errorf("failed to register service %s in network registry: %v", service.Name, err) + // only register remotely if the service is "local" + if res.Route.Options().Network == "local" { + if err := r.opts.NetworkRegistry.Register(service, registry.RegisterTTL(120*time.Second)); err != nil { + return fmt.Errorf("failed to register service %s in network registry: %v", service.Name, err) + } } - case "remove": - if err := r.opts.NetworkRegistry.Register(service); err != nil { - return fmt.Errorf("failed to deregister service %s from network registry: %v", service.Name, err) + case "delete": + // only deregister remotely if the service is "local" + if res.Route.Options().Network == "local" { + if err := r.opts.NetworkRegistry.Deregister(service); err != nil { + return fmt.Errorf("failed to deregister service %s from network registry: %v", service.Name, err) + } } } } @@ -285,7 +296,8 @@ func (r *router) watchTable(w Watcher) error { // Stop stops the router func (r *router) Stop() error { - // NOTE: we need a more efficient way of doing this e.g. network routes should be autoremoved when router stops gossiping + // NOTE: we need a more efficient way of doing this e.g. network routes + // should ideally be autodeleted when the router stops gossiping // deregister all services advertised by this router from remote registry query := NewQuery(QueryGateway(r), QueryNetwork(r.opts.NetworkAddress)) routes, err := r.opts.Table.Lookup(query) diff --git a/router/default_table.go b/router/default_table.go index 78b451ae..70aab636 100644 --- a/router/default_table.go +++ b/router/default_table.go @@ -70,6 +70,7 @@ func (t *table) Add(r Route) error { t.Lock() defer t.Unlock() + // check if the destination has any routes in the table if _, ok := t.m[destAddr]; !ok { t.m[destAddr] = make(map[uint64]Route) t.m[destAddr][sum] = r @@ -77,12 +78,15 @@ func (t *table) Add(r Route) error { return nil } + // only add the route if it exists and if override is requested if _, ok := t.m[destAddr][sum]; ok && r.Options().Policy == OverrideIfExists { t.m[destAddr][sum] = r go t.sendResult(&Result{Action: "update", Route: r}) return nil } + // if we reached this point without already returning the route already exists + // we return nil only if explicitly requested by the client if r.Options().Policy == IgnoreIfExists { return nil } @@ -90,8 +94,8 @@ func (t *table) Add(r Route) error { return ErrDuplicateRoute } -// Remove removes the route from the routing table -func (t *table) Remove(r Route) error { +// Delete deletes the route from the routing table +func (t *table) Delete(r Route) error { t.Lock() defer t.Unlock() @@ -103,7 +107,7 @@ func (t *table) Remove(r Route) error { } delete(t.m[destAddr], sum) - go t.sendResult(&Result{Action: "remove", Route: r}) + go t.sendResult(&Result{Action: "delete", Route: r}) return nil } @@ -116,10 +120,12 @@ func (t *table) Update(r Route) error { t.Lock() defer t.Unlock() + // check if the destAddr has ANY routes in the table if _, ok := t.m[destAddr]; !ok { return ErrRouteNotFound } + // if the route has been found update it if _, ok := t.m[destAddr][sum]; ok { t.m[destAddr][sum] = r go t.sendResult(&Result{Action: "update", Route: r}) diff --git a/router/table.go b/router/table.go index e1361380..53a6f8cd 100644 --- a/router/table.go +++ b/router/table.go @@ -19,8 +19,8 @@ type Table interface { Options() TableOptions // Add adds new route to the routing table Add(Route) error - // Remove removes existing route from the routing table - Remove(Route) error + // Delete deletes existing route from the routing table + Delete(Route) error // Update updates route in the routing table Update(Route) error // Lookup looks up routes in the routing table and returns them diff --git a/router/table_watcher.go b/router/table_watcher.go index 4afe85d0..e1797f25 100644 --- a/router/table_watcher.go +++ b/router/table_watcher.go @@ -23,7 +23,7 @@ type Watcher interface { // Result is returned by a call to Next on the watcher. type Result struct { - // Action is routing table action which is either of add, remove or update + // Action is routing table action which is either of add, delete or update Action string // Route is table rout Route Route @@ -58,8 +58,9 @@ type tableWatcher struct { done chan struct{} } -// TODO: this needs to be thought through properly // Next returns the next noticed action taken on table +// TODO: this needs to be thought through properly +// we are aiming to provide the same watch options Query() provides func (w *tableWatcher) Next() (*Result, error) { for { select { @@ -74,8 +75,6 @@ func (w *tableWatcher) Next() (*Result, error) { return res, nil } } - // ignore if no match is found - continue case <-w.done: return nil, ErrWatcherStopped } From b20dd16f92d92d1c72054bf1b08cb309c943d7ff Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Tue, 18 Jun 2019 10:57:43 +0100 Subject: [PATCH 028/287] Watcher now emits events instead of results. --- router/default_router.go | 14 ++++++------ router/default_table.go | 16 +++++++------- router/table_watcher.go | 48 +++++++++++++++++++++++++++++++--------- 3 files changed, 52 insertions(+), 26 deletions(-) diff --git a/router/default_router.go b/router/default_router.go index 89b28623..f6540966 100644 --- a/router/default_router.go +++ b/router/default_router.go @@ -253,7 +253,7 @@ func (r *router) watchTable(w Watcher) error { // watch for changes to services for { - res, err := w.Next() + event, err := w.Next() if err == ErrWatcherStopped { break } @@ -269,21 +269,21 @@ func (r *router) watchTable(w Watcher) error { } service := ®istry.Service{ - Name: res.Route.Options().DestAddr, + Name: event.Route.Options().DestAddr, Nodes: []*registry.Node{node}, } - switch res.Action { - case "add": + switch event.Type { + case CreateEvent: // only register remotely if the service is "local" - if res.Route.Options().Network == "local" { + if event.Route.Options().Network == "local" { if err := r.opts.NetworkRegistry.Register(service, registry.RegisterTTL(120*time.Second)); err != nil { return fmt.Errorf("failed to register service %s in network registry: %v", service.Name, err) } } - case "delete": + case UpdateEvent: // only deregister remotely if the service is "local" - if res.Route.Options().Network == "local" { + if event.Route.Options().Network == "local" { if err := r.opts.NetworkRegistry.Deregister(service); err != nil { return fmt.Errorf("failed to deregister service %s from network registry: %v", service.Name, err) } diff --git a/router/default_table.go b/router/default_table.go index 70aab636..caec7356 100644 --- a/router/default_table.go +++ b/router/default_table.go @@ -11,8 +11,8 @@ import ( "github.com/olekukonko/tablewriter" ) +// TODO: table options TBD in the future // TableOptions are routing table options -// TODO: This will allow for arbitrary routing table options in the future type TableOptions struct{} // table is in memory routing table @@ -74,14 +74,14 @@ func (t *table) Add(r Route) error { if _, ok := t.m[destAddr]; !ok { t.m[destAddr] = make(map[uint64]Route) t.m[destAddr][sum] = r - go t.sendResult(&Result{Action: "add", Route: r}) + go t.sendEvent(&Event{Type: CreateEvent, Route: r}) return nil } // only add the route if it exists and if override is requested if _, ok := t.m[destAddr][sum]; ok && r.Options().Policy == OverrideIfExists { t.m[destAddr][sum] = r - go t.sendResult(&Result{Action: "update", Route: r}) + go t.sendEvent(&Event{Type: UpdateEvent, Route: r}) return nil } @@ -107,7 +107,7 @@ func (t *table) Delete(r Route) error { } delete(t.m[destAddr], sum) - go t.sendResult(&Result{Action: "delete", Route: r}) + go t.sendEvent(&Event{Type: DeleteEvent, Route: r}) return nil } @@ -128,7 +128,7 @@ func (t *table) Update(r Route) error { // if the route has been found update it if _, ok := t.m[destAddr][sum]; ok { t.m[destAddr][sum] = r - go t.sendResult(&Result{Action: "update", Route: r}) + go t.sendEvent(&Event{Type: UpdateEvent, Route: r}) return nil } @@ -188,7 +188,7 @@ func (t *table) Watch(opts ...WatchOption) (Watcher, error) { watcher := &tableWatcher{ opts: wopts, - resChan: make(chan *Result, 10), + resChan: make(chan *Event, 10), done: make(chan struct{}), } @@ -199,8 +199,8 @@ func (t *table) Watch(opts ...WatchOption) (Watcher, error) { return watcher, nil } -// sendResult sends rules to all subscribe watchers -func (t *table) sendResult(r *Result) { +// sendEvent sends rules to all subscribe watchers +func (t *table) sendEvent(r *Event) { t.RLock() defer t.RUnlock() diff --git a/router/table_watcher.go b/router/table_watcher.go index e1797f25..e769906c 100644 --- a/router/table_watcher.go +++ b/router/table_watcher.go @@ -9,6 +9,40 @@ var ( ErrWatcherStopped = errors.New("routing table watcher stopped") ) +// EventType defines routing table event +type EventType int + +const ( + // CreateEvent is emitted when new route has been created + CreateEvent EventType = iota + // DeleteEvent is emitted when an existing route has been deleted + DeleteEvent + // UpdateEvent is emitted when a routing table has been updated + UpdateEvent +) + +// String returns string representation of the event +func (et EventType) String() string { + switch et { + case CreateEvent: + return "CREATE" + case DeleteEvent: + return "DELETE" + case UpdateEvent: + return "UPDATE" + default: + return "UNKNOWN" + } +} + +// Event is returned by a call to Next on the watcher. +type Event struct { + // Type defines type of event + Type EventType + // Route is table rout + Route Route +} + // WatchOption is used to define what routes to watch in the table type WatchOption func(*WatchOptions) @@ -16,19 +50,11 @@ type WatchOption func(*WatchOptions) // Watcher returns updates to the routing table type Watcher interface { // Next is a blocking call that returns watch result - Next() (*Result, error) + Next() (*Event, error) // Stop stops watcher Stop() } -// Result is returned by a call to Next on the watcher. -type Result struct { - // Action is routing table action which is either of add, delete or update - Action string - // Route is table rout - Route Route -} - // WatchOptions are table watcher options type WatchOptions struct { // Specify destination address to watch @@ -54,14 +80,14 @@ func WatchNetwork(n string) WatchOption { type tableWatcher struct { opts WatchOptions - resChan chan *Result + resChan chan *Event done chan struct{} } // Next returns the next noticed action taken on table // TODO: this needs to be thought through properly // we are aiming to provide the same watch options Query() provides -func (w *tableWatcher) Next() (*Result, error) { +func (w *tableWatcher) Next() (*Event, error) { for { select { case res := <-w.resChan: From 2674294cbe3d1a73570ff684593df48e00aca8e1 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Tue, 18 Jun 2019 11:44:09 +0100 Subject: [PATCH 029/287] Delete route when no node is available. --- router/default_router.go | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/router/default_router.go b/router/default_router.go index f6540966..30c75fd0 100644 --- a/router/default_router.go +++ b/router/default_router.go @@ -118,7 +118,7 @@ func (r *router) Start() error { return fmt.Errorf("failed to create network registry watcher: %v", err) } - // we only watch local netwrork entries which we then propagate upstream to network + // NOTE: we only watch local netwrork entries which we then propagate upstream to network tableWatcher, err := r.opts.Table.Watch(WatchNetwork("local")) if err != nil { return fmt.Errorf("failed to create routing table watcher: %v", err) @@ -225,7 +225,7 @@ func (r *router) manageServiceRoutes(w registry.Watcher, network string, metric } } case "delete": - if len(res.Service.Nodes) <= 1 { + if len(res.Service.Nodes) < 1 { // only return error if the route is present in the table, but something else has failed if err := r.opts.Table.Delete(route); err != nil && err != ErrRouteNotFound { return fmt.Errorf("failed to delete route for service: %v", res.Service.Name) @@ -268,6 +268,7 @@ func (r *router) watchTable(w Watcher) error { return fmt.Errorf("failed to parse router into node: %v", err) } + // we know that .DestAddr contains the registered service name service := ®istry.Service{ Name: event.Route.Options().DestAddr, Nodes: []*registry.Node{node}, @@ -275,18 +276,12 @@ func (r *router) watchTable(w Watcher) error { switch event.Type { case CreateEvent: - // only register remotely if the service is "local" - if event.Route.Options().Network == "local" { - if err := r.opts.NetworkRegistry.Register(service, registry.RegisterTTL(120*time.Second)); err != nil { - return fmt.Errorf("failed to register service %s in network registry: %v", service.Name, err) - } + if err := r.opts.NetworkRegistry.Register(service, registry.RegisterTTL(120*time.Second)); err != nil { + return fmt.Errorf("failed to register service %s in network registry: %v", service.Name, err) } - case UpdateEvent: - // only deregister remotely if the service is "local" - if event.Route.Options().Network == "local" { - if err := r.opts.NetworkRegistry.Deregister(service); err != nil { - return fmt.Errorf("failed to deregister service %s from network registry: %v", service.Name, err) - } + case DeleteEvent: + if err := r.opts.NetworkRegistry.Deregister(service); err != nil { + return fmt.Errorf("failed to deregister service %s from network registry: %v", service.Name, err) } } } From d3525ebab37ffc4812ff32cfe7efa2c92bb17597 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Tue, 18 Jun 2019 18:33:05 +0100 Subject: [PATCH 030/287] Debug messages. Squashed Add Route bugs and few others. --- router/default_router.go | 17 +++++++++++++++- router/default_table.go | 24 ++++++++++++++++++++-- router/query.go | 12 +++++++++++ router/route.go | 44 +++++++++++++++++++++++++++++++++++++--- 4 files changed, 91 insertions(+), 6 deletions(-) diff --git a/router/default_router.go b/router/default_router.go index 30c75fd0..6952bc87 100644 --- a/router/default_router.go +++ b/router/default_router.go @@ -7,6 +7,7 @@ import ( "sync" "time" + "github.com/micro/go-log" "github.com/micro/go-micro/registry" "github.com/olekukonko/tablewriter" ) @@ -206,6 +207,7 @@ func (r *router) manageServiceRoutes(w registry.Watcher, network string, metric if err != nil { watchErr = err + log.Logf("[router] registry error: %s", err) break } @@ -218,18 +220,25 @@ func (r *router) manageServiceRoutes(w registry.Watcher, network string, metric switch res.Action { case "create": + log.Logf("[router] received <%s> create event for service %s", network, res.Service.Name) if len(res.Service.Nodes) > 0 { + log.Logf("[router] adding <%s> service %s to routing table", network, res.Service.Name) /// only return error if the route is not duplicate, but something else has failed if err := r.opts.Table.Add(route); err != nil && err != ErrDuplicateRoute { return fmt.Errorf("failed to add route for service: %v", res.Service.Name) } + log.Logf("[router] route successfully added; routing table: \n%s", r.opts.Table) } case "delete": + log.Logf("[router] received <%s> delete event for service %s", network, res.Service.Name) + //log.Logf("[router] <%s> service nodes: %v", network, res.Service.Nodes) if len(res.Service.Nodes) < 1 { + log.Logf("[router] removing <%s> service %s from routing table", network, res.Service.Name) // only return error if the route is present in the table, but something else has failed if err := r.opts.Table.Delete(route); err != nil && err != ErrRouteNotFound { return fmt.Errorf("failed to delete route for service: %v", res.Service.Name) } + log.Logf("[router] route successfully deleted; routing table: \n%s", r.opts.Table) } } } @@ -260,6 +269,7 @@ func (r *router) watchTable(w Watcher) error { if err != nil { watchErr = err + log.Logf("[router] routing table error: %s", err) break } @@ -276,13 +286,18 @@ func (r *router) watchTable(w Watcher) error { switch event.Type { case CreateEvent: - if err := r.opts.NetworkRegistry.Register(service, registry.RegisterTTL(120*time.Second)); err != nil { + log.Logf("[router] adding service %s to network registry", event.Route.Options().DestAddr) + //if err := r.opts.NetworkRegistry.Register(service, registry.RegisterTTL(120*time.Second)); err != nil { + if err := r.opts.NetworkRegistry.Register(service, registry.RegisterTTL(5*time.Second)); err != nil { return fmt.Errorf("failed to register service %s in network registry: %v", service.Name, err) } + log.Logf("[router] successfully added service %s to network registry", event.Route.Options().DestAddr) case DeleteEvent: + log.Logf("[router] deleting service %s from network registry", event.Route.Options().DestAddr) if err := r.opts.NetworkRegistry.Deregister(service); err != nil { return fmt.Errorf("failed to deregister service %s from network registry: %v", service.Name, err) } + log.Logf("[router] successfully deleted service %s from network registry", event.Route.Options().DestAddr) } } diff --git a/router/default_table.go b/router/default_table.go index caec7356..648abd8f 100644 --- a/router/default_table.go +++ b/router/default_table.go @@ -8,6 +8,7 @@ import ( "sync" "github.com/google/uuid" + "github.com/micro/go-log" "github.com/olekukonko/tablewriter" ) @@ -70,16 +71,28 @@ func (t *table) Add(r Route) error { t.Lock() defer t.Unlock() + log.Logf("[table] AddRoute request %d %s: \n%s", sum, r.Options().Policy, r) + // check if the destination has any routes in the table if _, ok := t.m[destAddr]; !ok { + log.Logf("[table] destination does NOT exist ADDING: \n%s", r) t.m[destAddr] = make(map[uint64]Route) t.m[destAddr][sum] = r go t.sendEvent(&Event{Type: CreateEvent, Route: r}) return nil } + // add new route to the table for the given destination + if _, ok := t.m[destAddr][sum]; !ok { + log.Logf("[table] route does NOT exist ADDING: \n%s", r) + t.m[destAddr][sum] = r + go t.sendEvent(&Event{Type: CreateEvent, Route: r}) + return nil + } + // only add the route if it exists and if override is requested if _, ok := t.m[destAddr][sum]; ok && r.Options().Policy == OverrideIfExists { + log.Logf("[table] route does exist OVERRIDING: \n%s", r) t.m[destAddr][sum] = r go t.sendEvent(&Event{Type: UpdateEvent, Route: r}) return nil @@ -88,9 +101,12 @@ func (t *table) Add(r Route) error { // if we reached this point without already returning the route already exists // we return nil only if explicitly requested by the client if r.Options().Policy == IgnoreIfExists { + log.Logf("[table] route does exist IGNORING: \n%s", r) return nil } + log.Logf("[table] AddRoute request: DUPPLICATE ROUTE") + return ErrDuplicateRoute } @@ -102,7 +118,10 @@ func (t *table) Delete(r Route) error { destAddr := r.Options().DestAddr sum := t.hash(r) + log.Logf("[table] DeleteRoute request %d: \n%s", sum, r) + if _, ok := t.m[destAddr]; !ok { + log.Logf("[table] DeleteRoute Route NOT found: %s", r) return ErrRouteNotFound } @@ -237,7 +256,7 @@ func (t *table) String() string { strRoute := []string{ route.Options().DestAddr, route.Options().Gateway.Address(), - route.Options().Gateway.Network(), + route.Options().Network, fmt.Sprintf("%d", route.Options().Metric), } table.Append(strRoute) @@ -252,11 +271,12 @@ func (t *table) String() string { // hash hashes the route using router gateway and network address func (t *table) hash(r Route) uint64 { + destAddr := r.Options().DestAddr gwAddr := r.Options().Gateway.Address() netAddr := r.Options().Network t.h.Reset() - t.h.Write([]byte(gwAddr + netAddr)) + t.h.Write([]byte(destAddr + gwAddr + netAddr)) return t.h.Sum64() } diff --git a/router/query.go b/router/query.go index fe767856..54b52e22 100644 --- a/router/query.go +++ b/router/query.go @@ -10,6 +10,18 @@ const ( ClosestMatch ) +// String returns human representation of LookupPolicy +func (lp LookupPolicy) String() string { + switch lp { + case DiscardNoRoute: + return "DISCARD" + case ClosestMatch: + return "CLOSEST" + default: + return "UNKNOWN" + } +} + // QueryOption sets routing table query options type QueryOption func(*QueryOptions) diff --git a/router/route.go b/router/route.go index b0e120df..7942ed88 100644 --- a/router/route.go +++ b/router/route.go @@ -1,6 +1,11 @@ package router -import "context" +import ( + "fmt" + "strings" + + "github.com/olekukonko/tablewriter" +) var ( // DefaultLocalMetric is default route cost for local network @@ -19,6 +24,18 @@ const ( IgnoreIfExists ) +// String returns human reprensentation of policy +func (p AddPolicy) String() string { + switch p { + case OverrideIfExists: + return "OVERRIDE" + case IgnoreIfExists: + return "IGNORE" + default: + return "UNKNOWN" + } +} + // RouteOption is used to set routing table entry options type RouteOption func(*RouteOptions) @@ -34,8 +51,6 @@ type RouteOptions struct { Metric int // Policy defines route addition policy Policy AddPolicy - // Context stores other arbitrary options - Context context.Context } // DestAddr sets destination address @@ -100,3 +115,26 @@ func NewRoute(opts ...RouteOption) Route { func (r *route) Options() RouteOptions { return r.opts } + +// String allows to print the route +func (r *route) String() string { + // this will help us build routing table string + sb := &strings.Builder{} + + // create nice table printing structure + table := tablewriter.NewWriter(sb) + table.SetHeader([]string{"Destination", "Gateway", "Network", "Metric"}) + + strRoute := []string{ + r.opts.DestAddr, + r.opts.Gateway.Address(), + r.opts.Network, + fmt.Sprintf("%d", r.opts.Metric), + } + table.Append(strRoute) + + // render table into sb + table.Render() + + return sb.String() +} From 59035ab80121cbf8c30105a8301a666bb6815298 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Wed, 19 Jun 2019 18:01:48 +0100 Subject: [PATCH 031/287] Removed debug logs. advertiseToNetwork() replaced watchTable(). Debug logs that were helpful when squashing bugs have been removed. advertiseToNetwork replaced the watchTable which originally watched the routing table entries. We now take a different approach to propagating the local registry services into the network registry. --- router/default_router.go | 173 +++++++++++++++------------------------ router/default_table.go | 31 +++---- router/table.go | 2 + router/table_watcher.go | 24 +++++- 4 files changed, 109 insertions(+), 121 deletions(-) diff --git a/router/default_router.go b/router/default_router.go index 6952bc87..0923dffe 100644 --- a/router/default_router.go +++ b/router/default_router.go @@ -7,11 +7,19 @@ import ( "sync" "time" - "github.com/micro/go-log" "github.com/micro/go-micro/registry" "github.com/olekukonko/tablewriter" ) +var ( + // AdvertiseToNetworkTick defines how often in seconds do we scal the local registry + // to advertise the local services to the network registry + AdvertiseToNetworkTick = 5 * time.Second + // AdvertiseNetworkTTL defines network registry TTL in seconds + // NOTE: this is a rather arbitrary picked value subject to change + AdvertiseNetworkTTL = 120 * time.Second +) + type router struct { opts Options exit chan struct{} @@ -85,56 +93,46 @@ func (r *router) Start() error { return fmt.Errorf("failed adding routes for network services: %v", err) } - // routing table has been bootstrapped; - // NOTE: we only need to advertise local services upstream - // lookup local service routes and advertise them upstream - query := NewQuery(QueryNetwork("local")) - localRoutes, err := r.opts.Table.Lookup(query) - if err != nil && err != ErrRouteNotFound { - return fmt.Errorf("failed to lookup local service routes: %v", err) - } - node, err := r.parseToNode() if err != nil { return fmt.Errorf("failed to parse router into service node: %v", err) } - for _, route := range localRoutes { - service := ®istry.Service{ - Name: route.Options().DestAddr, - Nodes: []*registry.Node{node}, - } - if err := r.opts.NetworkRegistry.Register(service, registry.RegisterTTL(120*time.Second)); err != nil { - return fmt.Errorf("failed to register service %s in network registry: %v", service.Name, err) - } - } - - localWatcher, err := r.opts.LocalRegistry.Watch() + localRegWatcher, err := r.opts.LocalRegistry.Watch() if err != nil { return fmt.Errorf("failed to create local registry watcher: %v", err) } - networkWatcher, err := r.opts.NetworkRegistry.Watch() + networkRegWatcher, err := r.opts.NetworkRegistry.Watch() if err != nil { return fmt.Errorf("failed to create network registry watcher: %v", err) } - // NOTE: we only watch local netwrork entries which we then propagate upstream to network - tableWatcher, err := r.opts.Table.Watch(WatchNetwork("local")) - if err != nil { - return fmt.Errorf("failed to create routing table watcher: %v", err) - } + // error channel collecting goroutine errors + errChan := make(chan error, 3) r.wg.Add(1) - go r.manageServiceRoutes(localWatcher, "local", DefaultLocalMetric) + go func() { + defer r.wg.Done() + // watch local registry and register routes in routine table + errChan <- r.manageServiceRoutes(localRegWatcher, "local", DefaultLocalMetric) + }() r.wg.Add(1) - go r.manageServiceRoutes(networkWatcher, r.opts.NetworkAddress, DefaultNetworkMetric) + go func() { + defer r.wg.Done() + // watch network registry and register routes in routine table + errChan <- r.manageServiceRoutes(networkRegWatcher, r.opts.NetworkAddress, DefaultNetworkMetric) + }() r.wg.Add(1) - go r.watchTable(tableWatcher) + go func() { + defer r.wg.Done() + // watch local registry and advertise local service to the network + errChan <- r.advertiseToNetwork(node) + }() - return nil + return <-errChan } // addServiceRouteslists all available services in given registry and adds them to the routing table. @@ -182,11 +180,40 @@ func (r *router) parseToNode() (*registry.Node, error) { return node, nil } +// advertiseToNetwork periodically scans local registry and registers (i.e. advertises) all the local services in the network registry. +// It returns error if either the local services failed to be listed or if it fails to register local service in network registry. +func (r *router) advertiseToNetwork(node *registry.Node) error { + // ticker to periodically scan the local registry + ticker := time.NewTicker(AdvertiseToNetworkTick) + + for { + select { + case <-r.exit: + return nil + case <-ticker.C: + // list all local services + services, err := r.opts.LocalRegistry.ListServices() + if err != nil { + return fmt.Errorf("failed to list local services: %v", err) + } + // loop through all registered local services and register them in the network registry + for _, service := range services { + svc := ®istry.Service{ + Name: service.Name, + Nodes: []*registry.Node{node}, + } + // register the local service in the network registry + if err := r.opts.NetworkRegistry.Register(svc, registry.RegisterTTL(AdvertiseNetworkTTL)); err != nil { + return fmt.Errorf("failed to register service %s in network registry: %v", svc.Name, err) + } + } + } + } +} + // manageServiceRoutes watches services in given registry and updates the routing table accordingly. // It returns error if the service registry watcher has stopped or if the routing table failed to be updated. func (r *router) manageServiceRoutes(w registry.Watcher, network string, metric int) error { - defer r.wg.Done() - // wait in the background for the router to stop // when the router stops, stop the watcher and exit r.wg.Add(1) @@ -198,7 +225,6 @@ func (r *router) manageServiceRoutes(w registry.Watcher, network string, metric var watchErr error - // watch for changes to services for { res, err := w.Next() if err == registry.ErrWatcherStopped { @@ -207,7 +233,6 @@ func (r *router) manageServiceRoutes(w registry.Watcher, network string, metric if err != nil { watchErr = err - log.Logf("[router] registry error: %s", err) break } @@ -220,25 +245,18 @@ func (r *router) manageServiceRoutes(w registry.Watcher, network string, metric switch res.Action { case "create": - log.Logf("[router] received <%s> create event for service %s", network, res.Service.Name) if len(res.Service.Nodes) > 0 { - log.Logf("[router] adding <%s> service %s to routing table", network, res.Service.Name) /// only return error if the route is not duplicate, but something else has failed if err := r.opts.Table.Add(route); err != nil && err != ErrDuplicateRoute { return fmt.Errorf("failed to add route for service: %v", res.Service.Name) } - log.Logf("[router] route successfully added; routing table: \n%s", r.opts.Table) } case "delete": - log.Logf("[router] received <%s> delete event for service %s", network, res.Service.Name) - //log.Logf("[router] <%s> service nodes: %v", network, res.Service.Nodes) if len(res.Service.Nodes) < 1 { - log.Logf("[router] removing <%s> service %s from routing table", network, res.Service.Name) // only return error if the route is present in the table, but something else has failed if err := r.opts.Table.Delete(route); err != nil && err != ErrRouteNotFound { return fmt.Errorf("failed to delete route for service: %v", res.Service.Name) } - log.Logf("[router] route successfully deleted; routing table: \n%s", r.opts.Table) } } } @@ -246,66 +264,14 @@ func (r *router) manageServiceRoutes(w registry.Watcher, network string, metric return watchErr } -// watchTable watches routing table entries and either adds or deletes locally registered service to/from network registry -// It returns error if the locally registered services either fails to be added/deleted to/from network registry. -func (r *router) watchTable(w Watcher) error { - defer r.wg.Done() - - r.wg.Add(1) - go func() { - defer r.wg.Done() - <-r.exit - w.Stop() - }() - - var watchErr error - - // watch for changes to services - for { - event, err := w.Next() - if err == ErrWatcherStopped { - break - } - - if err != nil { - watchErr = err - log.Logf("[router] routing table error: %s", err) - break - } - - node, err := r.parseToNode() - if err != nil { - return fmt.Errorf("failed to parse router into node: %v", err) - } - - // we know that .DestAddr contains the registered service name - service := ®istry.Service{ - Name: event.Route.Options().DestAddr, - Nodes: []*registry.Node{node}, - } - - switch event.Type { - case CreateEvent: - log.Logf("[router] adding service %s to network registry", event.Route.Options().DestAddr) - //if err := r.opts.NetworkRegistry.Register(service, registry.RegisterTTL(120*time.Second)); err != nil { - if err := r.opts.NetworkRegistry.Register(service, registry.RegisterTTL(5*time.Second)); err != nil { - return fmt.Errorf("failed to register service %s in network registry: %v", service.Name, err) - } - log.Logf("[router] successfully added service %s to network registry", event.Route.Options().DestAddr) - case DeleteEvent: - log.Logf("[router] deleting service %s from network registry", event.Route.Options().DestAddr) - if err := r.opts.NetworkRegistry.Deregister(service); err != nil { - return fmt.Errorf("failed to deregister service %s from network registry: %v", service.Name, err) - } - log.Logf("[router] successfully deleted service %s from network registry", event.Route.Options().DestAddr) - } - } - - return watchErr -} - // Stop stops the router func (r *router) Stop() error { + // notify all goroutines to finish + close(r.exit) + + // wait for all goroutines to finish + r.wg.Wait() + // NOTE: we need a more efficient way of doing this e.g. network routes // should ideally be autodeleted when the router stops gossiping // deregister all services advertised by this router from remote registry @@ -315,6 +281,7 @@ func (r *router) Stop() error { return fmt.Errorf("failed to lookup routes for router %s: %v", r.opts.ID, err) } + // parse router to registry.Node node, err := r.parseToNode() if err != nil { return fmt.Errorf("failed to parse router into service node: %v", err) @@ -330,12 +297,6 @@ func (r *router) Stop() error { } } - // notify all goroutines to finish - close(r.exit) - - // wait for all goroutines to finish - r.wg.Wait() - return nil } diff --git a/router/default_table.go b/router/default_table.go index 648abd8f..3bed626f 100644 --- a/router/default_table.go +++ b/router/default_table.go @@ -8,12 +8,11 @@ import ( "sync" "github.com/google/uuid" - "github.com/micro/go-log" "github.com/olekukonko/tablewriter" ) -// TODO: table options TBD in the future // TableOptions are routing table options +// TODO: table options TBD in the future type TableOptions struct{} // table is in memory routing table @@ -71,11 +70,8 @@ func (t *table) Add(r Route) error { t.Lock() defer t.Unlock() - log.Logf("[table] AddRoute request %d %s: \n%s", sum, r.Options().Policy, r) - // check if the destination has any routes in the table if _, ok := t.m[destAddr]; !ok { - log.Logf("[table] destination does NOT exist ADDING: \n%s", r) t.m[destAddr] = make(map[uint64]Route) t.m[destAddr][sum] = r go t.sendEvent(&Event{Type: CreateEvent, Route: r}) @@ -84,15 +80,13 @@ func (t *table) Add(r Route) error { // add new route to the table for the given destination if _, ok := t.m[destAddr][sum]; !ok { - log.Logf("[table] route does NOT exist ADDING: \n%s", r) t.m[destAddr][sum] = r go t.sendEvent(&Event{Type: CreateEvent, Route: r}) return nil } - // only add the route if it exists and if override is requested + // only add the route if the route override is explicitly requested if _, ok := t.m[destAddr][sum]; ok && r.Options().Policy == OverrideIfExists { - log.Logf("[table] route does exist OVERRIDING: \n%s", r) t.m[destAddr][sum] = r go t.sendEvent(&Event{Type: UpdateEvent, Route: r}) return nil @@ -101,12 +95,9 @@ func (t *table) Add(r Route) error { // if we reached this point without already returning the route already exists // we return nil only if explicitly requested by the client if r.Options().Policy == IgnoreIfExists { - log.Logf("[table] route does exist IGNORING: \n%s", r) return nil } - log.Logf("[table] AddRoute request: DUPPLICATE ROUTE") - return ErrDuplicateRoute } @@ -118,10 +109,7 @@ func (t *table) Delete(r Route) error { destAddr := r.Options().DestAddr sum := t.hash(r) - log.Logf("[table] DeleteRoute request %d: \n%s", sum, r) - if _, ok := t.m[destAddr]; !ok { - log.Logf("[table] DeleteRoute Route NOT found: %s", r) return ErrRouteNotFound } @@ -154,6 +142,21 @@ func (t *table) Update(r Route) error { return ErrRouteNotFound } +// List returns a list of all routes in the table +func (t *table) List() ([]Route, error) { + t.RLock() + defer t.RUnlock() + + var routes []Route + for _, rmap := range t.m { + for _, route := range rmap { + routes = append(routes, route) + } + } + + return routes, nil +} + // Lookup queries routing table and returns all routes that match it func (t *table) Lookup(q Query) ([]Route, error) { t.RLock() diff --git a/router/table.go b/router/table.go index 53a6f8cd..c00484cd 100644 --- a/router/table.go +++ b/router/table.go @@ -23,6 +23,8 @@ type Table interface { Delete(Route) error // Update updates route in the routing table Update(Route) error + // List returns the list of all routes in the table + List() ([]Route, error) // Lookup looks up routes in the routing table and returns them Lookup(Query) ([]Route, error) // Watch returns a watcher which allows to track updates to the routing table diff --git a/router/table_watcher.go b/router/table_watcher.go index e769906c..bf18e8c0 100644 --- a/router/table_watcher.go +++ b/router/table_watcher.go @@ -2,6 +2,9 @@ package router import ( "errors" + "strings" + + "github.com/olekukonko/tablewriter" ) var ( @@ -86,7 +89,7 @@ type tableWatcher struct { // Next returns the next noticed action taken on table // TODO: this needs to be thought through properly -// we are aiming to provide the same watch options Query() provides +// we are aiming to provide the same options Query provides func (w *tableWatcher) Next() (*Event, error) { for { select { @@ -116,3 +119,22 @@ func (w *tableWatcher) Stop() { close(w.done) } } + +// String prints debug information +func (w *tableWatcher) String() string { + sb := &strings.Builder{} + + table := tablewriter.NewWriter(sb) + table.SetHeader([]string{"DestAddr", "Network"}) + + data := []string{ + w.opts.DestAddr, + w.opts.Network, + } + table.Append(data) + + // render table into sb + table.Render() + + return sb.String() +} From 4e5fbbf7eb1750b3d9d33c822380b4a27f1889d7 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Wed, 19 Jun 2019 18:11:16 +0100 Subject: [PATCH 032/287] Replaced the debug network string by the correct router local address. --- router/default_router.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/router/default_router.go b/router/default_router.go index 0923dffe..3303e047 100644 --- a/router/default_router.go +++ b/router/default_router.go @@ -84,7 +84,7 @@ func (r *router) Network() string { // Start starts the router func (r *router) Start() error { // add local service routes into the routing table - if err := r.addServiceRoutes(r.opts.LocalRegistry, "local", DefaultLocalMetric); err != nil { + if err := r.addServiceRoutes(r.opts.LocalRegistry, r.opts.Address, DefaultLocalMetric); err != nil { return fmt.Errorf("failed adding routes for local services: %v", err) } @@ -115,7 +115,7 @@ func (r *router) Start() error { go func() { defer r.wg.Done() // watch local registry and register routes in routine table - errChan <- r.manageServiceRoutes(localRegWatcher, "local", DefaultLocalMetric) + errChan <- r.manageServiceRoutes(localRegWatcher, r.opts.Address, DefaultLocalMetric) }() r.wg.Add(1) From 10a3636a9f1db9571e8fa58dce2d51d283e9a968 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Wed, 19 Jun 2019 21:22:14 +0100 Subject: [PATCH 033/287] Renamed variables, options and functions --- router/default_router.go | 82 ++++++++++++++---------------- router/default_table.go | 54 +++++++++++--------- router/options.go | 75 ++++++++++----------------- router/query.go | 42 ++++++++++------ router/rib.go | 30 ----------- router/route.go | 106 ++++++++------------------------------- router/router.go | 2 - router/table_watcher.go | 27 ++++++---- 8 files changed, 158 insertions(+), 260 deletions(-) delete mode 100644 router/rib.go diff --git a/router/default_router.go b/router/default_router.go index 3303e047..32de1886 100644 --- a/router/default_router.go +++ b/router/default_router.go @@ -12,12 +12,12 @@ import ( ) var ( - // AdvertiseToNetworkTick defines how often in seconds do we scal the local registry + // AdvertiseTick defines how often in seconds do we scal the local registry // to advertise the local services to the network registry - AdvertiseToNetworkTick = 5 * time.Second - // AdvertiseNetworkTTL defines network registry TTL in seconds + AdvertiseTick = 5 * time.Second + // AdvertiseTTL defines network registry TTL in seconds // NOTE: this is a rather arbitrary picked value subject to change - AdvertiseNetworkTTL = 120 * time.Second + AdvertiseTTL = 120 * time.Second ) type router struct { @@ -71,25 +71,20 @@ func (r *router) Address() string { return r.opts.Address } -// Gossip returns gossip bind address -func (r *router) Gossip() string { - return r.opts.GossipAddress -} - -// Network returns router's micro network +// Network returns the address router advertises to the network func (r *router) Network() string { - return r.opts.NetworkAddress + return r.opts.Advertise } // Start starts the router func (r *router) Start() error { // add local service routes into the routing table - if err := r.addServiceRoutes(r.opts.LocalRegistry, r.opts.Address, DefaultLocalMetric); err != nil { + if err := r.addServiceRoutes(r.opts.Registry, DefaultLocalMetric); err != nil { return fmt.Errorf("failed adding routes for local services: %v", err) } // add network service routes into the routing table - if err := r.addServiceRoutes(r.opts.NetworkRegistry, r.opts.NetworkAddress, DefaultNetworkMetric); err != nil { + if err := r.addServiceRoutes(r.opts.Network, DefaultNetworkMetric); err != nil { return fmt.Errorf("failed adding routes for network services: %v", err) } @@ -98,12 +93,12 @@ func (r *router) Start() error { return fmt.Errorf("failed to parse router into service node: %v", err) } - localRegWatcher, err := r.opts.LocalRegistry.Watch() + localWatcher, err := r.opts.Registry.Watch() if err != nil { return fmt.Errorf("failed to create local registry watcher: %v", err) } - networkRegWatcher, err := r.opts.NetworkRegistry.Watch() + networkWatcher, err := r.opts.Network.Watch() if err != nil { return fmt.Errorf("failed to create network registry watcher: %v", err) } @@ -115,14 +110,14 @@ func (r *router) Start() error { go func() { defer r.wg.Done() // watch local registry and register routes in routine table - errChan <- r.manageServiceRoutes(localRegWatcher, r.opts.Address, DefaultLocalMetric) + errChan <- r.manageServiceRoutes(localWatcher, DefaultLocalMetric) }() r.wg.Add(1) go func() { defer r.wg.Done() // watch network registry and register routes in routine table - errChan <- r.manageServiceRoutes(networkRegWatcher, r.opts.NetworkAddress, DefaultNetworkMetric) + errChan <- r.manageServiceRoutes(networkWatcher, DefaultNetworkMetric) }() r.wg.Add(1) @@ -138,19 +133,19 @@ func (r *router) Start() error { // addServiceRouteslists all available services in given registry and adds them to the routing table. // NOTE: this is a one-off operation done when bootstrapping the routing table of the new router. // It returns error if either the services could not be listed or if the routes could not be added to the routing table. -func (r *router) addServiceRoutes(reg registry.Registry, network string, metric int) error { +func (r *router) addServiceRoutes(reg registry.Registry, metric int) error { services, err := reg.ListServices() if err != nil { return fmt.Errorf("failed to list services: %v", err) } for _, service := range services { - route := NewRoute( - DestAddr(service.Name), - Gateway(r), - Network(network), - Metric(metric), - ) + route := Route{ + Destination: service.Name, + Router: r, + Network: r.opts.Advertise, + Metric: metric, + } if err := r.opts.Table.Add(route); err != nil && err != ErrDuplicateRoute { return fmt.Errorf("error adding route for service: %s", service.Name) } @@ -160,15 +155,15 @@ func (r *router) addServiceRoutes(reg registry.Registry, network string, metric } // parseToNode parses router into registry.Node and returns the result. -// It returns error if the router network address could not be parsed into service host and port. -// NOTE: We use ":" as the default delimiter when we split the network address. +// It returns error if the router network address could not be parsed into host and port. +// NOTE: We use ":" as the delimiter when we splitting the router network address. func (r *router) parseToNode() (*registry.Node, error) { // split on ":" as a standard host/port delimiter - addr := strings.Split(r.opts.NetworkAddress, ":") + addr := strings.Split(r.opts.Advertise, ":") // try to parse network port into integer port, err := strconv.Atoi(addr[1]) if err != nil { - return nil, fmt.Errorf("could not parse router network address from %s: %v", r.opts.NetworkAddress, err) + return nil, fmt.Errorf("could not parse router network address: %v", err) } node := ®istry.Node{ @@ -184,7 +179,7 @@ func (r *router) parseToNode() (*registry.Node, error) { // It returns error if either the local services failed to be listed or if it fails to register local service in network registry. func (r *router) advertiseToNetwork(node *registry.Node) error { // ticker to periodically scan the local registry - ticker := time.NewTicker(AdvertiseToNetworkTick) + ticker := time.NewTicker(AdvertiseTick) for { select { @@ -192,7 +187,7 @@ func (r *router) advertiseToNetwork(node *registry.Node) error { return nil case <-ticker.C: // list all local services - services, err := r.opts.LocalRegistry.ListServices() + services, err := r.opts.Registry.ListServices() if err != nil { return fmt.Errorf("failed to list local services: %v", err) } @@ -203,7 +198,7 @@ func (r *router) advertiseToNetwork(node *registry.Node) error { Nodes: []*registry.Node{node}, } // register the local service in the network registry - if err := r.opts.NetworkRegistry.Register(svc, registry.RegisterTTL(AdvertiseNetworkTTL)); err != nil { + if err := r.opts.Network.Register(svc, registry.RegisterTTL(AdvertiseTTL)); err != nil { return fmt.Errorf("failed to register service %s in network registry: %v", svc.Name, err) } } @@ -213,7 +208,7 @@ func (r *router) advertiseToNetwork(node *registry.Node) error { // manageServiceRoutes watches services in given registry and updates the routing table accordingly. // It returns error if the service registry watcher has stopped or if the routing table failed to be updated. -func (r *router) manageServiceRoutes(w registry.Watcher, network string, metric int) error { +func (r *router) manageServiceRoutes(w registry.Watcher, metric int) error { // wait in the background for the router to stop // when the router stops, stop the watcher and exit r.wg.Add(1) @@ -236,17 +231,17 @@ func (r *router) manageServiceRoutes(w registry.Watcher, network string, metric break } - route := NewRoute( - DestAddr(res.Service.Name), - Gateway(r), - Network(network), - Metric(metric), - ) + route := Route{ + Destination: res.Service.Name, + Router: r, + Network: r.opts.Advertise, + Metric: metric, + } switch res.Action { case "create": if len(res.Service.Nodes) > 0 { - /// only return error if the route is not duplicate, but something else has failed + // only return error if the route is not duplicate, but something else has failed if err := r.opts.Table.Add(route); err != nil && err != ErrDuplicateRoute { return fmt.Errorf("failed to add route for service: %v", res.Service.Name) } @@ -274,8 +269,7 @@ func (r *router) Stop() error { // NOTE: we need a more efficient way of doing this e.g. network routes // should ideally be autodeleted when the router stops gossiping - // deregister all services advertised by this router from remote registry - query := NewQuery(QueryGateway(r), QueryNetwork(r.opts.NetworkAddress)) + query := NewQuery(QueryRouter(r), QueryNetwork(r.opts.Advertise)) routes, err := r.opts.Table.Lookup(query) if err != nil && err != ErrRouteNotFound { return fmt.Errorf("failed to lookup routes for router %s: %v", r.opts.ID, err) @@ -289,10 +283,10 @@ func (r *router) Stop() error { for _, route := range routes { service := ®istry.Service{ - Name: route.Options().DestAddr, + Name: route.Destination, Nodes: []*registry.Node{node}, } - if err := r.opts.NetworkRegistry.Deregister(service); err != nil { + if err := r.opts.Network.Deregister(service); err != nil { return fmt.Errorf("failed to deregister service %s from network registry: %v", service.Name, err) } } @@ -310,7 +304,7 @@ func (r *router) String() string { data := []string{ r.opts.ID, r.opts.Address, - r.opts.NetworkAddress, + r.opts.Advertise, fmt.Sprintf("%d", r.opts.Table.Size()), } table.Append(data) diff --git a/router/default_table.go b/router/default_table.go index 3bed626f..04e8f6db 100644 --- a/router/default_table.go +++ b/router/default_table.go @@ -64,7 +64,7 @@ func (t *table) Options() TableOptions { // Add adds a route to the routing table func (t *table) Add(r Route) error { - destAddr := r.Options().DestAddr + destAddr := r.Destination sum := t.hash(r) t.Lock() @@ -86,7 +86,7 @@ func (t *table) Add(r Route) error { } // only add the route if the route override is explicitly requested - if _, ok := t.m[destAddr][sum]; ok && r.Options().Policy == OverrideIfExists { + if _, ok := t.m[destAddr][sum]; ok && r.Policy == OverrideIfExists { t.m[destAddr][sum] = r go t.sendEvent(&Event{Type: UpdateEvent, Route: r}) return nil @@ -94,7 +94,7 @@ func (t *table) Add(r Route) error { // if we reached this point without already returning the route already exists // we return nil only if explicitly requested by the client - if r.Options().Policy == IgnoreIfExists { + if r.Policy == IgnoreIfExists { return nil } @@ -106,7 +106,7 @@ func (t *table) Delete(r Route) error { t.Lock() defer t.Unlock() - destAddr := r.Options().DestAddr + destAddr := r.Destination sum := t.hash(r) if _, ok := t.m[destAddr]; !ok { @@ -121,7 +121,7 @@ func (t *table) Delete(r Route) error { // Update updates routing table with new route func (t *table) Update(r Route) error { - destAddr := r.Options().DestAddr + destAddr := r.Destination sum := t.hash(r) t.Lock() @@ -165,24 +165,28 @@ func (t *table) Lookup(q Query) ([]Route, error) { var results []Route for destAddr, routes := range t.m { - if q.Options().DestAddr != "*" { - if q.Options().DestAddr != destAddr { + if q.Options().Destination != "*" { + if q.Options().Destination != destAddr { continue } for _, route := range routes { - if q.Options().Network == "*" || q.Options().Network == route.Options().Network { - if q.Options().Gateway.ID() == "*" || q.Options().Gateway.ID() == route.Options().Gateway.ID() { - results = append(results, route) + if q.Options().Network == "*" || q.Options().Network == route.Network { + if q.Options().Router.ID() == "*" || q.Options().Router.ID() == route.Router.ID() { + if route.Metric <= q.Options().Metric { + results = append(results, route) + } } } } } - if q.Options().DestAddr == "*" { + if q.Options().Destination == "*" { for _, route := range routes { - if q.Options().Network == "*" || q.Options().Network == route.Options().Network { - if q.Options().Gateway.ID() == "*" || q.Options().Gateway.ID() == route.Options().Gateway.ID() { - results = append(results, route) + if q.Options().Network == "*" || q.Options().Network == route.Router.Network() { + if q.Options().Router.ID() == "*" || q.Options().Router.ID() == route.Router.ID() { + if route.Metric <= q.Options().Metric { + results = append(results, route) + } } } } @@ -200,8 +204,8 @@ func (t *table) Lookup(q Query) ([]Route, error) { func (t *table) Watch(opts ...WatchOption) (Watcher, error) { // by default watch everything wopts := WatchOptions{ - DestAddr: "*", - Network: "*", + Destination: "*", + Network: "*", } for _, o := range opts { @@ -252,15 +256,15 @@ func (t *table) String() string { // create nice table printing structure table := tablewriter.NewWriter(sb) - table.SetHeader([]string{"Destination", "Gateway", "Network", "Metric"}) + table.SetHeader([]string{"Destination", "Router", "Network", "Metric"}) for _, destRoute := range t.m { for _, route := range destRoute { strRoute := []string{ - route.Options().DestAddr, - route.Options().Gateway.Address(), - route.Options().Network, - fmt.Sprintf("%d", route.Options().Metric), + route.Destination, + route.Router.Address(), + route.Network, + fmt.Sprintf("%d", route.Metric), } table.Append(strRoute) } @@ -274,12 +278,12 @@ func (t *table) String() string { // hash hashes the route using router gateway and network address func (t *table) hash(r Route) uint64 { - destAddr := r.Options().DestAddr - gwAddr := r.Options().Gateway.Address() - netAddr := r.Options().Network + destAddr := r.Destination + routerAddr := r.Router.Address() + netAddr := r.Network t.h.Reset() - t.h.Write([]byte(destAddr + gwAddr + netAddr)) + t.h.Write([]byte(destAddr + routerAddr + netAddr)) return t.h.Sum64() } diff --git a/router/options.go b/router/options.go index b3da5a2d..ee0c6526 100644 --- a/router/options.go +++ b/router/options.go @@ -6,31 +6,26 @@ import ( ) var ( - // DefaultGossipAddress is default gossip bind address - DefaultGossipAddress = ":9093" - // DefaultNetworkAddress is default network bind address - DefaultNetworkAddress = ":9094" + // DefaultAddress is default router address + DefaultAddress = ":9093" + // DefaultAdvertise is default address advertised to the network + DefaultAdvertise = ":9094" ) // Options are router options type Options struct { // ID is router id ID string - // Address is router micro service address + // Address is router address Address string - // GossipAddress is router gossip address - GossipAddress string - // NetworkAddress is micro network address - NetworkAddress string - // LocalRegistry is router local registry - LocalRegistry registry.Registry - // NetworkRegistry is router remote registry - // NOTE: we need some abstraction on top of gossip.Registry - NetworkRegistry registry.Registry + // Advertise is the address advertised to the network + Advertise string + // Registry is the local registry + Registry registry.Registry + // Networkis the network registry + Network registry.Registry // Table is routing table Table Table - // RIB is Routing Information Base - RIB RIB } // ID sets Router ID @@ -47,59 +42,43 @@ func Address(a string) Option { } } -// GossipAddress sets router gossip address -func GossipAddress(a string) Option { +// Advertise sets the address that is advertise to the network +func Advertise(n string) Option { return func(o *Options) { - o.GossipAddress = a + o.Advertise = n } } -// NetworkAddress sets router network address -func NetworkAddress(n string) Option { - return func(o *Options) { - o.NetworkAddress = n - } -} - -// RoutingTable allows to specify custom routing table +// RoutingTable sets the routing table func RoutingTable(t Table) Option { return func(o *Options) { o.Table = t } } -// LocalRegistry allows to specify local registry -func LocalRegistry(r registry.Registry) Option { +// Registry sets the local registry +func Registry(r registry.Registry) Option { return func(o *Options) { - o.LocalRegistry = r + o.Registry = r } } -// NetworkRegistry allows to specify remote registry -func NetworkRegistry(r registry.Registry) Option { +// Network sets the network registry +func Network(r registry.Registry) Option { return func(o *Options) { - o.NetworkRegistry = r - } -} - -// RouterRIB allows to configure RIB -func RouterRIB(r RIB) Option { - return func(o *Options) { - o.RIB = r + o.Network = r } } // DefaultOptions returns router default options func DefaultOptions() Options { // NOTE: by default both local and network registies use default registry i.e. mdns - // TODO: DefaultRIB needs to be added once it's properly figured out return Options{ - ID: uuid.New().String(), - Address: ":8083", - GossipAddress: DefaultGossipAddress, - NetworkAddress: DefaultNetworkAddress, - LocalRegistry: registry.DefaultRegistry, - NetworkRegistry: registry.DefaultRegistry, - Table: NewTable(), + ID: uuid.New().String(), + Address: DefaultAddress, + Advertise: DefaultAdvertise, + Registry: registry.DefaultRegistry, + Network: registry.DefaultRegistry, + Table: NewTable(), } } diff --git a/router/query.go b/router/query.go index 54b52e22..7c18e075 100644 --- a/router/query.go +++ b/router/query.go @@ -27,20 +27,22 @@ type QueryOption func(*QueryOptions) // QueryOptions are routing table query options type QueryOptions struct { - // DestAddr is destination address - DestAddr string - // NetworkAddress is network address + // Destination is destination address + Destination string + // Network is network address Network string - // Gateway is gateway address - Gateway Router + // Router is gateway address + Router Router + // Metric is route metric + Metric int // Policy is query lookup policy Policy LookupPolicy } -// QueryDestAddr sets query destination address -func QueryDestAddr(a string) QueryOption { +// QueryDestination sets query destination address +func QueryDestination(a string) QueryOption { return func(o *QueryOptions) { - o.DestAddr = a + o.Destination = a } } @@ -51,14 +53,22 @@ func QueryNetwork(a string) QueryOption { } } -// QueryGateway sets query gateway address -func QueryGateway(r Router) QueryOption { +// QueryRouter sets query gateway address +func QueryRouter(r Router) QueryOption { return func(o *QueryOptions) { - o.Gateway = r + o.Router = r + } +} + +// QueryMetric sets query metric +func QueryMetric(m int) QueryOption { + return func(o *QueryOptions) { + o.Metric = m } } // QueryPolicy sets query policy +// NOTE: this might be renamed to filter or some such func QueryPolicy(p LookupPolicy) QueryOption { return func(o *QueryOptions) { o.Policy = p @@ -82,11 +92,13 @@ func NewQuery(opts ...QueryOption) Query { r := newRouter(ID("*")) // default options + // NOTE: by default we use DefaultNetworkMetric qopts := QueryOptions{ - DestAddr: "*", - Network: "*", - Gateway: r, - Policy: DiscardNoRoute, + Destination: "*", + Network: "*", + Router: r, + Metric: DefaultNetworkMetric, + Policy: DiscardNoRoute, } for _, o := range opts { diff --git a/router/rib.go b/router/rib.go deleted file mode 100644 index 8f2795c6..00000000 --- a/router/rib.go +++ /dev/null @@ -1,30 +0,0 @@ -package router - -// RIB is Routing Information Base. -// RIB is used to source the base routing table. -type RIB interface { - // Initi initializes RIB - Init(...RIBOption) error - // Options returns RIB options - Options() RIBOptions - // Routes returns routes - Routes() []Route - // String returns debug info - String() string -} - -// RIBOption sets RIB options -type RIBOption func(*RIBOptions) - -// RIBOptions are RIB options -type RIBOptions struct { - // Source defines RIB source URL - Source string -} - -// Source sets RIB source -func Source(s string) RIBOption { - return func(o *RIBOptions) { - o.Source = s - } -} diff --git a/router/route.go b/router/route.go index 7942ed88..88fe5b18 100644 --- a/router/route.go +++ b/router/route.go @@ -14,18 +14,18 @@ var ( DefaultNetworkMetric = 10 ) -// AddPolicy defines routing table addition policy -type AddPolicy int +// RoutePolicy defines routing table addition policy +type RoutePolicy int const ( // OverrideIfExists overrides route if it already exists - OverrideIfExists AddPolicy = iota + OverrideIfExists RoutePolicy = iota // IgnoreIfExists does not modify existing route IgnoreIfExists ) // String returns human reprensentation of policy -func (p AddPolicy) String() string { +func (p RoutePolicy) String() string { switch p { case OverrideIfExists: return "OVERRIDE" @@ -36,100 +36,34 @@ func (p AddPolicy) String() string { } } -// RouteOption is used to set routing table entry options -type RouteOption func(*RouteOptions) - -// RouteOptions are route options -type RouteOptions struct { - // DestAddr is destination address - DestAddr string - // Gateway is the next route hop - Gateway Router - // Network defines micro network +// Route is network route +type Route struct { + // Destination is destination address + Destination string + // Router is the network router + Router Router + // Network is micro network address Network string - // Metric is route cost metric + // Metric is the route cost metric Metric int - // Policy defines route addition policy - Policy AddPolicy -} - -// DestAddr sets destination address -func DestAddr(a string) RouteOption { - return func(o *RouteOptions) { - o.DestAddr = a - } -} - -// Gateway sets the route gateway -func Gateway(r Router) RouteOption { - return func(o *RouteOptions) { - o.Gateway = r - } -} - -// Network sets micro network -func Network(n string) RouteOption { - return func(o *RouteOptions) { - o.Network = n - } -} - -// Metric sets route metric -func Metric(m int) RouteOption { - return func(o *RouteOptions) { - o.Metric = m - } -} - -// RoutePolicy sets add route policy -func RoutePolicy(p AddPolicy) RouteOption { - return func(o *RouteOptions) { - o.Policy = p - } -} - -// Route is routing table route -type Route interface { - // Options returns route options - Options() RouteOptions -} - -type route struct { - opts RouteOptions -} - -// NewRoute returns new routing table route -func NewRoute(opts ...RouteOption) Route { - eopts := RouteOptions{} - - for _, o := range opts { - o(&eopts) - } - - return &route{ - opts: eopts, - } -} - -// Options returns route options -func (r *route) Options() RouteOptions { - return r.opts + // Policy defines route policy + Policy RoutePolicy } // String allows to print the route -func (r *route) String() string { +func (r *Route) String() string { // this will help us build routing table string sb := &strings.Builder{} // create nice table printing structure table := tablewriter.NewWriter(sb) - table.SetHeader([]string{"Destination", "Gateway", "Network", "Metric"}) + table.SetHeader([]string{"Destination", "Router", "Network", "Metric"}) strRoute := []string{ - r.opts.DestAddr, - r.opts.Gateway.Address(), - r.opts.Network, - fmt.Sprintf("%d", r.opts.Metric), + r.Destination, + r.Router.Address(), + r.Network, + fmt.Sprintf("%d", r.Metric), } table.Append(strRoute) diff --git a/router/router.go b/router/router.go index 0c70ecc7..f87aed75 100644 --- a/router/router.go +++ b/router/router.go @@ -13,8 +13,6 @@ type Router interface { Table() Table // Address returns the router adddress Address() string - // Gossip returns the router gossip address - Gossip() string // Network returns the router network address Network() string // Start starts the router diff --git a/router/table_watcher.go b/router/table_watcher.go index bf18e8c0..17a0971f 100644 --- a/router/table_watcher.go +++ b/router/table_watcher.go @@ -54,6 +54,8 @@ type WatchOption func(*WatchOptions) type Watcher interface { // Next is a blocking call that returns watch result Next() (*Event, error) + // Chan returns event channel + Chan() (<-chan *Event, error) // Stop stops watcher Stop() } @@ -61,16 +63,16 @@ type Watcher interface { // WatchOptions are table watcher options type WatchOptions struct { // Specify destination address to watch - DestAddr string + Destination string // Specify network to watch Network string } -// WatchDestAddr sets what destination to watch +// WatchDestination sets what destination to watch // Destination is usually microservice name -func WatchDestAddr(a string) WatchOption { +func WatchDestination(a string) WatchOption { return func(o *WatchOptions) { - o.DestAddr = a + o.Destination = a } } @@ -94,13 +96,13 @@ func (w *tableWatcher) Next() (*Event, error) { for { select { case res := <-w.resChan: - switch w.opts.DestAddr { + switch w.opts.Destination { case "*", "": - if w.opts.Network == "*" || w.opts.Network == res.Route.Options().Network { + if w.opts.Network == "*" || w.opts.Network == res.Route.Network { return res, nil } - case res.Route.Options().DestAddr: - if w.opts.Network == "*" || w.opts.Network == res.Route.Options().Network { + case res.Route.Destination: + if w.opts.Network == "*" || w.opts.Network == res.Route.Network { return res, nil } } @@ -110,6 +112,11 @@ func (w *tableWatcher) Next() (*Event, error) { } } +// Chan returns watcher events channel +func (w *tableWatcher) Chan() (<-chan *Event, error) { + return w.resChan, nil +} + // Stop stops routing table watcher func (w *tableWatcher) Stop() { select { @@ -125,10 +132,10 @@ func (w *tableWatcher) String() string { sb := &strings.Builder{} table := tablewriter.NewWriter(sb) - table.SetHeader([]string{"DestAddr", "Network"}) + table.SetHeader([]string{"Destination", "Network"}) data := []string{ - w.opts.DestAddr, + w.opts.Destination, w.opts.Network, } table.Append(data) From 3f910038a3b9a0b50c227c7c68f43817455fff8c Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 19 Jun 2019 22:04:13 +0100 Subject: [PATCH 034/287] Move store to data/store --- {store => data/store}/consul/consul.go | 2 +- {store => data/store}/memory/memory.go | 2 +- {store => data/store}/options.go | 0 {store => data/store}/store.go | 0 sync/map.go | 4 ++-- sync/options.go | 2 +- sync/sync.go | 2 +- 7 files changed, 6 insertions(+), 6 deletions(-) rename {store => data/store}/consul/consul.go (97%) rename {store => data/store}/memory/memory.go (97%) rename {store => data/store}/options.go (100%) rename {store => data/store}/store.go (100%) diff --git a/store/consul/consul.go b/data/store/consul/consul.go similarity index 97% rename from store/consul/consul.go rename to data/store/consul/consul.go index fe937e6c..174d043c 100644 --- a/store/consul/consul.go +++ b/data/store/consul/consul.go @@ -7,7 +7,7 @@ import ( "github.com/hashicorp/consul/api" "github.com/micro/go-micro/config/options" - "github.com/micro/go-micro/store" + "github.com/micro/go-micro/data/store" ) type ckv struct { diff --git a/store/memory/memory.go b/data/store/memory/memory.go similarity index 97% rename from store/memory/memory.go rename to data/store/memory/memory.go index d6b23e20..0e06eefa 100644 --- a/store/memory/memory.go +++ b/data/store/memory/memory.go @@ -6,7 +6,7 @@ import ( "time" "github.com/micro/go-micro/config/options" - "github.com/micro/go-micro/store" + "github.com/micro/go-micro/data/store" ) type memoryStore struct { diff --git a/store/options.go b/data/store/options.go similarity index 100% rename from store/options.go rename to data/store/options.go diff --git a/store/store.go b/data/store/store.go similarity index 100% rename from store/store.go rename to data/store/store.go diff --git a/sync/map.go b/sync/map.go index 2053c57d..5f7865e9 100644 --- a/sync/map.go +++ b/sync/map.go @@ -6,8 +6,8 @@ import ( "encoding/json" "fmt" - "github.com/micro/go-micro/store" - ckv "github.com/micro/go-micro/store/consul" + "github.com/micro/go-micro/data/store" + ckv "github.com/micro/go-micro/data/store/consul" lock "github.com/micro/go-micro/sync/lock/consul" ) diff --git a/sync/options.go b/sync/options.go index 0e5cf3d0..65f20e28 100644 --- a/sync/options.go +++ b/sync/options.go @@ -1,7 +1,7 @@ package sync import ( - "github.com/micro/go-micro/store" + "github.com/micro/go-micro/data/store" "github.com/micro/go-micro/sync/leader" "github.com/micro/go-micro/sync/lock" "github.com/micro/go-micro/sync/time" diff --git a/sync/sync.go b/sync/sync.go index 7b080b1d..27a6104a 100644 --- a/sync/sync.go +++ b/sync/sync.go @@ -2,7 +2,7 @@ package sync import ( - "github.com/micro/go-micro/store" + "github.com/micro/go-micro/data/store" "github.com/micro/go-micro/sync/leader" "github.com/micro/go-micro/sync/lock" "github.com/micro/go-micro/sync/task" From 8d5d812e3283187e47d3a64110b501172dca6151 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 20 Jun 2019 12:44:51 +0100 Subject: [PATCH 035/287] Fix a streaming bug --- server/rpc_router.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server/rpc_router.go b/server/rpc_router.go index 837137ae..b1eb66ff 100644 --- a/server/rpc_router.go +++ b/server/rpc_router.go @@ -188,7 +188,11 @@ func (s *service) call(ctx context.Context, router *router, sending *sync.Mutex, method: req.msg.Method, endpoint: req.msg.Endpoint, body: req.msg.Body, - rawBody: argv.Interface(), + } + + // only set if not nil + if argv.IsValid() { + r.rawBody = argv.Interface() } if !mtype.stream { From 1765be049bc129aa7075afa26f24900a9bdcceb3 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Thu, 20 Jun 2019 13:04:58 +0100 Subject: [PATCH 036/287] router.Start() is now router.Advertise(). Updated code documentation. --- router/default_router.go | 23 +++++++++++++++-------- router/router.go | 10 +++++----- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/router/default_router.go b/router/default_router.go index 32de1886..d600d1da 100644 --- a/router/default_router.go +++ b/router/default_router.go @@ -2,6 +2,7 @@ package router import ( "fmt" + "net" "strconv" "strings" "sync" @@ -76,8 +77,11 @@ func (r *router) Network() string { return r.opts.Advertise } -// Start starts the router -func (r *router) Start() error { +// Advertise advertises the router routes to the network. +// Advertise is a blocking function. It launches multiple goroutines that watch +// service registries and advertise the router routes to other routers in the network. +// It returns error if any of the launched goroutines fail with error. +func (r *router) Advertise() error { // add local service routes into the routing table if err := r.addServiceRoutes(r.opts.Registry, DefaultLocalMetric); err != nil { return fmt.Errorf("failed adding routes for local services: %v", err) @@ -130,7 +134,7 @@ func (r *router) Start() error { return <-errChan } -// addServiceRouteslists all available services in given registry and adds them to the routing table. +// addServiceRoutes adds all services in given registry to the routing table. // NOTE: this is a one-off operation done when bootstrapping the routing table of the new router. // It returns error if either the services could not be listed or if the routes could not be added to the routing table. func (r *router) addServiceRoutes(reg registry.Registry, metric int) error { @@ -156,19 +160,22 @@ func (r *router) addServiceRoutes(reg registry.Registry, metric int) error { // parseToNode parses router into registry.Node and returns the result. // It returns error if the router network address could not be parsed into host and port. -// NOTE: We use ":" as the delimiter when we splitting the router network address. func (r *router) parseToNode() (*registry.Node, error) { - // split on ":" as a standard host/port delimiter - addr := strings.Split(r.opts.Advertise, ":") + // split router address to host and port part + addr, portStr, err := net.SplitHostPort(r.opts.Advertise) + if err != nil { + return nil, fmt.Errorf("could not parse router address: %v", err) + } + // try to parse network port into integer - port, err := strconv.Atoi(addr[1]) + port, err := strconv.Atoi(portStr) if err != nil { return nil, fmt.Errorf("could not parse router network address: %v", err) } node := ®istry.Node{ Id: r.opts.ID, - Address: addr[0], + Address: addr, Port: port, } diff --git a/router/router.go b/router/router.go index f87aed75..51a629f9 100644 --- a/router/router.go +++ b/router/router.go @@ -7,16 +7,16 @@ type Router interface { Init(...Option) error // Options returns the router options Options() Options - // ID returns id of the router + // ID returns the id of the router ID() string - // Table returns the router routing table + // Table returns the routing table Table() Table // Address returns the router adddress Address() string - // Network returns the router network address + // Network returns the network address of the router Network() string - // Start starts the router - Start() error + // Advertise starts advertising the routes to the network + Advertise() error // Stop stops the router Stop() error // String returns debug info From 92b998c3abdd041bb7923019e3b739045e06d1ea Mon Sep 17 00:00:00 2001 From: magodo Date: Fri, 21 Jun 2019 00:25:39 +0800 Subject: [PATCH 037/287] consul config source support 1st-level array Check whetehr the 1st level encoded json is array or not, to support 1st level array in consul config. During debug, i suspected the incapability of arrray is caused by json reader, so i added test for array. I think it makes no harm to also check that in. --- config/reader/json/values_test.go | 74 +++++++++++++++++++++++------ config/source/consul/util.go | 78 +++++++++++++++++++++++-------- 2 files changed, 118 insertions(+), 34 deletions(-) diff --git a/config/reader/json/values_test.go b/config/reader/json/values_test.go index 516199a6..97aec68a 100644 --- a/config/reader/json/values_test.go +++ b/config/reader/json/values_test.go @@ -1,39 +1,85 @@ package json import ( + "reflect" "testing" "github.com/micro/go-micro/config/source" ) func TestValues(t *testing.T) { - data := []byte(`{"foo": "bar", "baz": {"bar": "cat"}}`) - + emptyStr := "" testData := []struct { - path []string - value string + csdata []byte + path []string + accepter interface{} + value interface{} }{ { + []byte(`{"foo": "bar", "baz": {"bar": "cat"}}`), []string{"foo"}, + emptyStr, "bar", }, { + []byte(`{"foo": "bar", "baz": {"bar": "cat"}}`), []string{"baz", "bar"}, + emptyStr, "cat", }, } - values, err := newValues(&source.ChangeSet{ - Data: data, - }) + for idx, test := range testData { + values, err := newValues(&source.ChangeSet{ + Data: test.csdata, + }) + if err != nil { + t.Fatal(err) + } - if err != nil { - t.Fatal(err) - } - - for _, test := range testData { - if v := values.Get(test.path...).String(""); v != test.value { - t.Fatalf("Expected %s got %s for path %v", test.value, v, test.path) + err = values.Get(test.path...).Scan(&test.accepter) + if err != nil { + t.Fatal(err) + } + if test.accepter != test.value { + t.Fatalf("No.%d Expected %v got %v for path %v", idx, test.value, test.accepter, test.path) + } + } +} + +func TestStructArray(t *testing.T) { + type T struct { + Foo string + } + + emptyTSlice := []T{} + + testData := []struct { + csdata []byte + accepter []T + value []T + }{ + { + []byte(`[{"foo": "bar"}]`), + emptyTSlice, + []T{T{Foo: "bar"}}, + }, + } + + for idx, test := range testData { + values, err := newValues(&source.ChangeSet{ + Data: test.csdata, + }) + if err != nil { + t.Fatal(err) + } + + err = values.Get().Scan(&test.accepter) + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(test.accepter, test.value) { + t.Fatalf("No.%d Expected %v got %v", idx, test.value, test.accepter) } } } diff --git a/config/source/consul/util.go b/config/source/consul/util.go index db6f708d..1edc5b48 100644 --- a/config/source/consul/util.go +++ b/config/source/consul/util.go @@ -8,40 +8,78 @@ import ( "github.com/micro/go-micro/config/encoder" ) +type jsonValue interface { + Value() interface{} + Decode(encoder.Encoder, []byte) (jsonValue, error) +} +type jsonArrayValue []interface{} +type jsonMapValue map[string]interface{} + +func (a jsonArrayValue) Value() interface{} { return a } +func (a jsonArrayValue) Decode(e encoder.Encoder, b []byte) (jsonValue, error) { + v := jsonArrayValue{} + err := e.Decode(b, &v) + return v, err +} +func (m jsonMapValue) Value() interface{} { return m } +func (m jsonMapValue) Decode(e encoder.Encoder, b []byte) (jsonValue, error) { + v := jsonMapValue{} + err := e.Decode(b, &v) + return v, err +} + func makeMap(e encoder.Encoder, kv api.KVPairs, stripPrefix string) (map[string]interface{}, error) { + data := make(map[string]interface{}) // consul guarantees lexicographic order, so no need to sort for _, v := range kv { pathString := strings.TrimPrefix(strings.TrimPrefix(v.Key, stripPrefix), "/") - var val map[string]interface{} + if pathString == "" { + continue + } + var val jsonValue + var err error // ensure a valid value is stored at this location if len(v.Value) > 0 { - if err := e.Decode(v.Value, &val); err != nil { - return nil, fmt.Errorf("faild decode value. path: %s, error: %s", pathString, err) - } - } - - // set target at the root - target := data - - // then descend to the target location, creating as we go, if need be - if pathString != "" { - path := strings.Split(pathString, "/") - // find (or create) the location we want to put this value at - for _, dir := range path { - if _, ok := target[dir]; !ok { - target[dir] = make(map[string]interface{}) + // check whether this is an array + if v.Value[0] == 91 && v.Value[len(v.Value)-1] == 93 { + val = jsonArrayValue{} + if val, err = val.Decode(e, v.Value); err != nil { + return nil, fmt.Errorf("faild decode value. path: %s, error: %s", pathString, err) + } + } else { + val = jsonMapValue{} + if val, err = val.Decode(e, v.Value); err != nil { + return nil, fmt.Errorf("faild decode value. path: %s, error: %s", pathString, err) } - target = target[dir].(map[string]interface{}) } - } + target := data + path := strings.Split(pathString, "/") + // find (or create) the leaf node we want to put this value at + for _, dir := range path[:len(path)-1] { + if _, ok := target[dir]; !ok { + target[dir] = make(map[string]interface{}) + } + target = target[dir].(map[string]interface{}) + } + + leafDir := path[len(path)-1] + // copy over the keys from the value - for k := range val { - target[k] = val[k] + switch val.(type) { + case jsonArrayValue: + target[leafDir] = val.Value() + case jsonMapValue: + target[leafDir] = make(map[string]interface{}) + target = target[leafDir].(map[string]interface{}) + mapv := val.Value().(jsonMapValue) + for k := range mapv { + target[k] = mapv[k] + } } } From 1983b4ae92a892e09bb6f3b28dc8c4f18a7bc88c Mon Sep 17 00:00:00 2001 From: magodo Date: Fri, 21 Jun 2019 15:30:45 +0800 Subject: [PATCH 038/287] variable rename to abstract encoder --- config/source/consul/util.go | 59 ++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/config/source/consul/util.go b/config/source/consul/util.go index 1edc5b48..fa1b8d66 100644 --- a/config/source/consul/util.go +++ b/config/source/consul/util.go @@ -8,24 +8,26 @@ import ( "github.com/micro/go-micro/config/encoder" ) -type jsonValue interface { +type configValue interface { Value() interface{} - Decode(encoder.Encoder, []byte) (jsonValue, error) + Decode(encoder.Encoder, []byte) error +} +type configArrayValue struct { + v []interface{} } -type jsonArrayValue []interface{} -type jsonMapValue map[string]interface{} -func (a jsonArrayValue) Value() interface{} { return a } -func (a jsonArrayValue) Decode(e encoder.Encoder, b []byte) (jsonValue, error) { - v := jsonArrayValue{} - err := e.Decode(b, &v) - return v, err +func (a *configArrayValue) Value() interface{} { return a.v } +func (a *configArrayValue) Decode(e encoder.Encoder, b []byte) error { + return e.Decode(b, &a.v) } -func (m jsonMapValue) Value() interface{} { return m } -func (m jsonMapValue) Decode(e encoder.Encoder, b []byte) (jsonValue, error) { - v := jsonMapValue{} - err := e.Decode(b, &v) - return v, err + +type configMapValue struct { + v map[string]interface{} +} + +func (m *configMapValue) Value() interface{} { return m.v } +func (m *configMapValue) Decode(e encoder.Encoder, b []byte) error { + return e.Decode(b, &m.v) } func makeMap(e encoder.Encoder, kv api.KVPairs, stripPrefix string) (map[string]interface{}, error) { @@ -38,22 +40,21 @@ func makeMap(e encoder.Encoder, kv api.KVPairs, stripPrefix string) (map[string] if pathString == "" { continue } - var val jsonValue + var val configValue var err error // ensure a valid value is stored at this location if len(v.Value) > 0 { - // check whether this is an array - if v.Value[0] == 91 && v.Value[len(v.Value)-1] == 93 { - val = jsonArrayValue{} - if val, err = val.Decode(e, v.Value); err != nil { - return nil, fmt.Errorf("faild decode value. path: %s, error: %s", pathString, err) - } - } else { - val = jsonMapValue{} - if val, err = val.Decode(e, v.Value); err != nil { - return nil, fmt.Errorf("faild decode value. path: %s, error: %s", pathString, err) - } + // try to decode into map value or array value + arrayV := &configArrayValue{v: []interface{}{}} + mapV := &configMapValue{v: map[string]interface{}{}} + switch { + case arrayV.Decode(e, v.Value) == nil: + val = arrayV + case mapV.Decode(e, v.Value) == nil: + val = mapV + default: + return nil, fmt.Errorf("faild decode value. path: %s, error: %s", pathString, err) } } @@ -71,12 +72,12 @@ func makeMap(e encoder.Encoder, kv api.KVPairs, stripPrefix string) (map[string] // copy over the keys from the value switch val.(type) { - case jsonArrayValue: + case *configArrayValue: target[leafDir] = val.Value() - case jsonMapValue: + case *configMapValue: target[leafDir] = make(map[string]interface{}) target = target[leafDir].(map[string]interface{}) - mapv := val.Value().(jsonMapValue) + mapv := val.Value().(map[string]interface{}) for k := range mapv { target[k] = mapv[k] } From 7acd24914716f77a3c4516e941d230980cecca73 Mon Sep 17 00:00:00 2001 From: magodo Date: Fri, 21 Jun 2019 16:35:48 +0800 Subject: [PATCH 039/287] config consul source supports slash as prefix `config.NewConfig()` with consul source will both read from consul and watch consul for changes. Hence, the `prefix` is used in these 2 cases: - read case: it is used to strip path based on the `KVPair` returned from consul `kv.List()` method - watch case: it is used as the `key` of watch query (`keyprefix` type) So for *watch case*, the `key` is leagal to be `/` for watching change on root. While for *read case*, because `KVPair.Key` is always stripped off the leading slash, so if user specified some `prefix` with leading slash, we should strip it also. An extream case would be: user want's to read & watch node in root dir. One would specify `prefix` as `/`, and it should work then. --- config/source/consul/README.md | 6 +++--- config/source/consul/consul.go | 2 +- config/source/consul/util.go | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/config/source/consul/README.md b/config/source/consul/README.md index 061c0a3f..2ba45e5b 100644 --- a/config/source/consul/README.md +++ b/config/source/consul/README.md @@ -4,7 +4,7 @@ The consul source reads config from consul key/values ## Consul Format -The consul source expects keys under the default prefix `micro/config` +The consul source expects keys under the default prefix `/micro/config` Values are expected to be json @@ -29,8 +29,8 @@ Specify source with data consulSource := consul.NewSource( // optionally specify consul address; default to localhost:8500 consul.WithAddress("10.0.0.10:8500"), - // optionally specify prefix; defaults to micro/config - consul.WithPrefix("my/prefix"), + // optionally specify prefix; defaults to /micro/config + consul.WithPrefix("/my/prefix"), // optionally strip the provided prefix from the keys, defaults to false consul.StripPrefix(true), ) diff --git a/config/source/consul/consul.go b/config/source/consul/consul.go index 785f20f7..16e85332 100644 --- a/config/source/consul/consul.go +++ b/config/source/consul/consul.go @@ -21,7 +21,7 @@ type consul struct { var ( // DefaultPrefix is the prefix that consul keys will be assumed to have if you // haven't specified one - DefaultPrefix = "micro/config/" + DefaultPrefix = "/micro/config/" ) func (c *consul) Read() (*source.ChangeSet, error) { diff --git a/config/source/consul/util.go b/config/source/consul/util.go index db6f708d..80de3d3f 100644 --- a/config/source/consul/util.go +++ b/config/source/consul/util.go @@ -13,7 +13,7 @@ func makeMap(e encoder.Encoder, kv api.KVPairs, stripPrefix string) (map[string] // consul guarantees lexicographic order, so no need to sort for _, v := range kv { - pathString := strings.TrimPrefix(strings.TrimPrefix(v.Key, stripPrefix), "/") + pathString := strings.TrimPrefix(strings.TrimPrefix(v.Key, strings.TrimPrefix(stripPrefix, "/")), "/") var val map[string]interface{} // ensure a valid value is stored at this location From 4aa0192ebae9fe68686dea839c7a5ff288529efd Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 21 Jun 2019 12:55:31 +0100 Subject: [PATCH 040/287] Update go mod --- go.mod | 52 ++++++++++++++-- go.sum | 189 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 236 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index a9590f1d..1b5454b1 100644 --- a/go.mod +++ b/go.mod @@ -3,42 +3,84 @@ module github.com/micro/go-micro go 1.12 require ( + cloud.google.com/go v0.40.0 // indirect github.com/BurntSushi/toml v0.3.1 + github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 // indirect + github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 // indirect + github.com/armon/go-radix v1.0.0 // indirect github.com/beevik/ntp v0.2.0 github.com/bitly/go-simplejson v0.5.0 github.com/bwmarrin/discordgo v0.19.0 + github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc // indirect github.com/forestgiant/sliceutil v0.0.0-20160425183142-94783f95db6c github.com/fsnotify/fsnotify v1.4.7 github.com/fsouza/go-dockerclient v1.4.1 github.com/ghodss/yaml v1.0.0 + github.com/gliderlabs/ssh v0.2.2 // indirect github.com/go-log/log v0.1.0 github.com/go-playground/locales v0.12.1 // indirect github.com/go-playground/universal-translator v0.16.0 // indirect + github.com/golang/mock v1.3.1 // indirect github.com/golang/protobuf v1.3.1 + github.com/google/btree v1.0.0 // indirect + github.com/google/pprof v0.0.0-20190515194954-54271f7e092f // indirect github.com/google/uuid v1.1.1 + github.com/googleapis/gax-go/v2 v2.0.5 // indirect github.com/gorilla/handlers v1.4.0 github.com/gorilla/websocket v1.4.0 github.com/hashicorp/consul/api v1.1.0 + github.com/hashicorp/go-immutable-radix v1.1.0 // indirect + github.com/hashicorp/go-msgpack v0.5.5 // indirect + github.com/hashicorp/go-retryablehttp v0.5.4 // indirect + github.com/hashicorp/go-rootcerts v1.0.1 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-version v1.2.0 // indirect github.com/hashicorp/hcl v1.0.0 + github.com/hashicorp/mdns v1.0.1 // indirect github.com/hashicorp/memberlist v0.1.4 + github.com/hashicorp/serf v0.8.3 // indirect github.com/imdario/mergo v0.3.7 github.com/joncalhoun/qson v0.0.0-20170526102502-8a9cab3a62b1 github.com/json-iterator/go v1.1.6 + github.com/kisielk/errcheck v1.2.0 // indirect + github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect + github.com/kr/pty v1.1.5 // indirect github.com/leodido/go-urn v1.1.0 // indirect github.com/lucas-clemente/quic-go v0.11.2 + github.com/marten-seemann/qtls v0.2.4 // indirect + github.com/mattn/go-colorable v0.1.2 // indirect + github.com/mattn/go-runewidth v0.0.4 // indirect github.com/micro/cli v0.2.0 github.com/micro/mdns v0.1.0 + github.com/miekg/dns v1.1.14 // indirect + github.com/mitchellh/gox v1.0.1 // indirect github.com/mitchellh/hashstructure v1.0.0 - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.1 // indirect github.com/nats-io/nats.go v1.8.1 github.com/nlopes/slack v0.5.0 + github.com/olekukonko/tablewriter v0.0.1 + github.com/onsi/ginkgo v1.8.0 // indirect + github.com/onsi/gomega v1.5.0 // indirect github.com/pkg/errors v0.8.1 + github.com/posener/complete v1.2.1 // indirect + github.com/prometheus/common v0.6.0 // indirect + github.com/sirupsen/logrus v1.4.2 // indirect + github.com/stretchr/objx v0.2.0 // indirect github.com/technoweenie/multipartstreamer v1.0.1 // indirect - golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 - golang.org/x/net v0.0.0-20190607181551-461777fb6f67 + go.opencensus.io v0.22.0 // indirect + golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443 + golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522 // indirect + golang.org/x/image v0.0.0-20190618124811-92942e4437e2 // indirect + golang.org/x/mobile v0.0.0-20190607214518-6fa95d984e88 // indirect + golang.org/x/mod v0.1.0 // indirect + golang.org/x/net v0.0.0-20190620200207-3b0461eec859 + golang.org/x/sys v0.0.0-20190621062556-bf70e4678053 // indirect + golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect + golang.org/x/tools v0.0.0-20190620191750-1fa568393b23 // indirect + google.golang.org/appengine v1.6.1 // indirect + google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601 // indirect google.golang.org/grpc v1.21.1 gopkg.in/go-playground/validator.v9 v9.29.0 - gopkg.in/src-d/go-git.v4 v4.11.0 + gopkg.in/src-d/go-git.v4 v4.12.0 gopkg.in/telegram-bot-api.v4 v4.6.4 + honnef.co/go/tools v0.0.0-20190614002413-cb51c254f01b // indirect ) diff --git a/go.sum b/go.sum index 380c6df5..b576c0b1 100644 --- a/go.sum +++ b/go.sum @@ -1,16 +1,30 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.40.0/go.mod h1:Tk58MuI9rbLMKlAjeO/bDnteAx7tX2gJIXw4T5Jwlro= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 h1:EFSB7Zo9Eg91v7MJPVsifUysc/wPdN+NOnVe6bWbdBM= +github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/beevik/ntp v0.2.0 h1:sGsd+kAXzT0bfVfzJfce04g+dSRfrs+tbQW8lweuYgw= github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y= github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= @@ -18,9 +32,13 @@ github.com/bwmarrin/discordgo v0.19.0 h1:kMED/DB0NR1QhRcalb85w0Cu3Ep2OrGAqZH1R5a github.com/bwmarrin/discordgo v0.19.0/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q= github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/containerd/continuity v0.0.0-20181203112020-004b46473808 h1:4BX8f882bXEDKfWIf0wa8HRvpnBoPszJJXL+TVbBw4M= github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc h1:TP+534wVlf61smEIq1nwLLAjQVEK2EADoW3CX9AuT+8= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/docker/docker v0.7.3-0.20190309235953-33c3200e0d16 h1:dmUn0SuGx7unKFwxyeQ/oLUHhEfZosEDrpmYM+6MTuc= @@ -31,6 +49,8 @@ github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/emirpasic/gods v1.9.0 h1:rUF4PuzEjMChMiNsVjdI+SyLu7rEqpQ5reNFnhC7oFo= github.com/emirpasic/gods v1.9.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/forestgiant/sliceutil v0.0.0-20160425183142-94783f95db6c h1:pBgVXWDXju1m8W4lnEeIqTHPOzhTUO81a7yknM/xQR4= @@ -42,27 +62,43 @@ github.com/fsouza/go-dockerclient v1.4.1/go.mod h1:PUNHxbowDqRXfRgZqMz1OeGtbWC6V github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/gliderlabs/ssh v0.1.3/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-log/log v0.1.0 h1:wudGTNsiGzrD5ZjgIkVZ517ugi2XRe9Q/xRCzwEO4/U= github.com/go-log/log v0.1.0/go.mod h1:4mBwpdRMFLiuXZDCwU2lKQFsoSCo72j3HqBK9d81N2M= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc= github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM= github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= 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/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 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/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gorilla/handlers v1.4.0 h1:XulKRWSQK5uChr4pEgSE4Tc/OcmnU9GJuSwdog/tZsA= github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= @@ -73,33 +109,51 @@ github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBt github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= 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-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.1.0 h1:vN9wG1D6KG6YHRTWr8512cxGOVgTMEfgEdSj/hr8MPc= +github.com/hashicorp/go-immutable-radix v1.1.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= +github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0 h1:Rqb66Oo1X/eSV1x66xbDccZjhJigjg0+e82kpwzSwCI= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-rootcerts v1.0.1 h1:DMo4fmknnz0E0evoNYnV48RjWndOsmd6OW+09R3cEP8= +github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/memberlist v0.1.4 h1:gkyML/r71w3FL8gUi74Vk76avkj/9lYAY9lvg0OcoGs= github.com/hashicorp/memberlist v0.1.4/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2 h1:YZ7UKsJv+hKjqGVUUbtE3HNj79Eln2oQ75tniF6iPt0= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/serf v0.8.3 h1:MWYcmct5EtKz0efYooPcL0yNkem+7kWxqXDi/UIh+8k= +github.com/hashicorp/serf v0.8.3/go.mod h1:UpNcs7fFbpKIyZaUuSW6EPiH+eZC7OuyFD+wc1oal+k= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd h1:anPrsicrIi2ColgWTVPk+TrN42hJIWlfPHSBP9S0ZkM= github.com/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd/go.mod h1:3LVOLeyx9XVvwPgrt2be44XgSqndprz1G18rSk8KD84= @@ -112,13 +166,19 @@ github.com/joncalhoun/qson v0.0.0-20170526102502-8a9cab3a62b1 h1:lnrOS18wZBYrzdD github.com/joncalhoun/qson v0.0.0-20170526102502-8a9cab3a62b1/go.mod h1:DFXrEwSRX0p/aSvxE21319menCBFeQO0jXpRj7LEZUA= github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= 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/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e h1:RgQk53JHp/Cjunrr1WlsXSZpqXn+uREuHvUVcK82CV8= github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= @@ -126,8 +186,15 @@ github.com/lucas-clemente/quic-go v0.11.2 h1:Mop0ac3zALaBR3wGs6j8OYe/tcFvFsxTUFM github.com/lucas-clemente/quic-go v0.11.2/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw= github.com/marten-seemann/qtls v0.2.3 h1:0yWJ43C62LsZt08vuQJDK1uC1czUc3FJeCLPoNAI4vA= github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= +github.com/marten-seemann/qtls v0.2.4 h1:mCJ6i1jAqcsm9XODrSGvXECodoAb1STta+TkxJCwCnE= +github.com/marten-seemann/qtls v0.2.4/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/micro/cli v0.2.0 h1:ut3rV5JWqZjsXIa2MvGF+qMUP8DAUTvHX9Br5gO4afA= github.com/micro/cli v0.2.0/go.mod h1:jRT9gmfVKWSS6pkKcXQ8YhUyj6bzwxK8Fp5b0Y7qNnk= github.com/micro/mdns v0.1.0 h1:fuLybUsfynbigJmCot/54i+gwe0hpc/vtCMvWt2WfDI= @@ -135,11 +202,17 @@ github.com/micro/mdns v0.1.0/go.mod h1:KJ0dW7KmicXU2BV++qkLlmHYcVv7/hHnbtguSWt9A github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.3 h1:1g0r1IvskvgL8rR+AcHzUA+oFmGcQlaIm4IqakufeMM= github.com/miekg/dns v1.1.3/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.14 h1:wkQWn9wIp4mZbwW8XV6Km6owkvRPbOiV004ZM2CkGvA= +github.com/miekg/dns v1.1.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/gox v1.0.1/go.mod h1:ED6BioOGXMswlXa2zxfh/xdd5QhwYliBFn9V18Ap4z4= github.com/mitchellh/hashstructure v1.0.0 h1:ZkRJX1CyOoTkar7p/mLS5TZU4nJ1Rn/F8u9dGS02Q3Y= github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= @@ -150,6 +223,7 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nats-io/nats.go v1.8.1 h1:6lF/f1/NN6kzUDBz6pyvQDEXO39jqXcWRLu/tKjtOUQ= github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= github.com/nats-io/nkeys v0.0.2 h1:+qM7QpgXnvDDixitZtQUBDY9w/s9mu1ghS+JIbsrx6M= @@ -158,9 +232,13 @@ github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nlopes/slack v0.5.0 h1:NbIae8Kd0NpqaEI3iUrsuS0KbcEDhzhc939jLW5fNm0= github.com/nlopes/slack v0.5.0/go.mod h1:jVI4BBK3lSktibKahxBF74txcK2vyvkza1z/+rRnVAM= +github.com/olekukonko/tablewriter v0.0.1 h1:b3iUnf1v+ppJiOfNX4yxxqfWKMQPZR5yoh8urCTFX88= +github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= @@ -168,6 +246,7 @@ github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zM github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-buffruneio v0.2.0 h1:U4t4R6YkofJ5xHm3dJzuRpPZ0mr5MMCoAWooScCR7aA= github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -175,75 +254,181 @@ 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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.1/go.mod h1:6gapUrK/U1TAN7ciCoNRIdVC5sbdBTUh1DKN0g6uH7E= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME= github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= 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/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM= github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/xanzy/ssh-agent v0.2.0 h1:Adglfbi5p9Z0BmK2oKU9nTG+zKfniSfnaMYB+ULd+Ro= github.com/xanzy/ssh-agent v0.2.0/go.mod h1:0NyE30eGUDliuLEHJgYte/zncp2zdTStcOnWhgSqHD8= +github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= +github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190130090550-b01c7a725664/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443 h1:IcSOAf4PyMp3U3XbIEj1/xJ2BjNN2jWv7JoyOsMxXUU= +golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190618124811-92942e4437e2/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190607214518-6fa95d984e88/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/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-20190125091013-d26f9f9a57f3/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-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190502183928-7f726cade0ab/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/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-20190607181551-461777fb6f67 h1:rJJxsykSlULwd2P2+pg/rtnwN2FrWp4IuCxOSyS0V00= golang.org/x/net v0.0.0-20190607181551-461777fb6f67/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +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/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180903190138-2b024373dcd9/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/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-20190221075227-b4e8571b14e0/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-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190310054646-10058d7d4faa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190621062556-bf70e4678053 h1:T0MJjz97TtCXa3ZNW2Oenb3KQWB91K965zMEbIJ4ThA= +golang.org/x/sys v0.0.0-20190621062556-bf70e4678053/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= 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/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190530171427-2b03ca6e44eb/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190620191750-1fa568393b23/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601 h1:9VBRTdmgQxbs6HE0sUnMrSWNePppAJU07NYvX5dIB04= +google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1 h1:j6XxA85m/6txkUCHvzlV5f+HBNl/1r5cZ2A/3IEFOO8= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-playground/validator.v9 v9.29.0 h1:5ofssLNYgAA/inWn6rTZ4juWpRJUwEnXc1LG2IeXwgQ= gopkg.in/go-playground/validator.v9 v9.29.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/src-d/go-billy.v4 v4.2.1 h1:omN5CrMrMcQ+4I8bJ0wEhOBPanIRWzFC953IiXKdYzo= gopkg.in/src-d/go-billy.v4 v4.2.1/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk= +gopkg.in/src-d/go-billy.v4 v4.3.0 h1:KtlZ4c1OWbIs4jCv5ZXrTqG8EQocr0g/d4DjNg70aek= +gopkg.in/src-d/go-billy.v4 v4.3.0/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk= gopkg.in/src-d/go-git-fixtures.v3 v3.1.1/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= +gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= gopkg.in/src-d/go-git.v4 v4.11.0 h1:cJwWgJ0DXifrNrXM6RGN1Y2yR60Rr1zQ9Q5DX5S9qgU= gopkg.in/src-d/go-git.v4 v4.11.0/go.mod h1:Vtut8izDyrM8BUVQnzJ+YvmNcem2J89EmfZYCkLokZk= +gopkg.in/src-d/go-git.v4 v4.12.0 h1:CKgvBCJCcdfNnyXPYI4Cp8PaDDAmAPEN0CtfEdEAbd8= +gopkg.in/src-d/go-git.v4 v4.12.0/go.mod h1:zjlNnzc1Wjn43v3Mtii7RVxiReNP0fIu9npcXKzuNp4= gopkg.in/telegram-bot-api.v4 v4.6.4 h1:hpHWhzn4jTCsAJZZ2loNKfy2QWyPDRJVl3aTFXeMW8g= gopkg.in/telegram-bot-api.v4 v4.6.4/go.mod h1:5DpGO5dbumb40px+dXcwCpcjmeHNYLpk0bp3XRNvWDM= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= @@ -254,3 +439,7 @@ gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190614002413-cb51c254f01b/go.mod h1:JlmFZigtG9vBVR3QGIQ9g/Usz4BzH+Xm6Z8iHQWRYUw= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= From c350e19552d36c71c9051189267b0a10842e2c61 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 21 Jun 2019 13:36:11 +0100 Subject: [PATCH 041/287] Move cmd => config/cmd --- api/handler/http/http_test.go | 2 +- api/router/options.go | 2 +- {cmd => config/cmd}/cmd.go | 0 {cmd => config/cmd}/options.go | 0 config/source/cli/cli.go | 2 +- config/source/cli/cli_test.go | 2 +- options.go | 2 +- service.go | 2 +- 8 files changed, 6 insertions(+), 6 deletions(-) rename {cmd => config/cmd}/cmd.go (100%) rename {cmd => config/cmd}/options.go (100%) diff --git a/api/handler/http/http_test.go b/api/handler/http/http_test.go index 37f3f2f1..78c135b6 100644 --- a/api/handler/http/http_test.go +++ b/api/handler/http/http_test.go @@ -11,7 +11,7 @@ import ( "github.com/micro/go-micro/api/handler" "github.com/micro/go-micro/api/router" regRouter "github.com/micro/go-micro/api/router/registry" - "github.com/micro/go-micro/cmd" + "github.com/micro/go-micro/config/cmd" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/registry/memory" ) diff --git a/api/router/options.go b/api/router/options.go index f41499a3..7285c74d 100644 --- a/api/router/options.go +++ b/api/router/options.go @@ -3,7 +3,7 @@ package router import ( "github.com/micro/go-micro/api/resolver" "github.com/micro/go-micro/api/resolver/micro" - "github.com/micro/go-micro/cmd" + "github.com/micro/go-micro/config/cmd" "github.com/micro/go-micro/registry" ) diff --git a/cmd/cmd.go b/config/cmd/cmd.go similarity index 100% rename from cmd/cmd.go rename to config/cmd/cmd.go diff --git a/cmd/options.go b/config/cmd/options.go similarity index 100% rename from cmd/options.go rename to config/cmd/options.go diff --git a/config/source/cli/cli.go b/config/source/cli/cli.go index 86b27f10..362ea79f 100644 --- a/config/source/cli/cli.go +++ b/config/source/cli/cli.go @@ -9,7 +9,7 @@ import ( "github.com/imdario/mergo" "github.com/micro/cli" - "github.com/micro/go-micro/cmd" + "github.com/micro/go-micro/config/cmd" "github.com/micro/go-micro/config/source" ) diff --git a/config/source/cli/cli_test.go b/config/source/cli/cli_test.go index ada1a0d6..8e1b743c 100644 --- a/config/source/cli/cli_test.go +++ b/config/source/cli/cli_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/micro/cli" - "github.com/micro/go-micro/cmd" + "github.com/micro/go-micro/config/cmd" "github.com/micro/go-micro/config/source" ) diff --git a/options.go b/options.go index 4012bb49..b1eca164 100644 --- a/options.go +++ b/options.go @@ -7,7 +7,7 @@ import ( "github.com/micro/cli" "github.com/micro/go-micro/broker" "github.com/micro/go-micro/client" - "github.com/micro/go-micro/cmd" + "github.com/micro/go-micro/config/cmd" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/selector" "github.com/micro/go-micro/server" diff --git a/service.go b/service.go index 6b7c6508..01c82e9c 100644 --- a/service.go +++ b/service.go @@ -7,7 +7,7 @@ import ( "syscall" "github.com/micro/go-micro/client" - "github.com/micro/go-micro/cmd" + "github.com/micro/go-micro/config/cmd" "github.com/micro/go-micro/metadata" "github.com/micro/go-micro/server" ) From ca5acba0c6e1cadc5b666a5f8780691484fc83f8 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 21 Jun 2019 15:13:54 +0100 Subject: [PATCH 042/287] Move selector to client/selector --- api/handler/api/api.go | 2 +- api/handler/api/util.go | 2 +- api/handler/http/http.go | 2 +- api/handler/rpc/rpc.go | 2 +- api/handler/web/web.go | 2 +- client/grpc/grpc.go | 2 +- client/grpc/grpc_test.go | 2 +- client/options.go | 2 +- client/rpc_client.go | 2 +- client/rpc_client_test.go | 2 +- {selector => client/selector}/common_test.go | 0 {selector => client/selector}/default.go | 0 {selector => client/selector}/default_test.go | 0 {selector => client/selector}/dns/dns.go | 2 +- {selector => client/selector}/filter.go | 0 {selector => client/selector}/filter_test.go | 0 {selector => client/selector}/options.go | 0 {selector => client/selector}/registry/options.go | 2 +- {selector => client/selector}/registry/registry.go | 2 +- {selector => client/selector}/selector.go | 0 {selector => client/selector}/static/static.go | 2 +- {selector => client/selector}/strategy.go | 0 {selector => client/selector}/strategy_test.go | 0 config/cmd/cmd.go | 6 +++--- config/cmd/options.go | 2 +- options.go | 2 +- util/http/http.go | 2 +- util/http/roundtripper.go | 2 +- 28 files changed, 21 insertions(+), 21 deletions(-) rename {selector => client/selector}/common_test.go (100%) rename {selector => client/selector}/default.go (100%) rename {selector => client/selector}/default_test.go (100%) rename {selector => client/selector}/dns/dns.go (98%) rename {selector => client/selector}/filter.go (100%) rename {selector => client/selector}/filter_test.go (100%) rename {selector => client/selector}/options.go (100%) rename {selector => client/selector}/registry/options.go (86%) rename {selector => client/selector}/registry/registry.go (84%) rename {selector => client/selector}/selector.go (100%) rename {selector => client/selector}/static/static.go (96%) rename {selector => client/selector}/strategy.go (100%) rename {selector => client/selector}/strategy_test.go (100%) diff --git a/api/handler/api/api.go b/api/handler/api/api.go index 20fa421d..366a9d87 100644 --- a/api/handler/api/api.go +++ b/api/handler/api/api.go @@ -9,7 +9,7 @@ import ( api "github.com/micro/go-micro/api/proto" "github.com/micro/go-micro/client" "github.com/micro/go-micro/errors" - "github.com/micro/go-micro/selector" + "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/util/ctx" ) diff --git a/api/handler/api/util.go b/api/handler/api/util.go index 123ad3f8..2ea1655e 100644 --- a/api/handler/api/util.go +++ b/api/handler/api/util.go @@ -10,7 +10,7 @@ import ( api "github.com/micro/go-micro/api/proto" "github.com/micro/go-micro/registry" - "github.com/micro/go-micro/selector" + "github.com/micro/go-micro/client/selector" ) func requestToProto(r *http.Request) (*api.Request, error) { diff --git a/api/handler/http/http.go b/api/handler/http/http.go index cbcd2992..b9380ce3 100644 --- a/api/handler/http/http.go +++ b/api/handler/http/http.go @@ -10,7 +10,7 @@ import ( "github.com/micro/go-micro/api" "github.com/micro/go-micro/api/handler" - "github.com/micro/go-micro/selector" + "github.com/micro/go-micro/client/selector" ) const ( diff --git a/api/handler/rpc/rpc.go b/api/handler/rpc/rpc.go index 28c67245..6ff79396 100644 --- a/api/handler/rpc/rpc.go +++ b/api/handler/rpc/rpc.go @@ -19,7 +19,7 @@ import ( "github.com/micro/go-micro/codec/protorpc" "github.com/micro/go-micro/errors" "github.com/micro/go-micro/registry" - "github.com/micro/go-micro/selector" + "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/util/ctx" ) diff --git a/api/handler/web/web.go b/api/handler/web/web.go index 2a6ba18f..415dd694 100644 --- a/api/handler/web/web.go +++ b/api/handler/web/web.go @@ -13,7 +13,7 @@ import ( "github.com/micro/go-micro/api" "github.com/micro/go-micro/api/handler" - "github.com/micro/go-micro/selector" + "github.com/micro/go-micro/client/selector" ) const ( diff --git a/client/grpc/grpc.go b/client/grpc/grpc.go index ac1dc82e..5c9ef01e 100644 --- a/client/grpc/grpc.go +++ b/client/grpc/grpc.go @@ -16,7 +16,7 @@ import ( "github.com/micro/go-micro/errors" "github.com/micro/go-micro/metadata" "github.com/micro/go-micro/registry" - "github.com/micro/go-micro/selector" + "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/transport" "google.golang.org/grpc" diff --git a/client/grpc/grpc_test.go b/client/grpc/grpc_test.go index 074d8931..85ba8ea2 100644 --- a/client/grpc/grpc_test.go +++ b/client/grpc/grpc_test.go @@ -10,7 +10,7 @@ import ( "github.com/micro/go-micro/client" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/registry/memory" - "github.com/micro/go-micro/selector" + "github.com/micro/go-micro/client/selector" pgrpc "google.golang.org/grpc" pb "google.golang.org/grpc/examples/helloworld/helloworld" ) diff --git a/client/options.go b/client/options.go index 30a6386c..35cbe704 100644 --- a/client/options.go +++ b/client/options.go @@ -7,7 +7,7 @@ import ( "github.com/micro/go-micro/broker" "github.com/micro/go-micro/codec" "github.com/micro/go-micro/registry" - "github.com/micro/go-micro/selector" + "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/transport" ) diff --git a/client/rpc_client.go b/client/rpc_client.go index d22e7e42..4f05e1ce 100644 --- a/client/rpc_client.go +++ b/client/rpc_client.go @@ -17,7 +17,7 @@ import ( "github.com/micro/go-micro/errors" "github.com/micro/go-micro/metadata" "github.com/micro/go-micro/registry" - "github.com/micro/go-micro/selector" + "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/transport" ) diff --git a/client/rpc_client_test.go b/client/rpc_client_test.go index 219580cd..6af32598 100644 --- a/client/rpc_client_test.go +++ b/client/rpc_client_test.go @@ -8,7 +8,7 @@ import ( "github.com/micro/go-micro/errors" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/registry/memory" - "github.com/micro/go-micro/selector" + "github.com/micro/go-micro/client/selector" ) func newTestRegistry() registry.Registry { diff --git a/selector/common_test.go b/client/selector/common_test.go similarity index 100% rename from selector/common_test.go rename to client/selector/common_test.go diff --git a/selector/default.go b/client/selector/default.go similarity index 100% rename from selector/default.go rename to client/selector/default.go diff --git a/selector/default_test.go b/client/selector/default_test.go similarity index 100% rename from selector/default_test.go rename to client/selector/default_test.go diff --git a/selector/dns/dns.go b/client/selector/dns/dns.go similarity index 98% rename from selector/dns/dns.go rename to client/selector/dns/dns.go index d3882ac1..1651a9d2 100644 --- a/selector/dns/dns.go +++ b/client/selector/dns/dns.go @@ -6,7 +6,7 @@ import ( "strconv" "github.com/micro/go-micro/registry" - "github.com/micro/go-micro/selector" + "github.com/micro/go-micro/client/selector" ) type dnsSelector struct { diff --git a/selector/filter.go b/client/selector/filter.go similarity index 100% rename from selector/filter.go rename to client/selector/filter.go diff --git a/selector/filter_test.go b/client/selector/filter_test.go similarity index 100% rename from selector/filter_test.go rename to client/selector/filter_test.go diff --git a/selector/options.go b/client/selector/options.go similarity index 100% rename from selector/options.go rename to client/selector/options.go diff --git a/selector/registry/options.go b/client/selector/registry/options.go similarity index 86% rename from selector/registry/options.go rename to client/selector/registry/options.go index 90aaf802..007c5023 100644 --- a/selector/registry/options.go +++ b/client/selector/registry/options.go @@ -4,7 +4,7 @@ import ( "context" "time" - "github.com/micro/go-micro/selector" + "github.com/micro/go-micro/client/selector" ) // Set the registry cache ttl diff --git a/selector/registry/registry.go b/client/selector/registry/registry.go similarity index 84% rename from selector/registry/registry.go rename to client/selector/registry/registry.go index b6d8600d..fe8373a7 100644 --- a/selector/registry/registry.go +++ b/client/selector/registry/registry.go @@ -2,7 +2,7 @@ package registry import ( - "github.com/micro/go-micro/selector" + "github.com/micro/go-micro/client/selector" ) // NewSelector returns a new registry selector diff --git a/selector/selector.go b/client/selector/selector.go similarity index 100% rename from selector/selector.go rename to client/selector/selector.go diff --git a/selector/static/static.go b/client/selector/static/static.go similarity index 96% rename from selector/static/static.go rename to client/selector/static/static.go index 11c2c9cf..3ee79a96 100644 --- a/selector/static/static.go +++ b/client/selector/static/static.go @@ -6,7 +6,7 @@ import ( "strconv" "github.com/micro/go-micro/registry" - "github.com/micro/go-micro/selector" + "github.com/micro/go-micro/client/selector" ) // staticSelector is a static selector diff --git a/selector/strategy.go b/client/selector/strategy.go similarity index 100% rename from selector/strategy.go rename to client/selector/strategy.go diff --git a/selector/strategy_test.go b/client/selector/strategy_test.go similarity index 100% rename from selector/strategy_test.go rename to client/selector/strategy_test.go diff --git a/config/cmd/cmd.go b/config/cmd/cmd.go index 37616312..2e7e2a6e 100644 --- a/config/cmd/cmd.go +++ b/config/cmd/cmd.go @@ -32,9 +32,9 @@ import ( rmem "github.com/micro/go-micro/registry/memory" // selectors - "github.com/micro/go-micro/selector" - "github.com/micro/go-micro/selector/dns" - "github.com/micro/go-micro/selector/static" + "github.com/micro/go-micro/client/selector" + "github.com/micro/go-micro/client/selector/dns" + "github.com/micro/go-micro/client/selector/static" // transports "github.com/micro/go-micro/transport" diff --git a/config/cmd/options.go b/config/cmd/options.go index 1dcd4755..a078375a 100644 --- a/config/cmd/options.go +++ b/config/cmd/options.go @@ -6,7 +6,7 @@ import ( "github.com/micro/go-micro/broker" "github.com/micro/go-micro/client" "github.com/micro/go-micro/registry" - "github.com/micro/go-micro/selector" + "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/server" "github.com/micro/go-micro/transport" ) diff --git a/options.go b/options.go index b1eca164..41b782b5 100644 --- a/options.go +++ b/options.go @@ -9,7 +9,7 @@ import ( "github.com/micro/go-micro/client" "github.com/micro/go-micro/config/cmd" "github.com/micro/go-micro/registry" - "github.com/micro/go-micro/selector" + "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/server" "github.com/micro/go-micro/transport" ) diff --git a/util/http/http.go b/util/http/http.go index 06bff69f..aec84207 100644 --- a/util/http/http.go +++ b/util/http/http.go @@ -4,7 +4,7 @@ import ( "net/http" "github.com/micro/go-micro/registry" - "github.com/micro/go-micro/selector" + "github.com/micro/go-micro/client/selector" ) func NewRoundTripper(opts ...Option) http.RoundTripper { diff --git a/util/http/roundtripper.go b/util/http/roundtripper.go index f90ef34f..af2299be 100644 --- a/util/http/roundtripper.go +++ b/util/http/roundtripper.go @@ -5,7 +5,7 @@ import ( "fmt" "net/http" - "github.com/micro/go-micro/selector" + "github.com/micro/go-micro/client/selector" ) type roundTripper struct { From 7936d74602379599af2d7c301b2740b281928956 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 21 Jun 2019 16:17:12 +0100 Subject: [PATCH 043/287] Update comments --- router/router.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/router/router.go b/router/router.go index 51a629f9..725248f0 100644 --- a/router/router.go +++ b/router/router.go @@ -1,7 +1,7 @@ -// Package router provides an interface for micro network router +// Package router provides a network routing control plane package router -// Router is micro network router +// Router is an interface for a routing control plane type Router interface { // Init initializes the router with options Init(...Option) error From 3f97743e34a2599ce1112b2359e2cc04b19a1d96 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 21 Jun 2019 17:20:31 +0100 Subject: [PATCH 044/287] Move router and proxy into network package --- {proxy => network/proxy}/README.md | 0 {proxy => network/proxy}/grpc/grpc.go | 2 +- {proxy => network/proxy}/http/http.go | 2 +- {proxy => network/proxy}/http/http_test.go | 0 {proxy => network/proxy}/mucp/mucp.go | 2 +- {proxy => network/proxy}/proxy.go | 0 {router => network/router}/default_router.go | 0 {router => network/router}/default_table.go | 0 {router => network/router}/options.go | 0 {router => network/router}/query.go | 0 {router => network/router}/route.go | 0 {router => network/router}/router.go | 0 {router => network/router}/table.go | 0 {router => network/router}/table_watcher.go | 0 14 files changed, 3 insertions(+), 3 deletions(-) rename {proxy => network/proxy}/README.md (100%) rename {proxy => network/proxy}/grpc/grpc.go (98%) rename {proxy => network/proxy}/http/http.go (98%) rename {proxy => network/proxy}/http/http_test.go (100%) rename {proxy => network/proxy}/mucp/mucp.go (98%) rename {proxy => network/proxy}/proxy.go (100%) rename {router => network/router}/default_router.go (100%) rename {router => network/router}/default_table.go (100%) rename {router => network/router}/options.go (100%) rename {router => network/router}/query.go (100%) rename {router => network/router}/route.go (100%) rename {router => network/router}/router.go (100%) rename {router => network/router}/table.go (100%) rename {router => network/router}/table_watcher.go (100%) diff --git a/proxy/README.md b/network/proxy/README.md similarity index 100% rename from proxy/README.md rename to network/proxy/README.md diff --git a/proxy/grpc/grpc.go b/network/proxy/grpc/grpc.go similarity index 98% rename from proxy/grpc/grpc.go rename to network/proxy/grpc/grpc.go index afb2453c..7aceb289 100644 --- a/proxy/grpc/grpc.go +++ b/network/proxy/grpc/grpc.go @@ -10,7 +10,7 @@ import ( "github.com/micro/go-micro/client/grpc" "github.com/micro/go-micro/codec" "github.com/micro/go-micro/config/options" - "github.com/micro/go-micro/proxy" + "github.com/micro/go-micro/network/proxy" "github.com/micro/go-micro/server" ) diff --git a/proxy/http/http.go b/network/proxy/http/http.go similarity index 98% rename from proxy/http/http.go rename to network/proxy/http/http.go index 61a6fc06..7c19b6e1 100644 --- a/proxy/http/http.go +++ b/network/proxy/http/http.go @@ -12,7 +12,7 @@ import ( "github.com/micro/go-micro/config/options" "github.com/micro/go-micro/errors" - "github.com/micro/go-micro/proxy" + "github.com/micro/go-micro/network/proxy" "github.com/micro/go-micro/server" ) diff --git a/proxy/http/http_test.go b/network/proxy/http/http_test.go similarity index 100% rename from proxy/http/http_test.go rename to network/proxy/http/http_test.go diff --git a/proxy/mucp/mucp.go b/network/proxy/mucp/mucp.go similarity index 98% rename from proxy/mucp/mucp.go rename to network/proxy/mucp/mucp.go index cca97c90..9e8afd39 100644 --- a/proxy/mucp/mucp.go +++ b/network/proxy/mucp/mucp.go @@ -10,7 +10,7 @@ import ( "github.com/micro/go-micro/codec" "github.com/micro/go-micro/codec/bytes" "github.com/micro/go-micro/config/options" - "github.com/micro/go-micro/proxy" + "github.com/micro/go-micro/network/proxy" "github.com/micro/go-micro/server" ) diff --git a/proxy/proxy.go b/network/proxy/proxy.go similarity index 100% rename from proxy/proxy.go rename to network/proxy/proxy.go diff --git a/router/default_router.go b/network/router/default_router.go similarity index 100% rename from router/default_router.go rename to network/router/default_router.go diff --git a/router/default_table.go b/network/router/default_table.go similarity index 100% rename from router/default_table.go rename to network/router/default_table.go diff --git a/router/options.go b/network/router/options.go similarity index 100% rename from router/options.go rename to network/router/options.go diff --git a/router/query.go b/network/router/query.go similarity index 100% rename from router/query.go rename to network/router/query.go diff --git a/router/route.go b/network/router/route.go similarity index 100% rename from router/route.go rename to network/router/route.go diff --git a/router/router.go b/network/router/router.go similarity index 100% rename from router/router.go rename to network/router/router.go diff --git a/router/table.go b/network/router/table.go similarity index 100% rename from router/table.go rename to network/router/table.go diff --git a/router/table_watcher.go b/network/router/table_watcher.go similarity index 100% rename from router/table_watcher.go rename to network/router/table_watcher.go From 1b4005e9a58838316731b03ae003e267eaeafe78 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 21 Jun 2019 17:20:41 +0100 Subject: [PATCH 045/287] Go fmt everything --- api/handler/api/api.go | 2 +- api/handler/api/util.go | 2 +- api/handler/rpc/rpc.go | 2 +- client/grpc/grpc.go | 2 +- client/grpc/grpc_test.go | 2 +- client/options.go | 2 +- client/rpc_client.go | 2 +- client/rpc_client_test.go | 2 +- client/selector/dns/dns.go | 2 +- client/selector/static/static.go | 2 +- config/cmd/options.go | 2 +- options.go | 2 +- util/http/http.go | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/api/handler/api/api.go b/api/handler/api/api.go index 366a9d87..0798f337 100644 --- a/api/handler/api/api.go +++ b/api/handler/api/api.go @@ -8,8 +8,8 @@ import ( "github.com/micro/go-micro/api/handler" api "github.com/micro/go-micro/api/proto" "github.com/micro/go-micro/client" - "github.com/micro/go-micro/errors" "github.com/micro/go-micro/client/selector" + "github.com/micro/go-micro/errors" "github.com/micro/go-micro/util/ctx" ) diff --git a/api/handler/api/util.go b/api/handler/api/util.go index 2ea1655e..7a4607c7 100644 --- a/api/handler/api/util.go +++ b/api/handler/api/util.go @@ -9,8 +9,8 @@ import ( "strings" api "github.com/micro/go-micro/api/proto" - "github.com/micro/go-micro/registry" "github.com/micro/go-micro/client/selector" + "github.com/micro/go-micro/registry" ) func requestToProto(r *http.Request) (*api.Request, error) { diff --git a/api/handler/rpc/rpc.go b/api/handler/rpc/rpc.go index 6ff79396..4ee2be8e 100644 --- a/api/handler/rpc/rpc.go +++ b/api/handler/rpc/rpc.go @@ -14,12 +14,12 @@ import ( "github.com/micro/go-micro/api/handler" proto "github.com/micro/go-micro/api/internal/proto" "github.com/micro/go-micro/client" + "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/codec" "github.com/micro/go-micro/codec/jsonrpc" "github.com/micro/go-micro/codec/protorpc" "github.com/micro/go-micro/errors" "github.com/micro/go-micro/registry" - "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/util/ctx" ) diff --git a/client/grpc/grpc.go b/client/grpc/grpc.go index 5c9ef01e..3430fbfc 100644 --- a/client/grpc/grpc.go +++ b/client/grpc/grpc.go @@ -12,11 +12,11 @@ import ( "github.com/micro/go-micro/broker" "github.com/micro/go-micro/client" + "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/codec" "github.com/micro/go-micro/errors" "github.com/micro/go-micro/metadata" "github.com/micro/go-micro/registry" - "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/transport" "google.golang.org/grpc" diff --git a/client/grpc/grpc_test.go b/client/grpc/grpc_test.go index 85ba8ea2..7c58fd4e 100644 --- a/client/grpc/grpc_test.go +++ b/client/grpc/grpc_test.go @@ -8,9 +8,9 @@ import ( "testing" "github.com/micro/go-micro/client" + "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/registry/memory" - "github.com/micro/go-micro/client/selector" pgrpc "google.golang.org/grpc" pb "google.golang.org/grpc/examples/helloworld/helloworld" ) diff --git a/client/options.go b/client/options.go index 35cbe704..5a0f4100 100644 --- a/client/options.go +++ b/client/options.go @@ -5,9 +5,9 @@ import ( "time" "github.com/micro/go-micro/broker" + "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/codec" "github.com/micro/go-micro/registry" - "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/transport" ) diff --git a/client/rpc_client.go b/client/rpc_client.go index 4f05e1ce..36b3dcf7 100644 --- a/client/rpc_client.go +++ b/client/rpc_client.go @@ -13,11 +13,11 @@ import ( "github.com/google/uuid" "github.com/micro/go-micro/broker" + "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/codec" "github.com/micro/go-micro/errors" "github.com/micro/go-micro/metadata" "github.com/micro/go-micro/registry" - "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/transport" ) diff --git a/client/rpc_client_test.go b/client/rpc_client_test.go index 6af32598..2db3ae90 100644 --- a/client/rpc_client_test.go +++ b/client/rpc_client_test.go @@ -5,10 +5,10 @@ import ( "fmt" "testing" + "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/errors" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/registry/memory" - "github.com/micro/go-micro/client/selector" ) func newTestRegistry() registry.Registry { diff --git a/client/selector/dns/dns.go b/client/selector/dns/dns.go index 1651a9d2..b1d19c95 100644 --- a/client/selector/dns/dns.go +++ b/client/selector/dns/dns.go @@ -5,8 +5,8 @@ import ( "net" "strconv" - "github.com/micro/go-micro/registry" "github.com/micro/go-micro/client/selector" + "github.com/micro/go-micro/registry" ) type dnsSelector struct { diff --git a/client/selector/static/static.go b/client/selector/static/static.go index 3ee79a96..c9b2fd83 100644 --- a/client/selector/static/static.go +++ b/client/selector/static/static.go @@ -5,8 +5,8 @@ import ( "net" "strconv" - "github.com/micro/go-micro/registry" "github.com/micro/go-micro/client/selector" + "github.com/micro/go-micro/registry" ) // staticSelector is a static selector diff --git a/config/cmd/options.go b/config/cmd/options.go index a078375a..1f221f35 100644 --- a/config/cmd/options.go +++ b/config/cmd/options.go @@ -5,8 +5,8 @@ import ( "github.com/micro/go-micro/broker" "github.com/micro/go-micro/client" - "github.com/micro/go-micro/registry" "github.com/micro/go-micro/client/selector" + "github.com/micro/go-micro/registry" "github.com/micro/go-micro/server" "github.com/micro/go-micro/transport" ) diff --git a/options.go b/options.go index 41b782b5..d566a353 100644 --- a/options.go +++ b/options.go @@ -7,9 +7,9 @@ import ( "github.com/micro/cli" "github.com/micro/go-micro/broker" "github.com/micro/go-micro/client" + "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/config/cmd" "github.com/micro/go-micro/registry" - "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/server" "github.com/micro/go-micro/transport" ) diff --git a/util/http/http.go b/util/http/http.go index aec84207..47fc33f4 100644 --- a/util/http/http.go +++ b/util/http/http.go @@ -3,8 +3,8 @@ package http import ( "net/http" - "github.com/micro/go-micro/registry" "github.com/micro/go-micro/client/selector" + "github.com/micro/go-micro/registry" ) func NewRoundTripper(opts ...Option) http.RoundTripper { From 2d91ba411e79cc7e3bacc44eed2760091ca736c3 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Sat, 22 Jun 2019 16:51:20 +0100 Subject: [PATCH 046/287] update the network interface --- network/network.go | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/network/network.go b/network/network.go index be83b8d0..18da91fd 100644 --- a/network/network.go +++ b/network/network.go @@ -5,13 +5,17 @@ import ( "github.com/micro/go-micro/config/options" ) -// Network is an interface defining networks or graphs +// Network is an interface defining a network type Network interface { options.Options // Id of this node - Id() uint64 - // Connect to a node - Connect(id uint64) (Link, error) + Id() string + // Address of the network + Address() string + // Connect to the network + Connect() (Node, error) + // Peer with a neighboring network + Peer(Network) (Link, error) // Close the network connection Close() error // Accept messages on the network @@ -22,15 +26,15 @@ type Network interface { Links() ([]Link, error) } -// Node represents a network node +// Node represents a single node on a network type Node interface { // Node is a network. Network is a node. Network } -// Link is a connection to another node +// Link is a connection between one network and another type Link interface { - // remote node + // remote node the link is to Node // length of link which dictates speed Length() int @@ -39,7 +43,12 @@ type Link interface { } // Message is the base type for opaque data -type Message []byte +type Message struct { + // Headers which provide local/remote info + Header map[string]string + // The opaque data being sent + Data []byte +} var ( // TODO: set default network From c3d2043caf5c0edd94af5aa23e218904f8a6d36f Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Sat, 22 Jun 2019 18:58:12 +0100 Subject: [PATCH 047/287] Reverts c0a628d65b024d1c1a95f9e6a0419d356da1e973 Fixes #540 --- registry/gossip/util.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/registry/gossip/util.go b/registry/gossip/util.go index 75fb2dbf..0fa8116d 100644 --- a/registry/gossip/util.go +++ b/registry/gossip/util.go @@ -115,20 +115,27 @@ func delNodes(old, del []*registry.Node) []*registry.Node { func delServices(old, del []*registry.Service) []*registry.Service { var services []*registry.Service + for _, o := range old { + srv := new(registry.Service) + *srv = *o + var rem bool + for _, s := range del { - if o.Version == s.Version { - s.Nodes = delNodes(s.Nodes, o.Nodes) - if len(s.Nodes) == 0 { + if srv.Version == s.Version { + srv.Nodes = delNodes(srv.Nodes, s.Nodes) + + if len(srv.Nodes) == 0 { rem = true - break } } } + if !rem { - services = append(services, o) + services = append(services, srv) } } + return services } From dffbe045e46c8703e58a3cc4f05e24d24e2b21d7 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Sat, 22 Jun 2019 19:02:57 +0100 Subject: [PATCH 048/287] move node functions --- network/network.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/network/network.go b/network/network.go index 18da91fd..29d6653d 100644 --- a/network/network.go +++ b/network/network.go @@ -10,18 +10,10 @@ type Network interface { options.Options // Id of this node Id() string - // Address of the network - Address() string // Connect to the network Connect() (Node, error) // Peer with a neighboring network Peer(Network) (Link, error) - // Close the network connection - Close() error - // Accept messages on the network - Accept() (*Message, error) - // Send a message to the network - Send(*Message) error // Retrieve list of connections Links() ([]Link, error) } @@ -30,6 +22,14 @@ type Network interface { type Node interface { // Node is a network. Network is a node. Network + // Address of the node + Address() string + // Close the network connection + Close() error + // Accept messages on the network + Accept() (*Message, error) + // Send a message to the network + Send(*Message) error } // Link is a connection between one network and another From 4f982bb9cda3c898a59a8ba94d77038c7d6e9239 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 24 Jun 2019 14:49:19 +0100 Subject: [PATCH 049/287] Default to json content-type in api --- api/handler/rpc/rpc.go | 58 ++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/api/handler/rpc/rpc.go b/api/handler/rpc/rpc.go index 4ee2be8e..0c01e10d 100644 --- a/api/handler/rpc/rpc.go +++ b/api/handler/rpc/rpc.go @@ -120,32 +120,6 @@ func (h *rpcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var rsp []byte switch { - // json codecs - case hasCodec(ct, jsonCodecs): - var request json.RawMessage - // if the extracted payload isn't empty lets use it - if len(br) > 0 { - request = json.RawMessage(br) - } - - // create request/response - var response json.RawMessage - - req := c.NewRequest( - service.Name, - service.Endpoint.Name, - &request, - client.WithContentType(ct), - ) - - // make the call - if err := c.Call(cx, req, &response, client.WithSelectOption(so)); err != nil { - writeError(w, r, err) - return - } - - // marshall response - rsp, _ = response.MarshalJSON() // proto codecs case hasCodec(ct, protoCodecs): request := &proto.Message{} @@ -173,8 +147,36 @@ func (h *rpcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // marshall response rsp, _ = response.Marshal() default: - http.Error(w, "Unsupported Content-Type", 400) - return + // if json codec is not present set to json + if !hasCodec(ct, jsonCodecs) { + ct = "application/json" + } + + // default to trying json + var request json.RawMessage + // if the extracted payload isn't empty lets use it + if len(br) > 0 { + request = json.RawMessage(br) + } + + // create request/response + var response json.RawMessage + + req := c.NewRequest( + service.Name, + service.Endpoint.Name, + &request, + client.WithContentType(ct), + ) + + // make the call + if err := c.Call(cx, req, &response, client.WithSelectOption(so)); err != nil { + writeError(w, r, err) + return + } + + // marshall response + rsp, _ = response.MarshalJSON() } // write the response From b89423bf37ebae8493ac5119dbfce8449f81f6ee Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 24 Jun 2019 15:11:11 +0100 Subject: [PATCH 050/287] add resolver --- network/resolver/dns/dns.go | 30 ++++++++++++++++++++++++++++++ network/resolver/resolver.go | 12 ++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 network/resolver/dns/dns.go create mode 100644 network/resolver/resolver.go diff --git a/network/resolver/dns/dns.go b/network/resolver/dns/dns.go new file mode 100644 index 00000000..c905df0e --- /dev/null +++ b/network/resolver/dns/dns.go @@ -0,0 +1,30 @@ +// Package dns resolves ids to dns srv records +package dns + +import ( + "fmt" + "net" + + "github.com/micro/go-micro/network/resolver" +) + +type Resolver struct{} + +// Resolve assumes ID is a domain name e.g micro.mu +func (r *Resolver) Resolve(id string) ([]*resolver.Record, error) { + _, addrs, err := net.LookupSRV("network", "udp", id) + if err != nil { + return nil, err + } + var records []*resolver.Record + for _, addr := range addrs { + address := addr.Target + if addr.Port > 0 { + address = fmt.Sprintf("%s:%d", addr.Target, addr.Port) + } + records = append(records, &resolver.Record{ + Address: address, + }) + } + return records, nil +} diff --git a/network/resolver/resolver.go b/network/resolver/resolver.go new file mode 100644 index 00000000..ba80e124 --- /dev/null +++ b/network/resolver/resolver.go @@ -0,0 +1,12 @@ +// Package resolver resolves network ids to addresses +package resolver + +type Resolver interface { + // Resolve returns a list of addresses for an id + Resolve(id string) ([]*Record, error) +} + +// A resoved id +type Record struct { + Address string +} From e5959f80d60430d7e03641b479d2ab59dadb87e2 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 24 Jun 2019 15:21:24 +0100 Subject: [PATCH 051/287] add http resolver --- network/resolver/http/http.go | 59 +++++++++++++++++++++++++++++++++++ network/resolver/resolver.go | 2 +- 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 network/resolver/http/http.go diff --git a/network/resolver/http/http.go b/network/resolver/http/http.go new file mode 100644 index 00000000..80ff4d61 --- /dev/null +++ b/network/resolver/http/http.go @@ -0,0 +1,59 @@ +// Package http resolves ids to network addresses using a http request +package http + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "net/url" + + "github.com/micro/go-micro/network/resolver" +) + +type Resolver struct { + // If not set, defaults to http + Proto string + + // Path sets the path to lookup. Defaults to /network + Path string +} + +// Resolve assumes ID is a domain which can be converted to a http://id/network request +func (r *Resolver) Resolve(id string) ([]*resolver.Record, error) { + proto := "http" + path := "/network" + + if len(r.Proto) > 0 { + proto = r.Proto + } + + if len(r.Path) > 0 { + path = r.Path + } + + uri := &url.URL{ + Scheme: proto, + Path: path, + Host: id, + } + + rsp, err := http.Get(uri.String()) + if err != nil { + return nil, err + } + defer rsp.Body.Close() + + b, err := ioutil.ReadAll(rsp.Body) + if err != nil { + return nil, err + } + + // encoding format is assumed to be json + var records []*resolver.Record + + if err := json.Unmarshal(b, &records); err != nil { + return nil, err + } + + return records, nil +} diff --git a/network/resolver/resolver.go b/network/resolver/resolver.go index ba80e124..ac8de831 100644 --- a/network/resolver/resolver.go +++ b/network/resolver/resolver.go @@ -8,5 +8,5 @@ type Resolver interface { // A resoved id type Record struct { - Address string + Address string `json:"address"` } From 4d08618517654e201fab1ad036a97f215e19c734 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 24 Jun 2019 15:22:12 +0100 Subject: [PATCH 052/287] fix typo --- network/resolver/resolver.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network/resolver/resolver.go b/network/resolver/resolver.go index ac8de831..14b6aeb0 100644 --- a/network/resolver/resolver.go +++ b/network/resolver/resolver.go @@ -6,7 +6,7 @@ type Resolver interface { Resolve(id string) ([]*Record, error) } -// A resoved id +// A resolved record type Record struct { Address string `json:"address"` } From 68764ebafc556123884a52cad47fc3b127d4b54a Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 24 Jun 2019 15:30:17 +0100 Subject: [PATCH 053/287] Add registry resolver --- network/resolver/registry/registry.go | 37 +++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 network/resolver/registry/registry.go diff --git a/network/resolver/registry/registry.go b/network/resolver/registry/registry.go new file mode 100644 index 00000000..c7ef796a --- /dev/null +++ b/network/resolver/registry/registry.go @@ -0,0 +1,37 @@ +// Package registry resolves ids using the go-micro registry +package registry + +import ( + "github.com/micro/go-micro/network/resolver" + "github.com/micro/go-micro/registry" +) + +type Resolver struct { + // Registry is the registry to use otherwise we use the defaul + Registry registry.Registry +} + +// Resolve assumes ID is a domain name e.g micro.mu +func (r *Resolver) Resolve(id string) ([]*resolver.Record, error) { + reg := r.Registry + if reg == nil { + reg = registry.DefaultRegistry + } + + services, err := reg.GetService(id) + if err != nil { + return nil, err + } + + var records []*resolver.Record + + for _, service := range services { + for _, node := range service.Nodes { + records = append(records, &resolver.Record{ + Address: node.Address, + }) + } + } + + return records, nil +} From 8e4fd16affa3e98cceb2d50f77c09ba01f644e0b Mon Sep 17 00:00:00 2001 From: magodo Date: Tue, 25 Jun 2019 18:31:32 +0800 Subject: [PATCH 054/287] Add consul-specific option for config (as registry) --- config/source/consul/consul.go | 5 +++++ config/source/consul/options.go | 12 ++++++++++++ 2 files changed, 17 insertions(+) diff --git a/config/source/consul/consul.go b/config/source/consul/consul.go index 16e85332..c4a6bf60 100644 --- a/config/source/consul/consul.go +++ b/config/source/consul/consul.go @@ -74,6 +74,11 @@ func NewSource(opts ...source.Option) source.Source { // use default config config := api.DefaultConfig() + // use the consul config passed in the options if any + if co, ok := options.Context.Value(consulConfigKey{}).(*api.Config); ok { + config = co + } + // check if there are any addrs a, ok := options.Context.Value(addressKey{}).(string) if ok { diff --git a/config/source/consul/options.go b/config/source/consul/options.go index 9420a803..a1a1fadb 100644 --- a/config/source/consul/options.go +++ b/config/source/consul/options.go @@ -3,6 +3,7 @@ package consul import ( "context" + "github.com/hashicorp/consul/api" "github.com/micro/go-micro/config/source" ) @@ -11,6 +12,7 @@ type prefixKey struct{} type stripPrefixKey struct{} type dcKey struct{} type tokenKey struct{} +type consulConfigKey struct{} // WithAddress sets the consul address func WithAddress(a string) source.Option { @@ -61,3 +63,13 @@ func WithToken(p string) source.Option { o.Context = context.WithValue(o.Context, tokenKey{}, p) } } + +// WithConsulConfig set consul-specific options +func WithConsulConfig(c *api.Config) source.Option { + return func(o *source.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, consulConfigKey{}, c) + } +} From a8dbca756c7e4842ff7c3d59dfde7416046fb4f2 Mon Sep 17 00:00:00 2001 From: magodo Date: Tue, 25 Jun 2019 22:41:31 +0800 Subject: [PATCH 055/287] rename stuff per feedback --- config/source/consul/consul.go | 2 +- config/source/consul/options.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/config/source/consul/consul.go b/config/source/consul/consul.go index c4a6bf60..f5c3c695 100644 --- a/config/source/consul/consul.go +++ b/config/source/consul/consul.go @@ -75,7 +75,7 @@ func NewSource(opts ...source.Option) source.Source { config := api.DefaultConfig() // use the consul config passed in the options if any - if co, ok := options.Context.Value(consulConfigKey{}).(*api.Config); ok { + if co, ok := options.Context.Value(configKey{}).(*api.Config); ok { config = co } diff --git a/config/source/consul/options.go b/config/source/consul/options.go index a1a1fadb..8bca6a66 100644 --- a/config/source/consul/options.go +++ b/config/source/consul/options.go @@ -12,7 +12,7 @@ type prefixKey struct{} type stripPrefixKey struct{} type dcKey struct{} type tokenKey struct{} -type consulConfigKey struct{} +type configKey struct{} // WithAddress sets the consul address func WithAddress(a string) source.Option { @@ -64,12 +64,12 @@ func WithToken(p string) source.Option { } } -// WithConsulConfig set consul-specific options -func WithConsulConfig(c *api.Config) source.Option { +// WithConfig set consul-specific options +func WithConfig(c *api.Config) source.Option { return func(o *source.Options) { if o.Context == nil { o.Context = context.Background() } - o.Context = context.WithValue(o.Context, consulConfigKey{}, c) + o.Context = context.WithValue(o.Context, configKey{}, c) } } From fe84a2d726fe4f2f4ebc11926ca7500eaec58770 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Wed, 26 Jun 2019 16:03:19 +0100 Subject: [PATCH 056/287] Route per service node. No Network Registry for now. --- network/router/default_router.go | 191 +++++++------------------------ network/router/default_table.go | 20 ++-- network/router/options.go | 31 ++--- network/router/query.go | 50 ++++++-- network/router/route.go | 13 ++- network/router/table_watcher.go | 27 ++--- 6 files changed, 110 insertions(+), 222 deletions(-) diff --git a/network/router/default_router.go b/network/router/default_router.go index d600d1da..a84a04ee 100644 --- a/network/router/default_router.go +++ b/network/router/default_router.go @@ -2,25 +2,14 @@ package router import ( "fmt" - "net" - "strconv" "strings" "sync" - "time" "github.com/micro/go-micro/registry" "github.com/olekukonko/tablewriter" ) -var ( - // AdvertiseTick defines how often in seconds do we scal the local registry - // to advertise the local services to the network registry - AdvertiseTick = 5 * time.Second - // AdvertiseTTL defines network registry TTL in seconds - // NOTE: this is a rather arbitrary picked value subject to change - AdvertiseTTL = 120 * time.Second -) - +// router provides default router implementation type router struct { opts Options exit chan struct{} @@ -29,6 +18,9 @@ type router struct { // newRouter creates new router and returns it func newRouter(opts ...Option) Router { + // TODO: we need to add default GW entry here + // Should default GW be part of router options? + // get default options options := DefaultOptions() @@ -74,41 +66,24 @@ func (r *router) Address() string { // Network returns the address router advertises to the network func (r *router) Network() string { - return r.opts.Advertise + return r.opts.Network } -// Advertise advertises the router routes to the network. -// Advertise is a blocking function. It launches multiple goroutines that watch -// service registries and advertise the router routes to other routers in the network. +// Advertise advertises the routes to the network. It is a blocking function. // It returns error if any of the launched goroutines fail with error. func (r *router) Advertise() error { // add local service routes into the routing table - if err := r.addServiceRoutes(r.opts.Registry, DefaultLocalMetric); err != nil { - return fmt.Errorf("failed adding routes for local services: %v", err) - } - - // add network service routes into the routing table - if err := r.addServiceRoutes(r.opts.Network, DefaultNetworkMetric); err != nil { - return fmt.Errorf("failed adding routes for network services: %v", err) - } - - node, err := r.parseToNode() - if err != nil { - return fmt.Errorf("failed to parse router into service node: %v", err) + if err := r.addServiceRoutes(r.opts.Registry, "local", DefaultLocalMetric); err != nil { + return fmt.Errorf("failed adding routes: %v", err) } localWatcher, err := r.opts.Registry.Watch() if err != nil { - return fmt.Errorf("failed to create local registry watcher: %v", err) - } - - networkWatcher, err := r.opts.Network.Watch() - if err != nil { - return fmt.Errorf("failed to create network registry watcher: %v", err) + return fmt.Errorf("failed to create registry watcher: %v", err) } // error channel collecting goroutine errors - errChan := make(chan error, 3) + errChan := make(chan error, 1) r.wg.Add(1) go func() { @@ -117,102 +92,42 @@ func (r *router) Advertise() error { errChan <- r.manageServiceRoutes(localWatcher, DefaultLocalMetric) }() - r.wg.Add(1) - go func() { - defer r.wg.Done() - // watch network registry and register routes in routine table - errChan <- r.manageServiceRoutes(networkWatcher, DefaultNetworkMetric) - }() - - r.wg.Add(1) - go func() { - defer r.wg.Done() - // watch local registry and advertise local service to the network - errChan <- r.advertiseToNetwork(node) - }() - return <-errChan } // addServiceRoutes adds all services in given registry to the routing table. -// NOTE: this is a one-off operation done when bootstrapping the routing table of the new router. -// It returns error if either the services could not be listed or if the routes could not be added to the routing table. -func (r *router) addServiceRoutes(reg registry.Registry, metric int) error { +// NOTE: this is a one-off operation done when bootstrapping the routing table +// It returns error if either the services failed to be listed or +// if the routes could not be added to the routing table. +func (r *router) addServiceRoutes(reg registry.Registry, network string, metric int) error { services, err := reg.ListServices() if err != nil { return fmt.Errorf("failed to list services: %v", err) } + // add each service node as a separate route; for _, service := range services { - route := Route{ - Destination: service.Name, - Router: r, - Network: r.opts.Advertise, - Metric: metric, - } - if err := r.opts.Table.Add(route); err != nil && err != ErrDuplicateRoute { - return fmt.Errorf("error adding route for service: %s", service.Name) + for _, node := range service.Nodes { + var gw string + if node.Port > 0 { + gw = fmt.Sprintf("%s:%d", node.Address, node.Port) + } + route := Route{ + Destination: service.Name, + Gateway: gw, + Router: r.opts.Address, + Network: r.opts.Network, + Metric: metric, + } + if err := r.opts.Table.Add(route); err != nil && err != ErrDuplicateRoute { + return fmt.Errorf("error adding route for service %s: %s", service.Name, err) + } } } return nil } -// parseToNode parses router into registry.Node and returns the result. -// It returns error if the router network address could not be parsed into host and port. -func (r *router) parseToNode() (*registry.Node, error) { - // split router address to host and port part - addr, portStr, err := net.SplitHostPort(r.opts.Advertise) - if err != nil { - return nil, fmt.Errorf("could not parse router address: %v", err) - } - - // try to parse network port into integer - port, err := strconv.Atoi(portStr) - if err != nil { - return nil, fmt.Errorf("could not parse router network address: %v", err) - } - - node := ®istry.Node{ - Id: r.opts.ID, - Address: addr, - Port: port, - } - - return node, nil -} - -// advertiseToNetwork periodically scans local registry and registers (i.e. advertises) all the local services in the network registry. -// It returns error if either the local services failed to be listed or if it fails to register local service in network registry. -func (r *router) advertiseToNetwork(node *registry.Node) error { - // ticker to periodically scan the local registry - ticker := time.NewTicker(AdvertiseTick) - - for { - select { - case <-r.exit: - return nil - case <-ticker.C: - // list all local services - services, err := r.opts.Registry.ListServices() - if err != nil { - return fmt.Errorf("failed to list local services: %v", err) - } - // loop through all registered local services and register them in the network registry - for _, service := range services { - svc := ®istry.Service{ - Name: service.Name, - Nodes: []*registry.Node{node}, - } - // register the local service in the network registry - if err := r.opts.Network.Register(svc, registry.RegisterTTL(AdvertiseTTL)); err != nil { - return fmt.Errorf("failed to register service %s in network registry: %v", svc.Name, err) - } - } - } - } -} - // manageServiceRoutes watches services in given registry and updates the routing table accordingly. // It returns error if the service registry watcher has stopped or if the routing table failed to be updated. func (r *router) manageServiceRoutes(w registry.Watcher, metric int) error { @@ -240,25 +155,21 @@ func (r *router) manageServiceRoutes(w registry.Watcher, metric int) error { route := Route{ Destination: res.Service.Name, - Router: r, - Network: r.opts.Advertise, + Router: r.opts.Address, + Network: r.opts.Network, Metric: metric, } switch res.Action { case "create": - if len(res.Service.Nodes) > 0 { - // only return error if the route is not duplicate, but something else has failed - if err := r.opts.Table.Add(route); err != nil && err != ErrDuplicateRoute { - return fmt.Errorf("failed to add route for service: %v", res.Service.Name) - } + // only return error if the route is not duplicate, but something else has failed + if err := r.opts.Table.Add(route); err != nil && err != ErrDuplicateRoute { + return fmt.Errorf("failed to add route for service %v: %s", res.Service.Name, err) } case "delete": - if len(res.Service.Nodes) < 1 { - // only return error if the route is present in the table, but something else has failed - if err := r.opts.Table.Delete(route); err != nil && err != ErrRouteNotFound { - return fmt.Errorf("failed to delete route for service: %v", res.Service.Name) - } + // only return error if the route is not in the table, but something else has failed + if err := r.opts.Table.Delete(route); err != nil && err != ErrRouteNotFound { + return fmt.Errorf("failed to delete route for service %v: %s", res.Service.Name, err) } } } @@ -274,30 +185,6 @@ func (r *router) Stop() error { // wait for all goroutines to finish r.wg.Wait() - // NOTE: we need a more efficient way of doing this e.g. network routes - // should ideally be autodeleted when the router stops gossiping - query := NewQuery(QueryRouter(r), QueryNetwork(r.opts.Advertise)) - routes, err := r.opts.Table.Lookup(query) - if err != nil && err != ErrRouteNotFound { - return fmt.Errorf("failed to lookup routes for router %s: %v", r.opts.ID, err) - } - - // parse router to registry.Node - node, err := r.parseToNode() - if err != nil { - return fmt.Errorf("failed to parse router into service node: %v", err) - } - - for _, route := range routes { - service := ®istry.Service{ - Name: route.Destination, - Nodes: []*registry.Node{node}, - } - if err := r.opts.Network.Deregister(service); err != nil { - return fmt.Errorf("failed to deregister service %s from network registry: %v", service.Name, err) - } - } - return nil } @@ -311,7 +198,7 @@ func (r *router) String() string { data := []string{ r.opts.ID, r.opts.Address, - r.opts.Advertise, + r.opts.Network, fmt.Sprintf("%d", r.opts.Table.Size()), } table.Append(data) diff --git a/network/router/default_table.go b/network/router/default_table.go index 04e8f6db..196ca4bf 100644 --- a/network/router/default_table.go +++ b/network/router/default_table.go @@ -171,7 +171,7 @@ func (t *table) Lookup(q Query) ([]Route, error) { } for _, route := range routes { if q.Options().Network == "*" || q.Options().Network == route.Network { - if q.Options().Router.ID() == "*" || q.Options().Router.ID() == route.Router.ID() { + if q.Options().Router == "*" { if route.Metric <= q.Options().Metric { results = append(results, route) } @@ -182,8 +182,8 @@ func (t *table) Lookup(q Query) ([]Route, error) { if q.Options().Destination == "*" { for _, route := range routes { - if q.Options().Network == "*" || q.Options().Network == route.Router.Network() { - if q.Options().Router.ID() == "*" || q.Options().Router.ID() == route.Router.ID() { + if q.Options().Network == "*" || q.Options().Network == route.Network { + if q.Options().Router == "*" { if route.Metric <= q.Options().Metric { results = append(results, route) } @@ -193,7 +193,7 @@ func (t *table) Lookup(q Query) ([]Route, error) { } } - if len(results) == 0 && q.Options().Policy != DiscardNoRoute { + if len(results) == 0 && q.Options().Policy != DiscardIfNone { return nil, ErrRouteNotFound } @@ -205,7 +205,6 @@ func (t *table) Watch(opts ...WatchOption) (Watcher, error) { // by default watch everything wopts := WatchOptions{ Destination: "*", - Network: "*", } for _, o := range opts { @@ -256,13 +255,14 @@ func (t *table) String() string { // create nice table printing structure table := tablewriter.NewWriter(sb) - table.SetHeader([]string{"Destination", "Router", "Network", "Metric"}) + table.SetHeader([]string{"Destination", "Gateway", "Router", "Network", "Metric"}) for _, destRoute := range t.m { for _, route := range destRoute { strRoute := []string{ route.Destination, - route.Router.Address(), + route.Gateway, + route.Router, route.Network, fmt.Sprintf("%d", route.Metric), } @@ -278,12 +278,8 @@ func (t *table) String() string { // hash hashes the route using router gateway and network address func (t *table) hash(r Route) uint64 { - destAddr := r.Destination - routerAddr := r.Router.Address() - netAddr := r.Network - t.h.Reset() - t.h.Write([]byte(destAddr + routerAddr + netAddr)) + t.h.Write([]byte(r.Destination + r.Gateway + r.Router + r.Network)) return t.h.Sum64() } diff --git a/network/router/options.go b/network/router/options.go index ee0c6526..3ede4776 100644 --- a/network/router/options.go +++ b/network/router/options.go @@ -8,8 +8,6 @@ import ( var ( // DefaultAddress is default router address DefaultAddress = ":9093" - // DefaultAdvertise is default address advertised to the network - DefaultAdvertise = ":9094" ) // Options are router options @@ -18,12 +16,10 @@ type Options struct { ID string // Address is router address Address string - // Advertise is the address advertised to the network - Advertise string + // Network is micro network + Network string // Registry is the local registry Registry registry.Registry - // Networkis the network registry - Network registry.Registry // Table is routing table Table Table } @@ -42,10 +38,10 @@ func Address(a string) Option { } } -// Advertise sets the address that is advertise to the network -func Advertise(n string) Option { +// Network sets router network +func Network(n string) Option { return func(o *Options) { - o.Advertise = n + o.Network = n } } @@ -63,22 +59,13 @@ func Registry(r registry.Registry) Option { } } -// Network sets the network registry -func Network(r registry.Registry) Option { - return func(o *Options) { - o.Network = r - } -} - // DefaultOptions returns router default options func DefaultOptions() Options { // NOTE: by default both local and network registies use default registry i.e. mdns return Options{ - ID: uuid.New().String(), - Address: DefaultAddress, - Advertise: DefaultAdvertise, - Registry: registry.DefaultRegistry, - Network: registry.DefaultRegistry, - Table: NewTable(), + ID: uuid.New().String(), + Address: DefaultAddress, + Registry: registry.DefaultRegistry, + Table: NewTable(), } } diff --git a/network/router/query.go b/network/router/query.go index 7c18e075..c479f9db 100644 --- a/network/router/query.go +++ b/network/router/query.go @@ -1,11 +1,18 @@ package router +import ( + "fmt" + "strings" + + "github.com/olekukonko/tablewriter" +) + // LookupPolicy defines query policy type LookupPolicy int const ( - // DiscardNoRoute discards query when no route is found - DiscardNoRoute LookupPolicy = iota + // DiscardIfNone discards query when no route is found + DiscardIfNone LookupPolicy = iota // ClosestMatch returns closest match to supplied query ClosestMatch ) @@ -13,7 +20,7 @@ const ( // String returns human representation of LookupPolicy func (lp LookupPolicy) String() string { switch lp { - case DiscardNoRoute: + case DiscardIfNone: return "DISCARD" case ClosestMatch: return "CLOSEST" @@ -29,10 +36,10 @@ type QueryOption func(*QueryOptions) type QueryOptions struct { // Destination is destination address Destination string + // Router is router address + Router string // Network is network address Network string - // Router is gateway address - Router Router // Metric is route metric Metric int // Policy is query lookup policy @@ -54,7 +61,7 @@ func QueryNetwork(a string) QueryOption { } // QueryRouter sets query gateway address -func QueryRouter(r Router) QueryOption { +func QueryRouter(r string) QueryOption { return func(o *QueryOptions) { o.Router = r } @@ -88,17 +95,14 @@ type query struct { // NewQuery creates new query and returns it func NewQuery(opts ...QueryOption) Query { - // default gateway for wildcard router - r := newRouter(ID("*")) - // default options // NOTE: by default we use DefaultNetworkMetric qopts := QueryOptions{ Destination: "*", + Router: "*", Network: "*", - Router: r, Metric: DefaultNetworkMetric, - Policy: DiscardNoRoute, + Policy: DiscardIfNone, } for _, o := range opts { @@ -114,3 +118,27 @@ func NewQuery(opts ...QueryOption) Query { func (q *query) Options() QueryOptions { return q.opts } + +// String prints routing table query in human readable form +func (q query) String() string { + // this will help us build routing table string + sb := &strings.Builder{} + + // create nice table printing structure + table := tablewriter.NewWriter(sb) + table.SetHeader([]string{"Destination", "Router", "Network", "Metric", "Policy"}) + + strQuery := []string{ + q.opts.Destination, + q.opts.Router, + q.opts.Network, + fmt.Sprintf("%d", q.opts.Metric), + fmt.Sprintf("%s", q.opts.Policy), + } + table.Append(strQuery) + + // render table into sb + table.Render() + + return sb.String() +} diff --git a/network/router/route.go b/network/router/route.go index 88fe5b18..d52c2688 100644 --- a/network/router/route.go +++ b/network/router/route.go @@ -20,7 +20,7 @@ type RoutePolicy int const ( // OverrideIfExists overrides route if it already exists OverrideIfExists RoutePolicy = iota - // IgnoreIfExists does not modify existing route + // IgnoreIfExists instructs to not modify existing route IgnoreIfExists ) @@ -40,8 +40,10 @@ func (p RoutePolicy) String() string { type Route struct { // Destination is destination address Destination string - // Router is the network router - Router Router + // Gateway is route gateway + Gateway string + // Router is the network router address + Router string // Network is micro network address Network string // Metric is the route cost metric @@ -57,11 +59,12 @@ func (r *Route) String() string { // create nice table printing structure table := tablewriter.NewWriter(sb) - table.SetHeader([]string{"Destination", "Router", "Network", "Metric"}) + table.SetHeader([]string{"Destination", "Gateway", "Router", "Network", "Metric"}) strRoute := []string{ r.Destination, - r.Router.Address(), + r.Gateway, + r.Router, r.Network, fmt.Sprintf("%d", r.Metric), } diff --git a/network/router/table_watcher.go b/network/router/table_watcher.go index 17a0971f..97d1f1b7 100644 --- a/network/router/table_watcher.go +++ b/network/router/table_watcher.go @@ -64,22 +64,13 @@ type Watcher interface { type WatchOptions struct { // Specify destination address to watch Destination string - // Specify network to watch - Network string } // WatchDestination sets what destination to watch // Destination is usually microservice name -func WatchDestination(a string) WatchOption { +func WatchDestination(d string) WatchOption { return func(o *WatchOptions) { - o.Destination = a - } -} - -// WatchNetwork sets what network to watch -func WatchNetwork(n string) WatchOption { - return func(o *WatchOptions) { - o.Network = n + o.Destination = d } } @@ -90,19 +81,16 @@ type tableWatcher struct { } // Next returns the next noticed action taken on table -// TODO: this needs to be thought through properly -// we are aiming to provide the same options Query provides +// TODO: this needs to be thought through properly; we only allow watching particular route destination func (w *tableWatcher) Next() (*Event, error) { for { select { case res := <-w.resChan: switch w.opts.Destination { case "*", "": - if w.opts.Network == "*" || w.opts.Network == res.Route.Network { - return res, nil - } - case res.Route.Destination: - if w.opts.Network == "*" || w.opts.Network == res.Route.Network { + return res, nil + default: + if w.opts.Destination == res.Route.Destination { return res, nil } } @@ -132,11 +120,10 @@ func (w *tableWatcher) String() string { sb := &strings.Builder{} table := tablewriter.NewWriter(sb) - table.SetHeader([]string{"Destination", "Network"}) + table.SetHeader([]string{"Destination"}) data := []string{ w.opts.Destination, - w.opts.Network, } table.Append(data) From ac098e4d784f1d4604af22453a84f47cc8f8b326 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 26 Jun 2019 16:12:57 +0100 Subject: [PATCH 057/287] add router selector and network defaults --- client/selector/router/router.go | 153 +++++++++++++++++++++++++++++++ config/cmd/cmd.go | 2 + network/default.go | 95 +++++++++++++++++++ network/network.go | 23 ++++- network/proxy/mucp/mucp.go | 15 +++ network/proxy/proxy.go | 6 ++ 6 files changed, 292 insertions(+), 2 deletions(-) create mode 100644 client/selector/router/router.go create mode 100644 network/default.go diff --git a/client/selector/router/router.go b/client/selector/router/router.go new file mode 100644 index 00000000..d67b8767 --- /dev/null +++ b/client/selector/router/router.go @@ -0,0 +1,153 @@ +// Package router is a network/router selector +package router + +import ( + "context" + "net" + "sort" + "strconv" + "sync" + + "github.com/micro/go-micro/client/selector" + "github.com/micro/go-micro/network/router" + "github.com/micro/go-micro/registry" +) + +type routerSelector struct { + opts selector.Options + + // the router + r router.Router +} + +type routerKey struct{} + +func (r *routerSelector) Init(opts ...selector.Option) error { + // no op + return nil +} + +func (r *routerSelector) Options() selector.Options { + return r.opts +} + +func (r *routerSelector) Select(service string, opts ...selector.SelectOption) (selector.Next, error) { + // lookup router for routes for the service + routes, err := r.r.Table().Lookup(router.NewQuery( + router.QueryDestination(service), + )) + + if err != nil { + return nil, err + } + + // no routes return not found error + if len(routes) == 0 { + return nil, selector.ErrNotFound + } + + // TODO: apply filters by pseudo constructing service + + // sort the routes based on metric + sort.Slice(routes, func(i, j int) bool { + return routes[i].Metric < routes[j].Metric + }) + + // roundrobin assuming routes are in metric preference order + var i int + var mtx sync.Mutex + + return func() (*registry.Node, error) { + // get index and increment counter with every call to next + mtx.Lock() + idx := i + i++ + mtx.Unlock() + + // get route based on idx + route := routes[idx%len(routes)] + + // defaults to gateway and no port + address := route.Gateway + port := 0 + + // check if its host:port + host, pr, err := net.SplitHostPort(address) + if err == nil { + pp, _ := strconv.Atoi(pr) + // set port + port = pp + // set address + address = host + } + + // return as a node + return ®istry.Node{ + // TODO: add id and metadata if we can + Address: address, + Port: port, + }, nil + }, nil +} + +func (r *routerSelector) Mark(service string, node *registry.Node, err error) { + // TODO: pass back metrics or information to the router + return +} + +func (r *routerSelector) Reset(service string) { + // TODO: reset the metrics or information at the router + return +} + +func (r *routerSelector) Close() error { + // stop the router advertisements + return r.r.Stop() +} + +func (r *routerSelector) String() string { + return "router" +} + +// NewSelector returns a new router based selector +func NewSelector(opts ...selector.Option) selector.Selector { + options := selector.Options{ + Context: context.Background(), + } + + for _, o := range opts { + o(&options) + } + + // set default registry if not set + if options.Registry == nil { + options.Registry = registry.DefaultRegistry + } + + // try get from the context + r, ok := options.Context.Value(routerKey{}).(router.Router) + if !ok { + // TODO: Use router.DefaultRouter? + r = router.NewRouter( + router.Registry(options.Registry), + ) + } + + // start the router advertisements + r.Advertise() + + return &routerSelector{ + opts: options, + r: r, + } +} + +// WithRouter sets the router as an option +func WithRouter(r router.Router) selector.Option { + return func(o *selector.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, routerKey{}, r) + } +} diff --git a/config/cmd/cmd.go b/config/cmd/cmd.go index 2e7e2a6e..8d7c3c03 100644 --- a/config/cmd/cmd.go +++ b/config/cmd/cmd.go @@ -34,6 +34,7 @@ import ( // selectors "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/client/selector/dns" + "github.com/micro/go-micro/client/selector/router" "github.com/micro/go-micro/client/selector/static" // transports @@ -196,6 +197,7 @@ var ( "default": selector.NewSelector, "dns": dns.NewSelector, "cache": selector.NewSelector, + "router": router.NewSelector, "static": static.NewSelector, } diff --git a/network/default.go b/network/default.go new file mode 100644 index 00000000..90164d33 --- /dev/null +++ b/network/default.go @@ -0,0 +1,95 @@ +package network + +import ( + "sync" + + "github.com/micro/go-micro/config/options" + "github.com/micro/go-micro/network/router" + "github.com/micro/go-micro/network/proxy" +) + +type network struct { + options.Options + + // router + r router.Router + + // proxy + p proxy.Proxy + + // id of this network + id string + + // links maintained for this network + mtx sync.RWMutex + links []Link +} + +type node struct { + *network + + // address of this node + address string +} + + +type link struct { + // the embedded node + *node + + // length and weight of the link + mtx sync.RWMutex + length, weight int +} + +// network methods + +func (n *network) Id() string { + return n.id +} + +func (n *network) Connect() (Node, error) { + return nil, nil +} + +func (n *network) Peer(Network) (Link, error) { + return nil, nil +} + +func (n *network) Links() ([]Link, error) { + n.mtx.RLock() + defer n.mtx.RUnlock() + return n.links, nil +} + +// node methods + +func (n *node) Address() string { + return n.address +} + +func (n *node) Close() error { + return nil +} + +func (n *node) Accept() (*Message, error) { + return nil, nil +} + +func (n *node) Send(*Message) error { + return nil +} + +// link methods + +func (l *link) Length() int { + l.mtx.RLock() + defer l.mtx.RUnlock() + return l.length +} + +func (l *link) Weight() int { + l.mtx.RLock() + defer l.mtx.RUnlock() + return l.weight +} diff --git a/network/network.go b/network/network.go index 29d6653d..098c0807 100644 --- a/network/network.go +++ b/network/network.go @@ -51,6 +51,25 @@ type Message struct { } var ( - // TODO: set default network - DefaultNetwork Network + // The default network ID is local + DefaultNetworkId = "local" + + // just the standard network element + DefaultNetwork = NewNetwork() ) + +// NewNetwork returns a new network +func NewNetwork(opts ...options.Option) Network { + options := options.NewOptions(opts...) + + // get router + + // get proxy + + return &network{ + Options: options, + // fill the blanks + // router: r, + // proxy: p, + } +} diff --git a/network/proxy/mucp/mucp.go b/network/proxy/mucp/mucp.go index 9e8afd39..2d52058a 100644 --- a/network/proxy/mucp/mucp.go +++ b/network/proxy/mucp/mucp.go @@ -7,10 +7,12 @@ import ( "strings" "github.com/micro/go-micro/client" + rselect "github.com/micro/go-micro/client/selector/router" "github.com/micro/go-micro/codec" "github.com/micro/go-micro/codec/bytes" "github.com/micro/go-micro/config/options" "github.com/micro/go-micro/network/proxy" + "github.com/micro/go-micro/network/router" "github.com/micro/go-micro/server" ) @@ -162,5 +164,18 @@ func NewProxy(opts ...options.Option) proxy.Proxy { p.Client = c.(client.Client) } + // get router + r, ok := p.Options.Values().Get("proxy.router") + if ok { + // set the router in the client + p.Client.Init( + // pass new selector as an option to the client + client.Selector(rselect.NewSelector( + // set the router in the selector + rselect.WithRouter(r.(router.Router)), + )), + ) + } + return p } diff --git a/network/proxy/proxy.go b/network/proxy/proxy.go index bb8fcc3b..22d485e8 100644 --- a/network/proxy/proxy.go +++ b/network/proxy/proxy.go @@ -6,6 +6,7 @@ import ( "github.com/micro/go-micro/client" "github.com/micro/go-micro/config/options" + "github.com/micro/go-micro/network/router" "github.com/micro/go-micro/server" ) @@ -29,3 +30,8 @@ func WithEndpoint(e string) options.Option { func WithClient(c client.Client) options.Option { return options.WithValue("proxy.client", c) } + +// WithRouter specifies the router to use +func WithRouter(r router.Router) options.Option { + return options.WithValue("proxy.router", r) +} From 27b145f9688a1f7e730ccdb6dd2cd3af5b32bfc5 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 26 Jun 2019 16:23:10 +0100 Subject: [PATCH 058/287] add router proto --- network/router/proto/router.micro.go | 91 ++++++++ network/router/proto/router.pb.go | 324 +++++++++++++++++++++++++++ network/router/proto/router.proto | 36 +++ 3 files changed, 451 insertions(+) create mode 100644 network/router/proto/router.micro.go create mode 100644 network/router/proto/router.pb.go create mode 100644 network/router/proto/router.proto diff --git a/network/router/proto/router.micro.go b/network/router/proto/router.micro.go new file mode 100644 index 00000000..06736f82 --- /dev/null +++ b/network/router/proto/router.micro.go @@ -0,0 +1,91 @@ +// Code generated by protoc-gen-micro. DO NOT EDIT. +// source: go-micro/network/router/proto/router.proto + +package router + +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" +) + +import ( + context "context" + client "github.com/micro/go-micro/client" + server "github.com/micro/go-micro/server" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ client.Option +var _ server.Option + +// Client API for Router service + +type RouterService interface { + Lookup(ctx context.Context, in *LookupRequest, opts ...client.CallOption) (*LookupResponse, error) +} + +type routerService struct { + c client.Client + name string +} + +func NewRouterService(name string, c client.Client) RouterService { + if c == nil { + c = client.NewClient() + } + if len(name) == 0 { + name = "router" + } + return &routerService{ + c: c, + name: name, + } +} + +func (c *routerService) Lookup(ctx context.Context, in *LookupRequest, opts ...client.CallOption) (*LookupResponse, error) { + req := c.c.NewRequest(c.name, "Router.Lookup", in) + out := new(LookupResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for Router service + +type RouterHandler interface { + Lookup(context.Context, *LookupRequest, *LookupResponse) error +} + +func RegisterRouterHandler(s server.Server, hdlr RouterHandler, opts ...server.HandlerOption) error { + type router interface { + Lookup(ctx context.Context, in *LookupRequest, out *LookupResponse) error + } + type Router struct { + router + } + h := &routerHandler{hdlr} + return s.Handle(s.NewHandler(&Router{h}, opts...)) +} + +type routerHandler struct { + RouterHandler +} + +func (h *routerHandler) Lookup(ctx context.Context, in *LookupRequest, out *LookupResponse) error { + return h.RouterHandler.Lookup(ctx, in, out) +} diff --git a/network/router/proto/router.pb.go b/network/router/proto/router.pb.go new file mode 100644 index 00000000..d0aff457 --- /dev/null +++ b/network/router/proto/router.pb.go @@ -0,0 +1,324 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: go-micro/network/router/proto/router.proto + +package router + +import ( + context "context" + fmt "fmt" + proto "github.com/golang/protobuf/proto" + grpc "google.golang.org/grpc" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +// LookupRequest is made to Lookup +type LookupRequest struct { + Query *Query `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *LookupRequest) Reset() { *m = LookupRequest{} } +func (m *LookupRequest) String() string { return proto.CompactTextString(m) } +func (*LookupRequest) ProtoMessage() {} +func (*LookupRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_fc08514fc6dadd29, []int{0} +} + +func (m *LookupRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_LookupRequest.Unmarshal(m, b) +} +func (m *LookupRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_LookupRequest.Marshal(b, m, deterministic) +} +func (m *LookupRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_LookupRequest.Merge(m, src) +} +func (m *LookupRequest) XXX_Size() int { + return xxx_messageInfo_LookupRequest.Size(m) +} +func (m *LookupRequest) XXX_DiscardUnknown() { + xxx_messageInfo_LookupRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_LookupRequest proto.InternalMessageInfo + +func (m *LookupRequest) GetQuery() *Query { + if m != nil { + return m.Query + } + return nil +} + +// LookupResponse is returns by Lookup +type LookupResponse struct { + Routes []*Route `protobuf:"bytes,1,rep,name=routes,proto3" json:"routes,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *LookupResponse) Reset() { *m = LookupResponse{} } +func (m *LookupResponse) String() string { return proto.CompactTextString(m) } +func (*LookupResponse) ProtoMessage() {} +func (*LookupResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_fc08514fc6dadd29, []int{1} +} + +func (m *LookupResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_LookupResponse.Unmarshal(m, b) +} +func (m *LookupResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_LookupResponse.Marshal(b, m, deterministic) +} +func (m *LookupResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_LookupResponse.Merge(m, src) +} +func (m *LookupResponse) XXX_Size() int { + return xxx_messageInfo_LookupResponse.Size(m) +} +func (m *LookupResponse) XXX_DiscardUnknown() { + xxx_messageInfo_LookupResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_LookupResponse proto.InternalMessageInfo + +func (m *LookupResponse) GetRoutes() []*Route { + if m != nil { + return m.Routes + } + return nil +} + +// Query is passed in a LookupRequest +type Query struct { + // destination to lookup + Destination string `protobuf:"bytes,1,opt,name=destination,proto3" json:"destination,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Query) Reset() { *m = Query{} } +func (m *Query) String() string { return proto.CompactTextString(m) } +func (*Query) ProtoMessage() {} +func (*Query) Descriptor() ([]byte, []int) { + return fileDescriptor_fc08514fc6dadd29, []int{2} +} + +func (m *Query) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Query.Unmarshal(m, b) +} +func (m *Query) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Query.Marshal(b, m, deterministic) +} +func (m *Query) XXX_Merge(src proto.Message) { + xxx_messageInfo_Query.Merge(m, src) +} +func (m *Query) XXX_Size() int { + return xxx_messageInfo_Query.Size(m) +} +func (m *Query) XXX_DiscardUnknown() { + xxx_messageInfo_Query.DiscardUnknown(m) +} + +var xxx_messageInfo_Query proto.InternalMessageInfo + +func (m *Query) GetDestination() string { + if m != nil { + return m.Destination + } + return "" +} + +// Route is a service route +type Route struct { + // service for the route + Destination string `protobuf:"bytes,1,opt,name=destination,proto3" json:"destination,omitempty"` + // gateway as the next hop + Gateway string `protobuf:"bytes,2,opt,name=gateway,proto3" json:"gateway,omitempty"` + // the router that advertise this route + Router string `protobuf:"bytes,3,opt,name=router,proto3" json:"router,omitempty"` + // the network for this destination + Network string `protobuf:"bytes,4,opt,name=network,proto3" json:"network,omitempty"` + // the metric / score of this route + Metric int64 `protobuf:"varint,5,opt,name=metric,proto3" json:"metric,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Route) Reset() { *m = Route{} } +func (m *Route) String() string { return proto.CompactTextString(m) } +func (*Route) ProtoMessage() {} +func (*Route) Descriptor() ([]byte, []int) { + return fileDescriptor_fc08514fc6dadd29, []int{3} +} + +func (m *Route) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Route.Unmarshal(m, b) +} +func (m *Route) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Route.Marshal(b, m, deterministic) +} +func (m *Route) XXX_Merge(src proto.Message) { + xxx_messageInfo_Route.Merge(m, src) +} +func (m *Route) XXX_Size() int { + return xxx_messageInfo_Route.Size(m) +} +func (m *Route) XXX_DiscardUnknown() { + xxx_messageInfo_Route.DiscardUnknown(m) +} + +var xxx_messageInfo_Route proto.InternalMessageInfo + +func (m *Route) GetDestination() string { + if m != nil { + return m.Destination + } + return "" +} + +func (m *Route) GetGateway() string { + if m != nil { + return m.Gateway + } + return "" +} + +func (m *Route) GetRouter() string { + if m != nil { + return m.Router + } + return "" +} + +func (m *Route) GetNetwork() string { + if m != nil { + return m.Network + } + return "" +} + +func (m *Route) GetMetric() int64 { + if m != nil { + return m.Metric + } + return 0 +} + +func init() { + proto.RegisterType((*LookupRequest)(nil), "LookupRequest") + proto.RegisterType((*LookupResponse)(nil), "LookupResponse") + proto.RegisterType((*Query)(nil), "Query") + proto.RegisterType((*Route)(nil), "Route") +} + +func init() { + proto.RegisterFile("go-micro/network/router/proto/router.proto", fileDescriptor_fc08514fc6dadd29) +} + +var fileDescriptor_fc08514fc6dadd29 = []byte{ + // 242 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x90, 0xc1, 0x4a, 0xc3, 0x40, + 0x10, 0x86, 0x5d, 0x63, 0x56, 0x9c, 0x62, 0x85, 0x3d, 0xc8, 0x22, 0x22, 0x61, 0x4f, 0x55, 0x69, + 0x22, 0x15, 0xdf, 0xc2, 0x8b, 0xfb, 0x06, 0xb1, 0x0e, 0x25, 0x94, 0x66, 0xd2, 0xdd, 0x09, 0xa5, + 0x0f, 0xe1, 0x3b, 0x4b, 0x26, 0x5b, 0x30, 0xa7, 0x1e, 0xbf, 0x99, 0xf9, 0x7e, 0x76, 0x7f, 0x78, + 0xd9, 0xd0, 0x72, 0xd7, 0xac, 0x03, 0x55, 0x2d, 0xf2, 0x81, 0xc2, 0xb6, 0x0a, 0xd4, 0x33, 0x86, + 0xaa, 0x0b, 0xc4, 0x94, 0xa0, 0x14, 0x70, 0x4b, 0xb8, 0xfd, 0x24, 0xda, 0xf6, 0x9d, 0xc7, 0x7d, + 0x8f, 0x91, 0xcd, 0x23, 0xe4, 0xfb, 0x1e, 0xc3, 0xd1, 0xaa, 0x42, 0x2d, 0x66, 0x2b, 0x5d, 0x7e, + 0x0d, 0xe4, 0xc7, 0xa1, 0x7b, 0x83, 0xf9, 0xe9, 0x3c, 0x76, 0xd4, 0x46, 0x34, 0x4f, 0xa0, 0x25, + 0x30, 0x5a, 0x55, 0x64, 0x22, 0xf8, 0x01, 0x7d, 0x9a, 0xba, 0x67, 0xc8, 0x25, 0xc1, 0x14, 0x30, + 0xfb, 0xc1, 0xc8, 0x4d, 0x5b, 0x73, 0x43, 0xad, 0xc4, 0xdf, 0xf8, 0xff, 0x23, 0xf7, 0xab, 0x20, + 0x17, 0xf9, 0xfc, 0xad, 0xb1, 0x70, 0xbd, 0xa9, 0x19, 0x0f, 0xf5, 0xd1, 0x5e, 0xca, 0xf6, 0x84, + 0xe6, 0x3e, 0x3d, 0x28, 0xd8, 0x4c, 0x16, 0x89, 0x06, 0x23, 0xd5, 0x61, 0xaf, 0x46, 0x23, 0xe1, + 0x60, 0xec, 0x90, 0x43, 0xb3, 0xb6, 0x79, 0xa1, 0x16, 0x99, 0x4f, 0xb4, 0xfa, 0x00, 0xed, 0x47, + 0xf7, 0x15, 0xf4, 0xf8, 0x6d, 0x33, 0x2f, 0x27, 0x75, 0x3d, 0xdc, 0x95, 0xd3, 0x3e, 0xdc, 0xc5, + 0xb7, 0x96, 0x66, 0xdf, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0x4d, 0x73, 0x18, 0x9e, 0x87, 0x01, + 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// RouterClient is the client API for Router service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type RouterClient interface { + Lookup(ctx context.Context, in *LookupRequest, opts ...grpc.CallOption) (*LookupResponse, error) +} + +type routerClient struct { + cc *grpc.ClientConn +} + +func NewRouterClient(cc *grpc.ClientConn) RouterClient { + return &routerClient{cc} +} + +func (c *routerClient) Lookup(ctx context.Context, in *LookupRequest, opts ...grpc.CallOption) (*LookupResponse, error) { + out := new(LookupResponse) + err := c.cc.Invoke(ctx, "/Router/Lookup", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// RouterServer is the server API for Router service. +type RouterServer interface { + Lookup(context.Context, *LookupRequest) (*LookupResponse, error) +} + +func RegisterRouterServer(s *grpc.Server, srv RouterServer) { + s.RegisterService(&_Router_serviceDesc, srv) +} + +func _Router_Lookup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(LookupRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RouterServer).Lookup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/Router/Lookup", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RouterServer).Lookup(ctx, req.(*LookupRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Router_serviceDesc = grpc.ServiceDesc{ + ServiceName: "Router", + HandlerType: (*RouterServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Lookup", + Handler: _Router_Lookup_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "go-micro/network/router/proto/router.proto", +} diff --git a/network/router/proto/router.proto b/network/router/proto/router.proto new file mode 100644 index 00000000..6f9e7323 --- /dev/null +++ b/network/router/proto/router.proto @@ -0,0 +1,36 @@ +syntax = "proto3"; + +// Router service is used by the proxy to lookup routes +service Router { + rpc Lookup(LookupRequest) returns (LookupResponse) {}; +} + +// LookupRequest is made to Lookup +message LookupRequest { + Query query = 1; +} + +// LookupResponse is returns by Lookup +message LookupResponse { + repeated Route routes = 1; +} + +// Query is passed in a LookupRequest +message Query { + // destination to lookup + string destination = 1; +} + +// Route is a service route +message Route { + // service for the route + string destination = 1; + // gateway as the next hop + string gateway = 2; + // the router that advertise this route + string router = 3; + // the network for this destination + string network = 4; + // the metric / score of this route + int64 metric = 5; +} From 76011b151d68caebe5dc48e5e330d172694725f4 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Wed, 26 Jun 2019 16:28:33 +0100 Subject: [PATCH 059/287] Bugfix: Set gateway to node.Address gw has not been initialized; it was basically an empty string and only got populated by Sprintf-ing the addr:port IF the port has been set. This commit sets the gw to node.Address to it's never an empty string. --- network/router/default_router.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network/router/default_router.go b/network/router/default_router.go index a84a04ee..b342666e 100644 --- a/network/router/default_router.go +++ b/network/router/default_router.go @@ -108,7 +108,7 @@ func (r *router) addServiceRoutes(reg registry.Registry, network string, metric // add each service node as a separate route; for _, service := range services { for _, node := range service.Nodes { - var gw string + gw := node.Address if node.Port > 0 { gw = fmt.Sprintf("%s:%d", node.Address, node.Port) } From cedcef032dacc013dac25ab6e08ddc91d20a4ff9 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 26 Jun 2019 19:27:38 +0100 Subject: [PATCH 060/287] Add remote lookup via router selector --- client/selector/router/router.go | 103 ++++++++++++++++++++++++++++--- 1 file changed, 94 insertions(+), 9 deletions(-) diff --git a/client/selector/router/router.go b/client/selector/router/router.go index d67b8767..dfa5d370 100644 --- a/client/selector/router/router.go +++ b/client/selector/router/router.go @@ -4,12 +4,15 @@ package router import ( "context" "net" + "os" "sort" "strconv" "sync" + "github.com/micro/go-micro/client" "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/network/router" + pb "github.com/micro/go-micro/network/router/proto" "github.com/micro/go-micro/registry" ) @@ -18,10 +21,64 @@ type routerSelector struct { // the router r router.Router + + // the client for the remote router + c pb.RouterService + + // address of the remote router + addr string + + // whether to use the remote router + remote bool } +type clientKey struct{} type routerKey struct{} +// getRoutes returns the routes whether they are remote or local +func (r *routerSelector) getRoutes(service string) ([]router.Route, error) { + if !r.remote { + // lookup router for routes for the service + return r.r.Table().Lookup(router.NewQuery( + router.QueryDestination(service), + )) + } + + // lookup the remote router + + var clientOpts []client.CallOption + + // set the remote address if specified + if len(r.addr) > 0 { + clientOpts = append(clientOpts, client.WithAddress(r.addr)) + } + + // call the router + pbRoutes, err := r.c.Lookup(context.Background(), &pb.LookupRequest{ + Query: &pb.Query{ + Destination: service, + }, + }, clientOpts...) + if err != nil { + return nil, err + } + + var routes []router.Route + + // convert from pb to []*router.Route + for _, r := range pbRoutes.Routes { + routes = append(routes, router.Route{ + Destination: r.Destination, + Gateway: r.Gateway, + Router: r.Router, + Network: r.Network, + Metric: int(r.Metric), + }) + } + + return routes, nil +} + func (r *routerSelector) Init(opts ...selector.Option) error { // no op return nil @@ -32,11 +89,8 @@ func (r *routerSelector) Options() selector.Options { } func (r *routerSelector) Select(service string, opts ...selector.SelectOption) (selector.Next, error) { - // lookup router for routes for the service - routes, err := r.r.Table().Lookup(router.NewQuery( - router.QueryDestination(service), - )) - + // TODO: pull routes asynchronously and cache + routes, err := r.getRoutes(service) if err != nil { return nil, err } @@ -124,7 +178,7 @@ func NewSelector(opts ...selector.Option) selector.Selector { options.Registry = registry.DefaultRegistry } - // try get from the context + // try get router from the context r, ok := options.Context.Value(routerKey{}).(router.Router) if !ok { // TODO: Use router.DefaultRouter? @@ -133,12 +187,43 @@ func NewSelector(opts ...selector.Option) selector.Selector { ) } - // start the router advertisements - r.Advertise() + // try get client from the context + c, ok := options.Context.Value(clientKey{}).(client.Client) + if !ok { + c = client.DefaultClient + } + + // get the router from env vars if its a remote service + remote := true + routerName := os.Getenv("MICRO_ROUTER") + routerAddress := os.Getenv("MICRO_ROUTER_ADDRESS") + + // start the router advertisements if we're running it locally + if len(routerName) == 0 && len(routerAddress) == 0 { + go r.Advertise() + remote = false + } return &routerSelector{ opts: options, - r: r, + // set the internal router + r: r, + // set the client + c: pb.NewRouterService(routerName, c), + // address of router + addr: routerAddress, + // let ourselves know to use the remote router + remote: remote, + } +} + +// WithClient sets the client for the request +func WithClient(c client.Client) selector.Option { + return func(o *selector.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, clientKey{}, c) } } From b904f383c188b193834ca7101ca588d3c46adf44 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 26 Jun 2019 19:28:30 +0100 Subject: [PATCH 061/287] go fmt --- network/default.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/network/default.go b/network/default.go index 90164d33..8ee82b04 100644 --- a/network/default.go +++ b/network/default.go @@ -4,8 +4,8 @@ import ( "sync" "github.com/micro/go-micro/config/options" - "github.com/micro/go-micro/network/router" "github.com/micro/go-micro/network/proxy" + "github.com/micro/go-micro/network/router" ) type network struct { @@ -21,7 +21,7 @@ type network struct { id string // links maintained for this network - mtx sync.RWMutex + mtx sync.RWMutex links []Link } @@ -32,14 +32,14 @@ type node struct { address string } - type link struct { // the embedded node *node // length and weight of the link - mtx sync.RWMutex - length, weight int + mtx sync.RWMutex + length int + weight int } // network methods From 940ea94a968bebb85150704dee274353e133d5f3 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 26 Jun 2019 19:56:40 +0100 Subject: [PATCH 062/287] Lookup router via registry --- client/selector/router/router.go | 69 +++++++++++++++++++++++++++----- 1 file changed, 59 insertions(+), 10 deletions(-) diff --git a/client/selector/router/router.go b/client/selector/router/router.go index dfa5d370..452c9b89 100644 --- a/client/selector/router/router.go +++ b/client/selector/router/router.go @@ -3,6 +3,7 @@ package router import ( "context" + "fmt" "net" "os" "sort" @@ -22,8 +23,14 @@ type routerSelector struct { // the router r router.Router + // the client we have + c client.Client + // the client for the remote router - c pb.RouterService + rs pb.RouterService + + // name of the router + name string // address of the remote router addr string @@ -46,23 +53,61 @@ func (r *routerSelector) getRoutes(service string) ([]router.Route, error) { // lookup the remote router - var clientOpts []client.CallOption + var addrs []string // set the remote address if specified if len(r.addr) > 0 { - clientOpts = append(clientOpts, client.WithAddress(r.addr)) + addrs = append(addrs, r.addr) + } else { + // we have a name so we need to check the registry + services, err := r.c.Options().Registry.GetService(r.name) + if err != nil { + return nil, err + } + + for _, service := range services { + for _, node := range service.Nodes { + addr := node.Address + if node.Port > 0 { + addr = fmt.Sprintf("%s:%d", node.Address, node.Port) + } + addrs = append(addrs, addr) + } + } } - // call the router - pbRoutes, err := r.c.Lookup(context.Background(), &pb.LookupRequest{ - Query: &pb.Query{ - Destination: service, - }, - }, clientOpts...) + // no router addresses available + if len(addrs) == 0 { + return nil, selector.ErrNoneAvailable + } + + var pbRoutes *pb.LookupResponse + var err error + + // TODO: implement backoff and retries + for _, addr := range addrs { + // call the router + pbRoutes, err = r.rs.Lookup(context.Background(), &pb.LookupRequest{ + Query: &pb.Query{ + Destination: service, + }, + }, client.WithAddress(addr)) + if err != nil { + continue + } + break + } + + // errored out if err != nil { return nil, err } + // no routes + if pbRoutes == nil { + return nil, selector.ErrNoneAvailable + } + var routes []router.Route // convert from pb to []*router.Route @@ -209,7 +254,11 @@ func NewSelector(opts ...selector.Option) selector.Selector { // set the internal router r: r, // set the client - c: pb.NewRouterService(routerName, c), + c: c, + // set the router client + rs: pb.NewRouterService(routerName, c), + // name of the router + name: routerName, // address of router addr: routerAddress, // let ourselves know to use the remote router From 0da8256426e865ebd4e31088ebcb535c18b47ece Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 26 Jun 2019 20:51:13 +0100 Subject: [PATCH 063/287] Accept a range of addresses --- client/grpc/grpc.go | 4 ++-- client/options.go | 8 ++++---- client/rpc_client.go | 29 ++++++++++++++++++----------- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/client/grpc/grpc.go b/client/grpc/grpc.go index 3430fbfc..df4163c7 100644 --- a/client/grpc/grpc.go +++ b/client/grpc/grpc.go @@ -59,14 +59,14 @@ func (g *grpcClient) next(request client.Request, opts client.CallOptions) (sele // get proxy address if prx := os.Getenv("MICRO_PROXY_ADDRESS"); len(prx) > 0 { - opts.Address = prx + opts.Address = []string{prx} } // return remote address if len(opts.Address) > 0 { return func() (*registry.Node, error) { return ®istry.Node{ - Address: opts.Address, + Address: opts.Address[0], }, nil }, nil } diff --git a/client/options.go b/client/options.go index 5a0f4100..9f363d74 100644 --- a/client/options.go +++ b/client/options.go @@ -43,8 +43,8 @@ type Options struct { type CallOptions struct { SelectOptions []selector.SelectOption - // Address of remote host - Address string + // Address of remote hosts + Address []string // Backoff func Backoff BackoffFunc // Check if retriable func @@ -245,8 +245,8 @@ func WithExchange(e string) PublishOption { } } -// WithAddress sets the remote address to use rather than using service discovery -func WithAddress(a string) CallOption { +// WithAddress sets the remote addresses to use rather than using service discovery +func WithAddress(a ...string) CallOption { return func(o *CallOptions) { o.Address = a } diff --git a/client/rpc_client.go b/client/rpc_client.go index 36b3dcf7..c724435a 100644 --- a/client/rpc_client.go +++ b/client/rpc_client.go @@ -283,29 +283,36 @@ func (r *rpcClient) next(request Request, opts CallOptions) (selector.Next, erro // get proxy address if prx := os.Getenv("MICRO_PROXY_ADDRESS"); len(prx) > 0 { - opts.Address = prx + opts.Address = []string{prx} } // return remote address if len(opts.Address) > 0 { - address := opts.Address - port := 0 + var nodes []*registry.Node - host, sport, err := net.SplitHostPort(opts.Address) - if err == nil { - address = host - port, _ = strconv.Atoi(sport) - } + for _, addr := range opts.Address { + address := addr + port := 0 - return func() (*registry.Node, error) { - return ®istry.Node{ + host, sport, err := net.SplitHostPort(addr) + if err == nil { + address = host + port, _ = strconv.Atoi(sport) + } + + nodes = append(nodes, ®istry.Node{ Address: address, Port: port, // Set the protocol Metadata: map[string]string{ "protocol": "mucp", }, - }, nil + }) + } + + // crude return method + return func() (*registry.Node, error) { + return nodes[time.Now().Unix()%int64(len(nodes))], nil }, nil } From 3b0ef425b6e3c45a85eab47bb73b980106c58857 Mon Sep 17 00:00:00 2001 From: lpxxn Date: Thu, 27 Jun 2019 13:06:53 +0800 Subject: [PATCH 064/287] pass parameter to anonymous function --- client/grpc/grpc.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/grpc/grpc.go b/client/grpc/grpc.go index df4163c7..b067d826 100644 --- a/client/grpc/grpc.go +++ b/client/grpc/grpc.go @@ -372,9 +372,9 @@ func (g *grpcClient) Call(ctx context.Context, req client.Request, rsp interface var gerr error for i := 0; i <= callOpts.Retries; i++ { - go func() { + go func(i int) { ch <- call(i) - }() + }(i) select { case <-ctx.Done(): @@ -455,10 +455,10 @@ func (g *grpcClient) Stream(ctx context.Context, req client.Request, opts ...cli var grr error for i := 0; i <= callOpts.Retries; i++ { - go func() { + go func(i int) { s, err := call(i) ch <- response{s, err} - }() + }(i) select { case <-ctx.Done(): From f6f6e1b5611380aefa9aac053cd8342ef6d26d24 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 27 Jun 2019 12:56:52 +0100 Subject: [PATCH 065/287] Use the router to get routes --- network/proxy/mucp/mucp.go | 193 ++++++++++++++++++++++++++++++++++--- 1 file changed, 179 insertions(+), 14 deletions(-) diff --git a/network/proxy/mucp/mucp.go b/network/proxy/mucp/mucp.go index 2d52058a..dcc19a73 100644 --- a/network/proxy/mucp/mucp.go +++ b/network/proxy/mucp/mucp.go @@ -3,17 +3,22 @@ package mucp import ( "context" + "fmt" "io" + "os" "strings" + "sync" "github.com/micro/go-micro/client" - rselect "github.com/micro/go-micro/client/selector/router" + "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/codec" "github.com/micro/go-micro/codec/bytes" "github.com/micro/go-micro/config/options" "github.com/micro/go-micro/network/proxy" "github.com/micro/go-micro/network/router" "github.com/micro/go-micro/server" + + pb "github.com/micro/go-micro/network/router/proto" ) // Proxy will transparently proxy requests to an endpoint. @@ -27,6 +32,16 @@ type Proxy struct { // The client to use for outbound requests Client client.Client + + // The router for routes + Router router.Router + + // The router service client + RouterService pb.RouterService + + // A fib of routes service:address + sync.RWMutex + Routes map[string][]router.Route } // read client request and write to server @@ -64,6 +79,142 @@ func readLoop(r server.Request, s client.Stream) error { } } +func (p *Proxy) getRoute(service string) ([]string, error) { + // converts routes to just addresses + toNodes := func(routes []router.Route) []string { + var nodes []string + for _, node := range routes { + nodes = append(nodes, node.Gateway) + } + return nodes + } + + // lookup the route cache first + p.RLock() + routes, ok := p.Routes[service] + // got it! + if ok { + p.RUnlock() + return toNodes(routes), nil + } + p.RUnlock() + + // route cache miss, now lookup the router + // if it does not exist, don't error out + // the proxy will just hand off to the client + // and try the registry + // in future we might set a default gateway + if p.Router != nil { + // lookup the router + routes, err := p.Router.Table().Lookup( + router.NewQuery(router.QueryDestination(service)), + ) + if err != nil { + return nil, err + } + + p.Lock() + if p.Routes == nil { + p.Routes = make(map[string][]router.Route) + } + p.Routes[service] = routes + p.Unlock() + + return toNodes(routes), nil + } + + // we've tried getting cached routes + // we've tried using the router + addr := os.Getenv("MICRO_ROUTER_ADDRESS") + name := os.Getenv("MICRO_ROUTER") + + // no router is specified we're going to set the default + if len(name) == 0 && len(addr) == 0 { + p.Router = router.DefaultRouter + // recursively execute getRoute + return p.getRoute(service) + } + + if len(name) == 0 { + name = "go.micro.router" + } + + // lookup the remote router + + var addrs []string + + // set the remote address if specified + if len(addr) > 0 { + addrs = append(addrs, addr) + } else { + // we have a name so we need to check the registry + services, err := p.Client.Options().Registry.GetService(name) + if err != nil { + return nil, err + } + + for _, service := range services { + for _, node := range service.Nodes { + addr := node.Address + if node.Port > 0 { + addr = fmt.Sprintf("%s:%d", node.Address, node.Port) + } + addrs = append(addrs, addr) + } + } + } + + // no router addresses available + if len(addrs) == 0 { + return nil, selector.ErrNoneAvailable + } + + var pbRoutes *pb.LookupResponse + var err error + + // set default client + if p.RouterService == nil { + p.RouterService = pb.NewRouterService(name, p.Client) + } + + // TODO: implement backoff and retries + for _, addr := range addrs { + // call the router + pbRoutes, err = p.RouterService.Lookup(context.Background(), &pb.LookupRequest{ + Query: &pb.Query{ + Destination: service, + }, + }, client.WithAddress(addr)) + if err != nil { + continue + } + break + } + + // errored out + if err != nil { + return nil, err + } + + // no routes + if pbRoutes == nil { + return nil, selector.ErrNoneAvailable + } + + // convert from pb to []*router.Route + for _, r := range pbRoutes.Routes { + routes = append(routes, router.Route{ + Destination: r.Destination, + Gateway: r.Gateway, + Router: r.Router, + Network: r.Network, + Metric: int(r.Metric), + }) + } + + return toNodes(routes), nil +} + // ServeRequest honours the server.Router interface func (p *Proxy) ServeRequest(ctx context.Context, req server.Request, rsp server.Response) error { // set default client @@ -71,21 +222,42 @@ func (p *Proxy) ServeRequest(ctx context.Context, req server.Request, rsp server p.Client = client.DefaultClient } - opts := []client.CallOption{} - // service name service := req.Service() endpoint := req.Endpoint() + var addresses []string - // call a specific backend + // call a specific backend endpoint either by name or address if len(p.Endpoint) > 0 { // address:port if parts := strings.Split(p.Endpoint, ":"); len(parts) > 1 { - opts = append(opts, client.WithAddress(p.Endpoint)) - // use as service name + addresses = []string{p.Endpoint} } else { + // get route for endpoint from router + addr, err := p.getRoute(p.Endpoint) + if err != nil { + return err + } + // set the address + addresses = addr + // set the name service = p.Endpoint } + } else { + // no endpoint was specified just lookup the route + // get route for endpoint from router + addr, err := p.getRoute(service) + if err != nil { + return err + } + addresses = addr + } + + var opts []client.CallOption + + // set address if available + if len(addresses) > 0 { + opts = append(opts, client.WithAddress(addresses...)) } // read initial request @@ -167,14 +339,7 @@ func NewProxy(opts ...options.Option) proxy.Proxy { // get router r, ok := p.Options.Values().Get("proxy.router") if ok { - // set the router in the client - p.Client.Init( - // pass new selector as an option to the client - client.Selector(rselect.NewSelector( - // set the router in the selector - rselect.WithRouter(r.(router.Router)), - )), - ) + p.Router = r.(router.Router) } return p From 43297f731c9151fc871fbb07a1d7239d32075aab Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 27 Jun 2019 12:57:23 +0100 Subject: [PATCH 066/287] Add default router --- network/router/options.go | 1 + network/router/router.go | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/network/router/options.go b/network/router/options.go index 3ede4776..9c5581d4 100644 --- a/network/router/options.go +++ b/network/router/options.go @@ -67,5 +67,6 @@ func DefaultOptions() Options { Address: DefaultAddress, Registry: registry.DefaultRegistry, Table: NewTable(), + Network: "local", } } diff --git a/network/router/router.go b/network/router/router.go index 725248f0..366c2fbf 100644 --- a/network/router/router.go +++ b/network/router/router.go @@ -26,6 +26,10 @@ type Router interface { // Option used by the router type Option func(*Options) +var ( + DefaultRouter = NewRouter() +) + // NewRouter creates new Router and returns it func NewRouter(opts ...Option) Router { return newRouter(opts...) From 9630e153a535f0eee4cf9a8c89188d7098a77a1d Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 27 Jun 2019 13:08:06 +0100 Subject: [PATCH 067/287] fix grpc proto wrapper --- client/grpc/grpc.go | 2 +- network/router/options.go | 2 +- server/grpc/grpc.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/grpc/grpc.go b/client/grpc/grpc.go index b067d826..9a1843bc 100644 --- a/client/grpc/grpc.go +++ b/client/grpc/grpc.go @@ -33,7 +33,7 @@ type grpcClient struct { func init() { encoding.RegisterCodec(wrapCodec{jsonCodec{}}) - encoding.RegisterCodec(wrapCodec{jsonCodec{}}) + encoding.RegisterCodec(wrapCodec{protoCodec{}}) encoding.RegisterCodec(wrapCodec{bytesCodec{}}) } diff --git a/network/router/options.go b/network/router/options.go index 9c5581d4..0d525f76 100644 --- a/network/router/options.go +++ b/network/router/options.go @@ -67,6 +67,6 @@ func DefaultOptions() Options { Address: DefaultAddress, Registry: registry.DefaultRegistry, Table: NewTable(), - Network: "local", + Network: "local", } } diff --git a/server/grpc/grpc.go b/server/grpc/grpc.go index 2f6e1d40..4ff4b79f 100644 --- a/server/grpc/grpc.go +++ b/server/grpc/grpc.go @@ -56,8 +56,8 @@ type grpcServer struct { } func init() { - encoding.RegisterCodec(wrapCodec{protoCodec{}}) encoding.RegisterCodec(wrapCodec{jsonCodec{}}) + encoding.RegisterCodec(wrapCodec{protoCodec{}}) encoding.RegisterCodec(wrapCodec{bytesCodec{}}) } From 67e3d560fe5c06cf540cc9768997c8521ed9d362 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 27 Jun 2019 14:37:52 +0100 Subject: [PATCH 068/287] Lookup every service. FML --- network/router/default_router.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/network/router/default_router.go b/network/router/default_router.go index b342666e..7c682150 100644 --- a/network/router/default_router.go +++ b/network/router/default_router.go @@ -107,7 +107,20 @@ func (r *router) addServiceRoutes(reg registry.Registry, network string, metric // add each service node as a separate route; for _, service := range services { - for _, node := range service.Nodes { + // get the service to retrieve all its info + srvs, err := reg.GetService(service.Name) + if err != nil { + continue + } + + // create a flat slide of nodes + var nodes []*registry.Node + for _, s := range srvs { + nodes = append(nodes, s.Nodes...) + } + + // range over the flat slice of nodes + for _, node := range nodes { gw := node.Address if node.Port > 0 { gw = fmt.Sprintf("%s:%d", node.Address, node.Port) From b4b76d452a06af8b713ad0eb27e408367507d615 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 27 Jun 2019 14:38:12 +0100 Subject: [PATCH 069/287] Call advertise --- network/proxy/mucp/mucp.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/network/proxy/mucp/mucp.go b/network/proxy/mucp/mucp.go index dcc19a73..aeecead1 100644 --- a/network/proxy/mucp/mucp.go +++ b/network/proxy/mucp/mucp.go @@ -131,6 +131,8 @@ func (p *Proxy) getRoute(service string) ([]string, error) { // no router is specified we're going to set the default if len(name) == 0 && len(addr) == 0 { p.Router = router.DefaultRouter + go p.Router.Advertise() + // recursively execute getRoute return p.getRoute(service) } @@ -170,7 +172,7 @@ func (p *Proxy) getRoute(service string) ([]string, error) { } var pbRoutes *pb.LookupResponse - var err error + var gerr error // set default client if p.RouterService == nil { @@ -180,20 +182,23 @@ func (p *Proxy) getRoute(service string) ([]string, error) { // TODO: implement backoff and retries for _, addr := range addrs { // call the router - pbRoutes, err = p.RouterService.Lookup(context.Background(), &pb.LookupRequest{ + proutes, err := p.RouterService.Lookup(context.Background(), &pb.LookupRequest{ Query: &pb.Query{ Destination: service, }, }, client.WithAddress(addr)) if err != nil { + gerr = err continue } + // set routes + pbRoutes = proutes break } // errored out - if err != nil { - return nil, err + if gerr != nil { + return nil, gerr } // no routes @@ -340,6 +345,8 @@ func NewProxy(opts ...options.Option) proxy.Proxy { r, ok := p.Options.Values().Get("proxy.router") if ok { p.Router = r.(router.Router) + // TODO: should we advertise? + go p.Router.Advertise() } return p From d8e998ad85feac9288dd34dfb2dd75ce66bde6f4 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 27 Jun 2019 14:53:01 +0100 Subject: [PATCH 070/287] add peer in context --- server/grpc/grpc.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/server/grpc/grpc.go b/server/grpc/grpc.go index 4ff4b79f..6575d3b6 100644 --- a/server/grpc/grpc.go +++ b/server/grpc/grpc.go @@ -28,6 +28,7 @@ import ( "google.golang.org/grpc/credentials" "google.golang.org/grpc/encoding" "google.golang.org/grpc/metadata" + "google.golang.org/grpc/peer" "google.golang.org/grpc/status" ) @@ -203,6 +204,12 @@ func (g *grpcServer) handler(srv interface{}, stream grpc.ServerStream) error { // create new context ctx := meta.NewContext(stream.Context(), md) + // get peer from context + if p, ok := peer.FromContext(stream.Context()); ok { + md["Remote"] = p.Addr.String() + ctx = peer.NewContext(ctx, p) + } + // set the timeout if we have it if len(to) > 0 { if n, err := strconv.ParseUint(to, 10, 64); err == nil { From 0899282277c6f7f6ee45c7c0d3225ac81dfea44f Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 1 Jul 2019 11:55:15 +0100 Subject: [PATCH 071/287] Checkpoint networking code --- network/default.go | 608 ++++++++++++++++++++++++++++++++- network/network.go | 65 +++- network/proto/network.micro.go | 21 ++ network/proto/network.pb.go | 197 +++++++++++ network/proto/network.proto | 27 ++ 5 files changed, 895 insertions(+), 23 deletions(-) create mode 100644 network/proto/network.micro.go create mode 100644 network/proto/network.pb.go create mode 100644 network/proto/network.proto diff --git a/network/default.go b/network/default.go index 8ee82b04..4262da8d 100644 --- a/network/default.go +++ b/network/default.go @@ -1,26 +1,47 @@ package network import ( + "crypto/sha256" + "fmt" + "io" + "runtime/debug" "sync" + "time" + gproto "github.com/golang/protobuf/proto" + "github.com/google/uuid" + "github.com/micro/go-micro/codec" + "github.com/micro/go-micro/codec/proto" "github.com/micro/go-micro/config/options" "github.com/micro/go-micro/network/proxy" + "github.com/micro/go-micro/network/resolver" "github.com/micro/go-micro/network/router" + "github.com/micro/go-micro/registry" + "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/util/log" + + pb "github.com/micro/go-micro/network/proto" + nreg "github.com/micro/go-micro/network/resolver/registry" ) type network struct { options.Options - // router - r router.Router + // resolver use to connect to the network + resolver resolver.Resolver - // proxy - p proxy.Proxy + // router used to find routes in the network + router router.Router + + // proxy used to route through the network + proxy proxy.Proxy // id of this network id string // links maintained for this network + // based on peers not nodes. maybe maintain + // node separately or note that links have nodes mtx sync.RWMutex links []Link } @@ -28,31 +49,233 @@ type network struct { type node struct { *network + // closed channel + closed chan bool + + mtx sync.RWMutex + + // the node id + id string + // address of this node address string + + // the node registry + registry registry.Registry + + // the base level transport + transport transport.Transport + + // the listener + listener transport.Listener + + // leases for connections to us + // link id:link + links map[string]*link } type link struct { // the embedded node *node + // the link id + id string + + // queue buffer for this link + queue chan *Message + + // the socket for this link + socket *socket + + // the lease for this link + lease *pb.Lease + // length and weight of the link - mtx sync.RWMutex + mtx sync.RWMutex + + // determines the cost of the link + // based on queue length and roundtrip length int weight int } +type socket struct { + node *node + codec codec.Marshaler + socket transport.Socket +} + // network methods +// lease generates a new lease with a node id/address +// TODO: use a consensus mechanism, pool or some deterministic +// unique prefixing method. +func (n *network) lease() *pb.Lease { + // create the id + id := uuid.New().String() + // create a timestamp + now := time.Now().UnixNano() + // create the address + h := sha256.New() + h.Write([]byte(fmt.Sprintf("%s-%d\n", id, now))) + address := fmt.Sprintf("%x", h.Sum(nil)) + + // return the node + return &pb.Lease{ + Id: id, + Timestamp: now, + Node: &pb.Node{ + Id: id, + Address: address, + }, + } +} + +// lookup returns a list of network records in priority order of local +func (n *network) lookup(r registry.Registry) []*resolver.Record { + // create a registry resolver to find local nodes + rr := nreg.Resolver{Registry: r} + + // get all the nodes for the network that are local + localRecords, err := rr.Resolve("network:" + n.Id()) + if err != nil { + // we're not in a good place here + } + + // if its a local network we never try lookup anything else + if n.Id() == "local" { + return localRecords + } + + // now resolve incrementally based on resolvers specified + networkRecords, err := n.resolver.Resolve(n.Id()) + if err != nil { + // still not in a good place + } + + // return aggregate records + return append(localRecords, networkRecords...) +} + func (n *network) Id() string { return n.id } +// Connect connects to the network and returns a new node. +// The node is the callers connection to the network. They +// should advertise this address to people. Anyone else +// on the network should be able to route to it. func (n *network) Connect() (Node, error) { - return nil, nil + // create a new node + node := new(node) + // closed channel + node.closed = make(chan bool) + // set the nodes network + node.network = n + + // initially we have no id + // create an id and address + // TODO: create a real unique id and address + // lease := n.lease() + // set the node id + // node.id = lease.Node.Id + + // get the transport we're going to use for our tunnels + t, ok := n.Options.Values().Get("network.transport") + if ok { + node.transport = t.(transport.Transport) + } else { + // TODO: set to quic + node.transport = transport.DefaultTransport + } + + // start the node + + // we listen on a random address, this is not advertised + // TODO: use util/addr to get something anyone in the same private network can talk to + l, err := node.transport.Listen(":0") + if err != nil { + return nil, err + } + // set the listener + node.listener = l + + // TODO: this should be an overlay address + // ideally received via some dhcp style broadcast + node.address = l.Addr() + + // TODO: start the router and broadcast advertisements + // receive updates and push them to the network in accept(l) below + // chan, err := n.router.Advertise() + // u <- chan + // socket.send("route", u) + // u := socket.recv() => r.router.Update(u) + + // process any incoming messages on the listener + // this is our inbound network connection + node.accept(l) + + // register the node with the registry for the network + // TODO: use a registrar or something else for local things + r, ok := n.Options.Values().Get("network.registry") + if ok { + node.registry = r.(registry.Registry) + } else { + node.registry = registry.DefaultRegistry + } + + // lookup the network to see if there's any nodes + records := n.lookup(node.registry) + + // should we actually do this? + if len(records) == 0 { + // set your own node id + lease := n.lease() + node.id = lease.Node.Id + } + + // register self with the network registry + // this is a local registry of nodes separate to the resolver + // maybe consolidate registry/resolver + // TODO: find a way to do this via gossip or something else + if err := node.registry.Register(®istry.Service{ + // register with the network id + Name: "network:" + n.Id(), + Nodes: []*registry.Node{ + {Id: node.id, Address: node.address}, + }, + }); err != nil { + node.Close() + return nil, err + } + + // create a channel to get links + linkChan := make(chan *link, 1) + + // we're going to wait for the first connection + go node.connect(linkChan) + + // wait forever to connect + // TODO: do something with the links we receive + <-linkChan + + return node, nil } +// TODO: establish links for peering networks func (n *network) Peer(Network) (Link, error) { + // New network was created using NewNetwork after receiving routes from a different node + + // Connect to the new network and be assigned a node + + // Transfer data between the networks + + // take other resolver + // order: registry (local), ...resolver + // resolve the network + + // periodically connect to nodes resolved in the network + // and add to the network links return nil, nil } @@ -64,24 +287,235 @@ func (n *network) Links() ([]Link, error) { // node methods +// Accept processes the incoming messages on its listener. +// This listener was created with the first call to network.Connect. +// Any inbound new socket here is essentially something else attempting +// to connect to the network. So we turn it into a socket, then process it. +func (n *node) accept(l transport.Listener) error { + return l.Accept(func(sock transport.Socket) { + defer func() { + // close socket + sock.Close() + + if r := recover(); r != nil { + log.Log("panic recovered: ", r) + log.Log(string(debug.Stack())) + } + }() + + // create a new link + // generate a new link + link := &link{ + node: n, + id: uuid.New().String(), + } + // create a new network socket + sk := new(socket) + sk.node = n + sk.codec = proto.Marshaler{} + sk.socket = sock + + // set link socket + link.socket = sk + + // accept messages on the socket + // blocks forever or until error + if err := link.up(); err != nil { + // TODO: delete link + } + }) +} + +// connect attempts to periodically connect to new nodes in the network. +// It will only do this if it has less than 3 connections. this method +// is called by network.Connect and fired in a go routine after establishing +// the first connection and creating a node. The node attempts to maintain +// its connection to the network via multiple links. +func (n *node) connect(linkChan chan *link) { + // TODO: adjustable ticker + t := time.NewTicker(time.Second) + var lease *pb.Lease + + for { + select { + // on every tick check the number of links and then attempt + // to connect to new nodes if we don't have sufficient links + case <-t.C: + n.mtx.RLock() + + // only start processing if we have less than 3 links + if len(n.links) > 2 { + n.mtx.RUnlock() + continue + } + + // get a list of link addresses so we don't reconnect + // to the ones we're already connected to + nodes := map[string]bool{} + for _, l := range n.links { + nodes[l.lease.Node.Address] = true + } + + n.mtx.RUnlock() + + records := n.network.lookup(n.registry) + + // for each record check we haven't already got a connection + // attempt to dial it, create a new socket and call + // connect with our existing network lease. + // if its the first call we don't actually have a lease + + // TODO: determine how to prioritise local records + // while still connecting to the global network + for _, record := range records { + // skip existing connections + if nodes[record.Address] { + continue + } + + // attempt to connect and create a link + + // connect to the node + s, err := n.transport.Dial(record.Address) + if err != nil { + continue + } + + // create a new socket + sk := &socket{ + node: n, + codec: &proto.Marshaler{}, + socket: s, + } + + // broadcast a "connect" request and get back "lease" + // this is your tunnel to the outside world and to the network + // then push updates and messages over this link + // first connect will not have a lease so we get one with node id/address + l, err := sk.connect(lease) + if err != nil { + s.Close() + continue + } + + // set lease for next time + lease = l + + // create a new link with the lease and socket + link := &link{ + id: uuid.New().String(), + lease: lease, + node: n, + queue: make(chan *Message, 128), + socket: sk, + } + + // bring up the link + go link.up() + + // save the new link + n.mtx.Lock() + n.links[link.id] = link + n.mtx.Unlock() + + // drop this down the link channel to the network + // so it can manage the links + select { + case linkChan <- link: + // we don't wait for anyone + default: + } + } + case <-n.closed: + return + } + } +} + func (n *node) Address() string { return n.address } +// Close shutdowns all the links and closes the listener func (n *node) Close() error { + select { + case <-n.closed: + return nil + default: + close(n.closed) + // shutdown all the links + n.mtx.Lock() + for id, link := range n.links { + link.down() + delete(n.links, id) + } + n.mtx.Unlock() + // deregister self + n.registry.Deregister(®istry.Service{ + Name: "network:" + n.network.Id(), + Nodes: []*registry.Node{ + {Id: n.id, Address: n.address}, + }, + }) + return n.listener.Close() + } return nil } func (n *node) Accept() (*Message, error) { + // process the inbound cruft + return nil, nil } -func (n *node) Send(*Message) error { - return nil +func (n *node) Links() ([]Link, error) { + n.mtx.RLock() + defer n.mtx.RUnlock() + + var links []Link + for _, l := range n.links { + links = append(links, l) + } + return links, nil +} + +func (n *node) Network() Network { + return n.network +} + +func (n *node) Send(m *Message) error { + n.mtx.RLock() + defer n.mtx.RUnlock() + + var gerr error + + // send to all links + // TODO: be smarter + for _, link := range n.links { + // TODO: process the error, do some link flap detection + // blackhold the connection, etc + if err := link.socket.send(m, nil); err != nil { + gerr = err + continue + } + } + + return gerr } // link methods +// bring up the link +func (l *link) up() error { + // TODO: manage the length/weight of the link + return l.socket.accept() +} + +// kill the link +func (l *link) down() error { + return l.socket.close() +} + func (l *link) Length() int { l.mtx.RLock() defer l.mtx.RUnlock() @@ -93,3 +527,161 @@ func (l *link) Weight() int { defer l.mtx.RUnlock() return l.weight } + +// accept is the state machine that processes messages on the socket +func (s *socket) accept() error { + for { + m := new(transport.Message) + err := s.socket.Recv(m) + if err == io.EOF { + return nil + } + if err != nil { + return err + } + + // TODO: pick a reliable header + event := m.Header["Micro-Method"] + + switch event { + // connect event + case "connect": + // process connect events from network.Connect() + // these are new connections to join the network + + // decode the connection event + conn := new(pb.Connect) + if err := s.codec.Unmarshal(m.Body, conn); err != nil { + // skip error + continue + } + + // get the existing lease if it exists + lease := conn.Lease + if lease == nil { + // create a new lease/node + lease = s.node.network.lease() + } + + // send back a lease offer for the node + if err := s.send(&Message{ + Header: map[string]string{ + "Micro-Method": "lease", + }, + }, lease); err != nil { + return err + } + + // record this mapping of socket to node/lease + s.node.mtx.Lock() + id := uuid.New().String() + s.node.links[id] = &link{ + node: s.node, + id: id, + lease: lease, + queue: make(chan *Message, 128), + socket: s, + } + s.node.mtx.Unlock() + // a route update + case "route": + // process router events + + // received a lease + case "lease": + // no op as we don't process lease events on existing connections + // these are in response to a connect message + default: + // process all other messages + } + } +} + +func (s *socket) close() error { + return s.socket.Close() +} + +// connect sends a connect request and waits on a lease. +// this is for a new connection. in the event we send +// an existing lease, the same lease should be returned. +// if it differs then we assume our address for this link +// is different... +func (s *socket) connect(l *pb.Lease) (*pb.Lease, error) { + // send a lease request + if err := s.send(&Message{ + Header: map[string]string{ + "Micro-Method": "connect", + }, + }, &pb.Connect{Lease: l}); err != nil { + return nil, err + } + + // create the new things + tm := new(Message) + lease := new(pb.Lease) + + // wait for a lease response + if err := s.recv(tm, lease); err != nil { + return nil, err + } + + return lease, nil +} + +func (s *socket) send(m *Message, v interface{}) error { + tm := new(transport.Message) + tm.Header = m.Header + tm.Body = m.Body + + // set the body if not nil + // we're assuming this is network message + if v != nil { + // encode the data + b, err := s.codec.Marshal(v) + if err != nil { + return err + } + + // set the content type + tm.Header["Content-Type"] = "application/protobuf" + // set the marshalled body + tm.Body = b + } + + // send via the transport socket + return s.socket.Send(&transport.Message{ + Header: m.Header, + Body: m.Body, + }) +} + +func (s *socket) recv(m *Message, v interface{}) error { + if m.Header == nil { + m.Header = make(map[string]string) + } + + tm := new(transport.Message) + + // receive the transport message + if err := s.socket.Recv(tm); err != nil { + return err + } + + // set the message + m.Header = tm.Header + m.Body = tm.Body + + // bail early + if v == nil { + return nil + } + + // try unmarshal the body + // skip if there's no content-type + if tm.Header["Content-Type"] != "application/protobuf" { + return nil + } + + // return unmarshalled + return s.codec.Unmarshal(m.Body, v.(gproto.Message)) +} diff --git a/network/network.go b/network/network.go index 098c0807..dfa0116b 100644 --- a/network/network.go +++ b/network/network.go @@ -3,9 +3,14 @@ package network import ( "github.com/micro/go-micro/config/options" + "github.com/micro/go-micro/network/proxy" + "github.com/micro/go-micro/network/proxy/mucp" + "github.com/micro/go-micro/network/resolver" + "github.com/micro/go-micro/network/resolver/registry" + "github.com/micro/go-micro/network/router" ) -// Network is an interface defining a network +// Network defines a network interface type Network interface { options.Options // Id of this node @@ -14,16 +19,20 @@ type Network interface { Connect() (Node, error) // Peer with a neighboring network Peer(Network) (Link, error) - // Retrieve list of connections + // Retrieve list of peers Links() ([]Link, error) } // Node represents a single node on a network type Node interface { - // Node is a network. Network is a node. - Network + // Id of the node + Id() string // Address of the node Address() string + // The network of the node + Network() Network + // Links to other nodes + Links() ([]Link, error) // Close the network connection Close() error // Accept messages on the network @@ -36,9 +45,9 @@ type Node interface { type Link interface { // remote node the link is to Node - // length of link which dictates speed + // length defines the speed or distance of the link Length() int - // weight of link which dictates curvature + // weight defines the saturation or usage of the link Weight() int } @@ -47,29 +56,55 @@ type Message struct { // Headers which provide local/remote info Header map[string]string // The opaque data being sent - Data []byte + Body []byte } var ( // The default network ID is local - DefaultNetworkId = "local" + DefaultId = "local" // just the standard network element DefaultNetwork = NewNetwork() ) -// NewNetwork returns a new network +// NewNetwork returns a new network interface func NewNetwork(opts ...options.Option) Network { options := options.NewOptions(opts...) + // new network instance + net := &network{ + id: DefaultId, + } + + // get network id + id, ok := options.Values().Get("network.id") + if ok { + net.id = id.(string) + } + // get router + r, ok := options.Values().Get("network.router") + if ok { + net.router = r.(router.Router) + } else { + net.router = router.DefaultRouter + } // get proxy - - return &network{ - Options: options, - // fill the blanks - // router: r, - // proxy: p, + p, ok := options.Values().Get("network.proxy") + if ok { + net.proxy = p.(proxy.Proxy) + } else { + net.proxy = new(mucp.Proxy) } + + // get resolver + res, ok := options.Values().Get("network.resolver") + if ok { + net.resolver = res.(resolver.Resolver) + } else { + net.resolver = new(registry.Resolver) + } + + return net } diff --git a/network/proto/network.micro.go b/network/proto/network.micro.go new file mode 100644 index 00000000..96883952 --- /dev/null +++ b/network/proto/network.micro.go @@ -0,0 +1,21 @@ +// Code generated by protoc-gen-micro. DO NOT EDIT. +// source: micro/go-micro/network/proto/network.proto + +package go_micro_network + +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package diff --git a/network/proto/network.pb.go b/network/proto/network.pb.go new file mode 100644 index 00000000..d8368e42 --- /dev/null +++ b/network/proto/network.pb.go @@ -0,0 +1,197 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: micro/go-micro/network/proto/network.proto + +package go_micro_network + +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +// A connect message is for connecting to the network +type Connect struct { + // Lease specifies an existing lease to indicate + // we don't need a new address, we just want to + // establish a link. + Lease *Lease `protobuf:"bytes,1,opt,name=lease,proto3" json:"lease,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Connect) Reset() { *m = Connect{} } +func (m *Connect) String() string { return proto.CompactTextString(m) } +func (*Connect) ProtoMessage() {} +func (*Connect) Descriptor() ([]byte, []int) { + return fileDescriptor_4daa91d05ddc28b6, []int{0} +} + +func (m *Connect) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Connect.Unmarshal(m, b) +} +func (m *Connect) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Connect.Marshal(b, m, deterministic) +} +func (m *Connect) XXX_Merge(src proto.Message) { + xxx_messageInfo_Connect.Merge(m, src) +} +func (m *Connect) XXX_Size() int { + return xxx_messageInfo_Connect.Size(m) +} +func (m *Connect) XXX_DiscardUnknown() { + xxx_messageInfo_Connect.DiscardUnknown(m) +} + +var xxx_messageInfo_Connect proto.InternalMessageInfo + +func (m *Connect) GetLease() *Lease { + if m != nil { + return m.Lease + } + return nil +} + +// A lease is returned to anyone attempting to connect. +type Lease struct { + // unique lease id + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // timestamp of lease + Timestamp int64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + // the node + Node *Node `protobuf:"bytes,3,opt,name=node,proto3" json:"node,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Lease) Reset() { *m = Lease{} } +func (m *Lease) String() string { return proto.CompactTextString(m) } +func (*Lease) ProtoMessage() {} +func (*Lease) Descriptor() ([]byte, []int) { + return fileDescriptor_4daa91d05ddc28b6, []int{1} +} + +func (m *Lease) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Lease.Unmarshal(m, b) +} +func (m *Lease) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Lease.Marshal(b, m, deterministic) +} +func (m *Lease) XXX_Merge(src proto.Message) { + xxx_messageInfo_Lease.Merge(m, src) +} +func (m *Lease) XXX_Size() int { + return xxx_messageInfo_Lease.Size(m) +} +func (m *Lease) XXX_DiscardUnknown() { + xxx_messageInfo_Lease.DiscardUnknown(m) +} + +var xxx_messageInfo_Lease proto.InternalMessageInfo + +func (m *Lease) GetId() string { + if m != nil { + return m.Id + } + return "" +} + +func (m *Lease) GetTimestamp() int64 { + if m != nil { + return m.Timestamp + } + return 0 +} + +func (m *Lease) GetNode() *Node { + if m != nil { + return m.Node + } + return nil +} + +// A node is the network node +type Node struct { + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Node) Reset() { *m = Node{} } +func (m *Node) String() string { return proto.CompactTextString(m) } +func (*Node) ProtoMessage() {} +func (*Node) Descriptor() ([]byte, []int) { + return fileDescriptor_4daa91d05ddc28b6, []int{2} +} + +func (m *Node) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Node.Unmarshal(m, b) +} +func (m *Node) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Node.Marshal(b, m, deterministic) +} +func (m *Node) XXX_Merge(src proto.Message) { + xxx_messageInfo_Node.Merge(m, src) +} +func (m *Node) XXX_Size() int { + return xxx_messageInfo_Node.Size(m) +} +func (m *Node) XXX_DiscardUnknown() { + xxx_messageInfo_Node.DiscardUnknown(m) +} + +var xxx_messageInfo_Node proto.InternalMessageInfo + +func (m *Node) GetId() string { + if m != nil { + return m.Id + } + return "" +} + +func (m *Node) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func init() { + proto.RegisterType((*Connect)(nil), "go.micro.network.Connect") + proto.RegisterType((*Lease)(nil), "go.micro.network.Lease") + proto.RegisterType((*Node)(nil), "go.micro.network.Node") +} + +func init() { + proto.RegisterFile("micro/go-micro/network/proto/network.proto", fileDescriptor_4daa91d05ddc28b6) +} + +var fileDescriptor_4daa91d05ddc28b6 = []byte{ + // 192 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x8f, 0x3d, 0x4b, 0xc0, 0x30, + 0x10, 0x86, 0xe9, 0x97, 0xa5, 0x27, 0x88, 0x64, 0xd0, 0x0c, 0x0e, 0xa5, 0x53, 0x29, 0x34, 0x15, + 0x5d, 0xdc, 0x5d, 0xc5, 0x21, 0xff, 0x20, 0x36, 0x47, 0x09, 0xda, 0x5c, 0x49, 0x02, 0xfe, 0x7d, + 0xe9, 0xd5, 0x0f, 0xb0, 0x5b, 0x9e, 0x37, 0xcf, 0xdd, 0xcb, 0xc1, 0xb0, 0xba, 0x39, 0xd0, 0xb4, + 0xd0, 0x78, 0x3c, 0x3c, 0xa6, 0x4f, 0x0a, 0xef, 0xd3, 0x16, 0x28, 0xfd, 0x92, 0x62, 0x12, 0xd7, + 0x0b, 0x29, 0xb6, 0xd4, 0x77, 0xde, 0x3d, 0x41, 0xfd, 0x4c, 0xde, 0xe3, 0x9c, 0xc4, 0x08, 0xd5, + 0x07, 0x9a, 0x88, 0x32, 0x6b, 0xb3, 0xfe, 0xf2, 0xe1, 0x56, 0xfd, 0x97, 0xd5, 0xcb, 0xfe, 0xad, + 0x0f, 0xab, 0x33, 0x50, 0x31, 0x8b, 0x2b, 0xc8, 0x9d, 0xe5, 0xa1, 0x46, 0xe7, 0xce, 0x8a, 0x3b, + 0x68, 0x92, 0x5b, 0x31, 0x26, 0xb3, 0x6e, 0x32, 0x6f, 0xb3, 0xbe, 0xd0, 0x7f, 0x81, 0x18, 0xa0, + 0xf4, 0x64, 0x51, 0x16, 0x5c, 0x72, 0x73, 0x2e, 0x79, 0x25, 0x8b, 0x9a, 0x9d, 0xee, 0x1e, 0xca, + 0x9d, 0x4e, 0x0d, 0x12, 0x6a, 0x63, 0x6d, 0xc0, 0x18, 0x79, 0x7f, 0xa3, 0x7f, 0xf0, 0xed, 0x82, + 0xef, 0x7c, 0xfc, 0x0a, 0x00, 0x00, 0xff, 0xff, 0x48, 0x8c, 0x11, 0x91, 0x15, 0x01, 0x00, 0x00, +} diff --git a/network/proto/network.proto b/network/proto/network.proto new file mode 100644 index 00000000..26cf2cbc --- /dev/null +++ b/network/proto/network.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; + +package go.micro.network; + +// A connect message is for connecting to the network +message Connect { + // Lease specifies an existing lease to indicate + // we don't need a new address, we just want to + // establish a link. + Lease lease = 1; +} + +// A lease is returned to anyone attempting to connect. +message Lease { + // unique lease id + string id = 1; + // timestamp of lease + int64 timestamp = 2; + // the node + Node node = 3; +} + +// A node is the network node +message Node { + string id = 1; + string address = 2; +} From 9d7420658d9ea223e3564b7cdd09dbc8213d122e Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Thu, 27 Jun 2019 22:52:51 +0100 Subject: [PATCH 072/287] Changed router interface. Added table watcher. Advertise routes * Changed router interface to return Advertisement channel * Added default gateway route to the routing table if supplied * Watch table for updates and advertise to the network * We hash the routes on 3-tuple (Destination, Gateway, Network) --- network/router/default_router.go | 158 +++++++++++++++++++++++++------ network/router/default_table.go | 8 +- network/router/options.go | 14 ++- network/router/route.go | 8 +- network/router/router.go | 23 +++-- network/router/table_watcher.go | 3 +- 6 files changed, 172 insertions(+), 42 deletions(-) diff --git a/network/router/default_router.go b/network/router/default_router.go index 7c682150..ae55ee9f 100644 --- a/network/router/default_router.go +++ b/network/router/default_router.go @@ -11,16 +11,15 @@ import ( // router provides default router implementation type router struct { - opts Options - exit chan struct{} - wg *sync.WaitGroup + opts Options + started bool + advertChan chan *Advertisement + exit chan struct{} + wg *sync.WaitGroup } // newRouter creates new router and returns it func newRouter(opts ...Option) Router { - // TODO: we need to add default GW entry here - // Should default GW be part of router options? - // get default options options := DefaultOptions() @@ -30,9 +29,11 @@ func newRouter(opts ...Option) Router { } return &router{ - opts: options, - exit: make(chan struct{}), - wg: &sync.WaitGroup{}, + opts: options, + started: false, + advertChan: make(chan *Advertisement), + exit: make(chan struct{}), + wg: &sync.WaitGroup{}, } } @@ -69,43 +70,106 @@ func (r *router) Network() string { return r.opts.Network } -// Advertise advertises the routes to the network. It is a blocking function. +// Advertise advertises the routes to the network. // It returns error if any of the launched goroutines fail with error. -func (r *router) Advertise() error { - // add local service routes into the routing table - if err := r.addServiceRoutes(r.opts.Registry, "local", DefaultLocalMetric); err != nil { - return fmt.Errorf("failed adding routes: %v", err) +func (r *router) Advertise() (<-chan *Advertisement, error) { + if !r.started { + // add local service routes into the routing table + if err := r.addServiceRoutes(r.opts.Registry, "local", DefaultLocalMetric); err != nil { + return nil, fmt.Errorf("failed adding routes: %v", err) + } + + // add default gateway into routing table + if r.opts.Gateway != "" { + // note, the only non-default value is the gateway + route := Route{ + Destination: "*", + Gateway: r.opts.Gateway, + Router: "*", + Network: "*", + Metric: DefaultLocalMetric, + } + if err := r.opts.Table.Add(route); err != nil { + return nil, fmt.Errorf("error adding default gateway route: %s", err) + } + } + + // routing table watcher that watches all routes being added + tableWatcher, err := r.opts.Table.Watch(WatchDestination("*")) + if err != nil { + return nil, fmt.Errorf("failed to create routing table watcher: %v", err) + } + + // registry watcher + regWatcher, err := r.opts.Registry.Watch() + if err != nil { + return nil, fmt.Errorf("failed to create registry watcher: %v", err) + } + + // error channel collecting goroutine errors + errChan := make(chan error, 2) + + r.wg.Add(1) + go func() { + defer r.wg.Done() + // watch local registry and register routes in routine table + errChan <- r.manageServiceRoutes(regWatcher, DefaultLocalMetric) + }() + + r.wg.Add(1) + go func() { + defer r.wg.Done() + // watch local registry and register routes in routine table + errChan <- r.watchTable(tableWatcher) + }() + + go func() { + select { + // wait for exit chan + case <-r.exit: + // wait for error + case <-errChan: + // TODO: we're missing the error context here + // might have to log it here as we don't send it down + } + + // close the advertise channel + close(r.advertChan) + }() + + // mark the router as started + r.started = true } - localWatcher, err := r.opts.Registry.Watch() - if err != nil { - return fmt.Errorf("failed to create registry watcher: %v", err) + return r.advertChan, nil +} + +// Update updates the routing table using the advertised values +func (r *router) Update(a *Advertisement) error { + // we extract the route from advertisement and update the routing table + route := Route{ + Destination: a.Event.Route.Destination, + Gateway: a.Event.Route.Gateway, + Router: a.Event.Route.Router, + Network: a.Event.Route.Network, + Metric: a.Event.Route.Metric, + Policy: AddIfNotExists, } - // error channel collecting goroutine errors - errChan := make(chan error, 1) - - r.wg.Add(1) - go func() { - defer r.wg.Done() - // watch local registry and register routes in routine table - errChan <- r.manageServiceRoutes(localWatcher, DefaultLocalMetric) - }() - - return <-errChan + return r.opts.Table.Update(route) } // addServiceRoutes adds all services in given registry to the routing table. // NOTE: this is a one-off operation done when bootstrapping the routing table // It returns error if either the services failed to be listed or -// if the routes could not be added to the routing table. +// if any of the the routes could not be added to the routing table. func (r *router) addServiceRoutes(reg registry.Registry, network string, metric int) error { services, err := reg.ListServices() if err != nil { return fmt.Errorf("failed to list services: %v", err) } - // add each service node as a separate route; + // add each service node as a separate route for _, service := range services { // get the service to retrieve all its info srvs, err := reg.GetService(service.Name) @@ -190,6 +254,40 @@ func (r *router) manageServiceRoutes(w registry.Watcher, metric int) error { return watchErr } +// watchTable watches routing table entries and either adds or deletes locally registered service to/from network registry +// It returns error if the locally registered services either fails to be added/deleted to/from network registry. +func (r *router) watchTable(w Watcher) error { + // wait in the background for the router to stop + // when the router stops, stop the watcher and exit + r.wg.Add(1) + go func() { + defer r.wg.Done() + <-r.exit + w.Stop() + }() + + var watchErr error + + for { + event, err := w.Next() + if err == ErrWatcherStopped { + break + } + + if err != nil { + watchErr = err + break + } + + r.advertChan <- &Advertisement{ + ID: r.ID(), + Event: event, + } + } + + return watchErr +} + // Stop stops the router func (r *router) Stop() error { // notify all goroutines to finish diff --git a/network/router/default_table.go b/network/router/default_table.go index 196ca4bf..d68398ad 100644 --- a/network/router/default_table.go +++ b/network/router/default_table.go @@ -129,6 +129,12 @@ func (t *table) Update(r Route) error { // check if the destAddr has ANY routes in the table if _, ok := t.m[destAddr]; !ok { + if r.Policy == AddIfNotExists { + t.m[destAddr] = make(map[uint64]Route) + t.m[destAddr][sum] = r + go t.sendEvent(&Event{Type: CreateEvent, Route: r}) + return nil + } return ErrRouteNotFound } @@ -279,7 +285,7 @@ func (t *table) String() string { // hash hashes the route using router gateway and network address func (t *table) hash(r Route) uint64 { t.h.Reset() - t.h.Write([]byte(r.Destination + r.Gateway + r.Router + r.Network)) + t.h.Write([]byte(r.Destination + r.Gateway + r.Network)) return t.h.Sum64() } diff --git a/network/router/options.go b/network/router/options.go index 0d525f76..2426fa32 100644 --- a/network/router/options.go +++ b/network/router/options.go @@ -8,6 +8,8 @@ import ( var ( // DefaultAddress is default router address DefaultAddress = ":9093" + // DefaultNetwork is default micro network + DefaultNetwork = "local" ) // Options are router options @@ -18,6 +20,8 @@ type Options struct { Address string // Network is micro network Network string + // Gateway is micro network gateway + Gateway string // Registry is the local registry Registry registry.Registry // Table is routing table @@ -45,6 +49,13 @@ func Network(n string) Option { } } +// Gateway sets network gateway +func Gateway(g string) Option { + return func(o *Options) { + o.Gateway = g + } +} + // RoutingTable sets the routing table func RoutingTable(t Table) Option { return func(o *Options) { @@ -61,12 +72,11 @@ func Registry(r registry.Registry) Option { // DefaultOptions returns router default options func DefaultOptions() Options { - // NOTE: by default both local and network registies use default registry i.e. mdns return Options{ ID: uuid.New().String(), Address: DefaultAddress, + Network: DefaultNetwork, Registry: registry.DefaultRegistry, Table: NewTable(), - Network: "local", } } diff --git a/network/router/route.go b/network/router/route.go index d52c2688..1f45b688 100644 --- a/network/router/route.go +++ b/network/router/route.go @@ -20,6 +20,8 @@ type RoutePolicy int const ( // OverrideIfExists overrides route if it already exists OverrideIfExists RoutePolicy = iota + // AddIfNotExist adds the route if it does not exist + AddIfNotExists // IgnoreIfExists instructs to not modify existing route IgnoreIfExists ) @@ -28,9 +30,11 @@ const ( func (p RoutePolicy) String() string { switch p { case OverrideIfExists: - return "OVERRIDE" + return "OVERRIDE_IF_EXISTS" + case AddIfNotExists: + return "ADD_IF_NOT_EXISTS" case IgnoreIfExists: - return "IGNORE" + return "IGNORE_IF_EXISTS" default: return "UNKNOWN" } diff --git a/network/router/router.go b/network/router/router.go index 366c2fbf..a8772768 100644 --- a/network/router/router.go +++ b/network/router/router.go @@ -1,6 +1,11 @@ // Package router provides a network routing control plane package router +var ( + // DefaultRouter is default network router + DefaultRouter = NewRouter() +) + // Router is an interface for a routing control plane type Router interface { // Init initializes the router with options @@ -15,21 +20,27 @@ type Router interface { Address() string // Network returns the network address of the router Network() string - // Advertise starts advertising the routes to the network - Advertise() error + // Advertise starts advertising routes to the network + Advertise() (<-chan *Advertisement, error) + // Update updates the routing table + Update(*Advertisement) error // Stop stops the router Stop() error // String returns debug info String() string } +// Advertisement is sent by the router to the network +type Advertisement struct { + // ID is the source router ID + ID string + // Event defines advertisement even + Event *Event +} + // Option used by the router type Option func(*Options) -var ( - DefaultRouter = NewRouter() -) - // NewRouter creates new Router and returns it func NewRouter(opts ...Option) Router { return newRouter(opts...) diff --git a/network/router/table_watcher.go b/network/router/table_watcher.go index 97d1f1b7..4e9d9a9e 100644 --- a/network/router/table_watcher.go +++ b/network/router/table_watcher.go @@ -81,7 +81,7 @@ type tableWatcher struct { } // Next returns the next noticed action taken on table -// TODO: this needs to be thought through properly; we only allow watching particular route destination +// TODO: this needs to be thought through properly; we only allow watching particular route destination for now func (w *tableWatcher) Next() (*Event, error) { for { select { @@ -93,6 +93,7 @@ func (w *tableWatcher) Next() (*Event, error) { if w.opts.Destination == res.Route.Destination { return res, nil } + continue } case <-w.done: return nil, ErrWatcherStopped From 8ad2f73ad6b94e991b35b1b0fa3c2fae6e84e660 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Fri, 28 Jun 2019 11:53:55 +0100 Subject: [PATCH 073/287] Advertisement is now Update; started bit is now running. --- network/router/default_router.go | 34 +++++++++++++++++++++----------- network/router/router.go | 12 +++++++---- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/network/router/default_router.go b/network/router/default_router.go index ae55ee9f..18544b6e 100644 --- a/network/router/default_router.go +++ b/network/router/default_router.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" "sync" + "time" "github.com/micro/go-micro/registry" "github.com/olekukonko/tablewriter" @@ -12,8 +13,8 @@ import ( // router provides default router implementation type router struct { opts Options - started bool - advertChan chan *Advertisement + running bool + advertChan chan *Update exit chan struct{} wg *sync.WaitGroup } @@ -30,8 +31,8 @@ func newRouter(opts ...Option) Router { return &router{ opts: options, - started: false, - advertChan: make(chan *Advertisement), + running: false, + advertChan: make(chan *Update), exit: make(chan struct{}), wg: &sync.WaitGroup{}, } @@ -72,8 +73,8 @@ func (r *router) Network() string { // Advertise advertises the routes to the network. // It returns error if any of the launched goroutines fail with error. -func (r *router) Advertise() (<-chan *Advertisement, error) { - if !r.started { +func (r *router) Advertise() (<-chan *Update, error) { + if !r.running { // add local service routes into the routing table if err := r.addServiceRoutes(r.opts.Registry, "local", DefaultLocalMetric); err != nil { return nil, fmt.Errorf("failed adding routes: %v", err) @@ -135,17 +136,19 @@ func (r *router) Advertise() (<-chan *Advertisement, error) { // close the advertise channel close(r.advertChan) + // mark the router as stopped + r.running = false }() - // mark the router as started - r.started = true + // mark the router as running + r.running = true } return r.advertChan, nil } // Update updates the routing table using the advertised values -func (r *router) Update(a *Advertisement) error { +func (r *router) Update(a *Update) error { // we extract the route from advertisement and update the routing table route := Route{ Destination: a.Event.Route.Destination, @@ -279,9 +282,16 @@ func (r *router) watchTable(w Watcher) error { break } - r.advertChan <- &Advertisement{ - ID: r.ID(), - Event: event, + u := &Update{ + ID: r.ID(), + Timestamp: time.Now(), + Event: event, + } + + select { + case <-r.exit: + return nil + case r.advertChan <- u: } } diff --git a/network/router/router.go b/network/router/router.go index a8772768..9aa8789a 100644 --- a/network/router/router.go +++ b/network/router/router.go @@ -1,6 +1,8 @@ // Package router provides a network routing control plane package router +import "time" + var ( // DefaultRouter is default network router DefaultRouter = NewRouter() @@ -21,19 +23,21 @@ type Router interface { // Network returns the network address of the router Network() string // Advertise starts advertising routes to the network - Advertise() (<-chan *Advertisement, error) + Advertise() (<-chan *Update, error) // Update updates the routing table - Update(*Advertisement) error + Update(*Update) error // Stop stops the router Stop() error // String returns debug info String() string } -// Advertisement is sent by the router to the network -type Advertisement struct { +// Update is sent by the router to the network +type Update struct { // ID is the source router ID ID string + // Timestamp marks the time when update is sent + Timestamp time.Time // Event defines advertisement even Event *Event } From 32300eadc1a90cb1fff09f8f072d622414c738f9 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Fri, 28 Jun 2019 18:35:53 +0100 Subject: [PATCH 074/287] Added Router Status which allows to track router status --- network/router/default_router.go | 45 ++++++++++++++++++++------------ network/router/router.go | 38 ++++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 18 deletions(-) diff --git a/network/router/default_router.go b/network/router/default_router.go index 18544b6e..cddd1169 100644 --- a/network/router/default_router.go +++ b/network/router/default_router.go @@ -13,10 +13,11 @@ import ( // router provides default router implementation type router struct { opts Options - running bool + status Status advertChan chan *Update exit chan struct{} wg *sync.WaitGroup + sync.RWMutex } // newRouter creates new router and returns it @@ -31,7 +32,7 @@ func newRouter(opts ...Option) Router { return &router{ opts: options, - running: false, + status: Status{Error: nil, Code: Stopped}, advertChan: make(chan *Update), exit: make(chan struct{}), wg: &sync.WaitGroup{}, @@ -74,7 +75,10 @@ func (r *router) Network() string { // Advertise advertises the routes to the network. // It returns error if any of the launched goroutines fail with error. func (r *router) Advertise() (<-chan *Update, error) { - if !r.running { + r.Lock() + defer r.Unlock() + + if r.status.Code != Running { // add local service routes into the routing table if err := r.addServiceRoutes(r.opts.Registry, "local", DefaultLocalMetric); err != nil { return nil, fmt.Errorf("failed adding routes: %v", err) @@ -91,11 +95,11 @@ func (r *router) Advertise() (<-chan *Update, error) { Metric: DefaultLocalMetric, } if err := r.opts.Table.Add(route); err != nil { - return nil, fmt.Errorf("error adding default gateway route: %s", err) + return nil, fmt.Errorf("error to add default gateway route: %s", err) } } - // routing table watcher that watches all routes being added + // routing table watcher which watches all routes i.e. to every destination tableWatcher, err := r.opts.Table.Watch(WatchDestination("*")) if err != nil { return nil, fmt.Errorf("failed to create routing table watcher: %v", err) @@ -120,28 +124,27 @@ func (r *router) Advertise() (<-chan *Update, error) { r.wg.Add(1) go func() { defer r.wg.Done() - // watch local registry and register routes in routine table + // watch local registry and register routes in routing table errChan <- r.watchTable(tableWatcher) }() + r.wg.Add(1) go func() { + defer r.wg.Done() select { // wait for exit chan case <-r.exit: - // wait for error - case <-errChan: - // TODO: we're missing the error context here - // might have to log it here as we don't send it down + r.status.Code = Stopped + case err := <-errChan: + r.status.Code = Error + r.status.Error = err } - // close the advertise channel close(r.advertChan) - // mark the router as stopped - r.running = false }() // mark the router as running - r.running = true + r.status.Code = Running } return r.advertChan, nil @@ -188,13 +191,13 @@ func (r *router) addServiceRoutes(reg registry.Registry, network string, metric // range over the flat slice of nodes for _, node := range nodes { - gw := node.Address + gateway := node.Address if node.Port > 0 { - gw = fmt.Sprintf("%s:%d", node.Address, node.Port) + gateway = fmt.Sprintf("%s:%d", node.Address, node.Port) } route := Route{ Destination: service.Name, - Gateway: gw, + Gateway: gateway, Router: r.opts.Address, Network: r.opts.Network, Metric: metric, @@ -298,6 +301,14 @@ func (r *router) watchTable(w Watcher) error { return watchErr } +// Status returns router status +func (r *router) Status() Status { + r.RLock() + defer r.RUnlock() + + return r.status +} + // Stop stops the router func (r *router) Stop() error { // notify all goroutines to finish diff --git a/network/router/router.go b/network/router/router.go index 9aa8789a..23da4b06 100644 --- a/network/router/router.go +++ b/network/router/router.go @@ -26,6 +26,8 @@ type Router interface { Advertise() (<-chan *Update, error) // Update updates the routing table Update(*Update) error + // Status returns router status + Status() Status // Stop stops the router Stop() error // String returns debug info @@ -34,7 +36,7 @@ type Router interface { // Update is sent by the router to the network type Update struct { - // ID is the source router ID + // ID is the router ID ID string // Timestamp marks the time when update is sent Timestamp time.Time @@ -42,6 +44,40 @@ type Update struct { Event *Event } +// StatusCode defines router status +type StatusCode int + +// Status is router status +type Status struct { + // Error is router error + Error error + // Code defines router status + Code StatusCode +} + +const ( + // Running means the rotuer is running + Running StatusCode = iota + // Error means the router has crashed with error + Error + // Stopped means the router has stopped + Stopped +) + +// String returns human readable status code +func (sc StatusCode) String() string { + switch sc { + case Running: + return "RUNNING" + case Error: + return "ERROR" + case Stopped: + return "STOPPED" + default: + return "UNKNOWN" + } +} + // Option used by the router type Option func(*Options) From cff46c3fd8edecf37883005db57d4338139b5911 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Sat, 29 Jun 2019 00:46:22 +0100 Subject: [PATCH 075/287] Added Init state. Recreate exit and advertise channels when recovering In order to differentiate between intialized and other states we introduced a new state: Init. The router is in this state only when it's created. We have cleaned up router status management which is now handled by manageStatus function only. --- network/router/default_router.go | 232 ++++++++++++++++++------------- network/router/router.go | 8 +- 2 files changed, 138 insertions(+), 102 deletions(-) diff --git a/network/router/default_router.go b/network/router/default_router.go index cddd1169..91f9e2a2 100644 --- a/network/router/default_router.go +++ b/network/router/default_router.go @@ -32,7 +32,7 @@ func newRouter(opts ...Option) Router { return &router{ opts: options, - status: Status{Error: nil, Code: Stopped}, + status: Status{Error: nil, Code: Init}, advertChan: make(chan *Update), exit: make(chan struct{}), wg: &sync.WaitGroup{}, @@ -72,99 +72,6 @@ func (r *router) Network() string { return r.opts.Network } -// Advertise advertises the routes to the network. -// It returns error if any of the launched goroutines fail with error. -func (r *router) Advertise() (<-chan *Update, error) { - r.Lock() - defer r.Unlock() - - if r.status.Code != Running { - // add local service routes into the routing table - if err := r.addServiceRoutes(r.opts.Registry, "local", DefaultLocalMetric); err != nil { - return nil, fmt.Errorf("failed adding routes: %v", err) - } - - // add default gateway into routing table - if r.opts.Gateway != "" { - // note, the only non-default value is the gateway - route := Route{ - Destination: "*", - Gateway: r.opts.Gateway, - Router: "*", - Network: "*", - Metric: DefaultLocalMetric, - } - if err := r.opts.Table.Add(route); err != nil { - return nil, fmt.Errorf("error to add default gateway route: %s", err) - } - } - - // routing table watcher which watches all routes i.e. to every destination - tableWatcher, err := r.opts.Table.Watch(WatchDestination("*")) - if err != nil { - return nil, fmt.Errorf("failed to create routing table watcher: %v", err) - } - - // registry watcher - regWatcher, err := r.opts.Registry.Watch() - if err != nil { - return nil, fmt.Errorf("failed to create registry watcher: %v", err) - } - - // error channel collecting goroutine errors - errChan := make(chan error, 2) - - r.wg.Add(1) - go func() { - defer r.wg.Done() - // watch local registry and register routes in routine table - errChan <- r.manageServiceRoutes(regWatcher, DefaultLocalMetric) - }() - - r.wg.Add(1) - go func() { - defer r.wg.Done() - // watch local registry and register routes in routing table - errChan <- r.watchTable(tableWatcher) - }() - - r.wg.Add(1) - go func() { - defer r.wg.Done() - select { - // wait for exit chan - case <-r.exit: - r.status.Code = Stopped - case err := <-errChan: - r.status.Code = Error - r.status.Error = err - } - // close the advertise channel - close(r.advertChan) - }() - - // mark the router as running - r.status.Code = Running - } - - return r.advertChan, nil -} - -// Update updates the routing table using the advertised values -func (r *router) Update(a *Update) error { - // we extract the route from advertisement and update the routing table - route := Route{ - Destination: a.Event.Route.Destination, - Gateway: a.Event.Route.Gateway, - Router: a.Event.Route.Router, - Network: a.Event.Route.Network, - Metric: a.Event.Route.Metric, - Policy: AddIfNotExists, - } - - return r.opts.Table.Update(route) -} - // addServiceRoutes adds all services in given registry to the routing table. // NOTE: this is a one-off operation done when bootstrapping the routing table // It returns error if either the services failed to be listed or @@ -301,21 +208,145 @@ func (r *router) watchTable(w Watcher) error { return watchErr } +// manageStatus manages router status +func (r *router) manageStatus(errChan <-chan error) { + defer r.wg.Done() + + r.Lock() + r.status.Code = Running + r.status.Error = nil + r.Unlock() + + var code StatusCode + var err error + + select { + case <-r.exit: + code = Stopped + case err = <-errChan: + code = Error + } + + r.Lock() + defer r.Unlock() + r.status.Code = code + r.status.Error = err + + // close the advertise channel + close(r.advertChan) + + // stop the router if some error happened + // this will notify all watcher goroutines to stop + if err != nil && code != Stopped { + close(r.exit) + } +} + +// Advertise advertises the routes to the network. +// It returns error if any of the launched goroutines fail with error. +func (r *router) Advertise() (<-chan *Update, error) { + r.Lock() + defer r.Unlock() + + if r.status.Code != Running { + // add local service routes into the routing table + if err := r.addServiceRoutes(r.opts.Registry, "local", DefaultLocalMetric); err != nil { + return nil, fmt.Errorf("failed adding routes: %v", err) + } + // add default gateway into routing table + if r.opts.Gateway != "" { + // note, the only non-default value is the gateway + route := Route{ + Destination: "*", + Gateway: r.opts.Gateway, + Router: "*", + Network: "*", + Metric: DefaultLocalMetric, + } + if err := r.opts.Table.Add(route); err != nil { + return nil, fmt.Errorf("error to add default gateway route: %s", err) + } + } + + // NOTE: we only need to recreate the exit/advertChan if the router errored or was stopped + if r.status.Code == Error || r.status.Code == Stopped { + r.exit = make(chan struct{}) + r.advertChan = make(chan *Update) + } + + // routing table watcher which watches all routes i.e. to every destination + tableWatcher, err := r.opts.Table.Watch(WatchDestination("*")) + if err != nil { + return nil, fmt.Errorf("failed to create routing table watcher: %v", err) + } + // registry watcher + regWatcher, err := r.opts.Registry.Watch() + if err != nil { + return nil, fmt.Errorf("failed to create registry watcher: %v", err) + } + + // error channel collecting goroutine errors + errChan := make(chan error, 2) + + r.wg.Add(1) + go func() { + defer r.wg.Done() + // watch local registry and register routes in routine table + errChan <- r.manageServiceRoutes(regWatcher, DefaultLocalMetric) + }() + + r.wg.Add(1) + go func() { + defer r.wg.Done() + // watch local registry and register routes in routing table + errChan <- r.watchTable(tableWatcher) + }() + + r.wg.Add(1) + go r.manageStatus(errChan) + } + + return r.advertChan, nil +} + +// Update updates the routing table using the advertised values +func (r *router) Update(a *Update) error { + // we extract the route from advertisement and update the routing table + route := Route{ + Destination: a.Event.Route.Destination, + Gateway: a.Event.Route.Gateway, + Router: a.Event.Route.Router, + Network: a.Event.Route.Network, + Metric: a.Event.Route.Metric, + Policy: AddIfNotExists, + } + + return r.opts.Table.Update(route) +} + // Status returns router status func (r *router) Status() Status { r.RLock() defer r.RUnlock() - return r.status + // make a copy of the status + status := r.status + + return status } // Stop stops the router func (r *router) Stop() error { - // notify all goroutines to finish - close(r.exit) + r.RLock() + defer r.RUnlock() - // wait for all goroutines to finish - r.wg.Wait() + // only close the channel if the router is running + if r.status.Code == Running { + // notify all goroutines to finish + close(r.exit) + // wait for all goroutines to finish + r.wg.Wait() + } return nil } @@ -325,13 +356,14 @@ func (r *router) String() string { sb := &strings.Builder{} table := tablewriter.NewWriter(sb) - table.SetHeader([]string{"ID", "Address", "Network", "Table"}) + table.SetHeader([]string{"ID", "Address", "Network", "Table", "Status"}) data := []string{ r.opts.ID, r.opts.Address, r.opts.Network, fmt.Sprintf("%d", r.opts.Table.Size()), + r.status.Code.String(), } table.Append(data) diff --git a/network/router/router.go b/network/router/router.go index 23da4b06..e45c0baa 100644 --- a/network/router/router.go +++ b/network/router/router.go @@ -56,8 +56,10 @@ type Status struct { } const ( - // Running means the rotuer is running - Running StatusCode = iota + // Init means the rotuer has just been initialized + Init StatusCode = iota + // Running means the router is running + Running // Error means the router has crashed with error Error // Stopped means the router has stopped @@ -67,6 +69,8 @@ const ( // String returns human readable status code func (sc StatusCode) String() string { switch sc { + case Init: + return "INITIALIZED" case Running: return "RUNNING" case Error: From f6e064cdbd1d363b4ff018a81a5b85ebce1bc981 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Mon, 1 Jul 2019 15:43:50 +0100 Subject: [PATCH 076/287] Fixed router idempotency. Return registry.ErrWatchStopped from mdns reg --- network/router/default_router.go | 63 +++++++++++++++++--------------- network/router/table_watcher.go | 2 +- registry/mdns_watcher.go | 3 +- 3 files changed, 36 insertions(+), 32 deletions(-) diff --git a/network/router/default_router.go b/network/router/default_router.go index 91f9e2a2..5c7b73ae 100644 --- a/network/router/default_router.go +++ b/network/router/default_router.go @@ -134,12 +134,10 @@ func (r *router) manageServiceRoutes(w registry.Watcher, metric int) error { for { res, err := w.Next() - if err == registry.ErrWatcherStopped { - break - } - if err != nil { - watchErr = err + if err != registry.ErrWatcherStopped { + watchErr = err + } break } @@ -181,14 +179,13 @@ func (r *router) watchTable(w Watcher) error { var watchErr error +exit: for { event, err := w.Next() - if err == ErrWatcherStopped { - break - } - if err != nil { - watchErr = err + if err != ErrWatcherStopped { + watchErr = err + } break } @@ -200,23 +197,21 @@ func (r *router) watchTable(w Watcher) error { select { case <-r.exit: - return nil + break exit case r.advertChan <- u: } } + // close the advertisement channel + close(r.advertChan) + return watchErr } -// manageStatus manages router status -func (r *router) manageStatus(errChan <-chan error) { +// watchError watches router errors +func (r *router) watchError(errChan <-chan error) { defer r.wg.Done() - r.Lock() - r.status.Code = Running - r.status.Error = nil - r.Unlock() - var code StatusCode var err error @@ -229,14 +224,13 @@ func (r *router) manageStatus(errChan <-chan error) { r.Lock() defer r.Unlock() - r.status.Code = code - r.status.Error = err - - // close the advertise channel - close(r.advertChan) + status := Status{ + Code: code, + Error: err, + } + r.status = status // stop the router if some error happened - // this will notify all watcher goroutines to stop if err != nil && code != Stopped { close(r.exit) } @@ -303,7 +297,14 @@ func (r *router) Advertise() (<-chan *Update, error) { }() r.wg.Add(1) - go r.manageStatus(errChan) + go r.watchError(errChan) + + // mark router as running and set its Error to nil + status := Status{ + Code: Running, + Error: nil, + } + r.status = status } return r.advertChan, nil @@ -338,15 +339,19 @@ func (r *router) Status() Status { // Stop stops the router func (r *router) Stop() error { r.RLock() - defer r.RUnlock() - // only close the channel if the router is running if r.status.Code == Running { // notify all goroutines to finish close(r.exit) - // wait for all goroutines to finish - r.wg.Wait() } + r.RUnlock() + + // drain the advertise channel + for range r.advertChan { + } + + // wait for all goroutines to finish + r.wg.Wait() return nil } diff --git a/network/router/table_watcher.go b/network/router/table_watcher.go index 4e9d9a9e..91411247 100644 --- a/network/router/table_watcher.go +++ b/network/router/table_watcher.go @@ -9,7 +9,7 @@ import ( var ( // ErrWatcherStopped is returned when routing table watcher has been stopped - ErrWatcherStopped = errors.New("routing table watcher stopped") + ErrWatcherStopped = errors.New("watcher stopped") ) // EventType defines routing table event diff --git a/registry/mdns_watcher.go b/registry/mdns_watcher.go index 7ccb6e80..bbcf90ea 100644 --- a/registry/mdns_watcher.go +++ b/registry/mdns_watcher.go @@ -1,7 +1,6 @@ package registry import ( - "errors" "strings" "github.com/micro/mdns" @@ -63,7 +62,7 @@ func (m *mdnsWatcher) Next() (*Result, error) { Service: service, }, nil case <-m.exit: - return nil, errors.New("watcher stopped") + return nil, ErrWatcherStopped } } } From ddee8412ff6cd5b8759d1e75039366beb0bb1705 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 1 Jul 2019 18:37:39 +0100 Subject: [PATCH 077/287] Add tunnel interface --- network/tunnel/default.go | 229 ++++++++++++++++++++++++++++++++++ network/tunnel/socket.go | 82 ++++++++++++ network/tunnel/socket_test.go | 62 +++++++++ network/tunnel/tunnel.go | 64 ++++++++++ 4 files changed, 437 insertions(+) create mode 100644 network/tunnel/default.go create mode 100644 network/tunnel/socket.go create mode 100644 network/tunnel/socket_test.go create mode 100644 network/tunnel/tunnel.go diff --git a/network/tunnel/default.go b/network/tunnel/default.go new file mode 100644 index 00000000..41c9778b --- /dev/null +++ b/network/tunnel/default.go @@ -0,0 +1,229 @@ +package tunnel + +import ( + "crypto/sha256" + "errors" + "fmt" + "sync" + + "github.com/google/uuid" + "github.com/micro/go-micro/transport" +) + +// tun represents a network tunnel +type tun struct { + // interface to use + net Interface + + // connect + mtx sync.RWMutex + connected bool + + // the send channel + send chan *message + // close channel + closed chan bool + + // sockets + sockets map[string]*socket +} + +// create new tunnel +func newTunnel(net Interface) *tun { + return &tun{ + net: net, + send: make(chan *message, 128), + closed: make(chan bool), + sockets: make(map[string]*socket), + } +} + +func (t *tun) getSocket(id string) (*socket, bool) { + // get the socket + t.mtx.RLock() + s, ok := t.sockets[id] + t.mtx.RUnlock() + return s, ok +} + +func (t *tun) newSocket(id string) *socket { + // new id if it doesn't exist + if len(id) == 0 { + id = uuid.New().String() + } + + // hash the id + h := sha256.New() + h.Write([]byte(id)) + id = fmt.Sprintf("%x", h.Sum(nil)) + + // new socket + s := &socket{ + id: id, + closed: make(chan bool), + recv: make(chan *message, 128), + send: t.send, + } + + // save socket + t.mtx.Lock() + t.sockets[id] = s + t.mtx.Unlock() + + // return socket + return s +} + +// process outgoing messages +func (t *tun) process() { + // manage the send buffer + // all pseudo sockets throw everything down this + for { + select { + case msg := <-t.send: + nmsg := &Message{ + Header: msg.data.Header, + Body: msg.data.Body, + } + + // set the stream id on the outgoing message + nmsg.Header["Micro-Stream"] = msg.id + + // send the message via the interface + if err := t.net.Send(nmsg); err != nil { + // no op + // TODO: do something + } + case <-t.closed: + return + } + } +} + +// process incoming messages +func (t *tun) listen() { + for { + // process anything via the net interface + msg, err := t.net.Recv() + if err != nil { + return + } + + // a stream id + id := msg.Header["Micro-Stream"] + + // get the socket + s, exists := t.getSocket(id) + if !exists { + // no op + continue + } + + // is the socket closed? + select { + case <-s.closed: + // closed + delete(t.sockets, id) + continue + default: + // process + } + + // is the socket new? + select { + // if its new it will block here + case <-s.wait: + // its not new + default: + // its new + // set remote address of the socket + s.remote = msg.Header["Remote"] + close(s.wait) + } + + tmsg := &transport.Message{ + Header: msg.Header, + Body: msg.Body, + } + + // TODO: don't block on queuing + // append to recv backlog + s.recv <- &message{id: id, data: tmsg} + } +} + +// Close the tunnel +func (t *tun) Close() error { + t.mtx.Lock() + defer t.mtx.Unlock() + + if !t.connected { + return nil + } + + select { + case <-t.closed: + return nil + default: + // close all the sockets + for _, s := range t.sockets { + s.Close() + } + // close the connection + close(t.closed) + t.connected = false + } + + return nil +} + +// Connect the tunnel +func (t *tun) Connect() error { + t.mtx.Lock() + defer t.mtx.Unlock() + + // already connected + if t.connected { + return nil + } + + // set as connected + t.connected = true + // create new close channel + t.closed = make(chan bool) + + // process messages to be sent + go t.process() + // process incoming messages + go t.listen() + + return nil +} + +// Dial an address +func (t *tun) Dial(addr string) (Conn, error) { + c := t.newSocket(addr) + // set remote + c.remote = addr + // set local + c.local = t.net.Addr() + return c, nil +} + +func (t *tun) Accept(addr string) (Conn, error) { + c := t.newSocket(addr) + // set remote + c.remote = t.net.Addr() + // set local + c.local = addr + + select { + case <-c.closed: + return nil, errors.New("error creating socket") + // wait for the first message + case <-c.wait: + } + + // return socket + return c, nil +} diff --git a/network/tunnel/socket.go b/network/tunnel/socket.go new file mode 100644 index 00000000..e0ce1350 --- /dev/null +++ b/network/tunnel/socket.go @@ -0,0 +1,82 @@ +package tunnel + +import ( + "errors" + + "github.com/micro/go-micro/transport" +) + +// socket is our pseudo socket for transport.Socket +type socket struct { + // socket id based on Micro-Stream + id string + // closed + closed chan bool + // remote addr + remote string + // local addr + local string + // send chan + send chan *message + // recv chan + recv chan *message + // wait until we have a connection + wait chan bool +} + +// message is sent over the send channel +type message struct { + // socket id + id string + // transport data + data *transport.Message +} + +func (s *socket) Remote() string { + return s.remote +} + +func (s *socket) Local() string { + return s.local +} + +func (s *socket) Id() string { + return s.id +} + +func (s *socket) Send(m *transport.Message) error { + select { + case <-s.closed: + return errors.New("socket is closed") + default: + // no op + } + // append to backlog + s.send <- &message{id: s.id, data: m} + return nil +} + +func (s *socket) Recv(m *transport.Message) error { + select { + case <-s.closed: + return errors.New("socket is closed") + default: + // no op + } + // recv from backlog + msg := <-s.recv + // set message + *m = *msg.data + // return nil + return nil +} + +func (s *socket) Close() error { + select { + case <-s.closed: + // no op + default: + close(s.closed) + } + return nil +} diff --git a/network/tunnel/socket_test.go b/network/tunnel/socket_test.go new file mode 100644 index 00000000..37c1aeaa --- /dev/null +++ b/network/tunnel/socket_test.go @@ -0,0 +1,62 @@ +package tunnel + +import ( + "testing" + + "github.com/micro/go-micro/transport" +) + +func TestTunnelSocket(t *testing.T) { + s := &socket{ + id: "1", + closed: make(chan bool), + remote: "remote", + local: "local", + send: make(chan *message, 1), + recv: make(chan *message, 1), + wait: make(chan bool), + } + + // check addresses local and remote + if s.Local() != s.local { + t.Fatalf("Expected s.Local %s got %s", s.local, s.Local()) + } + if s.Remote() != s.remote { + t.Fatalf("Expected s.Remote %s got %s", s.remote, s.Remote()) + } + + // send a message + s.Send(&transport.Message{Header: map[string]string{}}) + + // get sent message + msg := <-s.send + + if msg.id != s.id { + t.Fatalf("Expected sent message id %s got %s", s.id, msg.id) + } + + // recv a message + msg.data.Header["Foo"] = "bar" + s.recv <- msg + + m := new(transport.Message) + s.Recv(m) + + // check header + if m.Header["Foo"] != "bar" { + t.Fatalf("Did not receive correct message %+v", m) + } + + // close the connection + s.Close() + + // check connection + err := s.Send(m) + if err == nil { + t.Fatal("Expected closed connection") + } + err = s.Recv(m) + if err == nil { + t.Fatal("Expected closed connection") + } +} diff --git a/network/tunnel/tunnel.go b/network/tunnel/tunnel.go new file mode 100644 index 00000000..1f7cd2b7 --- /dev/null +++ b/network/tunnel/tunnel.go @@ -0,0 +1,64 @@ +// Package tunnel provides a network tunnel +package tunnel + +import ( + "github.com/micro/go-micro/config/options" + "github.com/micro/go-micro/transport" +) + +// Tunnel creates a network tunnel +type Tunnel interface { + // Connect connects the tunnel + Connect() error + // Close closes the tunnel + Close() error + // Dial an endpoint + Dial(addr string) (Conn, error) + // Accept connections + Accept(addr string) (Conn, error) +} + +// Conn return a transport socket with a unique id. +// This means Conn can be used as a transport.Socket +type Conn interface { + // Unique id of the connection + Id() string + // Underlying socket + transport.Socket +} + +// A network interface to use for sending/receiving. +// When Tunnel.Connect is called it starts processing +// messages over the interface. +type Interface interface { + // Address of the interface + Addr() string + // Receive new messages + Recv() (*Message, error) + // Send messages + Send(*Message) error +} + +// Messages received over the interface +type Message struct { + Header map[string]string + Body []byte +} + +// NewTunnel creates a new tunnel +func NewTunnel(opts ...options.Option) Tunnel { + options := options.NewOptions(opts...) + + i, ok := options.Values().Get("tunnel.net") + if !ok { + // wtf + return nil + } + + return newTunnel(i.(Interface)) +} + +// WithInterface passes in the interface +func WithInterface(net Interface) options.Option { + return options.WithValue("tunnel.net", net) +} From da299ea26b0004cff2a0968db97b9684e9e05378 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Mon, 1 Jul 2019 20:33:08 +0100 Subject: [PATCH 078/287] Simmplified RT Lookup. No more Metric in Query. --- network/router/default_router.go | 11 +++--- network/router/default_table.go | 62 ++++++++++++++++---------------- network/router/query.go | 30 +++++----------- 3 files changed, 47 insertions(+), 56 deletions(-) diff --git a/network/router/default_router.go b/network/router/default_router.go index 5c7b73ae..322402ef 100644 --- a/network/router/default_router.go +++ b/network/router/default_router.go @@ -232,7 +232,11 @@ func (r *router) watchError(errChan <-chan error) { // stop the router if some error happened if err != nil && code != Stopped { + // this will stop watchers which will close r.advertChan close(r.exit) + // drain the advertise channel + for range r.advertChan { + } } } @@ -343,13 +347,12 @@ func (r *router) Stop() error { if r.status.Code == Running { // notify all goroutines to finish close(r.exit) + // drain the advertise channel + for range r.advertChan { + } } r.RUnlock() - // drain the advertise channel - for range r.advertChan { - } - // wait for all goroutines to finish r.wg.Wait() diff --git a/network/router/default_table.go b/network/router/default_table.go index d68398ad..ad4510dd 100644 --- a/network/router/default_table.go +++ b/network/router/default_table.go @@ -163,44 +163,44 @@ func (t *table) List() ([]Route, error) { return routes, nil } -// Lookup queries routing table and returns all routes that match it +// isMatch checks if the route matches given network and router +func isMatch(route Route, network, router string) bool { + if network == "*" || network == route.Network { + if router == "*" || router == route.Router { + return true + } + } + return false +} + +// findRoutes finds all the routes for given network and router and returns them +func findRoutes(routes map[uint64]Route, network, router string) []Route { + var results []Route + for _, route := range routes { + if isMatch(route, network, router) { + results = append(results, route) + } + } + return results +} + +// Lookup queries routing table and returns all routes that match the lookup query func (t *table) Lookup(q Query) ([]Route, error) { t.RLock() defer t.RUnlock() - var results []Route - - for destAddr, routes := range t.m { - if q.Options().Destination != "*" { - if q.Options().Destination != destAddr { - continue - } - for _, route := range routes { - if q.Options().Network == "*" || q.Options().Network == route.Network { - if q.Options().Router == "*" { - if route.Metric <= q.Options().Metric { - results = append(results, route) - } - } - } - } - } - - if q.Options().Destination == "*" { - for _, route := range routes { - if q.Options().Network == "*" || q.Options().Network == route.Network { - if q.Options().Router == "*" { - if route.Metric <= q.Options().Metric { - results = append(results, route) - } - } - } - } + if q.Options().Destination != "*" { + // no routes found for the destination and query policy is not a DiscardIfNone + if _, ok := t.m[q.Options().Destination]; !ok && q.Options().Policy != DiscardIfNone { + return nil, ErrRouteNotFound } + return findRoutes(t.m[q.Options().Destination], q.Options().Network, q.Options().Router), nil } - if len(results) == 0 && q.Options().Policy != DiscardIfNone { - return nil, ErrRouteNotFound + var results []Route + // search through all destinations + for _, routes := range t.m { + results = append(results, findRoutes(routes, q.Options().Network, q.Options().Router)...) } return results, nil diff --git a/network/router/query.go b/network/router/query.go index c479f9db..befdd1d9 100644 --- a/network/router/query.go +++ b/network/router/query.go @@ -36,44 +36,35 @@ type QueryOption func(*QueryOptions) type QueryOptions struct { // Destination is destination address Destination string - // Router is router address - Router string // Network is network address Network string - // Metric is route metric - Metric int + // Router is router address + Router string // Policy is query lookup policy Policy LookupPolicy } -// QueryDestination sets query destination address -func QueryDestination(a string) QueryOption { +// QueryDestination sets destination address +func QueryDestination(d string) QueryOption { return func(o *QueryOptions) { - o.Destination = a + o.Destination = d } } -// QueryNetwork sets query network address +// QueryNetwork sets route network address func QueryNetwork(a string) QueryOption { return func(o *QueryOptions) { o.Network = a } } -// QueryRouter sets query gateway address +// QueryRouter sets route router address func QueryRouter(r string) QueryOption { return func(o *QueryOptions) { o.Router = r } } -// QueryMetric sets query metric -func QueryMetric(m int) QueryOption { - return func(o *QueryOptions) { - o.Metric = m - } -} - // QueryPolicy sets query policy // NOTE: this might be renamed to filter or some such func QueryPolicy(p LookupPolicy) QueryOption { @@ -99,9 +90,7 @@ func NewQuery(opts ...QueryOption) Query { // NOTE: by default we use DefaultNetworkMetric qopts := QueryOptions{ Destination: "*", - Router: "*", Network: "*", - Metric: DefaultNetworkMetric, Policy: DiscardIfNone, } @@ -126,13 +115,12 @@ func (q query) String() string { // create nice table printing structure table := tablewriter.NewWriter(sb) - table.SetHeader([]string{"Destination", "Router", "Network", "Metric", "Policy"}) + table.SetHeader([]string{"Destination", "Network", "Router", "Policy"}) strQuery := []string{ q.opts.Destination, - q.opts.Router, q.opts.Network, - fmt.Sprintf("%d", q.opts.Metric), + q.opts.Router, fmt.Sprintf("%s", q.opts.Policy), } table.Append(strQuery) From fbbc33d0f99a04e2da944a8bd0b483ef05337000 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 1 Jul 2019 22:41:27 +0100 Subject: [PATCH 079/287] Set Network() to string --- network/default.go | 6 ++---- network/network.go | 8 +++++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/network/default.go b/network/default.go index 4262da8d..8fe5362b 100644 --- a/network/default.go +++ b/network/default.go @@ -189,8 +189,6 @@ func (n *network) Connect() (Node, error) { node.transport = transport.DefaultTransport } - // start the node - // we listen on a random address, this is not advertised // TODO: use util/addr to get something anyone in the same private network can talk to l, err := node.transport.Listen(":0") @@ -479,8 +477,8 @@ func (n *node) Links() ([]Link, error) { return links, nil } -func (n *node) Network() Network { - return n.network +func (n *node) Network() string { + return n.network.id } func (n *node) Send(m *Message) error { diff --git a/network/network.go b/network/network.go index dfa0116b..f8b74391 100644 --- a/network/network.go +++ b/network/network.go @@ -10,10 +10,12 @@ import ( "github.com/micro/go-micro/network/router" ) -// Network defines a network interface +// Network defines a network interface. The network is a single +// shared network between all nodes connected to it. The network +// is responsible for routing messages to the correct services. type Network interface { options.Options - // Id of this node + // Id of the network Id() string // Connect to the network Connect() (Node, error) @@ -30,7 +32,7 @@ type Node interface { // Address of the node Address() string // The network of the node - Network() Network + Network() string // Links to other nodes Links() ([]Link, error) // Close the network connection From 8ccf61ebafaa0612c92e85afc9d23077661455cb Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 1 Jul 2019 22:52:28 +0100 Subject: [PATCH 080/287] Strip Link methods --- network/network.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/network/network.go b/network/network.go index f8b74391..45637541 100644 --- a/network/network.go +++ b/network/network.go @@ -21,8 +21,6 @@ type Network interface { Connect() (Node, error) // Peer with a neighboring network Peer(Network) (Link, error) - // Retrieve list of peers - Links() ([]Link, error) } // Node represents a single node on a network @@ -33,8 +31,6 @@ type Node interface { Address() string // The network of the node Network() string - // Links to other nodes - Links() ([]Link, error) // Close the network connection Close() error // Accept messages on the network From 032c3134c6109d7aecb1b981f5db2a5b7c47bfd2 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 1 Jul 2019 22:54:26 +0100 Subject: [PATCH 081/287] update comment --- network/network.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network/network.go b/network/network.go index 45637541..6d619254 100644 --- a/network/network.go +++ b/network/network.go @@ -41,7 +41,7 @@ type Node interface { // Link is a connection between one network and another type Link interface { - // remote node the link is to + // remote node the link is peered with Node // length defines the speed or distance of the link Length() int From ebe3633082ee472e2b8cb32ae76989f0dccf343f Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 1 Jul 2019 22:59:11 +0100 Subject: [PATCH 082/287] move network initialiser code --- network/default.go | 43 +++++++++++++++++++++++++++++++++++++++++++ network/network.go | 44 +------------------------------------------- 2 files changed, 44 insertions(+), 43 deletions(-) diff --git a/network/default.go b/network/default.go index 8fe5362b..24f42206 100644 --- a/network/default.go +++ b/network/default.go @@ -14,6 +14,7 @@ import ( "github.com/micro/go-micro/codec/proto" "github.com/micro/go-micro/config/options" "github.com/micro/go-micro/network/proxy" + "github.com/micro/go-micro/network/proxy/mucp" "github.com/micro/go-micro/network/resolver" "github.com/micro/go-micro/network/router" "github.com/micro/go-micro/registry" @@ -683,3 +684,45 @@ func (s *socket) recv(m *Message, v interface{}) error { // return unmarshalled return s.codec.Unmarshal(m.Body, v.(gproto.Message)) } + +// newNetwork returns a new network interface +func newNetwork(opts ...options.Option) *network { + options := options.NewOptions(opts...) + + // new network instance + net := &network{ + id: DefaultId, + } + + // get network id + id, ok := options.Values().Get("network.id") + if ok { + net.id = id.(string) + } + + // get router + r, ok := options.Values().Get("network.router") + if ok { + net.router = r.(router.Router) + } else { + net.router = router.DefaultRouter + } + + // get proxy + p, ok := options.Values().Get("network.proxy") + if ok { + net.proxy = p.(proxy.Proxy) + } else { + net.proxy = new(mucp.Proxy) + } + + // get resolver + res, ok := options.Values().Get("network.resolver") + if ok { + net.resolver = res.(resolver.Resolver) + } else { + net.resolver = new(nreg.Resolver) + } + + return net +} diff --git a/network/network.go b/network/network.go index 6d619254..c8f998ea 100644 --- a/network/network.go +++ b/network/network.go @@ -3,11 +3,6 @@ package network import ( "github.com/micro/go-micro/config/options" - "github.com/micro/go-micro/network/proxy" - "github.com/micro/go-micro/network/proxy/mucp" - "github.com/micro/go-micro/network/resolver" - "github.com/micro/go-micro/network/resolver/registry" - "github.com/micro/go-micro/network/router" ) // Network defines a network interface. The network is a single @@ -67,42 +62,5 @@ var ( // NewNetwork returns a new network interface func NewNetwork(opts ...options.Option) Network { - options := options.NewOptions(opts...) - - // new network instance - net := &network{ - id: DefaultId, - } - - // get network id - id, ok := options.Values().Get("network.id") - if ok { - net.id = id.(string) - } - - // get router - r, ok := options.Values().Get("network.router") - if ok { - net.router = r.(router.Router) - } else { - net.router = router.DefaultRouter - } - - // get proxy - p, ok := options.Values().Get("network.proxy") - if ok { - net.proxy = p.(proxy.Proxy) - } else { - net.proxy = new(mucp.Proxy) - } - - // get resolver - res, ok := options.Values().Get("network.resolver") - if ok { - net.resolver = res.(resolver.Resolver) - } else { - net.resolver = new(registry.Resolver) - } - - return net + return newNetwork(opts...) } From 5fd798c9b6cf092a9fc30a36dc002aa943b21e43 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 1 Jul 2019 23:11:55 +0100 Subject: [PATCH 083/287] add resolver comment --- network/resolver/resolver.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/network/resolver/resolver.go b/network/resolver/resolver.go index 14b6aeb0..6c54eb95 100644 --- a/network/resolver/resolver.go +++ b/network/resolver/resolver.go @@ -1,6 +1,9 @@ // Package resolver resolves network ids to addresses package resolver +// Resolver is network resolver. It's used to find network nodes +// via id to connect to. This is done based on Network.Id(). +// Before we can be part of any network, we have to connect to it. type Resolver interface { // Resolve returns a list of addresses for an id Resolve(id string) ([]*Record, error) From c108b51d2a03c54fd39be3bfd503a5ea97a8ecaa Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 1 Jul 2019 23:12:05 +0100 Subject: [PATCH 084/287] add network to Node proto --- network/proto/network.pb.go | 35 ++++++++++++++++++++++------------- network/proto/network.proto | 1 + 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/network/proto/network.pb.go b/network/proto/network.pb.go index d8368e42..2d959be3 100644 --- a/network/proto/network.pb.go +++ b/network/proto/network.pb.go @@ -126,6 +126,7 @@ func (m *Lease) GetNode() *Node { type Node struct { Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` + Network string `protobuf:"bytes,3,opt,name=network,proto3" json:"network,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -170,6 +171,13 @@ func (m *Node) GetAddress() string { return "" } +func (m *Node) GetNetwork() string { + if m != nil { + return m.Network + } + return "" +} + func init() { proto.RegisterType((*Connect)(nil), "go.micro.network.Connect") proto.RegisterType((*Lease)(nil), "go.micro.network.Lease") @@ -181,17 +189,18 @@ func init() { } var fileDescriptor_4daa91d05ddc28b6 = []byte{ - // 192 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x8f, 0x3d, 0x4b, 0xc0, 0x30, - 0x10, 0x86, 0xe9, 0x97, 0xa5, 0x27, 0x88, 0x64, 0xd0, 0x0c, 0x0e, 0xa5, 0x53, 0x29, 0x34, 0x15, - 0x5d, 0xdc, 0x5d, 0xc5, 0x21, 0xff, 0x20, 0x36, 0x47, 0x09, 0xda, 0x5c, 0x49, 0x02, 0xfe, 0x7d, - 0xe9, 0xd5, 0x0f, 0xb0, 0x5b, 0x9e, 0x37, 0xcf, 0xdd, 0xcb, 0xc1, 0xb0, 0xba, 0x39, 0xd0, 0xb4, - 0xd0, 0x78, 0x3c, 0x3c, 0xa6, 0x4f, 0x0a, 0xef, 0xd3, 0x16, 0x28, 0xfd, 0x92, 0x62, 0x12, 0xd7, - 0x0b, 0x29, 0xb6, 0xd4, 0x77, 0xde, 0x3d, 0x41, 0xfd, 0x4c, 0xde, 0xe3, 0x9c, 0xc4, 0x08, 0xd5, - 0x07, 0x9a, 0x88, 0x32, 0x6b, 0xb3, 0xfe, 0xf2, 0xe1, 0x56, 0xfd, 0x97, 0xd5, 0xcb, 0xfe, 0xad, - 0x0f, 0xab, 0x33, 0x50, 0x31, 0x8b, 0x2b, 0xc8, 0x9d, 0xe5, 0xa1, 0x46, 0xe7, 0xce, 0x8a, 0x3b, - 0x68, 0x92, 0x5b, 0x31, 0x26, 0xb3, 0x6e, 0x32, 0x6f, 0xb3, 0xbe, 0xd0, 0x7f, 0x81, 0x18, 0xa0, - 0xf4, 0x64, 0x51, 0x16, 0x5c, 0x72, 0x73, 0x2e, 0x79, 0x25, 0x8b, 0x9a, 0x9d, 0xee, 0x1e, 0xca, - 0x9d, 0x4e, 0x0d, 0x12, 0x6a, 0x63, 0x6d, 0xc0, 0x18, 0x79, 0x7f, 0xa3, 0x7f, 0xf0, 0xed, 0x82, - 0xef, 0x7c, 0xfc, 0x0a, 0x00, 0x00, 0xff, 0xff, 0x48, 0x8c, 0x11, 0x91, 0x15, 0x01, 0x00, 0x00, + // 203 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x90, 0xc1, 0x4a, 0xc4, 0x30, + 0x10, 0x86, 0x69, 0x77, 0xd7, 0x25, 0x23, 0x88, 0xe4, 0xa0, 0x39, 0x78, 0x58, 0x7a, 0x2a, 0x85, + 0xa6, 0xa0, 0x17, 0xef, 0xde, 0x44, 0x3c, 0xe4, 0x0d, 0x62, 0x33, 0x94, 0xa0, 0xcd, 0x94, 0x24, + 0xe0, 0xeb, 0x4b, 0xa7, 0xad, 0x82, 0xbd, 0xe5, 0x9b, 0xf9, 0xf3, 0x7f, 0x30, 0xd0, 0x8c, 0xbe, + 0x8f, 0xd4, 0x0d, 0xd4, 0x2e, 0x8f, 0x80, 0xf9, 0x9b, 0xe2, 0x67, 0x37, 0x45, 0xca, 0xbf, 0xa4, + 0x99, 0xe4, 0xed, 0x40, 0x9a, 0x53, 0x7a, 0x9d, 0x57, 0xcf, 0x70, 0x7e, 0xa1, 0x10, 0xb0, 0xcf, + 0xb2, 0x85, 0xd3, 0x17, 0xda, 0x84, 0xaa, 0xb8, 0x14, 0xf5, 0xf5, 0xe3, 0xbd, 0xfe, 0x1f, 0xd6, + 0x6f, 0xf3, 0xda, 0x2c, 0xa9, 0xca, 0xc2, 0x89, 0x59, 0xde, 0x40, 0xe9, 0x1d, 0x7f, 0x12, 0xa6, + 0xf4, 0x4e, 0x3e, 0x80, 0xc8, 0x7e, 0xc4, 0x94, 0xed, 0x38, 0xa9, 0xf2, 0x52, 0xd4, 0x07, 0xf3, + 0x37, 0x90, 0x0d, 0x1c, 0x03, 0x39, 0x54, 0x07, 0x96, 0xdc, 0xed, 0x25, 0xef, 0xe4, 0xd0, 0x70, + 0xa6, 0x7a, 0x85, 0xe3, 0x4c, 0x3b, 0x83, 0x82, 0xb3, 0x75, 0x2e, 0x62, 0x4a, 0xdc, 0x2f, 0xcc, + 0x86, 0xf3, 0x66, 0xed, 0x61, 0x81, 0x30, 0x1b, 0x7e, 0x5c, 0xf1, 0x05, 0x9e, 0x7e, 0x02, 0x00, + 0x00, 0xff, 0xff, 0xf3, 0x2b, 0x3d, 0x08, 0x2f, 0x01, 0x00, 0x00, } diff --git a/network/proto/network.proto b/network/proto/network.proto index 26cf2cbc..2bf9784f 100644 --- a/network/proto/network.proto +++ b/network/proto/network.proto @@ -24,4 +24,5 @@ message Lease { message Node { string id = 1; string address = 2; + string network = 3; } From ffac0b9a181f1a3b2cb212c7d74a17eed28a316e Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Mon, 1 Jul 2019 22:57:27 +0100 Subject: [PATCH 085/287] First batch of Add/Del/Update tests. --- network/router/default_table.go | 13 +- network/router/default_table_test.go | 193 +++++++++++++++++++++++++++ network/router/route.go | 6 +- 3 files changed, 208 insertions(+), 4 deletions(-) create mode 100644 network/router/default_table_test.go diff --git a/network/router/default_table.go b/network/router/default_table.go index ad4510dd..3297c028 100644 --- a/network/router/default_table.go +++ b/network/router/default_table.go @@ -138,6 +138,12 @@ func (t *table) Update(r Route) error { return ErrRouteNotFound } + if _, ok := t.m[destAddr][sum]; !ok && r.Policy == AddIfNotExists { + t.m[destAddr][sum] = r + go t.sendEvent(&Event{Type: CreateEvent, Route: r}) + return nil + } + // if the route has been found update it if _, ok := t.m[destAddr][sum]; ok { t.m[destAddr][sum] = r @@ -248,7 +254,12 @@ func (t *table) Size() int { t.RLock() defer t.RUnlock() - return len(t.m) + size := 0 + for dest, _ := range t.m { + size += len(t.m[dest]) + } + + return size } // String returns debug information diff --git a/network/router/default_table_test.go b/network/router/default_table_test.go new file mode 100644 index 00000000..93f28730 --- /dev/null +++ b/network/router/default_table_test.go @@ -0,0 +1,193 @@ +package router + +import "testing" + +func TestNewTable(t *testing.T) { + table := NewTable() + + if table.Size() != 0 { + t.Errorf("new table should be empty") + } +} + +func TestAdd(t *testing.T) { + table := NewTable() + + if table.Size() != 0 { + t.Errorf("new table should be empty") + } + + route := Route{ + Destination: "dest.svc", + Gateway: "dest.gw", + Router: "dest.router", + Network: "dest.network", + Metric: 10, + } + + if err := table.Add(route); err != nil { + t.Errorf("error adding route: %s", err) + } + + if table.Size() != 1 { + t.Errorf("invalid number of routes. expected: 1, given: %d", table.Size()) + } + + // adds new route for the original destination + route.Gateway = "dest.gw2" + + if err := table.Add(route); err != nil { + t.Errorf("error adding route: %s", err) + } + + if table.Size() != 2 { + t.Errorf("invalid number of routes. expected: 2, given: %d", table.Size()) + } + + // overrides an existing route: the size of the table does not change + route.Metric = 100 + route.Policy = OverrideIfExists + + if err := table.Add(route); err != nil { + t.Errorf("error adding route: %s", err) + } + + if table.Size() != 2 { + t.Errorf("invalid number of routes. expected: 2, given: %d", table.Size()) + } + + // dont add new route if it already exists + route.Policy = IgnoreIfExists + + if err := table.Add(route); err != nil { + t.Errorf("error adding route: %s", err) + } + + if table.Size() != 2 { + t.Errorf("invalid number of routes. expected: 2, given: %d", table.Size()) + } + + // adding the same route under this policy should error + route.Policy = AddIfNotExists + + if err := table.Add(route); err != ErrDuplicateRoute { + t.Errorf("error adding route. Expected error: %s, Given: %s", ErrDuplicateRoute, err) + } +} + +func TestDelete(t *testing.T) { + table := NewTable() + + if table.Size() != 0 { + t.Errorf("new table should be empty") + } + + route := Route{ + Destination: "dest.svc", + Gateway: "dest.gw", + Router: "dest.router", + Network: "dest.network", + Metric: 10, + } + + if err := table.Add(route); err != nil { + t.Errorf("error adding route: %s", err) + } + + if table.Size() != 1 { + t.Errorf("invalid number of routes. expected: 1, given: %d", table.Size()) + } + + // should fail to delete non-existant route + oldDest := route.Destination + route.Destination = "randDest" + + if err := table.Delete(route); err != ErrRouteNotFound { + t.Errorf("error deleting route. Expected error: %s, given: %s", ErrRouteNotFound, err) + } + + if table.Size() != 1 { + t.Errorf("invalid number of routes. expected: %d, given: %d", 1, table.Size()) + } + + // we should be able to delete the routes now + route.Destination = oldDest + + if err := table.Delete(route); err != nil { + t.Errorf("error deleting route: %s", err) + } + + if table.Size() != 0 { + t.Errorf("invalid number of routes. expected: %d, given: %d", 0, table.Size()) + } +} + +func TestUpdate(t *testing.T) { + table := NewTable() + + if table.Size() != 0 { + t.Errorf("new table should be empty") + } + + route := Route{ + Destination: "dest.svc", + Gateway: "dest.gw", + Router: "dest.router", + Network: "dest.network", + Metric: 10, + } + + if err := table.Add(route); err != nil { + t.Errorf("error adding route: %s", err) + } + + if table.Size() != 1 { + t.Errorf("invalid number of routes. expected: 1, given: %d", table.Size()) + } + + route.Metric = 200 + + if err := table.Update(route); err != nil { + t.Errorf("error updating route: %s", err) + } + + if table.Size() != 1 { + t.Errorf("invalid number of routes. expected: 1, given: %d", table.Size()) + } + + // this should add a new route; we are hashing routes on + route.Destination = "new.dest" + + if err := table.Update(route); err != nil { + t.Errorf("error updating route: %s", err) + } + + // NOTE: default policy is AddIfNotExists so the new route will be added here + if table.Size() != 2 { + t.Errorf("invalid number of routes. expected: 2, given: %d", table.Size()) + } + + // this should add a new route; we are hashing routes on + route.Gateway = "new.gw" + + if err := table.Update(route); err != nil { + t.Errorf("error updating route: %s", err) + } + + // NOTE: default policy is AddIfNotExists so the new route will be added here + if table.Size() != 3 { + t.Errorf("invalid number of routes. expected: 3, given: %d", table.Size()) + } + + // this should NOTE add a new route; we are setting the policy to IgnoreIfExists + route.Destination = "rand.dest" + route.Policy = IgnoreIfExists + + if err := table.Update(route); err != ErrRouteNotFound { + t.Errorf("error updating route. Expected error: %s, given: %s", ErrRouteNotFound, err) + } + + if table.Size() != 3 { + t.Errorf("invalid number of routes. expected: 3, given: %d", table.Size()) + } +} diff --git a/network/router/route.go b/network/router/route.go index 1f45b688..50526533 100644 --- a/network/router/route.go +++ b/network/router/route.go @@ -18,10 +18,10 @@ var ( type RoutePolicy int const ( - // OverrideIfExists overrides route if it already exists - OverrideIfExists RoutePolicy = iota // AddIfNotExist adds the route if it does not exist - AddIfNotExists + AddIfNotExists RoutePolicy = iota + // OverrideIfExists overrides route if it already exists + OverrideIfExists // IgnoreIfExists instructs to not modify existing route IgnoreIfExists ) From 956902f64103eb7e8c097f23c3eb9c20188bc576 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Mon, 1 Jul 2019 23:15:45 +0100 Subject: [PATCH 086/287] Added List tests. --- network/router/default_table_test.go | 82 +++++++++++++++------------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/network/router/default_table_test.go b/network/router/default_table_test.go index 93f28730..b1c16b3a 100644 --- a/network/router/default_table_test.go +++ b/network/router/default_table_test.go @@ -2,6 +2,20 @@ package router import "testing" +func testSetup() (Table, Route) { + table := NewTable() + + route := Route{ + Destination: "dest.svc", + Gateway: "dest.gw", + Router: "dest.router", + Network: "dest.network", + Metric: 10, + } + + return table, route +} + func TestNewTable(t *testing.T) { table := NewTable() @@ -11,19 +25,7 @@ func TestNewTable(t *testing.T) { } func TestAdd(t *testing.T) { - table := NewTable() - - if table.Size() != 0 { - t.Errorf("new table should be empty") - } - - route := Route{ - Destination: "dest.svc", - Gateway: "dest.gw", - Router: "dest.router", - Network: "dest.network", - Metric: 10, - } + table, route := testSetup() if err := table.Add(route); err != nil { t.Errorf("error adding route: %s", err) @@ -76,19 +78,7 @@ func TestAdd(t *testing.T) { } func TestDelete(t *testing.T) { - table := NewTable() - - if table.Size() != 0 { - t.Errorf("new table should be empty") - } - - route := Route{ - Destination: "dest.svc", - Gateway: "dest.gw", - Router: "dest.router", - Network: "dest.network", - Metric: 10, - } + table, route := testSetup() if err := table.Add(route); err != nil { t.Errorf("error adding route: %s", err) @@ -123,19 +113,7 @@ func TestDelete(t *testing.T) { } func TestUpdate(t *testing.T) { - table := NewTable() - - if table.Size() != 0 { - t.Errorf("new table should be empty") - } - - route := Route{ - Destination: "dest.svc", - Gateway: "dest.gw", - Router: "dest.router", - Network: "dest.network", - Metric: 10, - } + table, route := testSetup() if err := table.Add(route); err != nil { t.Errorf("error adding route: %s", err) @@ -191,3 +169,29 @@ func TestUpdate(t *testing.T) { t.Errorf("invalid number of routes. expected: 3, given: %d", table.Size()) } } + +func TestListRoutest(t *testing.T) { + table, route := testSetup() + + dest := []string{"one.svc", "two.svc", "three.svc"} + + for i := 0; i < len(dest); i++ { + route.Destination = dest[i] + if err := table.Add(route); err != nil { + t.Errorf("error adding route: %s", err) + } + } + + routes, err := table.List() + if err != nil { + t.Errorf("error listing routes: %s", err) + } + + if len(routes) != len(dest) { + t.Errorf("incorrect number of routes listed. Expected: %d, Given: %d", len(dest), len(routes)) + } + + if len(routes) != table.Size() { + t.Errorf("mismatch number of routes and table size. Routes: %d, Size: %d", len(routes), table.Size()) + } +} From 8f22e61a8bcb40dc6cb196a96efbaa1f7f536646 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Mon, 1 Jul 2019 23:19:35 +0100 Subject: [PATCH 087/287] List test function properly named. --- network/router/default_table_test.go | 10 +--------- network/router/route.go | 4 ++-- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/network/router/default_table_test.go b/network/router/default_table_test.go index b1c16b3a..c9e5a15e 100644 --- a/network/router/default_table_test.go +++ b/network/router/default_table_test.go @@ -16,14 +16,6 @@ func testSetup() (Table, Route) { return table, route } -func TestNewTable(t *testing.T) { - table := NewTable() - - if table.Size() != 0 { - t.Errorf("new table should be empty") - } -} - func TestAdd(t *testing.T) { table, route := testSetup() @@ -170,7 +162,7 @@ func TestUpdate(t *testing.T) { } } -func TestListRoutest(t *testing.T) { +func TestList(t *testing.T) { table, route := testSetup() dest := []string{"one.svc", "two.svc", "three.svc"} diff --git a/network/router/route.go b/network/router/route.go index 50526533..7ee3559c 100644 --- a/network/router/route.go +++ b/network/router/route.go @@ -29,10 +29,10 @@ const ( // String returns human reprensentation of policy func (p RoutePolicy) String() string { switch p { - case OverrideIfExists: - return "OVERRIDE_IF_EXISTS" case AddIfNotExists: return "ADD_IF_NOT_EXISTS" + case OverrideIfExists: + return "OVERRIDE_IF_EXISTS" case IgnoreIfExists: return "IGNORE_IF_EXISTS" default: From 0e1fcc4f28bd67707d8c2dcea36e50ebc1991516 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Mon, 1 Jul 2019 23:36:22 +0100 Subject: [PATCH 088/287] Stop hardcoding table sizes; increment as you move on. --- network/router/default_table_test.go | 80 +++++++++++++--------------- 1 file changed, 38 insertions(+), 42 deletions(-) diff --git a/network/router/default_table_test.go b/network/router/default_table_test.go index c9e5a15e..9098e5ad 100644 --- a/network/router/default_table_test.go +++ b/network/router/default_table_test.go @@ -2,6 +2,7 @@ package router import "testing" +// creates routing table and test route func testSetup() (Table, Route) { table := NewTable() @@ -18,14 +19,12 @@ func testSetup() (Table, Route) { func TestAdd(t *testing.T) { table, route := testSetup() + testTableSize := table.Size() if err := table.Add(route); err != nil { t.Errorf("error adding route: %s", err) } - - if table.Size() != 1 { - t.Errorf("invalid number of routes. expected: 1, given: %d", table.Size()) - } + testTableSize += 1 // adds new route for the original destination route.Gateway = "dest.gw2" @@ -33,12 +32,10 @@ func TestAdd(t *testing.T) { if err := table.Add(route); err != nil { t.Errorf("error adding route: %s", err) } + testTableSize += 1 - if table.Size() != 2 { - t.Errorf("invalid number of routes. expected: 2, given: %d", table.Size()) - } - - // overrides an existing route: the size of the table does not change + // overrides an existing route + // NOTE: the size of the table should not change route.Metric = 100 route.Policy = OverrideIfExists @@ -46,22 +43,23 @@ func TestAdd(t *testing.T) { t.Errorf("error adding route: %s", err) } - if table.Size() != 2 { - t.Errorf("invalid number of routes. expected: 2, given: %d", table.Size()) + if table.Size() != testTableSize { + t.Errorf("invalid number of routes. expected: %d, given: %d", testTableSize, table.Size()) } // dont add new route if it already exists + // NOTE: The size of the table should not change route.Policy = IgnoreIfExists if err := table.Add(route); err != nil { t.Errorf("error adding route: %s", err) } - if table.Size() != 2 { - t.Errorf("invalid number of routes. expected: 2, given: %d", table.Size()) + if table.Size() != testTableSize { + t.Errorf("invalid number of routes. expected: %d, given: %d", testTableSize, table.Size()) } - // adding the same route under this policy should error + // adding the same route under AddIfNotExists policy must error route.Policy = AddIfNotExists if err := table.Add(route); err != ErrDuplicateRoute { @@ -71,85 +69,83 @@ func TestAdd(t *testing.T) { func TestDelete(t *testing.T) { table, route := testSetup() + testTableSize := table.Size() if err := table.Add(route); err != nil { t.Errorf("error adding route: %s", err) } - - if table.Size() != 1 { - t.Errorf("invalid number of routes. expected: 1, given: %d", table.Size()) - } + testTableSize += 1 // should fail to delete non-existant route - oldDest := route.Destination + prevDest := route.Destination route.Destination = "randDest" if err := table.Delete(route); err != ErrRouteNotFound { t.Errorf("error deleting route. Expected error: %s, given: %s", ErrRouteNotFound, err) } - if table.Size() != 1 { - t.Errorf("invalid number of routes. expected: %d, given: %d", 1, table.Size()) - } - - // we should be able to delete the routes now - route.Destination = oldDest + // we should be able to delete the existing route + route.Destination = prevDest if err := table.Delete(route); err != nil { t.Errorf("error deleting route: %s", err) } + testTableSize -= 1 - if table.Size() != 0 { - t.Errorf("invalid number of routes. expected: %d, given: %d", 0, table.Size()) + if table.Size() != testTableSize { + t.Errorf("invalid number of routes. expected: %d, given: %d", testTableSize, table.Size()) } } func TestUpdate(t *testing.T) { table, route := testSetup() + testTableSize := table.Size() if err := table.Add(route); err != nil { t.Errorf("error adding route: %s", err) } + testTableSize += 1 - if table.Size() != 1 { - t.Errorf("invalid number of routes. expected: 1, given: %d", table.Size()) - } - + // change the metric of the original route + // NOTE: this should NOT change the size of the table route.Metric = 200 if err := table.Update(route); err != nil { t.Errorf("error updating route: %s", err) } - if table.Size() != 1 { - t.Errorf("invalid number of routes. expected: 1, given: %d", table.Size()) + if table.Size() != testTableSize { + t.Errorf("invalid number of routes. expected: %d, given: %d", testTableSize, table.Size()) } - // this should add a new route; we are hashing routes on + // NOTE: routing table routes on + // this should add a new route route.Destination = "new.dest" if err := table.Update(route); err != nil { t.Errorf("error updating route: %s", err) } + testTableSize += 1 // NOTE: default policy is AddIfNotExists so the new route will be added here - if table.Size() != 2 { - t.Errorf("invalid number of routes. expected: 2, given: %d", table.Size()) + if table.Size() != testTableSize { + t.Errorf("invalid number of routes. expected: %d, given: %d", testTableSize, table.Size()) } - // this should add a new route; we are hashing routes on + // NOTE: we are hashing routes on + // this should add a new route route.Gateway = "new.gw" if err := table.Update(route); err != nil { t.Errorf("error updating route: %s", err) } + testTableSize += 1 - // NOTE: default policy is AddIfNotExists so the new route will be added here - if table.Size() != 3 { - t.Errorf("invalid number of routes. expected: 3, given: %d", table.Size()) + if table.Size() != testTableSize { + t.Errorf("invalid number of routes. expected: %d, given: %d", testTableSize, table.Size()) } - // this should NOTE add a new route; we are setting the policy to IgnoreIfExists + // this should NOT add a new route as we are setting the policy to IgnoreIfExists route.Destination = "rand.dest" route.Policy = IgnoreIfExists @@ -158,7 +154,7 @@ func TestUpdate(t *testing.T) { } if table.Size() != 3 { - t.Errorf("invalid number of routes. expected: 3, given: %d", table.Size()) + t.Errorf("invalid number of routes. expected: %d, given: %d", testTableSize, table.Size()) } } From b4236f44304a76b82ae06a3bca7d932acc19c52f Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 2 Jul 2019 00:27:53 +0100 Subject: [PATCH 089/287] Add network transport --- transport/network/listener.go | 44 ++++ transport/network/network.go | 339 +++++++++++++++++++++++++++++++ transport/network/socket.go | 80 ++++++++ transport/network/socket_test.go | 61 ++++++ 4 files changed, 524 insertions(+) create mode 100644 transport/network/listener.go create mode 100644 transport/network/network.go create mode 100644 transport/network/socket.go create mode 100644 transport/network/socket_test.go diff --git a/transport/network/listener.go b/transport/network/listener.go new file mode 100644 index 00000000..6e8efc60 --- /dev/null +++ b/transport/network/listener.go @@ -0,0 +1,44 @@ +package network + +import ( + "github.com/micro/go-micro/transport" +) + +type listener struct { + // stream id + id string + // address of the listener + addr string + // close channel + closed chan bool + // accept socket + accept chan *socket +} + +func (n *listener) Addr() string { + return n.addr +} + +func (n *listener) Close() error { + select { + case <-n.closed: + default: + close(n.closed) + } + return nil +} + +func (n *listener) Accept(fn func(s transport.Socket)) error { + for { + select { + case <-n.closed: + return nil + case s, ok := <-n.accept: + if !ok { + return nil + } + go fn(s) + } + } + return nil +} diff --git a/transport/network/network.go b/transport/network/network.go new file mode 100644 index 00000000..791edbe7 --- /dev/null +++ b/transport/network/network.go @@ -0,0 +1,339 @@ +// Package network provides a network transport +package network + +import ( + "context" + "crypto/sha256" + "errors" + "fmt" + "sync" + + "github.com/micro/go-micro/network" + "github.com/micro/go-micro/transport" +) + +type networkKey struct{} + +type Transport struct { + options transport.Options + + // the network interface + network network.Network + + // protect all the things + sync.RWMutex + + // connect + connected bool + // connected node + node network.Node + // the send channel + send chan *message + // close channel + closed chan bool + + // sockets + sockets map[string]*socket + // listeners + listeners map[string]*listener +} + +func (n *Transport) newListener(addr string) *listener { + // hash the id + h := sha256.New() + h.Write([]byte(addr)) + id := fmt.Sprintf("%x", h.Sum(nil)) + + // create the listener + l := &listener{ + id: id, + addr: addr, + closed: make(chan bool), + accept: make(chan *socket, 128), + } + + // save it + n.Lock() + n.listeners[id] = l + n.Unlock() + + return l +} + +func (n *Transport) getListener(id string) (*listener, bool) { + // get the listener + n.RLock() + s, ok := n.listeners[id] + n.RUnlock() + return s, ok +} + +func (n *Transport) getSocket(id string) (*socket, bool) { + // get the socket + n.RLock() + s, ok := n.sockets[id] + n.RUnlock() + return s, ok +} + +func (n *Transport) newSocket(id string) *socket { + // hash the id + h := sha256.New() + h.Write([]byte(id)) + id = fmt.Sprintf("%x", h.Sum(nil)) + + // new socket + s := &socket{ + id: id, + closed: make(chan bool), + recv: make(chan *message, 128), + send: n.send, + } + + // save socket + n.Lock() + n.sockets[id] = s + n.Unlock() + + // return socket + return s +} + +// process outgoing messages +func (n *Transport) process() { + // manage the send buffer + // all pseudo sockets throw everything down this + for { + select { + case msg := <-n.send: + netmsg := &network.Message{ + Header: msg.data.Header, + Body: msg.data.Body, + } + + // set the stream id on the outgoing message + netmsg.Header["Micro-Stream"] = msg.id + + // send the message via the interface + if err := n.node.Send(netmsg); err != nil { + // no op + // TODO: do something + } + case <-n.closed: + return + } + } +} + +// process incoming messages +func (n *Transport) listen() { + for { + // process anything via the net interface + msg, err := n.node.Accept() + if err != nil { + return + } + + // a stream id + id := msg.Header["Micro-Stream"] + + // get the socket + s, exists := n.getSocket(id) + if !exists { + // get the listener + l, ok := n.getListener(id) + // there's no socket and there's no listener + if !ok { + continue + } + + // listener is closed + select { + case <-l.closed: + // delete it + n.Lock() + delete(n.listeners, l.id) + n.Unlock() + continue + default: + } + + // no socket, create one + s = n.newSocket(id) + // set remote address + s.remote = msg.Header["Remote"] + + // drop that to the listener + // TODO: non blocking + l.accept <- s + } + + // is the socket closed? + select { + case <-s.closed: + // closed + delete(n.sockets, id) + continue + default: + // process + } + + tmsg := &transport.Message{ + Header: msg.Header, + Body: msg.Body, + } + + // TODO: don't block on queuing + // append to recv backlog + s.recv <- &message{id: id, data: tmsg} + } +} + +func (n *Transport) Init(opts ...transport.Option) error { + for _, o := range opts { + o(&n.options) + } + return nil +} + +func (n *Transport) Options() transport.Options { + return n.options +} + +// Close the tunnel +func (n *Transport) Close() error { + n.Lock() + defer n.Unlock() + + if !n.connected { + return nil + } + + select { + case <-n.closed: + return nil + default: + // close all the sockets + for _, s := range n.sockets { + s.Close() + } + for _, l := range n.listeners { + l.Close() + } + // close the connection + close(n.closed) + // close node connection + n.node.Close() + // reset connected + n.connected = false + } + + return nil +} + +// Connect the tunnel +func (n *Transport) Connect() error { + n.Lock() + defer n.Unlock() + + // already connected + if n.connected { + return nil + } + + // get a new node + node, err := n.network.Connect() + if err != nil { + return err + } + + // set as connected + n.connected = true + // create new close channel + n.closed = make(chan bool) + // save node + n.node = node + + // process messages to be sent + go n.process() + // process incoming messages + go n.listen() + + return nil +} + +// Dial an address +func (n *Transport) Dial(addr string, opts ...transport.DialOption) (transport.Client, error) { + if err := n.Connect(); err != nil { + return nil, err + } + + // create new socket + s := n.newSocket(addr) + // set remote + s.remote = addr + // set local + n.RLock() + s.local = n.node.Address() + n.RUnlock() + + return s, nil +} + +func (n *Transport) Listen(addr string, opts ...transport.ListenOption) (transport.Listener, error) { + // check existing listeners + n.RLock() + for _, l := range n.listeners { + if l.addr == addr { + n.RUnlock() + return nil, errors.New("already listening on " + addr) + } + } + n.RUnlock() + + // try to connect to the network + if err := n.Connect(); err != nil { + return nil, err + } + + return n.newListener(addr), nil +} + +func (n *Transport) String() string { + return "network" +} + +// NewTransport creates a new network transport +func NewTransport(opts ...transport.Option) transport.Transport { + options := transport.Options{ + Context: context.Background(), + } + + for _, o := range opts { + o(&options) + } + + // get the network interface + n, ok := options.Context.Value(networkKey{}).(network.Network) + if !ok { + n = network.DefaultNetwork + } + + return &Transport{ + options: options, + network: n, + send: make(chan *message, 128), + closed: make(chan bool), + sockets: make(map[string]*socket), + } +} + +// WithNetwork sets the network interface +func WithNetwork(n network.Network) transport.Option { + return func(o *transport.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, networkKey{}, n) + } +} diff --git a/transport/network/socket.go b/transport/network/socket.go new file mode 100644 index 00000000..92de114f --- /dev/null +++ b/transport/network/socket.go @@ -0,0 +1,80 @@ +package network + +import ( + "errors" + + "github.com/micro/go-micro/transport" +) + +// socket is our pseudo socket for transport.Socket +type socket struct { + // socket id based on Micro-Stream + id string + // closed + closed chan bool + // remote addr + remote string + // local addr + local string + // send chan + send chan *message + // recv chan + recv chan *message +} + +// message is sent over the send channel +type message struct { + // socket id + id string + // transport data + data *transport.Message +} + +func (s *socket) Remote() string { + return s.remote +} + +func (s *socket) Local() string { + return s.local +} + +func (s *socket) Id() string { + return s.id +} + +func (s *socket) Send(m *transport.Message) error { + select { + case <-s.closed: + return errors.New("socket is closed") + default: + // no op + } + // append to backlog + s.send <- &message{id: s.id, data: m} + return nil +} + +func (s *socket) Recv(m *transport.Message) error { + select { + case <-s.closed: + return errors.New("socket is closed") + default: + // no op + } + // recv from backlog + msg := <-s.recv + // set message + *m = *msg.data + // return nil + return nil +} + +func (s *socket) Close() error { + select { + case <-s.closed: + // no op + default: + close(s.closed) + } + return nil +} diff --git a/transport/network/socket_test.go b/transport/network/socket_test.go new file mode 100644 index 00000000..8521a3da --- /dev/null +++ b/transport/network/socket_test.go @@ -0,0 +1,61 @@ +package network + +import ( + "testing" + + "github.com/micro/go-micro/transport" +) + +func TestTunnelSocket(t *testing.T) { + s := &socket{ + id: "1", + closed: make(chan bool), + remote: "remote", + local: "local", + send: make(chan *message, 1), + recv: make(chan *message, 1), + } + + // check addresses local and remote + if s.Local() != s.local { + t.Fatalf("Expected s.Local %s got %s", s.local, s.Local()) + } + if s.Remote() != s.remote { + t.Fatalf("Expected s.Remote %s got %s", s.remote, s.Remote()) + } + + // send a message + s.Send(&transport.Message{Header: map[string]string{}}) + + // get sent message + msg := <-s.send + + if msg.id != s.id { + t.Fatalf("Expected sent message id %s got %s", s.id, msg.id) + } + + // recv a message + msg.data.Header["Foo"] = "bar" + s.recv <- msg + + m := new(transport.Message) + s.Recv(m) + + // check header + if m.Header["Foo"] != "bar" { + t.Fatalf("Did not receive correct message %+v", m) + } + + // close the connection + s.Close() + + // check connection + err := s.Send(m) + if err == nil { + t.Fatal("Expected closed connection") + } + err = s.Recv(m) + if err == nil { + t.Fatal("Expected closed connection") + } +} From 372ad949ff4d47d88935fb79877c7c2c60fe2608 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 2 Jul 2019 00:48:15 +0100 Subject: [PATCH 090/287] Rename to mucp transport --- transport/{network => mucp}/listener.go | 2 +- transport/{network => mucp}/network.go | 7 +++++-- transport/{network => mucp}/socket.go | 2 +- transport/{network => mucp}/socket_test.go | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) rename transport/{network => mucp}/listener.go (97%) rename transport/{network => mucp}/network.go (96%) rename transport/{network => mucp}/socket.go (98%) rename transport/{network => mucp}/socket_test.go (98%) diff --git a/transport/network/listener.go b/transport/mucp/listener.go similarity index 97% rename from transport/network/listener.go rename to transport/mucp/listener.go index 6e8efc60..6f107323 100644 --- a/transport/network/listener.go +++ b/transport/mucp/listener.go @@ -1,4 +1,4 @@ -package network +package mucp import ( "github.com/micro/go-micro/transport" diff --git a/transport/network/network.go b/transport/mucp/network.go similarity index 96% rename from transport/network/network.go rename to transport/mucp/network.go index 791edbe7..3e9d8367 100644 --- a/transport/network/network.go +++ b/transport/mucp/network.go @@ -1,5 +1,5 @@ -// Package network provides a network transport -package network +// Package mucp provides a mucp network transport +package mucp import ( "context" @@ -14,6 +14,9 @@ import ( type networkKey struct{} +// Transport is a mucp transport. It should only +// be created with NewTransport and cast to +// *Transport if there's a need to close it. type Transport struct { options transport.Options diff --git a/transport/network/socket.go b/transport/mucp/socket.go similarity index 98% rename from transport/network/socket.go rename to transport/mucp/socket.go index 92de114f..f21788ec 100644 --- a/transport/network/socket.go +++ b/transport/mucp/socket.go @@ -1,4 +1,4 @@ -package network +package mucp import ( "errors" diff --git a/transport/network/socket_test.go b/transport/mucp/socket_test.go similarity index 98% rename from transport/network/socket_test.go rename to transport/mucp/socket_test.go index 8521a3da..df493fa0 100644 --- a/transport/network/socket_test.go +++ b/transport/mucp/socket_test.go @@ -1,4 +1,4 @@ -package network +package mucp import ( "testing" From 543dc0166c262b6a84b5490ab0c9e67a11cbe2f9 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 2 Jul 2019 08:45:00 +0100 Subject: [PATCH 091/287] Restructure network things before moving --- network/default.go | 566 +-------------------------------------------- network/link.go | 57 +++++ network/node.go | 347 +++++++++++++++++++++++++++ network/socket.go | 176 ++++++++++++++ 4 files changed, 581 insertions(+), 565 deletions(-) create mode 100644 network/link.go create mode 100644 network/node.go create mode 100644 network/socket.go diff --git a/network/default.go b/network/default.go index 24f42206..456be806 100644 --- a/network/default.go +++ b/network/default.go @@ -3,23 +3,16 @@ package network import ( "crypto/sha256" "fmt" - "io" - "runtime/debug" "sync" "time" - gproto "github.com/golang/protobuf/proto" "github.com/google/uuid" - "github.com/micro/go-micro/codec" - "github.com/micro/go-micro/codec/proto" "github.com/micro/go-micro/config/options" "github.com/micro/go-micro/network/proxy" "github.com/micro/go-micro/network/proxy/mucp" "github.com/micro/go-micro/network/resolver" "github.com/micro/go-micro/network/router" "github.com/micro/go-micro/registry" - "github.com/micro/go-micro/transport" - "github.com/micro/go-micro/util/log" pb "github.com/micro/go-micro/network/proto" nreg "github.com/micro/go-micro/network/resolver/registry" @@ -47,65 +40,6 @@ type network struct { links []Link } -type node struct { - *network - - // closed channel - closed chan bool - - mtx sync.RWMutex - - // the node id - id string - - // address of this node - address string - - // the node registry - registry registry.Registry - - // the base level transport - transport transport.Transport - - // the listener - listener transport.Listener - - // leases for connections to us - // link id:link - links map[string]*link -} - -type link struct { - // the embedded node - *node - - // the link id - id string - - // queue buffer for this link - queue chan *Message - - // the socket for this link - socket *socket - - // the lease for this link - lease *pb.Lease - - // length and weight of the link - mtx sync.RWMutex - - // determines the cost of the link - // based on queue length and roundtrip - length int - weight int -} - -type socket struct { - node *node - codec codec.Marshaler - socket transport.Socket -} - // network methods // lease generates a new lease with a node id/address @@ -167,98 +101,7 @@ func (n *network) Id() string { // should advertise this address to people. Anyone else // on the network should be able to route to it. func (n *network) Connect() (Node, error) { - // create a new node - node := new(node) - // closed channel - node.closed = make(chan bool) - // set the nodes network - node.network = n - - // initially we have no id - // create an id and address - // TODO: create a real unique id and address - // lease := n.lease() - // set the node id - // node.id = lease.Node.Id - - // get the transport we're going to use for our tunnels - t, ok := n.Options.Values().Get("network.transport") - if ok { - node.transport = t.(transport.Transport) - } else { - // TODO: set to quic - node.transport = transport.DefaultTransport - } - - // we listen on a random address, this is not advertised - // TODO: use util/addr to get something anyone in the same private network can talk to - l, err := node.transport.Listen(":0") - if err != nil { - return nil, err - } - // set the listener - node.listener = l - - // TODO: this should be an overlay address - // ideally received via some dhcp style broadcast - node.address = l.Addr() - - // TODO: start the router and broadcast advertisements - // receive updates and push them to the network in accept(l) below - // chan, err := n.router.Advertise() - // u <- chan - // socket.send("route", u) - // u := socket.recv() => r.router.Update(u) - - // process any incoming messages on the listener - // this is our inbound network connection - node.accept(l) - - // register the node with the registry for the network - // TODO: use a registrar or something else for local things - r, ok := n.Options.Values().Get("network.registry") - if ok { - node.registry = r.(registry.Registry) - } else { - node.registry = registry.DefaultRegistry - } - - // lookup the network to see if there's any nodes - records := n.lookup(node.registry) - - // should we actually do this? - if len(records) == 0 { - // set your own node id - lease := n.lease() - node.id = lease.Node.Id - } - - // register self with the network registry - // this is a local registry of nodes separate to the resolver - // maybe consolidate registry/resolver - // TODO: find a way to do this via gossip or something else - if err := node.registry.Register(®istry.Service{ - // register with the network id - Name: "network:" + n.Id(), - Nodes: []*registry.Node{ - {Id: node.id, Address: node.address}, - }, - }); err != nil { - node.Close() - return nil, err - } - - // create a channel to get links - linkChan := make(chan *link, 1) - - // we're going to wait for the first connection - go node.connect(linkChan) - - // wait forever to connect - // TODO: do something with the links we receive - <-linkChan - - return node, nil + return newNode(n) } // TODO: establish links for peering networks @@ -278,413 +121,6 @@ func (n *network) Peer(Network) (Link, error) { return nil, nil } -func (n *network) Links() ([]Link, error) { - n.mtx.RLock() - defer n.mtx.RUnlock() - return n.links, nil -} - -// node methods - -// Accept processes the incoming messages on its listener. -// This listener was created with the first call to network.Connect. -// Any inbound new socket here is essentially something else attempting -// to connect to the network. So we turn it into a socket, then process it. -func (n *node) accept(l transport.Listener) error { - return l.Accept(func(sock transport.Socket) { - defer func() { - // close socket - sock.Close() - - if r := recover(); r != nil { - log.Log("panic recovered: ", r) - log.Log(string(debug.Stack())) - } - }() - - // create a new link - // generate a new link - link := &link{ - node: n, - id: uuid.New().String(), - } - // create a new network socket - sk := new(socket) - sk.node = n - sk.codec = proto.Marshaler{} - sk.socket = sock - - // set link socket - link.socket = sk - - // accept messages on the socket - // blocks forever or until error - if err := link.up(); err != nil { - // TODO: delete link - } - }) -} - -// connect attempts to periodically connect to new nodes in the network. -// It will only do this if it has less than 3 connections. this method -// is called by network.Connect and fired in a go routine after establishing -// the first connection and creating a node. The node attempts to maintain -// its connection to the network via multiple links. -func (n *node) connect(linkChan chan *link) { - // TODO: adjustable ticker - t := time.NewTicker(time.Second) - var lease *pb.Lease - - for { - select { - // on every tick check the number of links and then attempt - // to connect to new nodes if we don't have sufficient links - case <-t.C: - n.mtx.RLock() - - // only start processing if we have less than 3 links - if len(n.links) > 2 { - n.mtx.RUnlock() - continue - } - - // get a list of link addresses so we don't reconnect - // to the ones we're already connected to - nodes := map[string]bool{} - for _, l := range n.links { - nodes[l.lease.Node.Address] = true - } - - n.mtx.RUnlock() - - records := n.network.lookup(n.registry) - - // for each record check we haven't already got a connection - // attempt to dial it, create a new socket and call - // connect with our existing network lease. - // if its the first call we don't actually have a lease - - // TODO: determine how to prioritise local records - // while still connecting to the global network - for _, record := range records { - // skip existing connections - if nodes[record.Address] { - continue - } - - // attempt to connect and create a link - - // connect to the node - s, err := n.transport.Dial(record.Address) - if err != nil { - continue - } - - // create a new socket - sk := &socket{ - node: n, - codec: &proto.Marshaler{}, - socket: s, - } - - // broadcast a "connect" request and get back "lease" - // this is your tunnel to the outside world and to the network - // then push updates and messages over this link - // first connect will not have a lease so we get one with node id/address - l, err := sk.connect(lease) - if err != nil { - s.Close() - continue - } - - // set lease for next time - lease = l - - // create a new link with the lease and socket - link := &link{ - id: uuid.New().String(), - lease: lease, - node: n, - queue: make(chan *Message, 128), - socket: sk, - } - - // bring up the link - go link.up() - - // save the new link - n.mtx.Lock() - n.links[link.id] = link - n.mtx.Unlock() - - // drop this down the link channel to the network - // so it can manage the links - select { - case linkChan <- link: - // we don't wait for anyone - default: - } - } - case <-n.closed: - return - } - } -} - -func (n *node) Address() string { - return n.address -} - -// Close shutdowns all the links and closes the listener -func (n *node) Close() error { - select { - case <-n.closed: - return nil - default: - close(n.closed) - // shutdown all the links - n.mtx.Lock() - for id, link := range n.links { - link.down() - delete(n.links, id) - } - n.mtx.Unlock() - // deregister self - n.registry.Deregister(®istry.Service{ - Name: "network:" + n.network.Id(), - Nodes: []*registry.Node{ - {Id: n.id, Address: n.address}, - }, - }) - return n.listener.Close() - } - return nil -} - -func (n *node) Accept() (*Message, error) { - // process the inbound cruft - - return nil, nil -} - -func (n *node) Links() ([]Link, error) { - n.mtx.RLock() - defer n.mtx.RUnlock() - - var links []Link - for _, l := range n.links { - links = append(links, l) - } - return links, nil -} - -func (n *node) Network() string { - return n.network.id -} - -func (n *node) Send(m *Message) error { - n.mtx.RLock() - defer n.mtx.RUnlock() - - var gerr error - - // send to all links - // TODO: be smarter - for _, link := range n.links { - // TODO: process the error, do some link flap detection - // blackhold the connection, etc - if err := link.socket.send(m, nil); err != nil { - gerr = err - continue - } - } - - return gerr -} - -// link methods - -// bring up the link -func (l *link) up() error { - // TODO: manage the length/weight of the link - return l.socket.accept() -} - -// kill the link -func (l *link) down() error { - return l.socket.close() -} - -func (l *link) Length() int { - l.mtx.RLock() - defer l.mtx.RUnlock() - return l.length -} - -func (l *link) Weight() int { - l.mtx.RLock() - defer l.mtx.RUnlock() - return l.weight -} - -// accept is the state machine that processes messages on the socket -func (s *socket) accept() error { - for { - m := new(transport.Message) - err := s.socket.Recv(m) - if err == io.EOF { - return nil - } - if err != nil { - return err - } - - // TODO: pick a reliable header - event := m.Header["Micro-Method"] - - switch event { - // connect event - case "connect": - // process connect events from network.Connect() - // these are new connections to join the network - - // decode the connection event - conn := new(pb.Connect) - if err := s.codec.Unmarshal(m.Body, conn); err != nil { - // skip error - continue - } - - // get the existing lease if it exists - lease := conn.Lease - if lease == nil { - // create a new lease/node - lease = s.node.network.lease() - } - - // send back a lease offer for the node - if err := s.send(&Message{ - Header: map[string]string{ - "Micro-Method": "lease", - }, - }, lease); err != nil { - return err - } - - // record this mapping of socket to node/lease - s.node.mtx.Lock() - id := uuid.New().String() - s.node.links[id] = &link{ - node: s.node, - id: id, - lease: lease, - queue: make(chan *Message, 128), - socket: s, - } - s.node.mtx.Unlock() - // a route update - case "route": - // process router events - - // received a lease - case "lease": - // no op as we don't process lease events on existing connections - // these are in response to a connect message - default: - // process all other messages - } - } -} - -func (s *socket) close() error { - return s.socket.Close() -} - -// connect sends a connect request and waits on a lease. -// this is for a new connection. in the event we send -// an existing lease, the same lease should be returned. -// if it differs then we assume our address for this link -// is different... -func (s *socket) connect(l *pb.Lease) (*pb.Lease, error) { - // send a lease request - if err := s.send(&Message{ - Header: map[string]string{ - "Micro-Method": "connect", - }, - }, &pb.Connect{Lease: l}); err != nil { - return nil, err - } - - // create the new things - tm := new(Message) - lease := new(pb.Lease) - - // wait for a lease response - if err := s.recv(tm, lease); err != nil { - return nil, err - } - - return lease, nil -} - -func (s *socket) send(m *Message, v interface{}) error { - tm := new(transport.Message) - tm.Header = m.Header - tm.Body = m.Body - - // set the body if not nil - // we're assuming this is network message - if v != nil { - // encode the data - b, err := s.codec.Marshal(v) - if err != nil { - return err - } - - // set the content type - tm.Header["Content-Type"] = "application/protobuf" - // set the marshalled body - tm.Body = b - } - - // send via the transport socket - return s.socket.Send(&transport.Message{ - Header: m.Header, - Body: m.Body, - }) -} - -func (s *socket) recv(m *Message, v interface{}) error { - if m.Header == nil { - m.Header = make(map[string]string) - } - - tm := new(transport.Message) - - // receive the transport message - if err := s.socket.Recv(tm); err != nil { - return err - } - - // set the message - m.Header = tm.Header - m.Body = tm.Body - - // bail early - if v == nil { - return nil - } - - // try unmarshal the body - // skip if there's no content-type - if tm.Header["Content-Type"] != "application/protobuf" { - return nil - } - - // return unmarshalled - return s.codec.Unmarshal(m.Body, v.(gproto.Message)) -} - // newNetwork returns a new network interface func newNetwork(opts ...options.Option) *network { options := options.NewOptions(opts...) diff --git a/network/link.go b/network/link.go new file mode 100644 index 00000000..5fb6b3e5 --- /dev/null +++ b/network/link.go @@ -0,0 +1,57 @@ +package network + +import ( + "sync" + + pb "github.com/micro/go-micro/network/proto" +) + +type link struct { + // the embedded node + *node + + // the link id + id string + + // queue buffer for this link + queue chan *Message + + // the socket for this link + socket *socket + + // the lease for this link + lease *pb.Lease + + // length and weight of the link + mtx sync.RWMutex + + // determines the cost of the link + // based on queue length and roundtrip + length int + weight int +} + +// link methods + +// bring up the link +func (l *link) up() error { + // TODO: manage the length/weight of the link + return l.socket.accept() +} + +// kill the link +func (l *link) down() error { + return l.socket.close() +} + +func (l *link) Length() int { + l.mtx.RLock() + defer l.mtx.RUnlock() + return l.length +} + +func (l *link) Weight() int { + l.mtx.RLock() + defer l.mtx.RUnlock() + return l.weight +} diff --git a/network/node.go b/network/node.go new file mode 100644 index 00000000..d9ebadd2 --- /dev/null +++ b/network/node.go @@ -0,0 +1,347 @@ +package network + +import ( + "runtime/debug" + "sync" + "time" + + "github.com/google/uuid" + "github.com/micro/go-micro/codec/proto" + "github.com/micro/go-micro/registry" + "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/util/log" + + pb "github.com/micro/go-micro/network/proto" +) + +type node struct { + *network + + // closed channel + closed chan bool + + mtx sync.RWMutex + + // the node id + id string + + // address of this node + address string + + // the node registry + registry registry.Registry + + // the base level transport + transport transport.Transport + + // the listener + listener transport.Listener + + // leases for connections to us + // link id:link + links map[string]*link +} + +// network methods + +func newNode(n *network) (*node, error) { + // create a new node + node := new(node) + // closed channel + node.closed = make(chan bool) + // set the nodes network + node.network = n + + // initially we have no id + // create an id and address + // TODO: create a real unique id and address + // lease := n.lease() + // set the node id + // node.id = lease.Node.Id + + // get the transport we're going to use for our tunnels + t, ok := n.Options.Values().Get("network.transport") + if ok { + node.transport = t.(transport.Transport) + } else { + // TODO: set to quic + node.transport = transport.DefaultTransport + } + + // we listen on a random address, this is not advertised + // TODO: use util/addr to get something anyone in the same private network can talk to + l, err := node.transport.Listen(":0") + if err != nil { + return nil, err + } + // set the listener + node.listener = l + + // TODO: this should be an overlay address + // ideally received via some dhcp style broadcast + node.address = l.Addr() + + // TODO: start the router and broadcast advertisements + // receive updates and push them to the network in accept(l) below + // chan, err := n.router.Advertise() + // u <- chan + // socket.send("route", u) + // u := socket.recv() => r.router.Update(u) + + // process any incoming messages on the listener + // this is our inbound network connection + node.accept(l) + + // register the node with the registry for the network + // TODO: use a registrar or something else for local things + r, ok := n.Options.Values().Get("network.registry") + if ok { + node.registry = r.(registry.Registry) + } else { + node.registry = registry.DefaultRegistry + } + + // lookup the network to see if there's any nodes + records := n.lookup(node.registry) + + // should we actually do this? + if len(records) == 0 { + // set your own node id + lease := n.lease() + node.id = lease.Node.Id + } + + // register self with the network registry + // this is a local registry of nodes separate to the resolver + // maybe consolidate registry/resolver + // TODO: find a way to do this via gossip or something else + if err := node.registry.Register(®istry.Service{ + // register with the network id + Name: "network:" + n.Id(), + Nodes: []*registry.Node{ + {Id: node.id, Address: node.address}, + }, + }); err != nil { + node.Close() + return nil, err + } + + // create a channel to get links + linkChan := make(chan *link, 1) + + // we're going to wait for the first connection + go node.connect(linkChan) + + // wait forever to connect + // TODO: do something with the links we receive + <-linkChan + + return node, nil +} + +// node methods + +// Accept processes the incoming messages on its listener. +// This listener was created with the first call to network.Connect. +// Any inbound new socket here is essentially something else attempting +// to connect to the network. So we turn it into a socket, then process it. +func (n *node) accept(l transport.Listener) error { + return l.Accept(func(sock transport.Socket) { + defer func() { + // close socket + sock.Close() + + if r := recover(); r != nil { + log.Log("panic recovered: ", r) + log.Log(string(debug.Stack())) + } + }() + + // create a new link + // generate a new link + link := &link{ + node: n, + id: uuid.New().String(), + } + // create a new network socket + sk := new(socket) + sk.node = n + sk.codec = proto.Marshaler{} + sk.socket = sock + + // set link socket + link.socket = sk + + // accept messages on the socket + // blocks forever or until error + if err := link.up(); err != nil { + // TODO: delete link + } + }) +} + +// connect attempts to periodically connect to new nodes in the network. +// It will only do this if it has less than 3 connections. this method +// is called by network.Connect and fired in a go routine after establishing +// the first connection and creating a node. The node attempts to maintain +// its connection to the network via multiple links. +func (n *node) connect(linkChan chan *link) { + // TODO: adjustable ticker + t := time.NewTicker(time.Second) + var lease *pb.Lease + + for { + select { + // on every tick check the number of links and then attempt + // to connect to new nodes if we don't have sufficient links + case <-t.C: + n.mtx.RLock() + + // only start processing if we have less than 3 links + if len(n.links) > 2 { + n.mtx.RUnlock() + continue + } + + // get a list of link addresses so we don't reconnect + // to the ones we're already connected to + nodes := map[string]bool{} + for _, l := range n.links { + nodes[l.lease.Node.Address] = true + } + + n.mtx.RUnlock() + + records := n.network.lookup(n.registry) + + // for each record check we haven't already got a connection + // attempt to dial it, create a new socket and call + // connect with our existing network lease. + // if its the first call we don't actually have a lease + + // TODO: determine how to prioritise local records + // while still connecting to the global network + for _, record := range records { + // skip existing connections + if nodes[record.Address] { + continue + } + + // attempt to connect and create a link + + // connect to the node + s, err := n.transport.Dial(record.Address) + if err != nil { + continue + } + + // create a new socket + sk := &socket{ + node: n, + codec: &proto.Marshaler{}, + socket: s, + } + + // broadcast a "connect" request and get back "lease" + // this is your tunnel to the outside world and to the network + // then push updates and messages over this link + // first connect will not have a lease so we get one with node id/address + l, err := sk.connect(lease) + if err != nil { + s.Close() + continue + } + + // set lease for next time + lease = l + + // create a new link with the lease and socket + link := &link{ + id: uuid.New().String(), + lease: lease, + node: n, + queue: make(chan *Message, 128), + socket: sk, + } + + // bring up the link + go link.up() + + // save the new link + n.mtx.Lock() + n.links[link.id] = link + n.mtx.Unlock() + + // drop this down the link channel to the network + // so it can manage the links + select { + case linkChan <- link: + // we don't wait for anyone + default: + } + } + case <-n.closed: + return + } + } +} + +func (n *node) Address() string { + return n.address +} + +// Close shutdowns all the links and closes the listener +func (n *node) Close() error { + select { + case <-n.closed: + return nil + default: + close(n.closed) + // shutdown all the links + n.mtx.Lock() + for id, link := range n.links { + link.down() + delete(n.links, id) + } + n.mtx.Unlock() + // deregister self + n.registry.Deregister(®istry.Service{ + Name: "network:" + n.network.Id(), + Nodes: []*registry.Node{ + {Id: n.id, Address: n.address}, + }, + }) + return n.listener.Close() + } + return nil +} + +func (n *node) Accept() (*Message, error) { + // process the inbound cruft + + return nil, nil +} + +func (n *node) Network() string { + return n.network.id +} + +func (n *node) Send(m *Message) error { + n.mtx.RLock() + defer n.mtx.RUnlock() + + var gerr error + + // send to all links + // TODO: be smarter + for _, link := range n.links { + // TODO: process the error, do some link flap detection + // blackhole the connection, etc + if err := link.socket.send(m, nil); err != nil { + gerr = err + continue + } + } + + return gerr +} diff --git a/network/socket.go b/network/socket.go new file mode 100644 index 00000000..3b6de23a --- /dev/null +++ b/network/socket.go @@ -0,0 +1,176 @@ +package network + +import ( + "io" + + gproto "github.com/golang/protobuf/proto" + "github.com/google/uuid" + "github.com/micro/go-micro/codec" + "github.com/micro/go-micro/transport" + + pb "github.com/micro/go-micro/network/proto" +) + +type socket struct { + node *node + codec codec.Marshaler + socket transport.Socket +} + +func (s *socket) close() error { + return s.socket.Close() +} + +// accept is the state machine that processes messages on the socket +func (s *socket) accept() error { + for { + m := new(transport.Message) + err := s.socket.Recv(m) + if err == io.EOF { + return nil + } + if err != nil { + return err + } + + // TODO: pick a reliable header + event := m.Header["Micro-Method"] + + switch event { + // connect event + case "connect": + // process connect events from network.Connect() + // these are new connections to join the network + + // decode the connection event + conn := new(pb.Connect) + if err := s.codec.Unmarshal(m.Body, conn); err != nil { + // skip error + continue + } + + // get the existing lease if it exists + lease := conn.Lease + if lease == nil { + // create a new lease/node + lease = s.node.network.lease() + } + + // send back a lease offer for the node + if err := s.send(&Message{ + Header: map[string]string{ + "Micro-Method": "lease", + }, + }, lease); err != nil { + return err + } + + // record this mapping of socket to node/lease + s.node.mtx.Lock() + id := uuid.New().String() + s.node.links[id] = &link{ + node: s.node, + id: id, + lease: lease, + queue: make(chan *Message, 128), + socket: s, + } + s.node.mtx.Unlock() + // a route update + case "route": + // process router events + + // received a lease + case "lease": + // no op as we don't process lease events on existing connections + // these are in response to a connect message + default: + // process all other messages + } + } +} + +// connect sends a connect request and waits on a lease. +// this is for a new connection. in the event we send +// an existing lease, the same lease should be returned. +// if it differs then we assume our address for this link +// is different... +func (s *socket) connect(l *pb.Lease) (*pb.Lease, error) { + // send a lease request + if err := s.send(&Message{ + Header: map[string]string{ + "Micro-Method": "connect", + }, + }, &pb.Connect{Lease: l}); err != nil { + return nil, err + } + + // create the new things + tm := new(Message) + lease := new(pb.Lease) + + // wait for a lease response + if err := s.recv(tm, lease); err != nil { + return nil, err + } + + return lease, nil +} + +func (s *socket) send(m *Message, v interface{}) error { + tm := new(transport.Message) + tm.Header = m.Header + tm.Body = m.Body + + // set the body if not nil + // we're assuming this is network message + if v != nil { + // encode the data + b, err := s.codec.Marshal(v) + if err != nil { + return err + } + + // set the content type + tm.Header["Content-Type"] = "application/protobuf" + // set the marshalled body + tm.Body = b + } + + // send via the transport socket + return s.socket.Send(&transport.Message{ + Header: m.Header, + Body: m.Body, + }) +} + +func (s *socket) recv(m *Message, v interface{}) error { + if m.Header == nil { + m.Header = make(map[string]string) + } + + tm := new(transport.Message) + + // receive the transport message + if err := s.socket.Recv(tm); err != nil { + return err + } + + // set the message + m.Header = tm.Header + m.Body = tm.Body + + // bail early + if v == nil { + return nil + } + + // try unmarshal the body + // skip if there's no content-type + if tm.Header["Content-Type"] != "application/protobuf" { + return nil + } + + // return unmarshalled + return s.codec.Unmarshal(m.Body, v.(gproto.Message)) +} From 686aa3aa050bf0f51fcc8a9ee3efc2958335602f Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 2 Jul 2019 19:21:43 +0100 Subject: [PATCH 092/287] log levels --- util/log/log.go | 78 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/util/log/log.go b/util/log/log.go index 86208c06..f7ad8324 100644 --- a/util/log/log.go +++ b/util/log/log.go @@ -8,9 +8,22 @@ import ( golog "github.com/go-log/log/log" ) +// level is a log level +type Level int + +const ( + trace Level = iota + debug + info + fatal +) + var ( // the local logger logger log.Logger = golog.New() + + // default log level is debug + level = info ) // Log makes use of github.com/go-log/log.Log @@ -23,15 +36,61 @@ func Logf(format string, v ...interface{}) { logger.Logf(format, v...) } +// WithLevel logs with the level specified +func WithLevel(l Level, v ...interface{}) { + if l < level { + return + } + Log(v...) +} + +// WithLevel logs with the level specified +func WithLevelf(l Level, format string, v ...interface{}) { + if l < level { + return + } + Logf(format, v...) +} + +// Trace provides trace level logging +func Trace(v ...interface{}) { + WithLevel(trace, v...) +} + +// Tracef provides trace level logging +func Tracef(format string, v ...interface{}) { + WithLevelf(trace, format, v...) +} + +// Debug provides debug level logging +func Debug(v ...interface{}) { + WithLevel(debug, v...) +} + +// Debugf provides debug level logging +func Debugf(format string, v ...interface{}) { + WithLevelf(debug, format, v...) +} + +// Info provides info level logging +func Info(v ...interface{}) { + WithLevel(info, v...) +} + +// Infof provides info level logging +func Infof(format string, v ...interface{}) { + WithLevelf(info, format, v...) +} + // Fatal logs with Log and then exits with os.Exit(1) func Fatal(v ...interface{}) { - Log(v...) + WithLevel(fatal, v...) os.Exit(1) } // Fatalf logs with Logf and then exits with os.Exit(1) func Fatalf(format string, v ...interface{}) { - Logf(format, v...) + WithLevelf(fatal, format, v...) os.Exit(1) } @@ -39,3 +98,18 @@ func Fatalf(format string, v ...interface{}) { func SetLogger(l log.Logger) { logger = l } + +// GetLogger returns the local logger +func GetLogger() log.Logger { + return logger +} + +// SetLevel sets the log level +func SetLevel(l Level) { + level = l +} + +// GetLevel returns the current level +func GetLevel() Level { + return level +} From c3611aead24321c42d853c967e8ad3d48006fb18 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 2 Jul 2019 20:53:42 +0100 Subject: [PATCH 093/287] go fmt --- transport/mucp/network.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/transport/mucp/network.go b/transport/mucp/network.go index 3e9d8367..789c5e76 100644 --- a/transport/mucp/network.go +++ b/transport/mucp/network.go @@ -15,7 +15,7 @@ import ( type networkKey struct{} // Transport is a mucp transport. It should only -// be created with NewTransport and cast to +// be created with NewTransport and cast to // *Transport if there's a need to close it. type Transport struct { options transport.Options From f619e46def2512dfec3531e4f3c9abc7ea22c259 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 2 Jul 2019 20:54:21 +0100 Subject: [PATCH 094/287] Some functioning network code --- network/default.go | 26 ++- network/link.go | 267 ++++++++++++++++++++-- network/node.go | 313 ++++++++++++++++++-------- network/resolver/registry/registry.go | 9 +- network/socket.go | 176 --------------- 5 files changed, 487 insertions(+), 304 deletions(-) delete mode 100644 network/socket.go diff --git a/network/default.go b/network/default.go index 456be806..88203a48 100644 --- a/network/default.go +++ b/network/default.go @@ -44,15 +44,17 @@ type network struct { // lease generates a new lease with a node id/address // TODO: use a consensus mechanism, pool or some deterministic -// unique prefixing method. +// unique addressing method. func (n *network) lease() *pb.Lease { // create the id id := uuid.New().String() // create a timestamp now := time.Now().UnixNano() - // create the address + + // create the address by hashing the id and timestamp h := sha256.New() h.Write([]byte(fmt.Sprintf("%s-%d\n", id, now))) + // magic new address address := fmt.Sprintf("%x", h.Sum(nil)) // return the node @@ -62,6 +64,7 @@ func (n *network) lease() *pb.Lease { Node: &pb.Node{ Id: id, Address: address, + Network: n.id, }, } } @@ -104,7 +107,10 @@ func (n *network) Connect() (Node, error) { return newNode(n) } -// TODO: establish links for peering networks +// Peer is used to establish a link between two networks. +// e.g micro.mu connects to example.com and share routes +// This is done by creating a new node on both networks +// and creating a link between them. func (n *network) Peer(Network) (Link, error) { // New network was created using NewNetwork after receiving routes from a different node @@ -125,9 +131,13 @@ func (n *network) Peer(Network) (Link, error) { func newNetwork(opts ...options.Option) *network { options := options.NewOptions(opts...) - // new network instance + // new network instance with defaults net := &network{ - id: DefaultId, + Options: options, + id: DefaultId, + router: router.DefaultRouter, + proxy: new(mucp.Proxy), + resolver: new(nreg.Resolver), } // get network id @@ -140,24 +150,18 @@ func newNetwork(opts ...options.Option) *network { r, ok := options.Values().Get("network.router") if ok { net.router = r.(router.Router) - } else { - net.router = router.DefaultRouter } // get proxy p, ok := options.Values().Get("network.proxy") if ok { net.proxy = p.(proxy.Proxy) - } else { - net.proxy = new(mucp.Proxy) } // get resolver res, ok := options.Values().Get("network.resolver") if ok { net.resolver = res.(resolver.Resolver) - } else { - net.resolver = new(nreg.Resolver) } return net diff --git a/network/link.go b/network/link.go index 5fb6b3e5..c6c1d023 100644 --- a/network/link.go +++ b/network/link.go @@ -1,30 +1,38 @@ package network import ( + "errors" + "fmt" + "io" "sync" + gproto "github.com/golang/protobuf/proto" + "github.com/micro/go-micro/codec" pb "github.com/micro/go-micro/network/proto" + "github.com/micro/go-micro/transport" ) type link struct { // the embedded node *node + sync.RWMutex + // the link id id string - // queue buffer for this link + // the send queue to the socket queue chan *Message + // codec we use to marshal things + codec codec.Marshaler + // the socket for this link - socket *socket + socket transport.Socket // the lease for this link lease *pb.Lease - // length and weight of the link - mtx sync.RWMutex - // determines the cost of the link // based on queue length and roundtrip length int @@ -33,25 +41,252 @@ type link struct { // link methods -// bring up the link -func (l *link) up() error { - // TODO: manage the length/weight of the link - return l.socket.accept() +// process processe messages on the send queue +func (l *link) process() { + for { + select { + case m := <-l.queue: + if err := l.send(m, nil); err != nil { + return + } + } + } } -// kill the link -func (l *link) down() error { - return l.socket.close() +// accept waits for the connect message from the remote end +// if it receives anything else it throws an error +func (l *link) accept() error { + for { + m := new(transport.Message) + err := l.socket.Recv(m) + if err == io.EOF { + return nil + } + if err != nil { + return err + } + + // TODO: pick a reliable header + event := m.Header["Micro-Method"] + + switch event { + // connect event + case "Connect": + // process connect events from network.Connect() + // these are new connections to join the network + + // decode the connection event + conn := new(pb.Connect) + if err := l.codec.Unmarshal(m.Body, conn); err != nil { + // skip error + continue + } + + // get the existing lease if it exists + lease := conn.Lease + // if there's no lease create a new one + if lease == nil { + // create a new lease/node + lease = l.node.network.lease() + } + + // send back a lease offer for the node + if err := l.send(&Message{ + Header: map[string]string{ + "Micro-Method": "Lease", + }, + }, lease); err != nil { + return err + } + + // the lease is saved + l.Lock() + l.lease = lease + l.Unlock() + + // we've connected + // start processing the messages + go l.process() + + return nil + case "Close": + l.Close() + return errors.New("connection closed") + default: + return errors.New("unknown method: " + event) + } + } +} + +// connect sends a connect request and waits on a lease. +// this is for a new connection. in the event we send +// an existing lease, the same lease should be returned. +// if it differs then we assume our address for this link +// is different... +func (l *link) connect() error { + // get the current lease + l.RLock() + lease := l.lease + l.RUnlock() + + // send a lease request + if err := l.send(&Message{ + Header: map[string]string{ + "Micro-Method": "Connect", + }, + }, &pb.Connect{Lease: lease}); err != nil { + return err + } + + // create the new things + tm := new(Message) + newLease := new(pb.Lease) + + // wait for a response, hopefully a lease + if err := l.recv(tm, newLease); err != nil { + return err + } + + event := tm.Header["Micro-Method"] + + // check the method + switch event { + case "Lease": + // save the lease + l.Lock() + l.lease = newLease + l.Unlock() + + // start processing the messages + go l.process() + case "Close": + l.socket.Close() + return errors.New("connection closed") + default: + return errors.New("unable to attain lease") + } + + return nil +} + +// send a message over the link +func (l *link) send(m *Message, v interface{}) error { + tm := new(transport.Message) + tm.Header = m.Header + tm.Body = m.Body + + // set the body if not nil + // we're assuming this is network message + if v != nil { + // encode the data + b, err := l.codec.Marshal(v) + if err != nil { + return err + } + + // set the content type + tm.Header["Content-Type"] = "application/protobuf" + // set the marshalled body + tm.Body = b + } + + fmt.Printf("link %s sending %+v %+v\n", l.id, m, v) + + // send via the transport socket + return l.socket.Send(&transport.Message{ + Header: m.Header, + Body: m.Body, + }) +} + +// recv a message on the link +func (l *link) recv(m *Message, v interface{}) error { + if m.Header == nil { + m.Header = make(map[string]string) + } + + tm := new(transport.Message) + + // receive the transport message + if err := l.socket.Recv(tm); err != nil { + return err + } + + fmt.Printf("link %s receiving %+v %+v\n", l.id, tm, v) + + // set the message + m.Header = tm.Header + m.Body = tm.Body + + // bail early + if v == nil { + return nil + } + + // try unmarshal the body + // skip if there's no content-type + if tm.Header["Content-Type"] != "application/protobuf" { + return nil + } + + // return unmarshalled + return l.codec.Unmarshal(m.Body, v.(gproto.Message)) +} + +// Close the link +func (l *link) Close() error { + // send a final close message + l.socket.Send(&transport.Message{ + Header: map[string]string{ + "Micro-Method": "Close", + }, + }) + // close the socket + return l.socket.Close() +} + +// returns the node id +func (l *link) Id() string { + l.RLock() + defer l.RUnlock() + if l.lease == nil { + return "" + } + return l.lease.Node.Id +} + +// Address of the node we're connected to +func (l *link) Address() string { + l.RLock() + defer l.RUnlock() + if l.lease == nil { + return l.socket.Remote() + } + // the node in the lease + return l.lease.Node.Address } func (l *link) Length() int { - l.mtx.RLock() - defer l.mtx.RUnlock() + l.RLock() + defer l.RUnlock() return l.length } func (l *link) Weight() int { - l.mtx.RLock() - defer l.mtx.RUnlock() + l.RLock() + defer l.RUnlock() return l.weight } + +func (l *link) Accept() (*Message, error) { + m := new(Message) + err := l.recv(m, nil) + if err != nil { + return nil, err + } + return m, nil +} + +func (l *link) Send(m *Message) error { + return l.send(m, nil) +} diff --git a/network/node.go b/network/node.go index d9ebadd2..914a602b 100644 --- a/network/node.go +++ b/network/node.go @@ -1,7 +1,11 @@ package network import ( + "errors" + "fmt" + "net" "runtime/debug" + "strconv" "sync" "time" @@ -9,6 +13,7 @@ import ( "github.com/micro/go-micro/codec/proto" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/util/addr" "github.com/micro/go-micro/util/log" pb "github.com/micro/go-micro/network/proto" @@ -20,7 +25,7 @@ type node struct { // closed channel closed chan bool - mtx sync.RWMutex + sync.RWMutex // the node id id string @@ -40,32 +45,46 @@ type node struct { // leases for connections to us // link id:link links map[string]*link + + // messages received over links + recv chan *Message + // messages received over links + send chan *Message } // network methods func newNode(n *network) (*node, error) { // create a new node - node := new(node) - // closed channel - node.closed = make(chan bool) - // set the nodes network - node.network = n - - // initially we have no id - // create an id and address - // TODO: create a real unique id and address - // lease := n.lease() - // set the node id - // node.id = lease.Node.Id + node := &node{ + // the links + links: make(map[string]*link), + // closed channel + closed: make(chan bool), + // set the nodes network + network: n, + // set the default transport + transport: transport.DefaultTransport, + // set the default registry + registry: registry.DefaultRegistry, + // receive channel for accepted connections + recv: make(chan *Message, 128), + // send channel for accepted connections + send: make(chan *Message, 128), + } // get the transport we're going to use for our tunnels + // TODO: set to quic or tunnel or something else t, ok := n.Options.Values().Get("network.transport") if ok { node.transport = t.(transport.Transport) - } else { - // TODO: set to quic - node.transport = transport.DefaultTransport + } + + // register the node with the registry for the network + // TODO: use a registrar or something else for local things + r, ok := n.Options.Values().Get("network.registry") + if ok { + node.registry = r.(registry.Registry) } // we listen on a random address, this is not advertised @@ -77,8 +96,6 @@ func newNode(n *network) (*node, error) { // set the listener node.listener = l - // TODO: this should be an overlay address - // ideally received via some dhcp style broadcast node.address = l.Addr() // TODO: start the router and broadcast advertisements @@ -90,36 +107,51 @@ func newNode(n *network) (*node, error) { // process any incoming messages on the listener // this is our inbound network connection - node.accept(l) + go node.accept(l) - // register the node with the registry for the network - // TODO: use a registrar or something else for local things - r, ok := n.Options.Values().Get("network.registry") - if ok { - node.registry = r.(registry.Registry) - } else { - node.registry = registry.DefaultRegistry - } + // process any messages being sent by node.Send + // forwards to every link we have + go node.process() // lookup the network to see if there's any nodes records := n.lookup(node.registry) - // should we actually do this? + // assuming if there are no records, we are the first + // we set ourselves a lease. should we actually do this? if len(records) == 0 { // set your own node id lease := n.lease() node.id = lease.Node.Id } - // register self with the network registry + var port int + // TODO: this should be an overlay address + // ideally received via some dhcp style broadcast + host, pp, err := net.SplitHostPort(l.Addr()) + if err == nil { + pt, _ := strconv.Atoi(pp) + port = pt + } + + // some horrible things are happening + if host == "::" { + host = "" + } + // set the address + addr, _ := addr.Extract(host) + + node.address = fmt.Sprintf("%s:%d", addr, port) + + // register self with the registry using network: prefix // this is a local registry of nodes separate to the resolver // maybe consolidate registry/resolver - // TODO: find a way to do this via gossip or something else + // TODO: find a way to do this via gossip or something like + // a registrar or tld or whatever if err := node.registry.Register(®istry.Service{ // register with the network id Name: "network:" + n.Id(), Nodes: []*registry.Node{ - {Id: node.id, Address: node.address}, + {Id: node.id, Address: addr, Port: port}, }, }); err != nil { node.Close() @@ -134,7 +166,20 @@ func newNode(n *network) (*node, error) { // wait forever to connect // TODO: do something with the links we receive - <-linkChan + link := <-linkChan + + // process this link + go node.manage(link) + + go func() { + // process any further new links + select { + case l := <-linkChan: + go node.manage(l) + case <-node.closed: + return + } + }() return node, nil } @@ -158,28 +203,82 @@ func (n *node) accept(l transport.Listener) error { }() // create a new link - // generate a new link link := &link{ + // link has a unique id + id: uuid.New().String(), + // proto marshaler + codec: proto.Marshaler{}, + // link has a socket + socket: sock, + // for generating leases, node: n, - id: uuid.New().String(), + // the send queue, + queue: make(chan *Message, 128), } - // create a new network socket - sk := new(socket) - sk.node = n - sk.codec = proto.Marshaler{} - sk.socket = sock - // set link socket - link.socket = sk + log.Debugf("Accepting connection from %s", link.socket.Remote()) - // accept messages on the socket - // blocks forever or until error - if err := link.up(); err != nil { - // TODO: delete link + // wait for the link to be connected + // the remote end will send "Connect" + // and we will return a "Lease" + if err := link.accept(); err != nil { + return } + + log.Debugf("Accepted link from %s", link.socket.Remote()) + + // save with the remote address as the key + // where we attempt to connect to nodes + // we do not connect to the same thing + n.Lock() + n.links[link.socket.Remote()] = link + n.Unlock() + + // manage the link for its lifetime + n.manage(link) }) } +// processes the send queue +func (n *node) process() { + for { + select { + case <-n.closed: + return + // process outbound messages on the send queue + // these messages are received from n.Send + case m := <-n.send: + // queue the message on each link + // TODO: more than likely use proxy + n.RLock() + for _, l := range n.links { + l.queue <- m + } + n.RUnlock() + } + } +} + +func (n *node) manage(l *link) { + // now process inbound messages on the link + // assumption is this handles everything else + for { + // get a message on the link + m := new(Message) + if err := l.recv(m, nil); err != nil { + // ??? + return + } + + select { + case <-n.closed: + return + // send to the recv channel e.g node.Accept() + case n.recv <- m: + } + } +} + // connect attempts to periodically connect to new nodes in the network. // It will only do this if it has less than 3 connections. this method // is called by network.Connect and fired in a go routine after establishing @@ -188,30 +287,37 @@ func (n *node) accept(l transport.Listener) error { func (n *node) connect(linkChan chan *link) { // TODO: adjustable ticker t := time.NewTicker(time.Second) + var lease *pb.Lease for { select { + // exit when told to do so + case <-n.closed: + return // on every tick check the number of links and then attempt // to connect to new nodes if we don't have sufficient links case <-t.C: - n.mtx.RLock() + n.RLock() // only start processing if we have less than 3 links if len(n.links) > 2 { - n.mtx.RUnlock() + n.RUnlock() continue } // get a list of link addresses so we don't reconnect // to the ones we're already connected to nodes := map[string]bool{} - for _, l := range n.links { - nodes[l.lease.Node.Address] = true + for addr, _ := range n.links { + // id is the lookup address used to connect + nodes[addr] = true } - n.mtx.RUnlock() + // unlock our read lock + n.RUnlock() + // lookup records for our network records := n.network.lookup(n.registry) // for each record check we haven't already got a connection @@ -224,53 +330,53 @@ func (n *node) connect(linkChan chan *link) { for _, record := range records { // skip existing connections if nodes[record.Address] { + log.Debugf("Skipping connection to %s", record.Address) continue } // attempt to connect and create a link + log.Debugf("Dialing connection to %s", record.Address) + // connect to the node - s, err := n.transport.Dial(record.Address) + sock, err := n.transport.Dial(record.Address) if err != nil { + log.Debugf("Dialing connection error %v", err) continue } - // create a new socket - sk := &socket{ - node: n, - codec: &proto.Marshaler{}, - socket: s, - } - - // broadcast a "connect" request and get back "lease" - // this is your tunnel to the outside world and to the network - // then push updates and messages over this link - // first connect will not have a lease so we get one with node id/address - l, err := sk.connect(lease) - if err != nil { - s.Close() - continue - } - - // set lease for next time - lease = l - // create a new link with the lease and socket link := &link{ + codec: &proto.Marshaler{}, id: uuid.New().String(), lease: lease, - node: n, + socket: sock, queue: make(chan *Message, 128), - socket: sk, } - // bring up the link - go link.up() + log.Debugf("Connecting link to %s", record.Address) + // connect the link: + // this broadcasts a "connect" request and gets back a "lease" + // this is the tunnel to the outside world and to the network + // then push updates and messages over this link + // first connect will not have a lease so we get one with node id/address + if err := link.connect(); err != nil { + // shit + link.Close() + continue + } + + log.Debugf("Connected link to %s", record.Address) + + n.Lock() + // set lease for next time we connect to anything else + // we want to use the same lease for that. in future + // we may have to expire the lease + lease = link.lease // save the new link - n.mtx.Lock() - n.links[link.id] = link - n.mtx.Unlock() + n.links[link.socket.Remote()] = link + n.Unlock() // drop this down the link channel to the network // so it can manage the links @@ -280,8 +386,6 @@ func (n *node) connect(linkChan chan *link) { default: } } - case <-n.closed: - return } } } @@ -296,14 +400,17 @@ func (n *node) Close() error { case <-n.closed: return nil default: + // mark as closed close(n.closed) + // shutdown all the links - n.mtx.Lock() + n.Lock() for id, link := range n.links { - link.down() + link.Close() delete(n.links, id) } - n.mtx.Unlock() + n.Unlock() + // deregister self n.registry.Deregister(®istry.Service{ Name: "network:" + n.network.Id(), @@ -311,14 +418,29 @@ func (n *node) Close() error { {Id: n.id, Address: n.address}, }, }) + + // shutdown the listener return n.listener.Close() } return nil } +// Accept receives the incoming messages from all links func (n *node) Accept() (*Message, error) { // process the inbound cruft - + for { + select { + case m, ok := <-n.recv: + if !ok { + return nil, errors.New("connection closed") + } + // return the message + return m, nil + case <-n.closed: + return nil, errors.New("connection closed") + } + } + // we never get here return nil, nil } @@ -326,22 +448,13 @@ func (n *node) Network() string { return n.network.id } +// Send propagates a message over all links. This should probably use its proxy. func (n *node) Send(m *Message) error { - n.mtx.RLock() - defer n.mtx.RUnlock() - - var gerr error - - // send to all links - // TODO: be smarter - for _, link := range n.links { - // TODO: process the error, do some link flap detection - // blackhole the connection, etc - if err := link.socket.send(m, nil); err != nil { - gerr = err - continue - } + select { + case <-n.closed: + return errors.New("connection closed") + case n.send <- m: + // send the message } - - return gerr + return nil } diff --git a/network/resolver/registry/registry.go b/network/resolver/registry/registry.go index c7ef796a..09228970 100644 --- a/network/resolver/registry/registry.go +++ b/network/resolver/registry/registry.go @@ -2,6 +2,8 @@ package registry import ( + "fmt" + "github.com/micro/go-micro/network/resolver" "github.com/micro/go-micro/registry" ) @@ -27,8 +29,13 @@ func (r *Resolver) Resolve(id string) ([]*resolver.Record, error) { for _, service := range services { for _, node := range service.Nodes { + addr := node.Address + // such a hack + if node.Port > 0 { + addr = fmt.Sprintf("%s:%d", node.Address, node.Port) + } records = append(records, &resolver.Record{ - Address: node.Address, + Address: addr, }) } } diff --git a/network/socket.go b/network/socket.go deleted file mode 100644 index 3b6de23a..00000000 --- a/network/socket.go +++ /dev/null @@ -1,176 +0,0 @@ -package network - -import ( - "io" - - gproto "github.com/golang/protobuf/proto" - "github.com/google/uuid" - "github.com/micro/go-micro/codec" - "github.com/micro/go-micro/transport" - - pb "github.com/micro/go-micro/network/proto" -) - -type socket struct { - node *node - codec codec.Marshaler - socket transport.Socket -} - -func (s *socket) close() error { - return s.socket.Close() -} - -// accept is the state machine that processes messages on the socket -func (s *socket) accept() error { - for { - m := new(transport.Message) - err := s.socket.Recv(m) - if err == io.EOF { - return nil - } - if err != nil { - return err - } - - // TODO: pick a reliable header - event := m.Header["Micro-Method"] - - switch event { - // connect event - case "connect": - // process connect events from network.Connect() - // these are new connections to join the network - - // decode the connection event - conn := new(pb.Connect) - if err := s.codec.Unmarshal(m.Body, conn); err != nil { - // skip error - continue - } - - // get the existing lease if it exists - lease := conn.Lease - if lease == nil { - // create a new lease/node - lease = s.node.network.lease() - } - - // send back a lease offer for the node - if err := s.send(&Message{ - Header: map[string]string{ - "Micro-Method": "lease", - }, - }, lease); err != nil { - return err - } - - // record this mapping of socket to node/lease - s.node.mtx.Lock() - id := uuid.New().String() - s.node.links[id] = &link{ - node: s.node, - id: id, - lease: lease, - queue: make(chan *Message, 128), - socket: s, - } - s.node.mtx.Unlock() - // a route update - case "route": - // process router events - - // received a lease - case "lease": - // no op as we don't process lease events on existing connections - // these are in response to a connect message - default: - // process all other messages - } - } -} - -// connect sends a connect request and waits on a lease. -// this is for a new connection. in the event we send -// an existing lease, the same lease should be returned. -// if it differs then we assume our address for this link -// is different... -func (s *socket) connect(l *pb.Lease) (*pb.Lease, error) { - // send a lease request - if err := s.send(&Message{ - Header: map[string]string{ - "Micro-Method": "connect", - }, - }, &pb.Connect{Lease: l}); err != nil { - return nil, err - } - - // create the new things - tm := new(Message) - lease := new(pb.Lease) - - // wait for a lease response - if err := s.recv(tm, lease); err != nil { - return nil, err - } - - return lease, nil -} - -func (s *socket) send(m *Message, v interface{}) error { - tm := new(transport.Message) - tm.Header = m.Header - tm.Body = m.Body - - // set the body if not nil - // we're assuming this is network message - if v != nil { - // encode the data - b, err := s.codec.Marshal(v) - if err != nil { - return err - } - - // set the content type - tm.Header["Content-Type"] = "application/protobuf" - // set the marshalled body - tm.Body = b - } - - // send via the transport socket - return s.socket.Send(&transport.Message{ - Header: m.Header, - Body: m.Body, - }) -} - -func (s *socket) recv(m *Message, v interface{}) error { - if m.Header == nil { - m.Header = make(map[string]string) - } - - tm := new(transport.Message) - - // receive the transport message - if err := s.socket.Recv(tm); err != nil { - return err - } - - // set the message - m.Header = tm.Header - m.Body = tm.Body - - // bail early - if v == nil { - return nil - } - - // try unmarshal the body - // skip if there's no content-type - if tm.Header["Content-Type"] != "application/protobuf" { - return nil - } - - // return unmarshalled - return s.codec.Unmarshal(m.Body, v.(gproto.Message)) -} From 7008809eff15660f21c7c27e21a8fe7b376ce891 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 2 Jul 2019 20:57:23 +0100 Subject: [PATCH 095/287] Make the link use debug --- network/link.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/network/link.go b/network/link.go index c6c1d023..e7c25e55 100644 --- a/network/link.go +++ b/network/link.go @@ -2,10 +2,10 @@ package network import ( "errors" - "fmt" "io" "sync" + "github.com/micro/go-micro/util/log" gproto "github.com/golang/protobuf/proto" "github.com/micro/go-micro/codec" pb "github.com/micro/go-micro/network/proto" @@ -190,7 +190,7 @@ func (l *link) send(m *Message, v interface{}) error { tm.Body = b } - fmt.Printf("link %s sending %+v %+v\n", l.id, m, v) + log.Debugf("link %s sending %+v %+v\n", l.id, m, v) // send via the transport socket return l.socket.Send(&transport.Message{ @@ -212,7 +212,7 @@ func (l *link) recv(m *Message, v interface{}) error { return err } - fmt.Printf("link %s receiving %+v %+v\n", l.id, tm, v) + log.Debugf("link %s receiving %+v %+v\n", l.id, tm, v) // set the message m.Header = tm.Header From e54de5637671585aa03aff4e7c70659ebc7a9f7d Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 3 Jul 2019 19:26:24 +0100 Subject: [PATCH 096/287] Functional loopback code --- network/default.go | 3 +- network/link.go | 147 +++++++++++++++++++------ network/node.go | 214 +++++++++++++++++++++++------------- network/proto/network.pb.go | 68 ++++++++---- network/proto/network.proto | 18 ++- 5 files changed, 313 insertions(+), 137 deletions(-) diff --git a/network/default.go b/network/default.go index 88203a48..fd0a6fdf 100644 --- a/network/default.go +++ b/network/default.go @@ -45,7 +45,7 @@ type network struct { // lease generates a new lease with a node id/address // TODO: use a consensus mechanism, pool or some deterministic // unique addressing method. -func (n *network) lease() *pb.Lease { +func (n *network) lease(muid string) *pb.Lease { // create the id id := uuid.New().String() // create a timestamp @@ -62,6 +62,7 @@ func (n *network) lease() *pb.Lease { Id: id, Timestamp: now, Node: &pb.Node{ + Muid: muid, Id: id, Address: address, Network: n.id, diff --git a/network/link.go b/network/link.go index e7c25e55..9dc5b7d7 100644 --- a/network/link.go +++ b/network/link.go @@ -5,24 +5,30 @@ import ( "io" "sync" - "github.com/micro/go-micro/util/log" gproto "github.com/golang/protobuf/proto" + "github.com/google/uuid" "github.com/micro/go-micro/codec" + "github.com/micro/go-micro/codec/proto" pb "github.com/micro/go-micro/network/proto" "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/util/log" ) type link struct { // the embedded node *node + closed chan bool + sync.RWMutex // the link id id string // the send queue to the socket - queue chan *Message + sendQueue chan *Message + // the recv queue to the socket + recvQueue chan *Message // codec we use to marshal things codec codec.Marshaler @@ -39,16 +45,53 @@ type link struct { weight int } +var ( + ErrLinkClosed = errors.New("link closed") +) + +func newLink(n *node, sock transport.Socket, lease *pb.Lease) *link { + return &link{ + id: uuid.New().String(), + closed: make(chan bool), + codec: &proto.Marshaler{}, + node: n, + lease: lease, + socket: sock, + sendQueue: make(chan *Message, 128), + recvQueue: make(chan *Message, 128), + } +} + // link methods -// process processe messages on the send queue +// process processes messages on the send queue. +// these are messages to be sent to the remote side. func (l *link) process() { - for { - select { - case m := <-l.queue: - if err := l.send(m, nil); err != nil { + go func() { + for { + m := new(Message) + if err := l.recv(m, nil); err != nil { + l.Close() return } + select { + case l.recvQueue <- m: + log.Debugf("%s processing recv", l.id) + case <-l.closed: + return + } + } + }() + + for { + select { + case m := <-l.sendQueue: + if err := l.send(m, nil); err != nil { + l.Close() + return + } + case <-l.closed: + return } } } @@ -71,29 +114,49 @@ func (l *link) accept() error { switch event { // connect event - case "Connect": + case "connect": // process connect events from network.Connect() // these are new connections to join the network // decode the connection event conn := new(pb.Connect) + // expecting a connect message if err := l.codec.Unmarshal(m.Body, conn); err != nil { // skip error continue } + // no micro id close the link + if len(conn.Muid) == 0 { + l.Close() + return errors.New("invalid muid " + conn.Muid) + } + // get the existing lease if it exists lease := conn.Lease // if there's no lease create a new one if lease == nil { // create a new lease/node - lease = l.node.network.lease() + lease = l.node.network.lease(conn.Muid) } + // check if we connected to ourself + if conn.Muid == l.node.muid { + // check our own leasae + l.node.Lock() + if l.node.lease == nil { + l.node.lease = lease + } + l.node.Unlock() + } + + // set the author to our own muid + lease.Author = l.node.muid + // send back a lease offer for the node if err := l.send(&Message{ Header: map[string]string{ - "Micro-Method": "Lease", + "Micro-Method": "lease", }, }, lease); err != nil { return err @@ -107,11 +170,10 @@ func (l *link) accept() error { // we've connected // start processing the messages go l.process() - return nil - case "Close": + case "close": l.Close() - return errors.New("connection closed") + return io.EOF default: return errors.New("unknown method: " + event) } @@ -132,9 +194,9 @@ func (l *link) connect() error { // send a lease request if err := l.send(&Message{ Header: map[string]string{ - "Micro-Method": "Connect", + "Micro-Method": "connect", }, - }, &pb.Connect{Lease: lease}); err != nil { + }, &pb.Connect{Muid: l.node.muid, Lease: lease}); err != nil { return err } @@ -151,7 +213,7 @@ func (l *link) connect() error { // check the method switch event { - case "Lease": + case "lease": // save the lease l.Lock() l.lease = newLease @@ -159,10 +221,11 @@ func (l *link) connect() error { // start processing the messages go l.process() - case "Close": - l.socket.Close() - return errors.New("connection closed") + case "close": + l.Close() + return io.EOF default: + l.Close() return errors.New("unable to attain lease") } @@ -190,13 +253,8 @@ func (l *link) send(m *Message, v interface{}) error { tm.Body = b } - log.Debugf("link %s sending %+v %+v\n", l.id, m, v) - // send via the transport socket - return l.socket.Send(&transport.Message{ - Header: m.Header, - Body: m.Body, - }) + return l.socket.Send(tm) } // recv a message on the link @@ -207,12 +265,14 @@ func (l *link) recv(m *Message, v interface{}) error { tm := new(transport.Message) + log.Debugf("link %s attempting receiving", l.id) + // receive the transport message if err := l.socket.Recv(tm); err != nil { return err } - log.Debugf("link %s receiving %+v %+v\n", l.id, tm, v) + log.Debugf("link %s received %+v %+v\n", l.id, tm, v) // set the message m.Header = tm.Header @@ -235,12 +295,20 @@ func (l *link) recv(m *Message, v interface{}) error { // Close the link func (l *link) Close() error { + select { + case <-l.closed: + return nil + default: + close(l.closed) + } + // send a final close message l.socket.Send(&transport.Message{ Header: map[string]string{ - "Micro-Method": "Close", + "Micro-Method": "close", }, }) + // close the socket return l.socket.Close() } @@ -273,20 +341,27 @@ func (l *link) Length() int { } func (l *link) Weight() int { - l.RLock() - defer l.RUnlock() - return l.weight + return len(l.sendQueue) + len(l.recvQueue) } +// Accept accepts a message on the socket func (l *link) Accept() (*Message, error) { - m := new(Message) - err := l.recv(m, nil) - if err != nil { - return nil, err + select { + case <-l.closed: + return nil, ErrLinkClosed + case m := <-l.recvQueue: + return m, nil } - return m, nil + // never reach + return nil, nil } +// Send sends a message on the socket immediately func (l *link) Send(m *Message) error { - return l.send(m, nil) + select { + case <-l.closed: + return ErrLinkClosed + case l.sendQueue <- m: + } + return nil } diff --git a/network/node.go b/network/node.go index 914a602b..1e6b7cd1 100644 --- a/network/node.go +++ b/network/node.go @@ -5,12 +5,12 @@ import ( "fmt" "net" "runtime/debug" + "sort" "strconv" "sync" "time" "github.com/google/uuid" - "github.com/micro/go-micro/codec/proto" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/transport" "github.com/micro/go-micro/util/addr" @@ -22,17 +22,23 @@ import ( type node struct { *network - // closed channel + // closed channel to close our connection to the network closed chan bool sync.RWMutex - // the node id + // the nodes unique micro assigned mac address + muid string + + // the node id registered in registry id string - // address of this node + // address of this node registered in registry address string + // our network lease with our network id/address + lease *pb.Lease + // the node registry registry registry.Registry @@ -42,9 +48,13 @@ type node struct { // the listener listener transport.Listener + // connected records + // record.Address:true + connected map[string]bool + // leases for connections to us - // link id:link - links map[string]*link + // link remote node:link + links map[string][]*link // messages received over links recv chan *Message @@ -57,8 +67,12 @@ type node struct { func newNode(n *network) (*node, error) { // create a new node node := &node{ + // this nodes unique micro assigned mac address + muid: fmt.Sprintf("%s-%s", n.id, uuid.New().String()), + // map of connected records + connected: make(map[string]bool), // the links - links: make(map[string]*link), + links: make(map[string][]*link), // closed channel closed: make(chan bool), // set the nodes network @@ -113,17 +127,6 @@ func newNode(n *network) (*node, error) { // forwards to every link we have go node.process() - // lookup the network to see if there's any nodes - records := n.lookup(node.registry) - - // assuming if there are no records, we are the first - // we set ourselves a lease. should we actually do this? - if len(records) == 0 { - // set your own node id - lease := n.lease() - node.id = lease.Node.Id - } - var port int // TODO: this should be an overlay address // ideally received via some dhcp style broadcast @@ -140,6 +143,9 @@ func newNode(n *network) (*node, error) { // set the address addr, _ := addr.Extract(host) + // used to register in registry for network resolution + // separate to our lease on the network itself + node.id = uuid.New().String() node.address = fmt.Sprintf("%s:%d", addr, port) // register self with the registry using network: prefix @@ -169,15 +175,19 @@ func newNode(n *network) (*node, error) { link := <-linkChan // process this link + log.Debugf("connect managing link %s", link.id) go node.manage(link) go func() { - // process any further new links - select { - case l := <-linkChan: - go node.manage(l) - case <-node.closed: - return + for { + // process any further new links + select { + case l := <-linkChan: + log.Debugf("Managing new link %s", l.id) + go node.manage(l) + case <-node.closed: + return + } } }() @@ -203,18 +213,7 @@ func (n *node) accept(l transport.Listener) error { }() // create a new link - link := &link{ - // link has a unique id - id: uuid.New().String(), - // proto marshaler - codec: proto.Marshaler{}, - // link has a socket - socket: sock, - // for generating leases, - node: n, - // the send queue, - queue: make(chan *Message, 128), - } + link := newLink(n, sock, nil) log.Debugf("Accepting connection from %s", link.socket.Remote()) @@ -222,24 +221,44 @@ func (n *node) accept(l transport.Listener) error { // the remote end will send "Connect" // and we will return a "Lease" if err := link.accept(); err != nil { + log.Debugf("Error accepting connection %v", err) return } log.Debugf("Accepted link from %s", link.socket.Remote()) - // save with the remote address as the key + // save with the muid as the key // where we attempt to connect to nodes // we do not connect to the same thing - n.Lock() - n.links[link.socket.Remote()] = link - n.Unlock() + + // TODO: figure out why this is an issue + // When we receive a connection from ourself + // we can't maintain the two links separately + // so we don't save it. It's basically some + // weird loopback issue because its our own socket. + if n.muid != link.lease.Node.Muid { + n.Lock() + // get the links + + links := n.links[link.lease.Node.Muid] + // append to the current links + links = append(links, link) + // save the links with muid as the key + n.links[link.lease.Node.Muid] = links + n.Unlock() + } // manage the link for its lifetime + log.Debugf("managing the link now %s", link.id) n.manage(link) }) } -// processes the send queue +// processes the sends the messages from n.Send into the queue of +// each link. If multiple links exist for a muid it should only +// send on link to figure it out. +// If we connected to a record and that link goes down we should +// also remove it from the n.connected map. func (n *node) process() { for { select { @@ -251,29 +270,51 @@ func (n *node) process() { // queue the message on each link // TODO: more than likely use proxy n.RLock() - for _, l := range n.links { - l.queue <- m + // range over all the links + for _, links := range n.links { + if len(links) == 0 { + continue + } + + // sort the links by weight + sort.Slice(links, func(i, j int) bool { + return links[i].Weight() < links[j].Weight() + }) + + // queue the message + log.Debugf("sending on link %s", links[0].id) + links[0].Send(m) } n.RUnlock() } } } +// Manage manages the link for its lifetime. It should ideally throw +// away the link in the n.links map if there's any issues or total disconnection +// it should look at link.Status. +// If we connected to a record and that link goes down we should +// also remove it from the n.connected map. func (n *node) manage(l *link) { // now process inbound messages on the link // assumption is this handles everything else for { - // get a message on the link - m := new(Message) - if err := l.recv(m, nil); err != nil { + // the send side uses a link queue but the receive side immediately sends it + // ideally we should probably have an internal queue on that side as well + // so we can judge link saturation both ways. + + m, err := l.Accept() + if err != nil { + log.Debugf("Error accepting message on link %s: %v", l.id, err) // ??? return } + // if the node connection is closed bail out select { case <-n.closed: return - // send to the recv channel e.g node.Accept() + // send to the network recv channel e.g node.Accept() case n.recv <- m: } } @@ -301,18 +342,15 @@ func (n *node) connect(linkChan chan *link) { n.RLock() // only start processing if we have less than 3 links - if len(n.links) > 2 { + conns := len(n.links) + if conns > 2 { n.RUnlock() continue } // get a list of link addresses so we don't reconnect // to the ones we're already connected to - nodes := map[string]bool{} - for addr, _ := range n.links { - // id is the lookup address used to connect - nodes[addr] = true - } + connected := n.connected // unlock our read lock n.RUnlock() @@ -329,11 +367,17 @@ func (n *node) connect(linkChan chan *link) { // while still connecting to the global network for _, record := range records { // skip existing connections - if nodes[record.Address] { - log.Debugf("Skipping connection to %s", record.Address) + if connected[record.Address] { + log.Tracef("Skipping connection to %s", record.Address) continue } + // check how many connections we have + if conns > 2 { + log.Debugf("Made enough connections") + break + } + // attempt to connect and create a link log.Debugf("Dialing connection to %s", record.Address) @@ -346,13 +390,7 @@ func (n *node) connect(linkChan chan *link) { } // create a new link with the lease and socket - link := &link{ - codec: &proto.Marshaler{}, - id: uuid.New().String(), - lease: lease, - socket: sock, - queue: make(chan *Message, 128), - } + link := newLink(n, sock, lease) log.Debugf("Connecting link to %s", record.Address) @@ -363,7 +401,6 @@ func (n *node) connect(linkChan chan *link) { // first connect will not have a lease so we get one with node id/address if err := link.connect(); err != nil { // shit - link.Close() continue } @@ -375,23 +412,39 @@ func (n *node) connect(linkChan chan *link) { // we may have to expire the lease lease = link.lease // save the new link - n.links[link.socket.Remote()] = link + // get existing links using the lease author + links := n.links[lease.Author] + // append to the links + links = append(links, link) + // save the links using the author + n.links[lease.Author] = links + n.Unlock() + + // update number of connections + conns++ + + // save the connection + n.Lock() + n.connected[record.Address] = true n.Unlock() // drop this down the link channel to the network // so it can manage the links - select { - case linkChan <- link: - // we don't wait for anyone - default: - } + linkChan <- link } } } } func (n *node) Address() string { - return n.address + n.RLock() + defer n.RUnlock() + // we have no address yet + if n.lease == nil { + return "" + } + // return node address in the lease + return n.lease.Node.Address } // Close shutdowns all the links and closes the listener @@ -400,15 +453,19 @@ func (n *node) Close() error { case <-n.closed: return nil default: - // mark as closed + // mark as closed, we're now useless and there's no coming back close(n.closed) // shutdown all the links n.Lock() - for id, link := range n.links { - link.Close() - delete(n.links, id) + for muid, links := range n.links { + for _, link := range links { + link.Close() + } + delete(n.links, muid) } + // reset connected + n.connected = nil n.Unlock() // deregister self @@ -444,6 +501,15 @@ func (n *node) Accept() (*Message, error) { return nil, nil } +func (n *node) Id() string { + n.RLock() + defer n.RUnlock() + if n.lease == nil { + return "" + } + return n.lease.Node.Id +} + func (n *node) Network() string { return n.network.id } diff --git a/network/proto/network.pb.go b/network/proto/network.pb.go index 2d959be3..06f52273 100644 --- a/network/proto/network.pb.go +++ b/network/proto/network.pb.go @@ -22,10 +22,12 @@ const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package // A connect message is for connecting to the network type Connect struct { + // the unique muid (mac) address of the node + Muid string `protobuf:"bytes,1,opt,name=muid,proto3" json:"muid,omitempty"` // Lease specifies an existing lease to indicate // we don't need a new address, we just want to // establish a link. - Lease *Lease `protobuf:"bytes,1,opt,name=lease,proto3" json:"lease,omitempty"` + Lease *Lease `protobuf:"bytes,2,opt,name=lease,proto3" json:"lease,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -56,6 +58,13 @@ func (m *Connect) XXX_DiscardUnknown() { var xxx_messageInfo_Connect proto.InternalMessageInfo +func (m *Connect) GetMuid() string { + if m != nil { + return m.Muid + } + return "" +} + func (m *Connect) GetLease() *Lease { if m != nil { return m.Lease @@ -63,14 +72,16 @@ func (m *Connect) GetLease() *Lease { return nil } -// A lease is returned to anyone attempting to connect. +// A lease is returned to anyone attempting to connect with a valid muid. type Lease struct { // unique lease id Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // timestamp of lease Timestamp int64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + // author is the muid of the author + Author string `protobuf:"bytes,3,opt,name=author,proto3" json:"author,omitempty"` // the node - Node *Node `protobuf:"bytes,3,opt,name=node,proto3" json:"node,omitempty"` + Node *Node `protobuf:"bytes,4,opt,name=node,proto3" json:"node,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -115,6 +126,13 @@ func (m *Lease) GetTimestamp() int64 { return 0 } +func (m *Lease) GetAuthor() string { + if m != nil { + return m.Author + } + return "" +} + func (m *Lease) GetNode() *Node { if m != nil { return m.Node @@ -124,9 +142,10 @@ func (m *Lease) GetNode() *Node { // A node is the network node type Node struct { - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` - Network string `protobuf:"bytes,3,opt,name=network,proto3" json:"network,omitempty"` + Muid string `protobuf:"bytes,1,opt,name=muid,proto3" json:"muid,omitempty"` + Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` + Address string `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"` + Network string `protobuf:"bytes,4,opt,name=network,proto3" json:"network,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -157,6 +176,13 @@ func (m *Node) XXX_DiscardUnknown() { var xxx_messageInfo_Node proto.InternalMessageInfo +func (m *Node) GetMuid() string { + if m != nil { + return m.Muid + } + return "" +} + func (m *Node) GetId() string { if m != nil { return m.Id @@ -189,18 +215,20 @@ func init() { } var fileDescriptor_4daa91d05ddc28b6 = []byte{ - // 203 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x90, 0xc1, 0x4a, 0xc4, 0x30, - 0x10, 0x86, 0x69, 0x77, 0xd7, 0x25, 0x23, 0x88, 0xe4, 0xa0, 0x39, 0x78, 0x58, 0x7a, 0x2a, 0x85, - 0xa6, 0xa0, 0x17, 0xef, 0xde, 0x44, 0x3c, 0xe4, 0x0d, 0x62, 0x33, 0x94, 0xa0, 0xcd, 0x94, 0x24, - 0xe0, 0xeb, 0x4b, 0xa7, 0xad, 0x82, 0xbd, 0xe5, 0x9b, 0xf9, 0xf3, 0x7f, 0x30, 0xd0, 0x8c, 0xbe, - 0x8f, 0xd4, 0x0d, 0xd4, 0x2e, 0x8f, 0x80, 0xf9, 0x9b, 0xe2, 0x67, 0x37, 0x45, 0xca, 0xbf, 0xa4, - 0x99, 0xe4, 0xed, 0x40, 0x9a, 0x53, 0x7a, 0x9d, 0x57, 0xcf, 0x70, 0x7e, 0xa1, 0x10, 0xb0, 0xcf, - 0xb2, 0x85, 0xd3, 0x17, 0xda, 0x84, 0xaa, 0xb8, 0x14, 0xf5, 0xf5, 0xe3, 0xbd, 0xfe, 0x1f, 0xd6, - 0x6f, 0xf3, 0xda, 0x2c, 0xa9, 0xca, 0xc2, 0x89, 0x59, 0xde, 0x40, 0xe9, 0x1d, 0x7f, 0x12, 0xa6, - 0xf4, 0x4e, 0x3e, 0x80, 0xc8, 0x7e, 0xc4, 0x94, 0xed, 0x38, 0xa9, 0xf2, 0x52, 0xd4, 0x07, 0xf3, - 0x37, 0x90, 0x0d, 0x1c, 0x03, 0x39, 0x54, 0x07, 0x96, 0xdc, 0xed, 0x25, 0xef, 0xe4, 0xd0, 0x70, - 0xa6, 0x7a, 0x85, 0xe3, 0x4c, 0x3b, 0x83, 0x82, 0xb3, 0x75, 0x2e, 0x62, 0x4a, 0xdc, 0x2f, 0xcc, - 0x86, 0xf3, 0x66, 0xed, 0x61, 0x81, 0x30, 0x1b, 0x7e, 0x5c, 0xf1, 0x05, 0x9e, 0x7e, 0x02, 0x00, - 0x00, 0xff, 0xff, 0xf3, 0x2b, 0x3d, 0x08, 0x2f, 0x01, 0x00, 0x00, + // 229 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x90, 0xc1, 0x6a, 0xc3, 0x30, + 0x0c, 0x86, 0x49, 0x9a, 0xb6, 0x44, 0x83, 0x31, 0x74, 0xe8, 0x7c, 0xd8, 0xa1, 0xe4, 0x54, 0x0a, + 0x75, 0x61, 0x7b, 0x84, 0x5d, 0xcb, 0x0e, 0x7e, 0x80, 0x41, 0x56, 0x8b, 0x2e, 0x6c, 0xb6, 0x8a, + 0xed, 0x32, 0xf6, 0xf6, 0x23, 0x8a, 0x93, 0xc1, 0xd6, 0x9b, 0x3e, 0xe9, 0xf7, 0xff, 0xcb, 0x82, + 0xad, 0xeb, 0x8e, 0x81, 0xf7, 0x27, 0xde, 0x0d, 0x85, 0xa7, 0xf4, 0xc5, 0xe1, 0x63, 0x7f, 0x0e, + 0x9c, 0x26, 0xd2, 0x42, 0x78, 0x77, 0x62, 0x2d, 0x2a, 0x9d, 0xfb, 0xcd, 0x01, 0x96, 0xcf, 0xec, + 0x3d, 0x1d, 0x13, 0x22, 0x54, 0xee, 0xd2, 0x59, 0x55, 0xac, 0x8b, 0x4d, 0x6d, 0xa4, 0xc6, 0x1d, + 0xcc, 0x3f, 0xa9, 0x8d, 0xa4, 0xca, 0x75, 0xb1, 0xb9, 0x79, 0xbc, 0xd7, 0x7f, 0x0d, 0xf4, 0xa1, + 0x1f, 0x9b, 0x41, 0xd5, 0x7c, 0xc3, 0x5c, 0x18, 0x6f, 0xa1, 0x9c, 0x9c, 0xca, 0xce, 0xe2, 0x03, + 0xd4, 0xa9, 0x73, 0x14, 0x53, 0xeb, 0xce, 0xe2, 0x35, 0x33, 0xbf, 0x0d, 0x5c, 0xc1, 0xa2, 0xbd, + 0xa4, 0x77, 0x0e, 0x6a, 0x26, 0x2f, 0x32, 0xe1, 0x16, 0x2a, 0xcf, 0x96, 0x54, 0x25, 0xe1, 0xab, + 0xff, 0xe1, 0x2f, 0x6c, 0xc9, 0x88, 0xa6, 0x79, 0x85, 0xaa, 0xa7, 0xab, 0xbf, 0x18, 0xb6, 0x29, + 0xa7, 0x6d, 0x14, 0x2c, 0x5b, 0x6b, 0x03, 0xc5, 0x98, 0x03, 0x47, 0xec, 0x27, 0xd9, 0x5b, 0x42, + 0x6b, 0x33, 0xe2, 0xdb, 0x42, 0x2e, 0xf8, 0xf4, 0x13, 0x00, 0x00, 0xff, 0xff, 0xba, 0xcc, 0x46, + 0x1e, 0x6f, 0x01, 0x00, 0x00, } diff --git a/network/proto/network.proto b/network/proto/network.proto index 2bf9784f..a1800e37 100644 --- a/network/proto/network.proto +++ b/network/proto/network.proto @@ -4,25 +4,31 @@ package go.micro.network; // A connect message is for connecting to the network message Connect { + // the unique muid (mac) address of the node + string muid = 1; + // Lease specifies an existing lease to indicate // we don't need a new address, we just want to // establish a link. - Lease lease = 1; + Lease lease = 2; } -// A lease is returned to anyone attempting to connect. +// A lease is returned to anyone attempting to connect with a valid muid. message Lease { // unique lease id string id = 1; // timestamp of lease int64 timestamp = 2; + // author is the muid of the author + string author = 3; // the node - Node node = 3; + Node node = 4; } // A node is the network node message Node { - string id = 1; - string address = 2; - string network = 3; + string muid = 1; + string id = 2; + string address = 3; + string network = 4; } From 2644497ccb4328afee53da52e08e5127b9aefcc9 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 3 Jul 2019 19:51:40 +0100 Subject: [PATCH 097/287] Fix some link connection logic --- network/link.go | 22 +++++++++------------- network/node.go | 5 ++++- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/network/link.go b/network/link.go index 9dc5b7d7..5b676be5 100644 --- a/network/link.go +++ b/network/link.go @@ -11,7 +11,6 @@ import ( "github.com/micro/go-micro/codec/proto" pb "github.com/micro/go-micro/network/proto" "github.com/micro/go-micro/transport" - "github.com/micro/go-micro/util/log" ) type link struct { @@ -71,12 +70,17 @@ func (l *link) process() { for { m := new(Message) if err := l.recv(m, nil); err != nil { + return + } + + // check if it's an internal close method + if m.Header["Micro-Method"] == "close" { l.Close() return } + select { case l.recvQueue <- m: - log.Debugf("%s processing recv", l.id) case <-l.closed: return } @@ -87,7 +91,6 @@ func (l *link) process() { select { case m := <-l.sendQueue: if err := l.send(m, nil); err != nil { - l.Close() return } case <-l.closed: @@ -265,15 +268,11 @@ func (l *link) recv(m *Message, v interface{}) error { tm := new(transport.Message) - log.Debugf("link %s attempting receiving", l.id) - // receive the transport message if err := l.socket.Recv(tm); err != nil { return err } - log.Debugf("link %s received %+v %+v\n", l.id, tm, v) - // set the message m.Header = tm.Header m.Body = tm.Body @@ -303,14 +302,11 @@ func (l *link) Close() error { } // send a final close message - l.socket.Send(&transport.Message{ + return l.socket.Send(&transport.Message{ Header: map[string]string{ "Micro-Method": "close", }, }) - - // close the socket - return l.socket.Close() } // returns the node id @@ -348,7 +344,7 @@ func (l *link) Weight() int { func (l *link) Accept() (*Message, error) { select { case <-l.closed: - return nil, ErrLinkClosed + return nil, io.EOF case m := <-l.recvQueue: return m, nil } @@ -360,7 +356,7 @@ func (l *link) Accept() (*Message, error) { func (l *link) Send(m *Message) error { select { case <-l.closed: - return ErrLinkClosed + return io.EOF case l.sendQueue <- m: } return nil diff --git a/network/node.go b/network/node.go index 1e6b7cd1..ea05824a 100644 --- a/network/node.go +++ b/network/node.go @@ -3,6 +3,7 @@ package network import ( "errors" "fmt" + "io" "net" "runtime/debug" "sort" @@ -282,7 +283,6 @@ func (n *node) process() { }) // queue the message - log.Debugf("sending on link %s", links[0].id) links[0].Send(m) } n.RUnlock() @@ -304,6 +304,9 @@ func (n *node) manage(l *link) { // so we can judge link saturation both ways. m, err := l.Accept() + if err == io.EOF { + return + } if err != nil { log.Debugf("Error accepting message on link %s: %v", l.id, err) // ??? From 0e34c572b48e15d1f8a38555c265fc61ec7de910 Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Thu, 4 Jul 2019 00:15:44 +0300 Subject: [PATCH 098/287] export registry util function to safe copy registry data Signed-off-by: Vasiliy Tolstov --- registry/cache/rcache.go | 39 +-------------- registry/gossip/gossip.go | 8 +-- registry/memory/helper.go | 76 ----------------------------- registry/memory/helper_test.go | 78 ------------------------------ registry/memory/memory.go | 46 +++++++++--------- registry/{gossip => }/util.go | 58 +++++++++++----------- registry/{gossip => }/util_test.go | 20 ++++---- 7 files changed, 66 insertions(+), 259 deletions(-) delete mode 100644 registry/memory/helper.go delete mode 100644 registry/memory/helper_test.go rename registry/{gossip => }/util.go (59%) rename registry/{gossip => }/util_test.go (72%) diff --git a/registry/cache/rcache.go b/registry/cache/rcache.go index 09ff3c48..cc5ca319 100644 --- a/registry/cache/rcache.go +++ b/registry/cache/rcache.go @@ -80,41 +80,6 @@ func (c *cache) quit() bool { } } -// cp copies a service. Because we're caching handing back pointers would -// create a race condition, so we do this instead its fast enough -func (c *cache) cp(current []*registry.Service) []*registry.Service { - var services []*registry.Service - - for _, service := range current { - // copy service - s := new(registry.Service) - *s = *service - - // copy nodes - var nodes []*registry.Node - for _, node := range service.Nodes { - n := new(registry.Node) - *n = *node - nodes = append(nodes, n) - } - s.Nodes = nodes - - // copy endpoints - var eps []*registry.Endpoint - for _, ep := range service.Endpoints { - e := new(registry.Endpoint) - *e = *ep - eps = append(eps, e) - } - s.Endpoints = eps - - // append service - services = append(services, s) - } - - return services -} - func (c *cache) del(service string) { delete(c.cache, service) delete(c.ttls, service) @@ -132,7 +97,7 @@ func (c *cache) get(service string) ([]*registry.Service, error) { // got services && within ttl so return cache if c.isValid(services, ttl) { // make a copy - cp := c.cp(services) + cp := registry.CopyServices(services) // unlock the read c.RUnlock() // return servics @@ -149,7 +114,7 @@ func (c *cache) get(service string) ([]*registry.Service, error) { // cache results c.Lock() - c.set(service, c.cp(services)) + c.set(service, registry.CopyServices(services)) c.Unlock() return services, nil diff --git a/registry/gossip/gossip.go b/registry/gossip/gossip.go index 45506392..508c9961 100644 --- a/registry/gossip/gossip.go +++ b/registry/gossip/gossip.go @@ -626,7 +626,7 @@ func (g *gossipRegistry) run() { g.services[u.Service.Name] = []*registry.Service{u.Service} } else { - g.services[u.Service.Name] = addServices(service, []*registry.Service{u.Service}) + g.services[u.Service.Name] = registry.AddServices(service, []*registry.Service{u.Service}) } g.Unlock() @@ -645,7 +645,7 @@ func (g *gossipRegistry) run() { case actionTypeDelete: g.Lock() if service, ok := g.services[u.Service.Name]; ok { - if services := delServices(service, []*registry.Service{u.Service}); len(services) == 0 { + if services := registry.DelServices(service, []*registry.Service{u.Service}); len(services) == 0 { delete(g.services, u.Service.Name) } else { g.services[u.Service.Name] = services @@ -706,7 +706,7 @@ func (g *gossipRegistry) Register(s *registry.Service, opts ...registry.Register if service, ok := g.services[s.Name]; !ok { g.services[s.Name] = []*registry.Service{s} } else { - g.services[s.Name] = addServices(service, []*registry.Service{s}) + g.services[s.Name] = registry.AddServices(service, []*registry.Service{s}) } g.Unlock() @@ -754,7 +754,7 @@ func (g *gossipRegistry) Deregister(s *registry.Service) error { g.Lock() if service, ok := g.services[s.Name]; ok { - if services := delServices(service, []*registry.Service{s}); len(services) == 0 { + if services := registry.DelServices(service, []*registry.Service{s}); len(services) == 0 { delete(g.services, s.Name) } else { g.services[s.Name] = services diff --git a/registry/memory/helper.go b/registry/memory/helper.go deleted file mode 100644 index 2308dde7..00000000 --- a/registry/memory/helper.go +++ /dev/null @@ -1,76 +0,0 @@ -package memory - -import ( - "github.com/micro/go-micro/registry" -) - -func addNodes(old, neu []*registry.Node) []*registry.Node { - for _, n := range neu { - var seen bool - for i, o := range old { - if o.Id == n.Id { - seen = true - old[i] = n - break - } - } - if !seen { - old = append(old, n) - } - } - return old -} - -func addServices(old, neu []*registry.Service) []*registry.Service { - for _, s := range neu { - var seen bool - for i, o := range old { - if o.Version == s.Version { - s.Nodes = addNodes(o.Nodes, s.Nodes) - seen = true - old[i] = s - break - } - } - if !seen { - old = append(old, s) - } - } - return old -} - -func delNodes(old, del []*registry.Node) []*registry.Node { - var nodes []*registry.Node - for _, o := range old { - var rem bool - for _, n := range del { - if o.Id == n.Id { - rem = true - break - } - } - if !rem { - nodes = append(nodes, o) - } - } - return nodes -} - -func delServices(old, del []*registry.Service) []*registry.Service { - var services []*registry.Service - for i, o := range old { - var rem bool - for _, s := range del { - if o.Version == s.Version { - old[i].Nodes = delNodes(o.Nodes, s.Nodes) - if len(old[i].Nodes) == 0 { - rem = true - } - } - } - if !rem { - services = append(services, o) - } - } - return services -} diff --git a/registry/memory/helper_test.go b/registry/memory/helper_test.go deleted file mode 100644 index f19d1c52..00000000 --- a/registry/memory/helper_test.go +++ /dev/null @@ -1,78 +0,0 @@ -package memory - -import ( - "testing" - - "github.com/micro/go-micro/registry" -) - -func TestDelServices(t *testing.T) { - services := []*registry.Service{ - { - Name: "foo", - Version: "1.0.0", - Nodes: []*registry.Node{ - { - Id: "foo-123", - Address: "localhost", - Port: 9999, - }, - }, - }, - { - Name: "foo", - Version: "1.0.0", - Nodes: []*registry.Node{ - { - Id: "foo-123", - Address: "localhost", - Port: 6666, - }, - }, - }, - } - - servs := delServices([]*registry.Service{services[0]}, []*registry.Service{services[1]}) - if i := len(servs); i > 0 { - t.Errorf("Expected 0 nodes, got %d: %+v", i, servs) - } - t.Logf("Services %+v", servs) -} - -func TestDelNodes(t *testing.T) { - services := []*registry.Service{ - { - Name: "foo", - Version: "1.0.0", - Nodes: []*registry.Node{ - { - Id: "foo-123", - Address: "localhost", - Port: 9999, - }, - { - Id: "foo-321", - Address: "localhost", - Port: 6666, - }, - }, - }, - { - Name: "foo", - Version: "1.0.0", - Nodes: []*registry.Node{ - { - Id: "foo-123", - Address: "localhost", - Port: 6666, - }, - }, - }, - } - - nodes := delNodes(services[0].Nodes, services[1].Nodes) - if i := len(nodes); i != 1 { - t.Errorf("Expected only 1 node, got %d: %+v", i, nodes) - } - t.Logf("Nodes %+v", nodes) -} diff --git a/registry/memory/memory.go b/registry/memory/memory.go index e159ce61..a978e1ac 100644 --- a/registry/memory/memory.go +++ b/registry/memory/memory.go @@ -22,17 +22,6 @@ var ( timeout = time.Millisecond * 10 ) -/* -// Setup sets mock data -func (m *Registry) Setup() { - m.Lock() - defer m.Unlock() - - // add some memory data - m.Services = Data -} -*/ - func (m *Registry) watch(r *registry.Result) { var watchers []*Watcher @@ -66,7 +55,7 @@ func (m *Registry) Init(opts ...registry.Option) error { m.Lock() for k, v := range getServices(m.options.Context) { s := m.Services[k] - m.Services[k] = addServices(s, v) + m.Services[k] = registry.AddServices(s, v) } m.Unlock() return nil @@ -76,20 +65,20 @@ func (m *Registry) Options() registry.Options { return m.options } -func (m *Registry) GetService(service string) ([]*registry.Service, error) { +func (m *Registry) GetService(name string) ([]*registry.Service, error) { m.RLock() - s, ok := m.Services[service] - if !ok || len(s) == 0 { - m.RUnlock() + service, ok := m.Services[name] + m.RUnlock() + if !ok { return nil, registry.ErrNotFound } - m.RUnlock() - return s, nil + + return service, nil } func (m *Registry) ListServices() ([]*registry.Service, error) { - m.RLock() var services []*registry.Service + m.RLock() for _, service := range m.Services { services = append(services, service...) } @@ -99,11 +88,14 @@ func (m *Registry) ListServices() ([]*registry.Service, error) { func (m *Registry) Register(s *registry.Service, opts ...registry.RegisterOption) error { go m.watch(®istry.Result{Action: "update", Service: s}) - m.Lock() - services := addServices(m.Services[s.Name], []*registry.Service{s}) - m.Services[s.Name] = services + if service, ok := m.Services[s.Name]; !ok { + m.Services[s.Name] = []*registry.Service{s} + } else { + m.Services[s.Name] = registry.AddServices(service, []*registry.Service{s}) + } m.Unlock() + return nil } @@ -111,9 +103,15 @@ func (m *Registry) Deregister(s *registry.Service) error { go m.watch(®istry.Result{Action: "delete", Service: s}) m.Lock() - services := delServices(m.Services[s.Name], []*registry.Service{s}) - m.Services[s.Name] = services + if service, ok := m.Services[s.Name]; ok { + if service := registry.DelServices(service, []*registry.Service{s}); len(service) == 0 { + delete(m.Services, s.Name) + } else { + m.Services[s.Name] = service + } + } m.Unlock() + return nil } diff --git a/registry/gossip/util.go b/registry/util.go similarity index 59% rename from registry/gossip/util.go rename to registry/util.go index 0fa8116d..7954cb0d 100644 --- a/registry/gossip/util.go +++ b/registry/util.go @@ -1,30 +1,26 @@ -package gossip +package registry -import ( - "github.com/micro/go-micro/registry" -) - -func cp(current []*registry.Service) []*registry.Service { - var services []*registry.Service +func CopyServices(current []*Service) []*Service { + var services []*Service for _, service := range current { // copy service - s := new(registry.Service) + s := new(Service) *s = *service // copy nodes - var nodes []*registry.Node + var nodes []*Node for _, node := range service.Nodes { - n := new(registry.Node) + n := new(Node) *n = *node nodes = append(nodes, n) } s.Nodes = nodes // copy endpoints - var eps []*registry.Endpoint + var eps []*Endpoint for _, ep := range service.Endpoints { - e := new(registry.Endpoint) + e := new(Endpoint) *e = *ep eps = append(eps, e) } @@ -37,8 +33,8 @@ func cp(current []*registry.Service) []*registry.Service { return services } -func addNodes(old, neu []*registry.Node) []*registry.Node { - var nodes []*registry.Node +func addServiceNodes(old, neu []*Node) []*Node { + var nodes []*Node // add all new nodes for _, n := range neu { @@ -69,35 +65,39 @@ func addNodes(old, neu []*registry.Node) []*registry.Node { return nodes } -func addServices(old, neu []*registry.Service) []*registry.Service { - var srv []*registry.Service +func AddServices(olist []*Service, nlist []*Service) []*Service { + var srv []*Service - for _, s := range neu { + for _, n := range nlist { var seen bool - for _, o := range old { - if o.Version == s.Version { - sp := new(registry.Service) + for _, o := range olist { + if o.Version == n.Version { + sp := new(Service) // make copy *sp = *o // set nodes - sp.Nodes = addNodes(o.Nodes, s.Nodes) + sp.Nodes = addServiceNodes(o.Nodes, n.Nodes) // mark as seen seen = true srv = append(srv, sp) break + } else { + sp := new(Service) + // make copy + *sp = *o + srv = append(srv, sp) } } if !seen { - srv = append(srv, cp([]*registry.Service{s})...) + srv = append(srv, CopyServices([]*Service{n})...) } } - return srv } -func delNodes(old, del []*registry.Node) []*registry.Node { - var nodes []*registry.Node +func delServiceNodes(old, del []*Node) []*Node { + var nodes []*Node for _, o := range old { var rem bool for _, n := range del { @@ -113,18 +113,18 @@ func delNodes(old, del []*registry.Node) []*registry.Node { return nodes } -func delServices(old, del []*registry.Service) []*registry.Service { - var services []*registry.Service +func DelServices(old, del []*Service) []*Service { + var services []*Service for _, o := range old { - srv := new(registry.Service) + srv := new(Service) *srv = *o var rem bool for _, s := range del { if srv.Version == s.Version { - srv.Nodes = delNodes(srv.Nodes, s.Nodes) + srv.Nodes = delServiceNodes(srv.Nodes, s.Nodes) if len(srv.Nodes) == 0 { rem = true diff --git a/registry/gossip/util_test.go b/registry/util_test.go similarity index 72% rename from registry/gossip/util_test.go rename to registry/util_test.go index a77dda52..6e4dccd5 100644 --- a/registry/gossip/util_test.go +++ b/registry/util_test.go @@ -1,17 +1,15 @@ -package gossip +package registry import ( "testing" - - "github.com/micro/go-micro/registry" ) func TestDelServices(t *testing.T) { - services := []*registry.Service{ + services := []*Service{ { Name: "foo", Version: "1.0.0", - Nodes: []*registry.Node{ + Nodes: []*Node{ { Id: "foo-123", Address: "localhost", @@ -22,7 +20,7 @@ func TestDelServices(t *testing.T) { { Name: "foo", Version: "1.0.0", - Nodes: []*registry.Node{ + Nodes: []*Node{ { Id: "foo-123", Address: "localhost", @@ -32,7 +30,7 @@ func TestDelServices(t *testing.T) { }, } - servs := delServices([]*registry.Service{services[0]}, []*registry.Service{services[1]}) + servs := DelServices([]*Service{services[0]}, []*Service{services[1]}) if i := len(servs); i > 0 { t.Errorf("Expected 0 nodes, got %d: %+v", i, servs) } @@ -40,11 +38,11 @@ func TestDelServices(t *testing.T) { } func TestDelNodes(t *testing.T) { - services := []*registry.Service{ + services := []*Service{ { Name: "foo", Version: "1.0.0", - Nodes: []*registry.Node{ + Nodes: []*Node{ { Id: "foo-123", Address: "localhost", @@ -60,7 +58,7 @@ func TestDelNodes(t *testing.T) { { Name: "foo", Version: "1.0.0", - Nodes: []*registry.Node{ + Nodes: []*Node{ { Id: "foo-123", Address: "localhost", @@ -70,7 +68,7 @@ func TestDelNodes(t *testing.T) { }, } - nodes := delNodes(services[0].Nodes, services[1].Nodes) + nodes := delServiceNodes(services[0].Nodes, services[1].Nodes) if i := len(nodes); i != 1 { t.Errorf("Expected only 1 node, got %d: %+v", i, nodes) } From e88041dc26eeaf32db22014255c7286ceae838d2 Mon Sep 17 00:00:00 2001 From: Joe Date: Thu, 4 Jul 2019 16:43:36 +0800 Subject: [PATCH 099/287] if unmarshal target is proto.Message, using jsonpb --- client/grpc/codec.go | 5 +++++ server/grpc/codec.go | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/client/grpc/codec.go b/client/grpc/codec.go index 62f30384..fe59c361 100644 --- a/client/grpc/codec.go +++ b/client/grpc/codec.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/golang/protobuf/jsonpb" "github.com/golang/protobuf/proto" "github.com/json-iterator/go" "github.com/micro/go-micro/codec" @@ -114,6 +115,10 @@ func (jsonCodec) Marshal(v interface{}) ([]byte, error) { } func (jsonCodec) Unmarshal(data []byte, v interface{}) error { + if pb, ok := v.(proto.Message); ok { + return jsonpb.UnmarshalString(string(data), pb) + } + return json.Unmarshal(data, v) } diff --git a/server/grpc/codec.go b/server/grpc/codec.go index cfa97f92..7562a044 100644 --- a/server/grpc/codec.go +++ b/server/grpc/codec.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/golang/protobuf/jsonpb" "github.com/golang/protobuf/proto" "github.com/micro/go-micro/codec" "github.com/micro/go-micro/codec/bytes" @@ -79,6 +80,10 @@ func (jsonCodec) Marshal(v interface{}) ([]byte, error) { } func (jsonCodec) Unmarshal(data []byte, v interface{}) error { + if pb, ok := v.(proto.Message); ok { + return jsonpb.UnmarshalString(string(data), pb) + } + return json.Unmarshal(data, v) } From 00ba1655ca5f42b782976949f406f3f6c6499ac0 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 4 Jul 2019 11:15:54 +0100 Subject: [PATCH 100/287] remove some readmes --- api/README.md | 18 ------------------ config/README.md | 2 +- network/proxy/README.md | 25 ------------------------- 3 files changed, 1 insertion(+), 44 deletions(-) delete mode 100644 api/README.md delete mode 100644 network/proxy/README.md diff --git a/api/README.md b/api/README.md deleted file mode 100644 index 371d5ff3..00000000 --- a/api/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Go API [![License](https://img.shields.io/:license-apache-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![GoDoc](https://godoc.org/github.com/micro/go-micro/api?status.svg)](https://godoc.org/github.com/micro/go-micro/api) [![Travis CI](https://api.travis-ci.org/micro/go-micro/api.svg?branch=master)](https://travis-ci.org/micro/go-micro/api) [![Go Report Card](https://goreportcard.com/badge/micro/go-micro/api)](https://goreportcard.com/report/github.com/micro/go-micro/api) - -Go API is a pluggable API framework driven by service discovery to help build powerful public API gateways. - -## Overview - -The Go API library provides api gateway routing capabilities. A microservice architecture decouples application logic into -separate service. An api gateway provides a single entry point to consolidate these services into a unified api. The -Go API uses routes defined in service discovery metadata to generate routing rules and serve http requests. - -Go API - -Go API is the basis for the [micro api](https://micro.mu/docs/api.html). - -## Getting Started - -See the [docs](https://micro.mu/docs/go-api.html) to learn more - diff --git a/config/README.md b/config/README.md index f1265f51..56e21db9 100644 --- a/config/README.md +++ b/config/README.md @@ -1,6 +1,6 @@ # Config [![GoDoc](https://godoc.org/github.com/micro/go-micro/config?status.svg)](https://godoc.org/github.com/micro/go-micro/config) -Go Config is a pluggable dynamic config library. +Config is a pluggable dynamic config package Most config in applications are statically configured or include complex logic to load from multiple sources. Go Config makes this easy, pluggable and mergeable. You'll never have to deal with config in the same way again. diff --git a/network/proxy/README.md b/network/proxy/README.md deleted file mode 100644 index fdbeaf8c..00000000 --- a/network/proxy/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# Go Proxy [![License](https://img.shields.io/:license-apache-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![GoDoc](https://godoc.org/github.com/micro/go-proxy?status.svg)](https://godoc.org/github.com/micro/go-proxy) - -Go Proxy is a proxy library for Go Micro. - -## Overview - -Go Micro is a distributed systems framework for client/server communication. It handles the details -around discovery, fault tolerance, rpc communication, etc. We may want to leverage this in broader ecosystems -which make use of standard http or we may also want to offload a number of requirements to a single proxy. - -## Features - -- **Transparent Proxy** - Proxy requests to any micro services through a single location. Go Proxy enables -you to write Go Micro proxies which handle and forward requests. This is good for incorporating wrappers. - -- **Single Backend Router** - Enable the single backend router to proxy directly to your local app. The proxy -allows you to set a router which serves your backend service whether its http, grpc, etc. - -- **Protocol Aware Handler** - Set a request handler which speaks your app protocol to make outbound requests. -Your app may not speak the MUCP protocol so it may be easier to translate internally. - -- **Control Planes** - Additionally we support use of control planes to offload many distributed systems concerns. - * [x] [Consul](https://www.consul.io/docs/connect/native.html) - Using Connect-Native to provide secure mTLS. - * [x] [NATS](https://nats.io/) - Fully leveraging NATS as the control plane and data plane. - From a412486c39ecb4de949297bda6bcdd89333fd7fa Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 4 Jul 2019 11:36:49 +0100 Subject: [PATCH 101/287] Update registry util semantics --- registry/cache/rcache.go | 4 +- registry/gossip/gossip.go | 8 +-- registry/memory/memory.go | 6 +- registry/util.go | 113 +++++++++++++++++++------------------- registry/util_test.go | 8 +-- 5 files changed, 71 insertions(+), 68 deletions(-) diff --git a/registry/cache/rcache.go b/registry/cache/rcache.go index cc5ca319..e2e0da35 100644 --- a/registry/cache/rcache.go +++ b/registry/cache/rcache.go @@ -97,7 +97,7 @@ func (c *cache) get(service string) ([]*registry.Service, error) { // got services && within ttl so return cache if c.isValid(services, ttl) { // make a copy - cp := registry.CopyServices(services) + cp := registry.Copy(services) // unlock the read c.RUnlock() // return servics @@ -114,7 +114,7 @@ func (c *cache) get(service string) ([]*registry.Service, error) { // cache results c.Lock() - c.set(service, registry.CopyServices(services)) + c.set(service, registry.Copy(services)) c.Unlock() return services, nil diff --git a/registry/gossip/gossip.go b/registry/gossip/gossip.go index 508c9961..24006438 100644 --- a/registry/gossip/gossip.go +++ b/registry/gossip/gossip.go @@ -626,7 +626,7 @@ func (g *gossipRegistry) run() { g.services[u.Service.Name] = []*registry.Service{u.Service} } else { - g.services[u.Service.Name] = registry.AddServices(service, []*registry.Service{u.Service}) + g.services[u.Service.Name] = registry.Merge(service, []*registry.Service{u.Service}) } g.Unlock() @@ -645,7 +645,7 @@ func (g *gossipRegistry) run() { case actionTypeDelete: g.Lock() if service, ok := g.services[u.Service.Name]; ok { - if services := registry.DelServices(service, []*registry.Service{u.Service}); len(services) == 0 { + if services := registry.Remove(service, []*registry.Service{u.Service}); len(services) == 0 { delete(g.services, u.Service.Name) } else { g.services[u.Service.Name] = services @@ -706,7 +706,7 @@ func (g *gossipRegistry) Register(s *registry.Service, opts ...registry.Register if service, ok := g.services[s.Name]; !ok { g.services[s.Name] = []*registry.Service{s} } else { - g.services[s.Name] = registry.AddServices(service, []*registry.Service{s}) + g.services[s.Name] = registry.Merge(service, []*registry.Service{s}) } g.Unlock() @@ -754,7 +754,7 @@ func (g *gossipRegistry) Deregister(s *registry.Service) error { g.Lock() if service, ok := g.services[s.Name]; ok { - if services := registry.DelServices(service, []*registry.Service{s}); len(services) == 0 { + if services := registry.Remove(service, []*registry.Service{s}); len(services) == 0 { delete(g.services, s.Name) } else { g.services[s.Name] = services diff --git a/registry/memory/memory.go b/registry/memory/memory.go index a978e1ac..6c03df67 100644 --- a/registry/memory/memory.go +++ b/registry/memory/memory.go @@ -55,7 +55,7 @@ func (m *Registry) Init(opts ...registry.Option) error { m.Lock() for k, v := range getServices(m.options.Context) { s := m.Services[k] - m.Services[k] = registry.AddServices(s, v) + m.Services[k] = registry.Merge(s, v) } m.Unlock() return nil @@ -92,7 +92,7 @@ func (m *Registry) Register(s *registry.Service, opts ...registry.RegisterOption if service, ok := m.Services[s.Name]; !ok { m.Services[s.Name] = []*registry.Service{s} } else { - m.Services[s.Name] = registry.AddServices(service, []*registry.Service{s}) + m.Services[s.Name] = registry.Merge(service, []*registry.Service{s}) } m.Unlock() @@ -104,7 +104,7 @@ func (m *Registry) Deregister(s *registry.Service) error { m.Lock() if service, ok := m.Services[s.Name]; ok { - if service := registry.DelServices(service, []*registry.Service{s}); len(service) == 0 { + if service := registry.Remove(service, []*registry.Service{s}); len(service) == 0 { delete(m.Services, s.Name) } else { m.Services[s.Name] = service diff --git a/registry/util.go b/registry/util.go index 7954cb0d..5eb51a62 100644 --- a/registry/util.go +++ b/registry/util.go @@ -1,6 +1,56 @@ package registry -func CopyServices(current []*Service) []*Service { +func addNodes(old, neu []*Node) []*Node { + var nodes []*Node + + // add all new nodes + for _, n := range neu { + node := *n + nodes = append(nodes, &node) + } + + // look at old nodes + for _, o := range old { + var exists bool + + // check against new nodes + for _, n := range nodes { + // ids match then skip + if o.Id == n.Id { + exists = true + break + } + } + + // keep old node + if !exists { + node := *o + nodes = append(nodes, &node) + } + } + + return nodes +} + +func delNodes(old, del []*Node) []*Node { + var nodes []*Node + for _, o := range old { + var rem bool + for _, n := range del { + if o.Id == n.Id { + rem = true + break + } + } + if !rem { + nodes = append(nodes, o) + } + } + return nodes +} + +// Copy makes a copy of services +func Copy(current []*Service) []*Service { var services []*Service for _, service := range current { @@ -33,39 +83,8 @@ func CopyServices(current []*Service) []*Service { return services } -func addServiceNodes(old, neu []*Node) []*Node { - var nodes []*Node - - // add all new nodes - for _, n := range neu { - node := *n - nodes = append(nodes, &node) - } - - // look at old nodes - for _, o := range old { - var exists bool - - // check against new nodes - for _, n := range nodes { - // ids match then skip - if o.Id == n.Id { - exists = true - break - } - } - - // keep old node - if !exists { - node := *o - nodes = append(nodes, &node) - } - } - - return nodes -} - -func AddServices(olist []*Service, nlist []*Service) []*Service { +// Merge merges two lists of services and returns a new copy +func Merge(olist []*Service, nlist []*Service) []*Service { var srv []*Service for _, n := range nlist { @@ -76,7 +95,7 @@ func AddServices(olist []*Service, nlist []*Service) []*Service { // make copy *sp = *o // set nodes - sp.Nodes = addServiceNodes(o.Nodes, n.Nodes) + sp.Nodes = addNodes(o.Nodes, n.Nodes) // mark as seen seen = true @@ -90,30 +109,14 @@ func AddServices(olist []*Service, nlist []*Service) []*Service { } } if !seen { - srv = append(srv, CopyServices([]*Service{n})...) + srv = append(srv, Copy([]*Service{n})...) } } return srv } -func delServiceNodes(old, del []*Node) []*Node { - var nodes []*Node - for _, o := range old { - var rem bool - for _, n := range del { - if o.Id == n.Id { - rem = true - break - } - } - if !rem { - nodes = append(nodes, o) - } - } - return nodes -} - -func DelServices(old, del []*Service) []*Service { +// Remove removes services and returns a new copy +func Remove(old, del []*Service) []*Service { var services []*Service for _, o := range old { @@ -124,7 +127,7 @@ func DelServices(old, del []*Service) []*Service { for _, s := range del { if srv.Version == s.Version { - srv.Nodes = delServiceNodes(srv.Nodes, s.Nodes) + srv.Nodes = delNodes(srv.Nodes, s.Nodes) if len(srv.Nodes) == 0 { rem = true diff --git a/registry/util_test.go b/registry/util_test.go index 6e4dccd5..9d14c659 100644 --- a/registry/util_test.go +++ b/registry/util_test.go @@ -4,7 +4,7 @@ import ( "testing" ) -func TestDelServices(t *testing.T) { +func TestRemove(t *testing.T) { services := []*Service{ { Name: "foo", @@ -30,14 +30,14 @@ func TestDelServices(t *testing.T) { }, } - servs := DelServices([]*Service{services[0]}, []*Service{services[1]}) + servs := Remove([]*Service{services[0]}, []*Service{services[1]}) if i := len(servs); i > 0 { t.Errorf("Expected 0 nodes, got %d: %+v", i, servs) } t.Logf("Services %+v", servs) } -func TestDelNodes(t *testing.T) { +func TestRemoveNodes(t *testing.T) { services := []*Service{ { Name: "foo", @@ -68,7 +68,7 @@ func TestDelNodes(t *testing.T) { }, } - nodes := delServiceNodes(services[0].Nodes, services[1].Nodes) + nodes := delNodes(services[0].Nodes, services[1].Nodes) if i := len(nodes); i != 1 { t.Errorf("Expected only 1 node, got %d: %+v", i, nodes) } From e40307c567557e9a531ead1fe96525b2e3e1f369 Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Thu, 4 Jul 2019 14:06:29 +0300 Subject: [PATCH 102/287] codec grpc: fix extra allocations on message unmarshal Signed-off-by: Vasiliy Tolstov --- client/grpc/codec.go | 6 ++++-- server/grpc/codec.go | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/client/grpc/codec.go b/client/grpc/codec.go index fe59c361..f223a55c 100644 --- a/client/grpc/codec.go +++ b/client/grpc/codec.go @@ -4,9 +4,11 @@ import ( "fmt" "strings" + b "bytes" + "github.com/golang/protobuf/jsonpb" "github.com/golang/protobuf/proto" - "github.com/json-iterator/go" + jsoniter "github.com/json-iterator/go" "github.com/micro/go-micro/codec" "github.com/micro/go-micro/codec/bytes" "github.com/micro/go-micro/codec/jsonrpc" @@ -116,7 +118,7 @@ func (jsonCodec) Marshal(v interface{}) ([]byte, error) { func (jsonCodec) Unmarshal(data []byte, v interface{}) error { if pb, ok := v.(proto.Message); ok { - return jsonpb.UnmarshalString(string(data), pb) + return jsonpb.Unmarshal(b.NewReader(data), pb) } return json.Unmarshal(data, v) diff --git a/server/grpc/codec.go b/server/grpc/codec.go index 7562a044..7362f49c 100644 --- a/server/grpc/codec.go +++ b/server/grpc/codec.go @@ -5,6 +5,8 @@ import ( "fmt" "strings" + b "bytes" + "github.com/golang/protobuf/jsonpb" "github.com/golang/protobuf/proto" "github.com/micro/go-micro/codec" @@ -81,7 +83,7 @@ func (jsonCodec) Marshal(v interface{}) ([]byte, error) { func (jsonCodec) Unmarshal(data []byte, v interface{}) error { if pb, ok := v.(proto.Message); ok { - return jsonpb.UnmarshalString(string(data), pb) + return jsonpb.Unmarshal(b.NewReader(data), pb) } return json.Unmarshal(data, v) From eafc930f841712622a98b5a04b9dac33fc3e582b Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Sun, 7 Jul 2019 10:10:38 +0100 Subject: [PATCH 103/287] Change network id to name --- network/default.go | 24 ++++++++++++------------ network/network.go | 8 ++++---- network/node.go | 8 ++++---- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/network/default.go b/network/default.go index fd0a6fdf..29e0bbb2 100644 --- a/network/default.go +++ b/network/default.go @@ -30,8 +30,8 @@ type network struct { // proxy used to route through the network proxy proxy.Proxy - // id of this network - id string + // name of this network + name string // links maintained for this network // based on peers not nodes. maybe maintain @@ -65,7 +65,7 @@ func (n *network) lease(muid string) *pb.Lease { Muid: muid, Id: id, Address: address, - Network: n.id, + Network: n.name, }, } } @@ -76,18 +76,18 @@ func (n *network) lookup(r registry.Registry) []*resolver.Record { rr := nreg.Resolver{Registry: r} // get all the nodes for the network that are local - localRecords, err := rr.Resolve("network:" + n.Id()) + localRecords, err := rr.Resolve(n.Name()) if err != nil { // we're not in a good place here } // if its a local network we never try lookup anything else - if n.Id() == "local" { + if n.Name() == "local" { return localRecords } // now resolve incrementally based on resolvers specified - networkRecords, err := n.resolver.Resolve(n.Id()) + networkRecords, err := n.resolver.Resolve(n.Name()) if err != nil { // still not in a good place } @@ -96,8 +96,8 @@ func (n *network) lookup(r registry.Registry) []*resolver.Record { return append(localRecords, networkRecords...) } -func (n *network) Id() string { - return n.id +func (n *network) Name() string { + return n.name } // Connect connects to the network and returns a new node. @@ -135,16 +135,16 @@ func newNetwork(opts ...options.Option) *network { // new network instance with defaults net := &network{ Options: options, - id: DefaultId, + name: DefaultName, router: router.DefaultRouter, proxy: new(mucp.Proxy), resolver: new(nreg.Resolver), } - // get network id - id, ok := options.Values().Get("network.id") + // get network name + name, ok := options.Values().Get("network.name") if ok { - net.id = id.(string) + net.name = name.(string) } // get router diff --git a/network/network.go b/network/network.go index c8f998ea..f9b32090 100644 --- a/network/network.go +++ b/network/network.go @@ -10,8 +10,8 @@ import ( // is responsible for routing messages to the correct services. type Network interface { options.Options - // Id of the network - Id() string + // Name of the network + Name() string // Connect to the network Connect() (Node, error) // Peer with a neighboring network @@ -53,8 +53,8 @@ type Message struct { } var ( - // The default network ID is local - DefaultId = "local" + // The default network name is local + DefaultName = "local" // just the standard network element DefaultNetwork = NewNetwork() diff --git a/network/node.go b/network/node.go index ea05824a..90649f09 100644 --- a/network/node.go +++ b/network/node.go @@ -69,7 +69,7 @@ func newNode(n *network) (*node, error) { // create a new node node := &node{ // this nodes unique micro assigned mac address - muid: fmt.Sprintf("%s-%s", n.id, uuid.New().String()), + muid: fmt.Sprintf("%s-%s", n.name, uuid.New().String()), // map of connected records connected: make(map[string]bool), // the links @@ -156,7 +156,7 @@ func newNode(n *network) (*node, error) { // a registrar or tld or whatever if err := node.registry.Register(®istry.Service{ // register with the network id - Name: "network:" + n.Id(), + Name: n.Name(), Nodes: []*registry.Node{ {Id: node.id, Address: addr, Port: port}, }, @@ -473,7 +473,7 @@ func (n *node) Close() error { // deregister self n.registry.Deregister(®istry.Service{ - Name: "network:" + n.network.Id(), + Name: n.network.Name(), Nodes: []*registry.Node{ {Id: n.id, Address: n.address}, }, @@ -514,7 +514,7 @@ func (n *node) Id() string { } func (n *node) Network() string { - return n.network.id + return n.network.Name() } // Send propagates a message over all links. This should probably use its proxy. From d2d6841f020f59c796e928187c5ac0bbed2ec8c6 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Sun, 7 Jul 2019 10:37:34 +0100 Subject: [PATCH 104/287] Move transport to network/transport --- client/grpc/grpc.go | 2 +- client/options.go | 2 +- client/options_test.go | 2 +- client/rpc_client.go | 2 +- client/rpc_codec.go | 2 +- client/rpc_pool.go | 2 +- client/rpc_pool_test.go | 4 ++-- client/rpc_response.go | 2 +- config/cmd/cmd.go | 8 ++++---- config/cmd/options.go | 2 +- network/link.go | 2 +- network/node.go | 2 +- {transport => network/transport}/grpc/grpc.go | 4 ++-- {transport => network/transport}/grpc/grpc_test.go | 2 +- {transport => network/transport}/grpc/handler.go | 4 ++-- .../transport}/grpc/proto/transport.micro.go | 2 +- .../transport}/grpc/proto/transport.pb.go | 6 +++--- .../transport}/grpc/proto/transport.proto | 0 {transport => network/transport}/grpc/socket.go | 4 ++-- {transport => network/transport}/http/http.go | 2 +- {transport => network/transport}/http/http_test.go | 2 +- {transport => network/transport}/http/options.go | 2 +- {transport => network/transport}/http_proxy.go | 0 {transport => network/transport}/http_transport.go | 0 {transport => network/transport}/http_transport_test.go | 0 {transport => network/transport}/memory/memory.go | 2 +- {transport => network/transport}/memory/memory_test.go | 2 +- {transport => network/transport}/mucp/listener.go | 2 +- {transport => network/transport}/mucp/network.go | 2 +- {transport => network/transport}/mucp/socket.go | 2 +- {transport => network/transport}/mucp/socket_test.go | 2 +- {transport => network/transport}/options.go | 0 {transport => network/transport}/quic/quic.go | 2 +- {transport => network/transport}/transport.go | 0 network/tunnel/default.go | 2 +- network/tunnel/socket.go | 2 +- network/tunnel/socket_test.go | 2 +- network/tunnel/tunnel.go | 2 +- options.go | 2 +- server/grpc/options.go | 2 +- server/options.go | 2 +- server/rpc_codec.go | 2 +- server/rpc_codec_test.go | 2 +- server/rpc_request.go | 2 +- server/rpc_response.go | 2 +- server/rpc_server.go | 2 +- 46 files changed, 49 insertions(+), 49 deletions(-) rename {transport => network/transport}/grpc/grpc.go (97%) rename {transport => network/transport}/grpc/grpc_test.go (97%) rename {transport => network/transport}/grpc/handler.go (85%) rename {transport => network/transport}/grpc/proto/transport.micro.go (98%) rename {transport => network/transport}/grpc/proto/transport.pb.go (96%) rename {transport => network/transport}/grpc/proto/transport.proto (100%) rename {transport => network/transport}/grpc/socket.go (93%) rename {transport => network/transport}/http/http.go (85%) rename {transport => network/transport}/http/http_test.go (97%) rename {transport => network/transport}/http/options.go (91%) rename {transport => network/transport}/http_proxy.go (100%) rename {transport => network/transport}/http_transport.go (100%) rename {transport => network/transport}/http_transport_test.go (100%) rename {transport => network/transport}/memory/memory.go (98%) rename {transport => network/transport}/memory/memory_test.go (97%) rename {transport => network/transport}/mucp/listener.go (92%) rename {transport => network/transport}/mucp/network.go (99%) rename {transport => network/transport}/mucp/socket.go (96%) rename {transport => network/transport}/mucp/socket_test.go (95%) rename {transport => network/transport}/options.go (100%) rename {transport => network/transport}/quic/quic.go (98%) rename {transport => network/transport}/transport.go (100%) diff --git a/client/grpc/grpc.go b/client/grpc/grpc.go index 9a1843bc..d4d54938 100644 --- a/client/grpc/grpc.go +++ b/client/grpc/grpc.go @@ -17,7 +17,7 @@ import ( "github.com/micro/go-micro/errors" "github.com/micro/go-micro/metadata" "github.com/micro/go-micro/registry" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" "google.golang.org/grpc" "google.golang.org/grpc/credentials" diff --git a/client/options.go b/client/options.go index 9f363d74..00d70ead 100644 --- a/client/options.go +++ b/client/options.go @@ -8,7 +8,7 @@ import ( "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/codec" "github.com/micro/go-micro/registry" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) type Options struct { diff --git a/client/options_test.go b/client/options_test.go index 9252994c..f7c892ca 100644 --- a/client/options_test.go +++ b/client/options_test.go @@ -4,7 +4,7 @@ import ( "testing" "time" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) func TestCallOptions(t *testing.T) { diff --git a/client/rpc_client.go b/client/rpc_client.go index c724435a..4061fa40 100644 --- a/client/rpc_client.go +++ b/client/rpc_client.go @@ -18,7 +18,7 @@ import ( "github.com/micro/go-micro/errors" "github.com/micro/go-micro/metadata" "github.com/micro/go-micro/registry" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) type rpcClient struct { diff --git a/client/rpc_codec.go b/client/rpc_codec.go index 6ff84a64..ca390e39 100644 --- a/client/rpc_codec.go +++ b/client/rpc_codec.go @@ -13,7 +13,7 @@ import ( "github.com/micro/go-micro/codec/protorpc" "github.com/micro/go-micro/errors" "github.com/micro/go-micro/registry" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) const ( diff --git a/client/rpc_pool.go b/client/rpc_pool.go index 9fdd7736..9cff2587 100644 --- a/client/rpc_pool.go +++ b/client/rpc_pool.go @@ -4,7 +4,7 @@ import ( "sync" "time" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) type pool struct { diff --git a/client/rpc_pool_test.go b/client/rpc_pool_test.go index 6c5875f1..2f7bcb5e 100644 --- a/client/rpc_pool_test.go +++ b/client/rpc_pool_test.go @@ -4,8 +4,8 @@ import ( "testing" "time" - "github.com/micro/go-micro/transport" - "github.com/micro/go-micro/transport/memory" + "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/network/transport/memory" ) func testPool(t *testing.T, size int, ttl time.Duration) { diff --git a/client/rpc_response.go b/client/rpc_response.go index 08aaa84d..d2fa61f2 100644 --- a/client/rpc_response.go +++ b/client/rpc_response.go @@ -2,7 +2,7 @@ package client import ( "github.com/micro/go-micro/codec" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) type rpcResponse struct { diff --git a/config/cmd/cmd.go b/config/cmd/cmd.go index 8d7c3c03..f2537de7 100644 --- a/config/cmd/cmd.go +++ b/config/cmd/cmd.go @@ -38,10 +38,10 @@ import ( "github.com/micro/go-micro/client/selector/static" // transports - "github.com/micro/go-micro/transport" - tgrpc "github.com/micro/go-micro/transport/grpc" - thttp "github.com/micro/go-micro/transport/http" - tmem "github.com/micro/go-micro/transport/memory" + "github.com/micro/go-micro/network/transport" + tgrpc "github.com/micro/go-micro/network/transport/grpc" + thttp "github.com/micro/go-micro/network/transport/http" + tmem "github.com/micro/go-micro/network/transport/memory" ) type Cmd interface { diff --git a/config/cmd/options.go b/config/cmd/options.go index 1f221f35..3711235c 100644 --- a/config/cmd/options.go +++ b/config/cmd/options.go @@ -8,7 +8,7 @@ import ( "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/server" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) type Options struct { diff --git a/network/link.go b/network/link.go index 5b676be5..656abe24 100644 --- a/network/link.go +++ b/network/link.go @@ -10,7 +10,7 @@ import ( "github.com/micro/go-micro/codec" "github.com/micro/go-micro/codec/proto" pb "github.com/micro/go-micro/network/proto" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) type link struct { diff --git a/network/node.go b/network/node.go index 90649f09..440d9c49 100644 --- a/network/node.go +++ b/network/node.go @@ -13,7 +13,7 @@ import ( "github.com/google/uuid" "github.com/micro/go-micro/registry" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" "github.com/micro/go-micro/util/addr" "github.com/micro/go-micro/util/log" diff --git a/transport/grpc/grpc.go b/network/transport/grpc/grpc.go similarity index 97% rename from transport/grpc/grpc.go rename to network/transport/grpc/grpc.go index a60ec70e..6b8dc8c8 100644 --- a/transport/grpc/grpc.go +++ b/network/transport/grpc/grpc.go @@ -6,7 +6,7 @@ import ( "crypto/tls" "net" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" maddr "github.com/micro/go-micro/util/addr" mnet "github.com/micro/go-micro/util/net" mls "github.com/micro/go-micro/util/tls" @@ -14,7 +14,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials" - pb "github.com/micro/go-micro/transport/grpc/proto" + pb "github.com/micro/go-micro/network/transport/grpc/proto" ) type grpcTransport struct { diff --git a/transport/grpc/grpc_test.go b/network/transport/grpc/grpc_test.go similarity index 97% rename from transport/grpc/grpc_test.go rename to network/transport/grpc/grpc_test.go index d4e82346..85abf12d 100644 --- a/transport/grpc/grpc_test.go +++ b/network/transport/grpc/grpc_test.go @@ -4,7 +4,7 @@ import ( "strings" "testing" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) func expectedPort(t *testing.T, expected string, lsn transport.Listener) { diff --git a/transport/grpc/handler.go b/network/transport/grpc/handler.go similarity index 85% rename from transport/grpc/handler.go rename to network/transport/grpc/handler.go index 3220f7dd..6dc1b512 100644 --- a/transport/grpc/handler.go +++ b/network/transport/grpc/handler.go @@ -3,8 +3,8 @@ package grpc import ( "runtime/debug" - "github.com/micro/go-micro/transport" - pb "github.com/micro/go-micro/transport/grpc/proto" + "github.com/micro/go-micro/network/transport" + pb "github.com/micro/go-micro/network/transport/grpc/proto" "github.com/micro/go-micro/util/log" "google.golang.org/grpc/peer" ) diff --git a/transport/grpc/proto/transport.micro.go b/network/transport/grpc/proto/transport.micro.go similarity index 98% rename from transport/grpc/proto/transport.micro.go rename to network/transport/grpc/proto/transport.micro.go index 81cf981c..1b8d840e 100644 --- a/transport/grpc/proto/transport.micro.go +++ b/network/transport/grpc/proto/transport.micro.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-micro. DO NOT EDIT. -// source: go-micro/transport/grpc/proto/transport.proto +// source: go-micro/network/transport/grpc/proto/transport.proto package go_micro_grpc_transport diff --git a/transport/grpc/proto/transport.pb.go b/network/transport/grpc/proto/transport.pb.go similarity index 96% rename from transport/grpc/proto/transport.pb.go rename to network/transport/grpc/proto/transport.pb.go index a9702987..c8fb8933 100644 --- a/transport/grpc/proto/transport.pb.go +++ b/network/transport/grpc/proto/transport.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-go. DO NOT EDIT. -// source: go-micro/transport/grpc/proto/transport.proto +// source: go-micro/network/transport/grpc/proto/transport.proto package go_micro_grpc_transport @@ -75,7 +75,7 @@ func init() { } func init() { - proto.RegisterFile("go-micro/transport/grpc/proto/transport.proto", fileDescriptor_29b90b9ccd5e0da5) + proto.RegisterFile("go-micro/network/transport/grpc/proto/transport.proto", fileDescriptor_29b90b9ccd5e0da5) } var fileDescriptor_29b90b9ccd5e0da5 = []byte{ @@ -197,5 +197,5 @@ var _Transport_serviceDesc = grpc.ServiceDesc{ ClientStreams: true, }, }, - Metadata: "go-micro/transport/grpc/proto/transport.proto", + Metadata: "go-micro/network/transport/grpc/proto/transport.proto", } diff --git a/transport/grpc/proto/transport.proto b/network/transport/grpc/proto/transport.proto similarity index 100% rename from transport/grpc/proto/transport.proto rename to network/transport/grpc/proto/transport.proto diff --git a/transport/grpc/socket.go b/network/transport/grpc/socket.go similarity index 93% rename from transport/grpc/socket.go rename to network/transport/grpc/socket.go index 2567559d..1d072cbe 100644 --- a/transport/grpc/socket.go +++ b/network/transport/grpc/socket.go @@ -1,8 +1,8 @@ package grpc import ( - "github.com/micro/go-micro/transport" - pb "github.com/micro/go-micro/transport/grpc/proto" + "github.com/micro/go-micro/network/transport" + pb "github.com/micro/go-micro/network/transport/grpc/proto" "google.golang.org/grpc" ) diff --git a/transport/http/http.go b/network/transport/http/http.go similarity index 85% rename from transport/http/http.go rename to network/transport/http/http.go index 672db54c..a3a6bbfc 100644 --- a/transport/http/http.go +++ b/network/transport/http/http.go @@ -2,7 +2,7 @@ package http import ( - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) // NewTransport returns a new http transport using net/http and supporting http2 diff --git a/transport/http/http_test.go b/network/transport/http/http_test.go similarity index 97% rename from transport/http/http_test.go rename to network/transport/http/http_test.go index faaf5215..57445031 100644 --- a/transport/http/http_test.go +++ b/network/transport/http/http_test.go @@ -4,7 +4,7 @@ import ( "sync" "testing" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) func call(b *testing.B, c int) { diff --git a/transport/http/options.go b/network/transport/http/options.go similarity index 91% rename from transport/http/options.go rename to network/transport/http/options.go index 2a6e56c5..3d70f94b 100644 --- a/transport/http/options.go +++ b/network/transport/http/options.go @@ -4,7 +4,7 @@ import ( "context" "net/http" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) // Handle registers the handler for the given pattern. diff --git a/transport/http_proxy.go b/network/transport/http_proxy.go similarity index 100% rename from transport/http_proxy.go rename to network/transport/http_proxy.go diff --git a/transport/http_transport.go b/network/transport/http_transport.go similarity index 100% rename from transport/http_transport.go rename to network/transport/http_transport.go diff --git a/transport/http_transport_test.go b/network/transport/http_transport_test.go similarity index 100% rename from transport/http_transport_test.go rename to network/transport/http_transport_test.go diff --git a/transport/memory/memory.go b/network/transport/memory/memory.go similarity index 98% rename from transport/memory/memory.go rename to network/transport/memory/memory.go index ed00ce69..25782d50 100644 --- a/transport/memory/memory.go +++ b/network/transport/memory/memory.go @@ -9,7 +9,7 @@ import ( "sync" "time" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) type memorySocket struct { diff --git a/transport/memory/memory_test.go b/network/transport/memory/memory_test.go similarity index 97% rename from transport/memory/memory_test.go rename to network/transport/memory/memory_test.go index 72952e09..0ff5b31d 100644 --- a/transport/memory/memory_test.go +++ b/network/transport/memory/memory_test.go @@ -3,7 +3,7 @@ package memory import ( "testing" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) func TestMemoryTransport(t *testing.T) { diff --git a/transport/mucp/listener.go b/network/transport/mucp/listener.go similarity index 92% rename from transport/mucp/listener.go rename to network/transport/mucp/listener.go index 6f107323..ceb7aae0 100644 --- a/transport/mucp/listener.go +++ b/network/transport/mucp/listener.go @@ -1,7 +1,7 @@ package mucp import ( - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) type listener struct { diff --git a/transport/mucp/network.go b/network/transport/mucp/network.go similarity index 99% rename from transport/mucp/network.go rename to network/transport/mucp/network.go index 789c5e76..ae0046b9 100644 --- a/transport/mucp/network.go +++ b/network/transport/mucp/network.go @@ -9,7 +9,7 @@ import ( "sync" "github.com/micro/go-micro/network" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) type networkKey struct{} diff --git a/transport/mucp/socket.go b/network/transport/mucp/socket.go similarity index 96% rename from transport/mucp/socket.go rename to network/transport/mucp/socket.go index f21788ec..862da50a 100644 --- a/transport/mucp/socket.go +++ b/network/transport/mucp/socket.go @@ -3,7 +3,7 @@ package mucp import ( "errors" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) // socket is our pseudo socket for transport.Socket diff --git a/transport/mucp/socket_test.go b/network/transport/mucp/socket_test.go similarity index 95% rename from transport/mucp/socket_test.go rename to network/transport/mucp/socket_test.go index df493fa0..a9dfbd5a 100644 --- a/transport/mucp/socket_test.go +++ b/network/transport/mucp/socket_test.go @@ -3,7 +3,7 @@ package mucp import ( "testing" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) func TestTunnelSocket(t *testing.T) { diff --git a/transport/options.go b/network/transport/options.go similarity index 100% rename from transport/options.go rename to network/transport/options.go diff --git a/transport/quic/quic.go b/network/transport/quic/quic.go similarity index 98% rename from transport/quic/quic.go rename to network/transport/quic/quic.go index 2622ec84..548b1bc2 100644 --- a/transport/quic/quic.go +++ b/network/transport/quic/quic.go @@ -6,7 +6,7 @@ import ( "encoding/gob" "github.com/lucas-clemente/quic-go" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" utls "github.com/micro/go-micro/util/tls" ) diff --git a/transport/transport.go b/network/transport/transport.go similarity index 100% rename from transport/transport.go rename to network/transport/transport.go diff --git a/network/tunnel/default.go b/network/tunnel/default.go index 41c9778b..c417d935 100644 --- a/network/tunnel/default.go +++ b/network/tunnel/default.go @@ -7,7 +7,7 @@ import ( "sync" "github.com/google/uuid" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) // tun represents a network tunnel diff --git a/network/tunnel/socket.go b/network/tunnel/socket.go index e0ce1350..dac5837d 100644 --- a/network/tunnel/socket.go +++ b/network/tunnel/socket.go @@ -3,7 +3,7 @@ package tunnel import ( "errors" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) // socket is our pseudo socket for transport.Socket diff --git a/network/tunnel/socket_test.go b/network/tunnel/socket_test.go index 37c1aeaa..086bf60f 100644 --- a/network/tunnel/socket_test.go +++ b/network/tunnel/socket_test.go @@ -3,7 +3,7 @@ package tunnel import ( "testing" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) func TestTunnelSocket(t *testing.T) { diff --git a/network/tunnel/tunnel.go b/network/tunnel/tunnel.go index 1f7cd2b7..d25d228d 100644 --- a/network/tunnel/tunnel.go +++ b/network/tunnel/tunnel.go @@ -3,7 +3,7 @@ package tunnel import ( "github.com/micro/go-micro/config/options" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) // Tunnel creates a network tunnel diff --git a/options.go b/options.go index d566a353..95c65e73 100644 --- a/options.go +++ b/options.go @@ -11,7 +11,7 @@ import ( "github.com/micro/go-micro/config/cmd" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/server" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) type Options struct { diff --git a/server/grpc/options.go b/server/grpc/options.go index 65d82fcc..6a5e07f6 100644 --- a/server/grpc/options.go +++ b/server/grpc/options.go @@ -9,7 +9,7 @@ import ( "github.com/micro/go-micro/registry" "github.com/micro/go-micro/server" "github.com/micro/go-micro/server/debug" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" "google.golang.org/grpc" "google.golang.org/grpc/encoding" ) diff --git a/server/options.go b/server/options.go index 15de9b83..c00c2e9f 100644 --- a/server/options.go +++ b/server/options.go @@ -9,7 +9,7 @@ import ( "github.com/micro/go-micro/codec" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/server/debug" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) type Options struct { diff --git a/server/rpc_codec.go b/server/rpc_codec.go index 797fa79c..a23b0a3a 100644 --- a/server/rpc_codec.go +++ b/server/rpc_codec.go @@ -10,7 +10,7 @@ import ( "github.com/micro/go-micro/codec/jsonrpc" "github.com/micro/go-micro/codec/proto" "github.com/micro/go-micro/codec/protorpc" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" "github.com/pkg/errors" ) diff --git a/server/rpc_codec_test.go b/server/rpc_codec_test.go index 1088af01..3fb03cf4 100644 --- a/server/rpc_codec_test.go +++ b/server/rpc_codec_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/micro/go-micro/codec" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) // testCodec is a dummy codec that only knows how to encode nil bodies diff --git a/server/rpc_request.go b/server/rpc_request.go index 40995b14..c69c8605 100644 --- a/server/rpc_request.go +++ b/server/rpc_request.go @@ -2,7 +2,7 @@ package server import ( "github.com/micro/go-micro/codec" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) type rpcRequest struct { diff --git a/server/rpc_response.go b/server/rpc_response.go index d89fa0b6..55b5b126 100644 --- a/server/rpc_response.go +++ b/server/rpc_response.go @@ -4,7 +4,7 @@ import ( "net/http" "github.com/micro/go-micro/codec" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" ) type rpcResponse struct { diff --git a/server/rpc_server.go b/server/rpc_server.go index 6caca4e3..aec4cae7 100644 --- a/server/rpc_server.go +++ b/server/rpc_server.go @@ -14,7 +14,7 @@ import ( "github.com/micro/go-micro/codec" "github.com/micro/go-micro/metadata" "github.com/micro/go-micro/registry" - "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/network/transport" "github.com/micro/go-micro/util/addr" log "github.com/micro/go-micro/util/log" ) From 5f664faeba02fcbccf1ed5a55c20bb05644bada0 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Sun, 7 Jul 2019 12:23:03 +0100 Subject: [PATCH 105/287] Add transport options comments --- network/transport/options.go | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/network/transport/options.go b/network/transport/options.go index 5aaebe4b..bea0d227 100644 --- a/network/transport/options.go +++ b/network/transport/options.go @@ -9,9 +9,17 @@ import ( ) type Options struct { - Addrs []string - Codec codec.Marshaler - Secure bool + // Addrs is the list of intermediary addresses to connect to + Addrs []string + // Codec is the codec interface to use where headers are not supported + // by the transport and the entire payload must be encoded + Codec codec.Marshaler + // Secure tells the transport to secure the connection. + // In the case TLSConfig is not specified best effort self-signed + // certs should be used + Secure bool + // TLSConfig to secure the connection. The assumption is that this + // is mTLS keypair TLSConfig *tls.Config // Timeout sets the timeout for Send/Recv Timeout time.Duration @@ -21,7 +29,10 @@ type Options struct { } type DialOptions struct { - Stream bool + // Tells the transport this is a streaming connection with + // multiple calls to send/recv and that send may not even be called + Stream bool + // Timeout for dialing Timeout time.Duration // TODO: add tls options when dialling From c1097a4509be889a968209127d67369c567ba2d4 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Sun, 7 Jul 2019 12:33:47 +0100 Subject: [PATCH 106/287] strip broker address --- broker/broker.go | 3 +-- broker/http_broker.go | 1 + server/grpc/grpc.go | 5 ++++- server/rpc_server.go | 5 ++++- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/broker/broker.go b/broker/broker.go index 39db9f17..31013784 100644 --- a/broker/broker.go +++ b/broker/broker.go @@ -3,11 +3,10 @@ package broker // Broker is an interface used for asynchronous messaging. type Broker interface { + Init(...Option) error Options() Options - Address() string Connect() error Disconnect() error - Init(...Option) error Publish(string, *Message, ...PublishOption) error Subscribe(string, Handler, ...SubscribeOption) (Subscriber, error) String() string diff --git a/broker/http_broker.go b/broker/http_broker.go index 9f3f1012..01e39495 100644 --- a/broker/http_broker.go +++ b/broker/http_broker.go @@ -403,6 +403,7 @@ func (h *httpBroker) Connect() error { go func() { h.run(l) h.Lock() + h.opts.Addrs = []string{addr} h.address = addr h.Unlock() }() diff --git a/server/grpc/grpc.go b/server/grpc/grpc.go index 6575d3b6..75b8823f 100644 --- a/server/grpc/grpc.go +++ b/server/grpc/grpc.go @@ -714,7 +714,10 @@ func (g *grpcServer) Start() error { return err } - log.Logf("Broker [%s] Listening on %s", config.Broker.String(), config.Broker.Address()) + baddr := strings.Join(config.Broker.Options().Addrs, ",") + bname := config.Broker.String() + + log.Logf("Broker [%s] Listening on %s", bname, baddr) // announce self to the world if err := g.Register(); err != nil { diff --git a/server/rpc_server.go b/server/rpc_server.go index aec4cae7..524691fd 100644 --- a/server/rpc_server.go +++ b/server/rpc_server.go @@ -500,7 +500,10 @@ func (s *rpcServer) Start() error { return err } - log.Logf("Broker [%s] Connected to %s", config.Broker.String(), config.Broker.Address()) + baddr := strings.Join(config.Broker.Options().Addrs, ",") + bname := config.Broker.String() + + log.Logf("Broker [%s] Connected to %s", bname, baddr) // use RegisterCheck func before register if err = s.opts.RegisterCheck(s.opts.Context); err != nil { From 777a203f962a22e3a3a7c3da17fae037458c5d8c Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Sun, 7 Jul 2019 12:33:54 +0100 Subject: [PATCH 107/287] gofmt --- client/grpc/grpc.go | 2 +- client/options.go | 2 +- client/rpc_client.go | 2 +- client/rpc_codec.go | 2 +- config/cmd/options.go | 2 +- network/node.go | 2 +- options.go | 2 +- server/grpc/options.go | 2 +- server/options.go | 2 +- server/rpc_server.go | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/client/grpc/grpc.go b/client/grpc/grpc.go index d4d54938..939019f5 100644 --- a/client/grpc/grpc.go +++ b/client/grpc/grpc.go @@ -16,8 +16,8 @@ import ( "github.com/micro/go-micro/codec" "github.com/micro/go-micro/errors" "github.com/micro/go-micro/metadata" - "github.com/micro/go-micro/registry" "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/registry" "google.golang.org/grpc" "google.golang.org/grpc/credentials" diff --git a/client/options.go b/client/options.go index 00d70ead..3032d23b 100644 --- a/client/options.go +++ b/client/options.go @@ -7,8 +7,8 @@ import ( "github.com/micro/go-micro/broker" "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/codec" - "github.com/micro/go-micro/registry" "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/registry" ) type Options struct { diff --git a/client/rpc_client.go b/client/rpc_client.go index 4061fa40..52b2a092 100644 --- a/client/rpc_client.go +++ b/client/rpc_client.go @@ -17,8 +17,8 @@ import ( "github.com/micro/go-micro/codec" "github.com/micro/go-micro/errors" "github.com/micro/go-micro/metadata" - "github.com/micro/go-micro/registry" "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/registry" ) type rpcClient struct { diff --git a/client/rpc_codec.go b/client/rpc_codec.go index ca390e39..91aae303 100644 --- a/client/rpc_codec.go +++ b/client/rpc_codec.go @@ -12,8 +12,8 @@ import ( "github.com/micro/go-micro/codec/proto" "github.com/micro/go-micro/codec/protorpc" "github.com/micro/go-micro/errors" - "github.com/micro/go-micro/registry" "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/registry" ) const ( diff --git a/config/cmd/options.go b/config/cmd/options.go index 3711235c..be703f56 100644 --- a/config/cmd/options.go +++ b/config/cmd/options.go @@ -6,9 +6,9 @@ import ( "github.com/micro/go-micro/broker" "github.com/micro/go-micro/client" "github.com/micro/go-micro/client/selector" + "github.com/micro/go-micro/network/transport" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/server" - "github.com/micro/go-micro/network/transport" ) type Options struct { diff --git a/network/node.go b/network/node.go index 440d9c49..cb0f19ad 100644 --- a/network/node.go +++ b/network/node.go @@ -12,8 +12,8 @@ import ( "time" "github.com/google/uuid" - "github.com/micro/go-micro/registry" "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/registry" "github.com/micro/go-micro/util/addr" "github.com/micro/go-micro/util/log" diff --git a/options.go b/options.go index 95c65e73..355e1cfc 100644 --- a/options.go +++ b/options.go @@ -9,9 +9,9 @@ import ( "github.com/micro/go-micro/client" "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/config/cmd" + "github.com/micro/go-micro/network/transport" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/server" - "github.com/micro/go-micro/network/transport" ) type Options struct { diff --git a/server/grpc/options.go b/server/grpc/options.go index 6a5e07f6..e1c2efc9 100644 --- a/server/grpc/options.go +++ b/server/grpc/options.go @@ -6,10 +6,10 @@ import ( "github.com/micro/go-micro/broker" "github.com/micro/go-micro/codec" + "github.com/micro/go-micro/network/transport" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/server" "github.com/micro/go-micro/server/debug" - "github.com/micro/go-micro/network/transport" "google.golang.org/grpc" "google.golang.org/grpc/encoding" ) diff --git a/server/options.go b/server/options.go index c00c2e9f..200a7a18 100644 --- a/server/options.go +++ b/server/options.go @@ -7,9 +7,9 @@ import ( "github.com/micro/go-micro/broker" "github.com/micro/go-micro/codec" + "github.com/micro/go-micro/network/transport" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/server/debug" - "github.com/micro/go-micro/network/transport" ) type Options struct { diff --git a/server/rpc_server.go b/server/rpc_server.go index 524691fd..d182ae2e 100644 --- a/server/rpc_server.go +++ b/server/rpc_server.go @@ -13,8 +13,8 @@ import ( "github.com/micro/go-micro/broker" "github.com/micro/go-micro/codec" "github.com/micro/go-micro/metadata" - "github.com/micro/go-micro/registry" "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/registry" "github.com/micro/go-micro/util/addr" log "github.com/micro/go-micro/util/log" ) From 79b03a6825d9630bb6ac605c05e5e5a765ed480c Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Sun, 7 Jul 2019 12:36:14 +0100 Subject: [PATCH 108/287] add broker args --- broker/broker.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/broker/broker.go b/broker/broker.go index 31013784..28fe953a 100644 --- a/broker/broker.go +++ b/broker/broker.go @@ -7,8 +7,8 @@ type Broker interface { Options() Options Connect() error Disconnect() error - Publish(string, *Message, ...PublishOption) error - Subscribe(string, Handler, ...SubscribeOption) (Subscriber, error) + Publish(topic string, m *Message, opts ...PublishOption) error + Subscribe(topic string, h Handler, opts ...SubscribeOption) (Subscriber, error) String() string } From 4b4ad68eb9c1d3aacaeacc6844ee5165eeeb9627 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Sun, 7 Jul 2019 12:44:09 +0100 Subject: [PATCH 109/287] Change Publication to Event --- api/handler/broker/broker.go | 2 +- broker/broker.go | 6 +++--- broker/http_broker.go | 10 +++++----- broker/http_broker_test.go | 10 +++++----- broker/memory/memory.go | 10 +++++----- broker/memory/memory_test.go | 2 +- client/grpc/grpc.go | 4 ++-- client/grpc/message.go | 12 ++++++------ client/rpc_client.go | 2 +- codec/codec.go | 2 +- codec/jsonrpc/jsonrpc.go | 6 +++--- codec/protorpc/protorpc.go | 6 +++--- server/grpc/subscriber.go | 4 ++-- server/subscriber.go | 4 ++-- sync/task/broker/broker.go | 4 ++-- 15 files changed, 42 insertions(+), 42 deletions(-) diff --git a/api/handler/broker/broker.go b/api/handler/broker/broker.go index a9f0800d..2d2905d9 100644 --- a/api/handler/broker/broker.go +++ b/api/handler/broker/broker.go @@ -120,7 +120,7 @@ func (c *conn) writeLoop() { opts = append(opts, broker.Queue(c.queue)) } - subscriber, err := c.b.Subscribe(c.topic, func(p broker.Publication) error { + subscriber, err := c.b.Subscribe(c.topic, func(p broker.Event) error { b, err := json.Marshal(p.Message()) if err != nil { return nil diff --git a/broker/broker.go b/broker/broker.go index 28fe953a..b7b9dcb0 100644 --- a/broker/broker.go +++ b/broker/broker.go @@ -15,15 +15,15 @@ type Broker interface { // Handler is used to process messages via a subscription of a topic. // The handler is passed a publication interface which contains the // message and optional Ack method to acknowledge receipt of the message. -type Handler func(Publication) error +type Handler func(Event) error type Message struct { Header map[string]string Body []byte } -// Publication is given to a subscription handler for processing -type Publication interface { +// Event is given to a subscription handler for processing +type Event interface { Topic() string Message() *Message Ack() error diff --git a/broker/http_broker.go b/broker/http_broker.go index 01e39495..d148da5d 100644 --- a/broker/http_broker.go +++ b/broker/http_broker.go @@ -59,7 +59,7 @@ type httpSubscriber struct { hb *httpBroker } -type httpPublication struct { +type httpEvent struct { m *Message t string } @@ -155,15 +155,15 @@ func newHttpBroker(opts ...Option) Broker { return h } -func (h *httpPublication) Ack() error { +func (h *httpEvent) Ack() error { return nil } -func (h *httpPublication) Message() *Message { +func (h *httpEvent) Message() *Message { return h.m } -func (h *httpPublication) Topic() string { +func (h *httpEvent) Topic() string { return h.t } @@ -323,7 +323,7 @@ func (h *httpBroker) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - p := &httpPublication{m: m, t: topic} + p := &httpEvent{m: m, t: topic} id := req.Form.Get("id") h.RLock() diff --git a/broker/http_broker_test.go b/broker/http_broker_test.go index 83db509b..4695033e 100644 --- a/broker/http_broker_test.go +++ b/broker/http_broker_test.go @@ -47,7 +47,7 @@ func sub(be *testing.B, c int) { done := make(chan bool, c) for i := 0; i < c; i++ { - sub, err := b.Subscribe(topic, func(p Publication) error { + sub, err := b.Subscribe(topic, func(p Event) error { done <- true m := p.Message() @@ -107,7 +107,7 @@ func pub(be *testing.B, c int) { done := make(chan bool, c*4) - sub, err := b.Subscribe(topic, func(p Publication) error { + sub, err := b.Subscribe(topic, func(p Event) error { done <- true m := p.Message() if string(m.Body) != string(msg.Body) { @@ -175,7 +175,7 @@ func TestBroker(t *testing.T) { done := make(chan bool) - sub, err := b.Subscribe("test", func(p Publication) error { + sub, err := b.Subscribe("test", func(p Event) error { m := p.Message() if string(m.Body) != string(msg.Body) { @@ -224,7 +224,7 @@ func TestConcurrentSubBroker(t *testing.T) { var wg sync.WaitGroup for i := 0; i < 10; i++ { - sub, err := b.Subscribe("test", func(p Publication) error { + sub, err := b.Subscribe("test", func(p Event) error { defer wg.Done() m := p.Message() @@ -279,7 +279,7 @@ func TestConcurrentPubBroker(t *testing.T) { var wg sync.WaitGroup - sub, err := b.Subscribe("test", func(p Publication) error { + sub, err := b.Subscribe("test", func(p Event) error { defer wg.Done() m := p.Message() diff --git a/broker/memory/memory.go b/broker/memory/memory.go index 7446bb21..fb077faa 100644 --- a/broker/memory/memory.go +++ b/broker/memory/memory.go @@ -17,7 +17,7 @@ type memoryBroker struct { Subscribers map[string][]*memorySubscriber } -type memoryPublication struct { +type memoryEvent struct { topic string message *broker.Message } @@ -84,7 +84,7 @@ func (m *memoryBroker) Publish(topic string, message *broker.Message, opts ...br return nil } - p := &memoryPublication{ + p := &memoryEvent{ topic: topic, message: message, } @@ -142,15 +142,15 @@ func (m *memoryBroker) String() string { return "memory" } -func (m *memoryPublication) Topic() string { +func (m *memoryEvent) Topic() string { return m.topic } -func (m *memoryPublication) Message() *broker.Message { +func (m *memoryEvent) Message() *broker.Message { return m.message } -func (m *memoryPublication) Ack() error { +func (m *memoryEvent) Ack() error { return nil } diff --git a/broker/memory/memory_test.go b/broker/memory/memory_test.go index 5c0021b1..625c7ee7 100644 --- a/broker/memory/memory_test.go +++ b/broker/memory/memory_test.go @@ -17,7 +17,7 @@ func TestMemoryBroker(t *testing.T) { topic := "test" count := 10 - fn := func(p broker.Publication) error { + fn := func(p broker.Event) error { return nil } diff --git a/client/grpc/grpc.go b/client/grpc/grpc.go index 939019f5..809eec2a 100644 --- a/client/grpc/grpc.go +++ b/client/grpc/grpc.go @@ -295,7 +295,7 @@ func (g *grpcClient) Options() client.Options { } func (g *grpcClient) NewMessage(topic string, msg interface{}, opts ...client.MessageOption) client.Message { - return newGRPCPublication(topic, msg, g.opts.ContentType, opts...) + return newGRPCEvent(topic, msg, g.opts.ContentType, opts...) } func (g *grpcClient) NewRequest(service, method string, req interface{}, reqOpts ...client.RequestOption) client.Request { @@ -498,7 +498,7 @@ func (g *grpcClient) Publish(ctx context.Context, p client.Message, opts ...clie } b := &buffer{bytes.NewBuffer(nil)} - if err := cf(b).Write(&codec.Message{Type: codec.Publication}, p.Payload()); err != nil { + if err := cf(b).Write(&codec.Message{Type: codec.Event}, p.Payload()); err != nil { return errors.InternalServerError("go.micro.client", err.Error()) } diff --git a/client/grpc/message.go b/client/grpc/message.go index 6938064e..5691868e 100644 --- a/client/grpc/message.go +++ b/client/grpc/message.go @@ -4,13 +4,13 @@ import ( "github.com/micro/go-micro/client" ) -type grpcPublication struct { +type grpcEvent struct { topic string contentType string payload interface{} } -func newGRPCPublication(topic string, payload interface{}, contentType string, opts ...client.MessageOption) client.Message { +func newGRPCEvent(topic string, payload interface{}, contentType string, opts ...client.MessageOption) client.Message { var options client.MessageOptions for _, o := range opts { o(&options) @@ -20,21 +20,21 @@ func newGRPCPublication(topic string, payload interface{}, contentType string, o contentType = options.ContentType } - return &grpcPublication{ + return &grpcEvent{ payload: payload, topic: topic, contentType: contentType, } } -func (g *grpcPublication) ContentType() string { +func (g *grpcEvent) ContentType() string { return g.contentType } -func (g *grpcPublication) Topic() string { +func (g *grpcEvent) Topic() string { return g.topic } -func (g *grpcPublication) Payload() interface{} { +func (g *grpcEvent) Payload() interface{} { return g.payload } diff --git a/client/rpc_client.go b/client/rpc_client.go index 52b2a092..d2ebe74a 100644 --- a/client/rpc_client.go +++ b/client/rpc_client.go @@ -547,7 +547,7 @@ func (r *rpcClient) Publish(ctx context.Context, msg Message, opts ...PublishOpt b := &buffer{bytes.NewBuffer(nil)} if err := cf(b).Write(&codec.Message{ Target: topic, - Type: codec.Publication, + Type: codec.Event, Header: map[string]string{ "Micro-Id": id, "Micro-Topic": msg.Topic(), diff --git a/codec/codec.go b/codec/codec.go index 092caa05..b4feb0a4 100644 --- a/codec/codec.go +++ b/codec/codec.go @@ -9,7 +9,7 @@ const ( Error MessageType = iota Request Response - Publication + Event ) type MessageType int diff --git a/codec/jsonrpc/jsonrpc.go b/codec/jsonrpc/jsonrpc.go index 8f0c2c4f..f98b2842 100644 --- a/codec/jsonrpc/jsonrpc.go +++ b/codec/jsonrpc/jsonrpc.go @@ -33,7 +33,7 @@ func (j *jsonCodec) Write(m *codec.Message, b interface{}) error { return j.c.Write(m, b) case codec.Response, codec.Error: return j.s.Write(m, b) - case codec.Publication: + case codec.Event: data, err := json.Marshal(b) if err != nil { return err @@ -54,7 +54,7 @@ func (j *jsonCodec) ReadHeader(m *codec.Message, mt codec.MessageType) error { return j.s.ReadHeader(m) case codec.Response: return j.c.ReadHeader(m) - case codec.Publication: + case codec.Event: _, err := io.Copy(j.buf, j.rwc) return err default: @@ -69,7 +69,7 @@ func (j *jsonCodec) ReadBody(b interface{}) error { return j.s.ReadBody(b) case codec.Response: return j.c.ReadBody(b) - case codec.Publication: + case codec.Event: if b != nil { return json.Unmarshal(j.buf.Bytes(), b) } diff --git a/codec/protorpc/protorpc.go b/codec/protorpc/protorpc.go index 4732b98e..255b93a4 100644 --- a/codec/protorpc/protorpc.go +++ b/codec/protorpc/protorpc.go @@ -99,7 +99,7 @@ func (c *protoCodec) Write(m *codec.Message, b interface{}) error { return err } } - case codec.Publication: + case codec.Event: data, err := proto.Marshal(b.(proto.Message)) if err != nil { return err @@ -141,7 +141,7 @@ func (c *protoCodec) ReadHeader(m *codec.Message, mt codec.MessageType) error { m.Method = rtmp.GetServiceMethod() m.Id = fmt.Sprintf("%d", rtmp.GetSeq()) m.Error = rtmp.GetError() - case codec.Publication: + case codec.Event: _, err := io.Copy(c.buf, c.rwc) return err default: @@ -159,7 +159,7 @@ func (c *protoCodec) ReadBody(b interface{}) error { if err != nil { return err } - case codec.Publication: + case codec.Event: data = c.buf.Bytes() default: return fmt.Errorf("Unrecognised message type: %v", c.mt) diff --git a/server/grpc/subscriber.go b/server/grpc/subscriber.go index 7a9f19af..97b9d75e 100644 --- a/server/grpc/subscriber.go +++ b/server/grpc/subscriber.go @@ -167,7 +167,7 @@ func validateSubscriber(sub server.Subscriber) error { } func (g *grpcServer) createSubHandler(sb *subscriber, opts server.Options) broker.Handler { - return func(p broker.Publication) error { + return func(p broker.Event) error { msg := p.Message() ct := msg.Header["Content-Type"] if len(ct) == 0 { @@ -208,7 +208,7 @@ func (g *grpcServer) createSubHandler(sb *subscriber, opts server.Options) broke co := cf(b) defer co.Close() - if err := co.ReadHeader(&codec.Message{}, codec.Publication); err != nil { + if err := co.ReadHeader(&codec.Message{}, codec.Event); err != nil { return err } diff --git a/server/subscriber.go b/server/subscriber.go index 77971565..3d87fea1 100644 --- a/server/subscriber.go +++ b/server/subscriber.go @@ -165,7 +165,7 @@ func validateSubscriber(sub Subscriber) error { } func (s *rpcServer) createSubHandler(sb *subscriber, opts Options) broker.Handler { - return func(p broker.Publication) error { + return func(p broker.Event) error { msg := p.Message() // get codec @@ -214,7 +214,7 @@ func (s *rpcServer) createSubHandler(sb *subscriber, opts Options) broker.Handle co := cf(b) defer co.Close() - if err := co.ReadHeader(&codec.Message{}, codec.Publication); err != nil { + if err := co.ReadHeader(&codec.Message{}, codec.Event); err != nil { return err } diff --git a/sync/task/broker/broker.go b/sync/task/broker/broker.go index af0ee673..f643fb2d 100644 --- a/sync/task/broker/broker.go +++ b/sync/task/broker/broker.go @@ -47,7 +47,7 @@ func (t *Task) Run(c task.Command) error { errCh := make(chan error, t.Options.Pool) // subscribe for distributed work - workFn := func(p broker.Publication) error { + workFn := func(p broker.Event) error { msg := p.Message() // get command name @@ -110,7 +110,7 @@ func (t *Task) Run(c task.Command) error { } // subscribe to all status messages - subStatus, err := t.Broker.Subscribe(topic, func(p broker.Publication) error { + subStatus, err := t.Broker.Subscribe(topic, func(p broker.Event) error { msg := p.Message() // get command name From 0b732b2c492ed4a54538fe061cb46ebe4fc9abb6 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Sun, 7 Jul 2019 15:03:08 +0100 Subject: [PATCH 110/287] update transport package comments --- network/transport/transport.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/network/transport/transport.go b/network/transport/transport.go index 6e11e341..2add7e6d 100644 --- a/network/transport/transport.go +++ b/network/transport/transport.go @@ -1,10 +1,21 @@ -// Package transport is an interface for synchronous communication +// Package transport is an interface for connection based communication package transport import ( "time" ) +// Transport is an interface which is used for communication between +// services. It uses connection based socket send/recv semantics and +// has various implementations; http, grpc, quic. +type Transport interface { + Init(...Option) error + Options() Options + Dial(addr string, opts ...DialOption) (Client, error) + Listen(addr string, opts ...ListenOption) (Listener, error) + String() string +} + type Message struct { Header map[string]string Body []byte @@ -28,17 +39,6 @@ type Listener interface { Accept(func(Socket)) error } -// Transport is an interface which is used for communication between -// services. It uses socket send/recv semantics and had various -// implementations {HTTP, RabbitMQ, NATS, ...} -type Transport interface { - Init(...Option) error - Options() Options - Dial(addr string, opts ...DialOption) (Client, error) - Listen(addr string, opts ...ListenOption) (Listener, error) - String() string -} - type Option func(*Options) type DialOption func(*DialOptions) From 5b7454e5a8b2c3ec3fa2f05cdddbe49c19696891 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Sun, 7 Jul 2019 15:04:07 +0100 Subject: [PATCH 111/287] update transport package comments --- network/transport/transport.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network/transport/transport.go b/network/transport/transport.go index 2add7e6d..84f05a2b 100644 --- a/network/transport/transport.go +++ b/network/transport/transport.go @@ -1,4 +1,4 @@ -// Package transport is an interface for connection based communication +// Package transport is an interface for synchronous connection based communication package transport import ( From b655f7f55a9052f0b8cc7db3a802f58b61eb5e03 Mon Sep 17 00:00:00 2001 From: Joe Date: Mon, 8 Jul 2019 10:32:10 +0800 Subject: [PATCH 112/287] grpc: using jsonpb.Marshaler to do Marshal, map to jsonpb.Unmarsh --- client/grpc/codec.go | 8 ++++++++ server/grpc/codec.go | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/client/grpc/codec.go b/client/grpc/codec.go index f223a55c..e7891eef 100644 --- a/client/grpc/codec.go +++ b/client/grpc/codec.go @@ -22,6 +22,8 @@ type protoCodec struct{} type bytesCodec struct{} type wrapCodec struct{ encoding.Codec } +var jsonpbMarshaler = &jsonpb.Marshaler{} + var ( defaultGRPCCodecs = map[string]encoding.Codec{ "application/json": jsonCodec{}, @@ -113,6 +115,12 @@ func (bytesCodec) Name() string { } func (jsonCodec) Marshal(v interface{}) ([]byte, error) { + if pb, ok := v.(proto.Message); ok { + s, err := jsonpbMarshaler.MarshalToString(pb) + + return []byte(s), err + } + return json.Marshal(v) } diff --git a/server/grpc/codec.go b/server/grpc/codec.go index 7362f49c..53de36c3 100644 --- a/server/grpc/codec.go +++ b/server/grpc/codec.go @@ -23,6 +23,8 @@ type bytesCodec struct{} type protoCodec struct{} type wrapCodec struct{ encoding.Codec } +var jsonpbMarshaler = &jsonpb.Marshaler{} + var ( defaultGRPCCodecs = map[string]encoding.Codec{ "application/json": jsonCodec{}, @@ -78,6 +80,12 @@ func (protoCodec) Name() string { } func (jsonCodec) Marshal(v interface{}) ([]byte, error) { + if pb, ok := v.(proto.Message); ok { + s, err := jsonpbMarshaler.MarshalToString(pb) + + return []byte(s), err + } + return json.Marshal(v) } From e0bf1c2283147a07dbdc713786c035c2535f46d0 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 8 Jul 2019 08:01:42 +0100 Subject: [PATCH 113/287] Remove Port from registry --- api/handler/http/http.go | 2 +- api/handler/http/http_test.go | 13 +------------ api/handler/web/web.go | 2 +- broker/common_test.go | 12 ++++-------- broker/http_broker.go | 5 ++--- client/common_test.go | 12 ++++-------- client/grpc/grpc.go | 6 ------ client/grpc/grpc_test.go | 4 ++-- client/rpc_client.go | 20 +------------------- client/rpc_client_test.go | 13 +++---------- client/selector/common_test.go | 12 ++++-------- client/selector/dns/dns.go | 4 ++-- client/selector/router/router.go | 21 +-------------------- client/selector/static/static.go | 15 +-------------- client/selector/strategy_test.go | 12 ++++-------- common_test.go | 12 ++++-------- network/node.go | 2 +- network/proxy/mucp/mucp.go | 7 +------ network/resolver/registry/registry.go | 9 +-------- network/router/default_router.go | 6 +----- registry/consul/consul.go | 13 ++++++++----- registry/consul/watcher.go | 4 ++-- registry/mdns_registry.go | 17 +++++++++++++---- registry/mdns_test.go | 13 +++---------- registry/mdns_watcher.go | 4 ++-- registry/memory/memory_test.go | 21 +++++++-------------- registry/service.go | 1 - registry/util_test.go | 15 +++++---------- registry/watcher_test.go | 13 +++---------- server/grpc/grpc.go | 6 ++---- server/rpc_server.go | 6 ++---- util/http/http_test.go | 7 +------ util/http/roundtripper.go | 3 +-- web/service.go | 4 ++-- web/service_test.go | 4 ++-- 35 files changed, 92 insertions(+), 228 deletions(-) diff --git a/api/handler/http/http.go b/api/handler/http/http.go index b9380ce3..ad2b1c66 100644 --- a/api/handler/http/http.go +++ b/api/handler/http/http.go @@ -73,7 +73,7 @@ func (h *httpHandler) getService(r *http.Request) (string, error) { return "", nil } - return fmt.Sprintf("http://%s:%d", s.Address, s.Port), nil + return fmt.Sprintf("http://%s", s.Address), nil } func (h *httpHandler) String() string { diff --git a/api/handler/http/http_test.go b/api/handler/http/http_test.go index 78c135b6..31847221 100644 --- a/api/handler/http/http_test.go +++ b/api/handler/http/http_test.go @@ -4,8 +4,6 @@ import ( "net" "net/http" "net/http/httptest" - "strconv" - "strings" "testing" "github.com/micro/go-micro/api/handler" @@ -26,21 +24,12 @@ func testHttp(t *testing.T, path, service, ns string) { } defer l.Close() - parts := strings.Split(l.Addr().String(), ":") - - var host string - var port int - - host = parts[0] - port, _ = strconv.Atoi(parts[1]) - s := ®istry.Service{ Name: service, Nodes: []*registry.Node{ ®istry.Node{ Id: service + "-1", - Address: host, - Port: port, + Address: l.Addr().String(), }, }, } diff --git a/api/handler/web/web.go b/api/handler/web/web.go index 415dd694..77a0f6af 100644 --- a/api/handler/web/web.go +++ b/api/handler/web/web.go @@ -79,7 +79,7 @@ func (wh *webHandler) getService(r *http.Request) (string, error) { return "", nil } - return fmt.Sprintf("http://%s:%d", s.Address, s.Port), nil + return fmt.Sprintf("http://%s", s.Address), nil } // serveWebSocket used to serve a web socket proxied connection diff --git a/broker/common_test.go b/broker/common_test.go index af54db18..262a77eb 100644 --- a/broker/common_test.go +++ b/broker/common_test.go @@ -14,13 +14,11 @@ var ( Nodes: []*registry.Node{ { Id: "foo-1.0.0-123", - Address: "localhost", - Port: 9999, + Address: "localhost:9999", }, { Id: "foo-1.0.0-321", - Address: "localhost", - Port: 9999, + Address: "localhost:9999", }, }, }, @@ -30,8 +28,7 @@ var ( Nodes: []*registry.Node{ { Id: "foo-1.0.1-321", - Address: "localhost", - Port: 6666, + Address: "localhost:6666", }, }, }, @@ -41,8 +38,7 @@ var ( Nodes: []*registry.Node{ { Id: "foo-1.0.3-345", - Address: "localhost", - Port: 8888, + Address: "localhost:8888", }, }, }, diff --git a/broker/http_broker.go b/broker/http_broker.go index d148da5d..d28eeb2c 100644 --- a/broker/http_broker.go +++ b/broker/http_broker.go @@ -543,7 +543,7 @@ func (h *httpBroker) Publish(topic string, msg *Message, opts ...PublishOption) vals := url.Values{} vals.Add("id", node.Id) - uri := fmt.Sprintf("%s://%s:%d%s?%s", scheme, node.Address, node.Port, DefaultSubPath, vals.Encode()) + uri := fmt.Sprintf("%s://%s%s?%s", scheme, node.Address, DefaultSubPath, vals.Encode()) r, err := h.c.Post(uri, "application/json", bytes.NewReader(b)) if err != nil { return err @@ -638,8 +638,7 @@ func (h *httpBroker) Subscribe(topic string, handler Handler, opts ...SubscribeO // register service node := ®istry.Node{ Id: id, - Address: addr, - Port: port, + Address: fmt.Sprintf("%s:%d", addr, port), Metadata: map[string]string{ "secure": fmt.Sprintf("%t", secure), }, diff --git a/client/common_test.go b/client/common_test.go index d172812b..15ddc158 100644 --- a/client/common_test.go +++ b/client/common_test.go @@ -14,13 +14,11 @@ var ( Nodes: []*registry.Node{ { Id: "foo-1.0.0-123", - Address: "localhost", - Port: 9999, + Address: "localhost:9999", }, { Id: "foo-1.0.0-321", - Address: "localhost", - Port: 9999, + Address: "localhost:9999", }, }, }, @@ -30,8 +28,7 @@ var ( Nodes: []*registry.Node{ { Id: "foo-1.0.1-321", - Address: "localhost", - Port: 6666, + Address: "localhost:6666", }, }, }, @@ -41,8 +38,7 @@ var ( Nodes: []*registry.Node{ { Id: "foo-1.0.3-345", - Address: "localhost", - Port: 8888, + Address: "localhost:8888", }, }, }, diff --git a/client/grpc/grpc.go b/client/grpc/grpc.go index 809eec2a..e79b5406 100644 --- a/client/grpc/grpc.go +++ b/client/grpc/grpc.go @@ -84,9 +84,6 @@ func (g *grpcClient) next(request client.Request, opts client.CallOptions) (sele func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.Request, rsp interface{}, opts client.CallOptions) error { address := node.Address - if node.Port > 0 { - address = fmt.Sprintf("%s:%d", address, node.Port) - } header := make(map[string]string) if md, ok := metadata.FromContext(ctx); ok { @@ -146,9 +143,6 @@ func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.R func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client.Request, opts client.CallOptions) (client.Stream, error) { address := node.Address - if node.Port > 0 { - address = fmt.Sprintf("%s:%d", address, node.Port) - } header := make(map[string]string) if md, ok := metadata.FromContext(ctx); ok { diff --git a/client/grpc/grpc_test.go b/client/grpc/grpc_test.go index 7c58fd4e..3652ec6b 100644 --- a/client/grpc/grpc_test.go +++ b/client/grpc/grpc_test.go @@ -2,6 +2,7 @@ package grpc import ( "context" + "fmt" "net" "strconv" "strings" @@ -50,8 +51,7 @@ func TestGRPCClient(t *testing.T) { Nodes: []*registry.Node{ ®istry.Node{ Id: "test-1", - Address: addr, - Port: port, + Address: fmt.Sprintf("%s:%d", addr, port), }, }, }) diff --git a/client/rpc_client.go b/client/rpc_client.go index d2ebe74a..8f729252 100644 --- a/client/rpc_client.go +++ b/client/rpc_client.go @@ -4,9 +4,7 @@ import ( "bytes" "context" "fmt" - "net" "os" - "strconv" "sync" "sync/atomic" "time" @@ -60,9 +58,6 @@ func (r *rpcClient) newCodec(contentType string) (codec.NewCodec, error) { func (r *rpcClient) call(ctx context.Context, node *registry.Node, req Request, resp interface{}, opts CallOptions) error { address := node.Address - if node.Port > 0 { - address = fmt.Sprintf("%s:%d", address, node.Port) - } msg := &transport.Message{ Header: make(map[string]string), @@ -160,9 +155,6 @@ func (r *rpcClient) call(ctx context.Context, node *registry.Node, req Request, func (r *rpcClient) stream(ctx context.Context, node *registry.Node, req Request, opts CallOptions) (Stream, error) { address := node.Address - if node.Port > 0 { - address = fmt.Sprintf("%s:%d", address, node.Port) - } msg := &transport.Message{ Header: make(map[string]string), @@ -290,19 +282,9 @@ func (r *rpcClient) next(request Request, opts CallOptions) (selector.Next, erro if len(opts.Address) > 0 { var nodes []*registry.Node - for _, addr := range opts.Address { - address := addr - port := 0 - - host, sport, err := net.SplitHostPort(addr) - if err == nil { - address = host - port, _ = strconv.Atoi(sport) - } - + for _, address := range opts.Address { nodes = append(nodes, ®istry.Node{ Address: address, - Port: port, // Set the protocol Metadata: map[string]string{ "protocol": "mucp", diff --git a/client/rpc_client_test.go b/client/rpc_client_test.go index 2db3ae90..14547e9f 100644 --- a/client/rpc_client_test.go +++ b/client/rpc_client_test.go @@ -22,8 +22,7 @@ func TestCallAddress(t *testing.T) { var called bool service := "test.service" endpoint := "Test.Endpoint" - address := "10.1.10.1" - port := 8080 + address := "10.1.10.1:8080" wrap := func(cf CallFunc) CallFunc { return func(ctx context.Context, node *registry.Node, req Request, rsp interface{}, opts CallOptions) error { @@ -41,10 +40,6 @@ func TestCallAddress(t *testing.T) { return fmt.Errorf("expected address: %s got %s", address, node.Address) } - if node.Port != port { - return fmt.Errorf("expected address: %d got %d", port, node.Port) - } - // don't do the call return nil } @@ -60,7 +55,7 @@ func TestCallAddress(t *testing.T) { req := c.NewRequest(service, endpoint, nil) // test calling remote address - if err := c.Call(context.Background(), req, nil, WithAddress(fmt.Sprintf("%s:%d", address, port))); err != nil { + if err := c.Call(context.Background(), req, nil, WithAddress(address)); err != nil { t.Fatal("call with address error", err) } @@ -114,8 +109,7 @@ func TestCallWrapper(t *testing.T) { id := "test.1" service := "test.service" endpoint := "Test.Endpoint" - address := "10.1.10.1" - port := 8080 + address := "10.1.10.1:8080" wrap := func(cf CallFunc) CallFunc { return func(ctx context.Context, node *registry.Node, req Request, rsp interface{}, opts CallOptions) error { @@ -152,7 +146,6 @@ func TestCallWrapper(t *testing.T) { ®istry.Node{ Id: id, Address: address, - Port: port, }, }, }) diff --git a/client/selector/common_test.go b/client/selector/common_test.go index aa8c15c7..7aba0542 100644 --- a/client/selector/common_test.go +++ b/client/selector/common_test.go @@ -14,13 +14,11 @@ var ( Nodes: []*registry.Node{ { Id: "foo-1.0.0-123", - Address: "localhost", - Port: 9999, + Address: "localhost:9999", }, { Id: "foo-1.0.0-321", - Address: "localhost", - Port: 9999, + Address: "localhost:9999", }, }, }, @@ -30,8 +28,7 @@ var ( Nodes: []*registry.Node{ { Id: "foo-1.0.1-321", - Address: "localhost", - Port: 6666, + Address: "localhost:6666", }, }, }, @@ -41,8 +38,7 @@ var ( Nodes: []*registry.Node{ { Id: "foo-1.0.3-345", - Address: "localhost", - Port: 8888, + Address: "localhost:8888", }, }, }, diff --git a/client/selector/dns/dns.go b/client/selector/dns/dns.go index b1d19c95..df6c209f 100644 --- a/client/selector/dns/dns.go +++ b/client/selector/dns/dns.go @@ -2,6 +2,7 @@ package dns import ( + "fmt" "net" "strconv" @@ -66,8 +67,7 @@ func (d *dnsSelector) Select(service string, opts ...selector.SelectOption) (sel for _, node := range srv { nodes = append(nodes, ®istry.Node{ Id: node.Target, - Address: node.Target, - Port: int(node.Port), + Address: fmt.Sprintf("%s:%d", node.Target, node.Port), }) } diff --git a/client/selector/router/router.go b/client/selector/router/router.go index 452c9b89..4bcdecd1 100644 --- a/client/selector/router/router.go +++ b/client/selector/router/router.go @@ -3,11 +3,8 @@ package router import ( "context" - "fmt" - "net" "os" "sort" - "strconv" "sync" "github.com/micro/go-micro/client" @@ -67,11 +64,7 @@ func (r *routerSelector) getRoutes(service string) ([]router.Route, error) { for _, service := range services { for _, node := range service.Nodes { - addr := node.Address - if node.Port > 0 { - addr = fmt.Sprintf("%s:%d", node.Address, node.Port) - } - addrs = append(addrs, addr) + addrs = append(addrs, node.Address) } } } @@ -168,23 +161,11 @@ func (r *routerSelector) Select(service string, opts ...selector.SelectOption) ( // defaults to gateway and no port address := route.Gateway - port := 0 - - // check if its host:port - host, pr, err := net.SplitHostPort(address) - if err == nil { - pp, _ := strconv.Atoi(pr) - // set port - port = pp - // set address - address = host - } // return as a node return ®istry.Node{ // TODO: add id and metadata if we can Address: address, - Port: port, }, nil }, nil } diff --git a/client/selector/static/static.go b/client/selector/static/static.go index c9b2fd83..9bd18f03 100644 --- a/client/selector/static/static.go +++ b/client/selector/static/static.go @@ -2,9 +2,6 @@ package static import ( - "net" - "strconv" - "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/registry" ) @@ -26,20 +23,10 @@ func (s *staticSelector) Options() selector.Options { } func (s *staticSelector) Select(service string, opts ...selector.SelectOption) (selector.Next, error) { - var port int - addr, pt, err := net.SplitHostPort(service) - if err != nil { - addr = service - port = 0 - } else { - port, _ = strconv.Atoi(pt) - } - return func() (*registry.Node, error) { return ®istry.Node{ Id: service, - Address: addr, - Port: port, + Address: service, }, nil }, nil } diff --git a/client/selector/strategy_test.go b/client/selector/strategy_test.go index 17090e73..8ea9376a 100644 --- a/client/selector/strategy_test.go +++ b/client/selector/strategy_test.go @@ -14,13 +14,11 @@ func TestStrategies(t *testing.T) { Nodes: []*registry.Node{ ®istry.Node{ Id: "test1-1", - Address: "10.0.0.1", - Port: 1001, + Address: "10.0.0.1:1001", }, ®istry.Node{ Id: "test1-2", - Address: "10.0.0.2", - Port: 1002, + Address: "10.0.0.2:1002", }, }, }, @@ -30,13 +28,11 @@ func TestStrategies(t *testing.T) { Nodes: []*registry.Node{ ®istry.Node{ Id: "test1-3", - Address: "10.0.0.3", - Port: 1003, + Address: "10.0.0.3:1003", }, ®istry.Node{ Id: "test1-4", - Address: "10.0.0.4", - Port: 1004, + Address: "10.0.0.4:1004", }, }, }, diff --git a/common_test.go b/common_test.go index 612cdb37..d4fd4bfb 100644 --- a/common_test.go +++ b/common_test.go @@ -14,13 +14,11 @@ var ( Nodes: []*registry.Node{ { Id: "foo-1.0.0-123", - Address: "localhost", - Port: 9999, + Address: "localhost:9999", }, { Id: "foo-1.0.0-321", - Address: "localhost", - Port: 9999, + Address: "localhost:9999", }, }, }, @@ -30,8 +28,7 @@ var ( Nodes: []*registry.Node{ { Id: "foo-1.0.1-321", - Address: "localhost", - Port: 6666, + Address: "localhost:6666", }, }, }, @@ -41,8 +38,7 @@ var ( Nodes: []*registry.Node{ { Id: "foo-1.0.3-345", - Address: "localhost", - Port: 8888, + Address: "localhost:8888", }, }, }, diff --git a/network/node.go b/network/node.go index cb0f19ad..93372c7d 100644 --- a/network/node.go +++ b/network/node.go @@ -158,7 +158,7 @@ func newNode(n *network) (*node, error) { // register with the network id Name: n.Name(), Nodes: []*registry.Node{ - {Id: node.id, Address: addr, Port: port}, + {Id: node.id, Address: node.address}, }, }); err != nil { node.Close() diff --git a/network/proxy/mucp/mucp.go b/network/proxy/mucp/mucp.go index aeecead1..1abe976b 100644 --- a/network/proxy/mucp/mucp.go +++ b/network/proxy/mucp/mucp.go @@ -3,7 +3,6 @@ package mucp import ( "context" - "fmt" "io" "os" "strings" @@ -157,11 +156,7 @@ func (p *Proxy) getRoute(service string) ([]string, error) { for _, service := range services { for _, node := range service.Nodes { - addr := node.Address - if node.Port > 0 { - addr = fmt.Sprintf("%s:%d", node.Address, node.Port) - } - addrs = append(addrs, addr) + addrs = append(addrs, node.Address) } } } diff --git a/network/resolver/registry/registry.go b/network/resolver/registry/registry.go index 09228970..c7ef796a 100644 --- a/network/resolver/registry/registry.go +++ b/network/resolver/registry/registry.go @@ -2,8 +2,6 @@ package registry import ( - "fmt" - "github.com/micro/go-micro/network/resolver" "github.com/micro/go-micro/registry" ) @@ -29,13 +27,8 @@ func (r *Resolver) Resolve(id string) ([]*resolver.Record, error) { for _, service := range services { for _, node := range service.Nodes { - addr := node.Address - // such a hack - if node.Port > 0 { - addr = fmt.Sprintf("%s:%d", node.Address, node.Port) - } records = append(records, &resolver.Record{ - Address: addr, + Address: node.Address, }) } } diff --git a/network/router/default_router.go b/network/router/default_router.go index 322402ef..9a7b933e 100644 --- a/network/router/default_router.go +++ b/network/router/default_router.go @@ -98,13 +98,9 @@ func (r *router) addServiceRoutes(reg registry.Registry, network string, metric // range over the flat slice of nodes for _, node := range nodes { - gateway := node.Address - if node.Port > 0 { - gateway = fmt.Sprintf("%s:%d", node.Address, node.Port) - } route := Route{ Destination: service.Name, - Gateway: gateway, + Gateway: node.Address, Router: r.opts.Address, Network: r.opts.Network, Metric: metric, diff --git a/registry/consul/consul.go b/registry/consul/consul.go index 89f0a2d0..9a15c826 100644 --- a/registry/consul/consul.go +++ b/registry/consul/consul.go @@ -7,6 +7,7 @@ import ( "net" "net/http" "runtime" + "strconv" "sync" "time" @@ -220,7 +221,7 @@ func (c *consulRegistry) Register(s *registry.Service, opts ...registry.Register deregTTL := getDeregisterTTL(regInterval) check = &consul.AgentServiceCheck{ - TCP: fmt.Sprintf("%s:%d", node.Address, node.Port), + TCP: node.Address, Interval: fmt.Sprintf("%v", regInterval), DeregisterCriticalServiceAfter: fmt.Sprintf("%v", deregTTL), } @@ -235,13 +236,16 @@ func (c *consulRegistry) Register(s *registry.Service, opts ...registry.Register } } + host, pt, _ := net.SplitHostPort(node.Address) + port, _ := strconv.Atoi(pt) + // register the service asr := &consul.AgentServiceRegistration{ ID: node.Id, Name: s.Name, Tags: tags, - Port: node.Port, - Address: node.Address, + Port: port, + Address: host, Check: check, } @@ -334,8 +338,7 @@ func (c *consulRegistry) GetService(name string) ([]*registry.Service, error) { svc.Nodes = append(svc.Nodes, ®istry.Node{ Id: id, - Address: address, - Port: s.Service.Port, + Address: fmt.Sprintf("%s:%d", address, s.Service.Port), Metadata: decodeMetadata(s.Service.Tags), }) } diff --git a/registry/consul/watcher.go b/registry/consul/watcher.go index 1bb9d5b7..7d843482 100644 --- a/registry/consul/watcher.go +++ b/registry/consul/watcher.go @@ -1,6 +1,7 @@ package consul import ( + "fmt" "log" "os" "sync" @@ -102,8 +103,7 @@ func (cw *consulWatcher) serviceHandler(idx uint64, data interface{}) { svc.Nodes = append(svc.Nodes, ®istry.Node{ Id: id, - Address: address, - Port: e.Service.Port, + Address: fmt.Sprintf("%s:%d", address, e.Service.Port), Metadata: decodeMetadata(e.Service.Tags), }) } diff --git a/registry/mdns_registry.go b/registry/mdns_registry.go index 4a3d09ec..8e68948a 100644 --- a/registry/mdns_registry.go +++ b/registry/mdns_registry.go @@ -3,7 +3,9 @@ package registry import ( "context" + "fmt" "net" + "strconv" "strings" "sync" "time" @@ -127,14 +129,22 @@ func (m *mdnsRegistry) Register(service *Service, opts ...RegisterOption) error continue } + // + host, pt, err := net.SplitHostPort(node.Address) + if err != nil { + gerr = err + continue + } + port, _ := strconv.Atoi(pt) + // we got here, new node s, err := mdns.NewMDNSService( node.Id, service.Name, "", "", - node.Port, - []net.IP{net.ParseIP(node.Address)}, + port, + []net.IP{net.ParseIP(host)}, txt, ) if err != nil { @@ -238,8 +248,7 @@ func (m *mdnsRegistry) GetService(service string) ([]*Service, error) { s.Nodes = append(s.Nodes, &Node{ Id: strings.TrimSuffix(e.Name, "."+p.Service+"."+p.Domain+"."), - Address: e.AddrV4.String(), - Port: e.Port, + Address: fmt.Sprintf("%s:%d", e.AddrV4.String(), e.Port), Metadata: txt.Metadata, }) diff --git a/registry/mdns_test.go b/registry/mdns_test.go index 5690fe39..e9813c69 100644 --- a/registry/mdns_test.go +++ b/registry/mdns_test.go @@ -13,8 +13,7 @@ func TestMDNS(t *testing.T) { Nodes: []*Node{ &Node{ Id: "test1-1", - Address: "10.0.0.1", - Port: 10001, + Address: "10.0.0.1:10001", Metadata: map[string]string{ "foo": "bar", }, @@ -27,8 +26,7 @@ func TestMDNS(t *testing.T) { Nodes: []*Node{ &Node{ Id: "test2-1", - Address: "10.0.0.2", - Port: 10002, + Address: "10.0.0.2:10002", Metadata: map[string]string{ "foo2": "bar2", }, @@ -41,8 +39,7 @@ func TestMDNS(t *testing.T) { Nodes: []*Node{ &Node{ Id: "test3-1", - Address: "10.0.0.3", - Port: 10003, + Address: "10.0.0.3:10003", Metadata: map[string]string{ "foo3": "bar3", }, @@ -92,10 +89,6 @@ func TestMDNS(t *testing.T) { if node.Address != service.Nodes[0].Address { t.Fatalf("Expected node address %s got %s", service.Nodes[0].Address, node.Address) } - - if node.Port != service.Nodes[0].Port { - t.Fatalf("Expected node port %d got %d", service.Nodes[0].Port, node.Port) - } } services, err := r.ListServices() diff --git a/registry/mdns_watcher.go b/registry/mdns_watcher.go index bbcf90ea..e1c326ff 100644 --- a/registry/mdns_watcher.go +++ b/registry/mdns_watcher.go @@ -1,6 +1,7 @@ package registry import ( + "fmt" "strings" "github.com/micro/mdns" @@ -52,8 +53,7 @@ func (m *mdnsWatcher) Next() (*Result, error) { service.Nodes = append(service.Nodes, &Node{ Id: strings.TrimSuffix(e.Name, "."+service.Name+".local."), - Address: e.AddrV4.String(), - Port: e.Port, + Address: fmt.Sprintf("%s:%d", e.AddrV4.String(), e.Port), Metadata: txt.Metadata, }) diff --git a/registry/memory/memory_test.go b/registry/memory/memory_test.go index 3b5cd8be..fa8b53f1 100644 --- a/registry/memory/memory_test.go +++ b/registry/memory/memory_test.go @@ -15,13 +15,11 @@ var ( Nodes: []*registry.Node{ { Id: "foo-1.0.0-123", - Address: "localhost", - Port: 9999, + Address: "localhost:9999", }, { Id: "foo-1.0.0-321", - Address: "localhost", - Port: 9999, + Address: "localhost:9999", }, }, }, @@ -31,8 +29,7 @@ var ( Nodes: []*registry.Node{ { Id: "foo-1.0.1-321", - Address: "localhost", - Port: 6666, + Address: "localhost:6666", }, }, }, @@ -42,8 +39,7 @@ var ( Nodes: []*registry.Node{ { Id: "foo-1.0.3-345", - Address: "localhost", - Port: 8888, + Address: "localhost:8888", }, }, }, @@ -55,13 +51,11 @@ var ( Nodes: []*registry.Node{ { Id: "bar-1.0.0-123", - Address: "localhost", - Port: 9999, + Address: "localhost:9999", }, { Id: "bar-1.0.0-321", - Address: "localhost", - Port: 9999, + Address: "localhost:9999", }, }, }, @@ -71,8 +65,7 @@ var ( Nodes: []*registry.Node{ { Id: "bar-1.0.1-321", - Address: "localhost", - Port: 6666, + Address: "localhost:6666", }, }, }, diff --git a/registry/service.go b/registry/service.go index 5e13a002..5259a6b6 100644 --- a/registry/service.go +++ b/registry/service.go @@ -11,7 +11,6 @@ type Service struct { type Node struct { Id string `json:"id"` Address string `json:"address"` - Port int `json:"port"` Metadata map[string]string `json:"metadata"` } diff --git a/registry/util_test.go b/registry/util_test.go index 9d14c659..75fd5133 100644 --- a/registry/util_test.go +++ b/registry/util_test.go @@ -12,8 +12,7 @@ func TestRemove(t *testing.T) { Nodes: []*Node{ { Id: "foo-123", - Address: "localhost", - Port: 9999, + Address: "localhost:9999", }, }, }, @@ -23,8 +22,7 @@ func TestRemove(t *testing.T) { Nodes: []*Node{ { Id: "foo-123", - Address: "localhost", - Port: 6666, + Address: "localhost:6666", }, }, }, @@ -45,13 +43,11 @@ func TestRemoveNodes(t *testing.T) { Nodes: []*Node{ { Id: "foo-123", - Address: "localhost", - Port: 9999, + Address: "localhost:9999", }, { Id: "foo-321", - Address: "localhost", - Port: 6666, + Address: "localhost:6666", }, }, }, @@ -61,8 +57,7 @@ func TestRemoveNodes(t *testing.T) { Nodes: []*Node{ { Id: "foo-123", - Address: "localhost", - Port: 6666, + Address: "localhost:6666", }, }, }, diff --git a/registry/watcher_test.go b/registry/watcher_test.go index 41b606b2..94c8c275 100644 --- a/registry/watcher_test.go +++ b/registry/watcher_test.go @@ -12,8 +12,7 @@ func TestWatcher(t *testing.T) { Nodes: []*Node{ &Node{ Id: "test1-1", - Address: "10.0.0.1", - Port: 10001, + Address: "10.0.0.1:10001", Metadata: map[string]string{ "foo": "bar", }, @@ -26,8 +25,7 @@ func TestWatcher(t *testing.T) { Nodes: []*Node{ &Node{ Id: "test2-1", - Address: "10.0.0.2", - Port: 10002, + Address: "10.0.0.2:10002", Metadata: map[string]string{ "foo2": "bar2", }, @@ -40,8 +38,7 @@ func TestWatcher(t *testing.T) { Nodes: []*Node{ &Node{ Id: "test3-1", - Address: "10.0.0.3", - Port: 10003, + Address: "10.0.0.3:10003", Metadata: map[string]string{ "foo3": "bar3", }, @@ -77,10 +74,6 @@ func TestWatcher(t *testing.T) { if node.Address != service.Nodes[0].Address { t.Fatalf("Expected node address %s got %s", service.Nodes[0].Address, node.Address) } - - if node.Port != service.Nodes[0].Port { - t.Fatalf("Expected node port %d got %d", service.Nodes[0].Port, node.Port) - } } // new registry diff --git a/server/grpc/grpc.go b/server/grpc/grpc.go index 75b8823f..8d2a2d8f 100644 --- a/server/grpc/grpc.go +++ b/server/grpc/grpc.go @@ -534,8 +534,7 @@ func (g *grpcServer) Register() error { // register service node := ®istry.Node{ Id: config.Name + "-" + config.Id, - Address: addr, - Port: port, + Address: fmt.Sprintf("%s:%d", addr, port), Metadata: config.Metadata, } @@ -658,8 +657,7 @@ func (g *grpcServer) Deregister() error { node := ®istry.Node{ Id: config.Name + "-" + config.Id, - Address: addr, - Port: port, + Address: fmt.Sprintf("%s:%d", addr, port), } service := ®istry.Service{ diff --git a/server/rpc_server.go b/server/rpc_server.go index d182ae2e..2cabb635 100644 --- a/server/rpc_server.go +++ b/server/rpc_server.go @@ -313,8 +313,7 @@ func (s *rpcServer) Register() error { // register service node := ®istry.Node{ Id: config.Name + "-" + config.Id, - Address: addr, - Port: port, + Address: fmt.Sprintf("%s:%d", addr, port), Metadata: md, } @@ -441,8 +440,7 @@ func (s *rpcServer) Deregister() error { node := ®istry.Node{ Id: config.Name + "-" + config.Id, - Address: addr, - Port: port, + Address: fmt.Sprintf("%s:%d", addr, port), } service := ®istry.Service{ diff --git a/util/http/http_test.go b/util/http/http_test.go index b7bfe370..60196038 100644 --- a/util/http/http_test.go +++ b/util/http/http_test.go @@ -4,7 +4,6 @@ import ( "io/ioutil" "net" "net/http" - "strconv" "testing" "github.com/micro/go-micro/registry" @@ -30,16 +29,12 @@ func TestRoundTripper(t *testing.T) { go http.Serve(l, nil) - host, p, _ := net.SplitHostPort(l.Addr().String()) - port, _ := strconv.Atoi(p) - m.Register(®istry.Service{ Name: "example.com", Nodes: []*registry.Node{ { Id: "1", - Address: host, - Port: port, + Address: l.Addr().String(), }, }, }) diff --git a/util/http/roundtripper.go b/util/http/roundtripper.go index af2299be..36c26b5c 100644 --- a/util/http/roundtripper.go +++ b/util/http/roundtripper.go @@ -2,7 +2,6 @@ package http import ( "errors" - "fmt" "net/http" "github.com/micro/go-micro/client/selector" @@ -28,7 +27,7 @@ func (r *roundTripper) RoundTrip(req *http.Request) (*http.Response, error) { if err != nil { continue } - req.URL.Host = fmt.Sprintf("%s:%d", n.Address, n.Port) + req.URL.Host = n.Address w, err := r.rt.RoundTrip(req) if err != nil { continue diff --git a/web/service.go b/web/service.go index e4836472..65359a2b 100644 --- a/web/service.go +++ b/web/service.go @@ -2,6 +2,7 @@ package web import ( "crypto/tls" + "fmt" "net" "net/http" "os" @@ -83,8 +84,7 @@ func (s *service) genSrv() *registry.Service { Version: s.opts.Version, Nodes: []*registry.Node{®istry.Node{ Id: s.opts.Id, - Address: addr, - Port: port, + Address: fmt.Sprintf("%s:%d", addr, port), Metadata: s.opts.Metadata, }}, } diff --git a/web/service_test.go b/web/service_test.go index f9d5af8d..588531b8 100644 --- a/web/service_test.go +++ b/web/service_test.go @@ -75,7 +75,7 @@ func TestService(t *testing.T) { t.Fatalf("Expected %d but got %d services", want, have) } - rsp, err := http.Get(fmt.Sprintf("http://%s:%d", s[0].Nodes[0].Address, s[0].Nodes[0].Port)) + rsp, err := http.Get(fmt.Sprintf("http://%s", s[0].Nodes[0].Address)) if err != nil { t.Fatal(err) } @@ -243,7 +243,7 @@ func TestTLS(t *testing.T) { TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, } client := &http.Client{Transport: tr} - rsp, err := client.Get(fmt.Sprintf("https://%s:%d", s[0].Nodes[0].Address, s[0].Nodes[0].Port)) + rsp, err := client.Get(fmt.Sprintf("https://%s", s[0].Nodes[0].Address)) if err != nil { t.Fatal(err) } From 4a02e1ff2fea5925b182988be0104c93f4e59781 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 8 Jul 2019 16:24:57 +0100 Subject: [PATCH 114/287] rewrite network interface --- network/default.go | 226 ++++++++--------- network/default_test.go | 86 +++++++ network/link.go | 243 ++---------------- network/network.go | 58 ++--- network/transport/mucp/listener.go | 44 ---- network/transport/mucp/network.go | 342 -------------------------- network/transport/mucp/socket.go | 80 ------ network/transport/mucp/socket_test.go | 61 ----- 8 files changed, 244 insertions(+), 896 deletions(-) create mode 100644 network/default_test.go delete mode 100644 network/transport/mucp/listener.go delete mode 100644 network/transport/mucp/network.go delete mode 100644 network/transport/mucp/socket.go delete mode 100644 network/transport/mucp/socket_test.go diff --git a/network/default.go b/network/default.go index 29e0bbb2..bc4024f6 100644 --- a/network/default.go +++ b/network/default.go @@ -1,144 +1,136 @@ package network import ( - "crypto/sha256" "fmt" + "io" "sync" - "time" "github.com/google/uuid" "github.com/micro/go-micro/config/options" - "github.com/micro/go-micro/network/proxy" - "github.com/micro/go-micro/network/proxy/mucp" - "github.com/micro/go-micro/network/resolver" - "github.com/micro/go-micro/network/router" - "github.com/micro/go-micro/registry" - - pb "github.com/micro/go-micro/network/proto" - nreg "github.com/micro/go-micro/network/resolver/registry" + "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/util/addr" ) +// default network implementation type network struct { options.Options - // resolver use to connect to the network - resolver resolver.Resolver - - // router used to find routes in the network - router router.Router - - // proxy used to route through the network - proxy proxy.Proxy - - // name of this network + // name of the network name string - // links maintained for this network - // based on peers not nodes. maybe maintain - // node separately or note that links have nodes - mtx sync.RWMutex - links []Link + // transport + transport transport.Transport } -// network methods +type listener struct { + // start accepting once + once sync.Once + // close channel to close the connection + closed chan bool + // the listener + listener transport.Listener + // the connection queue + conns chan Conn +} -// lease generates a new lease with a node id/address -// TODO: use a consensus mechanism, pool or some deterministic -// unique addressing method. -func (n *network) lease(muid string) *pb.Lease { - // create the id - id := uuid.New().String() - // create a timestamp - now := time.Now().UnixNano() - - // create the address by hashing the id and timestamp - h := sha256.New() - h.Write([]byte(fmt.Sprintf("%s-%d\n", id, now))) - // magic new address - address := fmt.Sprintf("%x", h.Sum(nil)) - - // return the node - return &pb.Lease{ - Id: id, - Timestamp: now, - Node: &pb.Node{ - Muid: muid, - Id: id, - Address: address, - Network: n.name, +func (n *network) Create() (*Node, error) { + ip, err := addr.Extract("") + if err != nil { + return nil, err + } + return &Node{ + Id: fmt.Sprintf("%s-%s", n.name, uuid.New().String()), + Address: ip, + Metadata: map[string]string{ + "network": n.Name(), }, - } -} - -// lookup returns a list of network records in priority order of local -func (n *network) lookup(r registry.Registry) []*resolver.Record { - // create a registry resolver to find local nodes - rr := nreg.Resolver{Registry: r} - - // get all the nodes for the network that are local - localRecords, err := rr.Resolve(n.Name()) - if err != nil { - // we're not in a good place here - } - - // if its a local network we never try lookup anything else - if n.Name() == "local" { - return localRecords - } - - // now resolve incrementally based on resolvers specified - networkRecords, err := n.resolver.Resolve(n.Name()) - if err != nil { - // still not in a good place - } - - // return aggregate records - return append(localRecords, networkRecords...) + }, nil } func (n *network) Name() string { return n.name } -// Connect connects to the network and returns a new node. -// The node is the callers connection to the network. They -// should advertise this address to people. Anyone else -// on the network should be able to route to it. -func (n *network) Connect() (Node, error) { - return newNode(n) +func (n *network) Connect(node *Node) (Conn, error) { + c, err := n.transport.Dial(node.Address) + if err != nil { + return nil, err + } + return newLink(c.(transport.Socket)), nil } -// Peer is used to establish a link between two networks. -// e.g micro.mu connects to example.com and share routes -// This is done by creating a new node on both networks -// and creating a link between them. -func (n *network) Peer(Network) (Link, error) { - // New network was created using NewNetwork after receiving routes from a different node - - // Connect to the new network and be assigned a node - - // Transfer data between the networks - - // take other resolver - // order: registry (local), ...resolver - // resolve the network - - // periodically connect to nodes resolved in the network - // and add to the network links - return nil, nil +func (n *network) Listen(node *Node) (Listener, error) { + l, err := n.transport.Listen(node.Address) + if err != nil { + return nil, err + } + return newListener(l), nil +} + +func (l *listener) process() { + if err := l.listener.Accept(l.accept); err != nil { + // close the listener + l.Close() + } +} + +func (l *listener) accept(sock transport.Socket) { + // create a new link and pass it through + link := newLink(sock) + + // send it + l.conns <- link + + // wait for it to be closed + select { + case <-l.closed: + return + case <-link.closed: + return + } +} + +func (l *listener) Address() string { + return l.listener.Addr() +} + +func (l *listener) Close() error { + select { + case <-l.closed: + return nil + default: + close(l.closed) + } + return nil +} + +func (l *listener) Accept() (Conn, error) { + l.once.Do(func() { + // TODO: catch the error + go l.process() + }) + select { + case c := <-l.conns: + return c, nil + case <-l.closed: + return nil, io.EOF + } +} + +func newListener(l transport.Listener) *listener { + return &listener{ + closed: make(chan bool), + conns: make(chan Conn), + listener: l, + } } -// newNetwork returns a new network interface func newNetwork(opts ...options.Option) *network { options := options.NewOptions(opts...) - // new network instance with defaults net := &network{ - Options: options, - name: DefaultName, - router: router.DefaultRouter, - proxy: new(mucp.Proxy), - resolver: new(nreg.Resolver), + name: DefaultName, + transport: transport.DefaultTransport, } // get network name @@ -147,22 +139,10 @@ func newNetwork(opts ...options.Option) *network { net.name = name.(string) } - // get router - r, ok := options.Values().Get("network.router") + // get network transport + t, ok := options.Values().Get("network.transport") if ok { - net.router = r.(router.Router) - } - - // get proxy - p, ok := options.Values().Get("network.proxy") - if ok { - net.proxy = p.(proxy.Proxy) - } - - // get resolver - res, ok := options.Values().Get("network.resolver") - if ok { - net.resolver = res.(resolver.Resolver) + net.transport = t.(transport.Transport) } return net diff --git a/network/default_test.go b/network/default_test.go new file mode 100644 index 00000000..da10fdc8 --- /dev/null +++ b/network/default_test.go @@ -0,0 +1,86 @@ +package network + +import ( + "io" + "testing" +) + +func TestNetwork(t *testing.T) { + // create a new network + n := newNetwork() + + // create a new node + node, err := n.Create() + if err != nil { + t.Fatal(err) + } + + // set ourselves a random port + node.Address = node.Address + ":0" + + l, err := n.Listen(node) + if err != nil { + t.Fatal(err) + } + + wait := make(chan error) + + go func() { + var gerr error + + for { + c, err := l.Accept() + if err != nil { + gerr = err + break + } + m := new(Message) + if err := c.Recv(m); err != nil { + gerr = err + break + } + if err := c.Send(m); err != nil { + gerr = err + break + } + } + + wait <- gerr + }() + + node.Address = l.Address() + + // connect to the node + conn, err := n.Connect(node) + if err != nil { + t.Fatal(err) + } + + // send a message + if err := conn.Send(&Message{ + Header: map[string]string{"Foo": "bar"}, + Body: []byte(`hello world`), + }); err != nil { + t.Fatal(err) + } + + m := new(Message) + // send a message + if err := conn.Recv(m); err != nil { + t.Fatal(err) + } + + if m.Header["Foo"] != "bar" { + t.Fatalf("Received unexpected message %+v", m) + } + + // close the listener + l.Close() + + // get listener error + err = <-wait + + if err != io.EOF { + t.Fatal(err) + } +} diff --git a/network/link.go b/network/link.go index 656abe24..e805e55c 100644 --- a/network/link.go +++ b/network/link.go @@ -5,18 +5,11 @@ import ( "io" "sync" - gproto "github.com/golang/protobuf/proto" "github.com/google/uuid" - "github.com/micro/go-micro/codec" - "github.com/micro/go-micro/codec/proto" - pb "github.com/micro/go-micro/network/proto" "github.com/micro/go-micro/network/transport" ) type link struct { - // the embedded node - *node - closed chan bool sync.RWMutex @@ -29,15 +22,9 @@ type link struct { // the recv queue to the socket recvQueue chan *Message - // codec we use to marshal things - codec codec.Marshaler - // the socket for this link socket transport.Socket - // the lease for this link - lease *pb.Lease - // determines the cost of the link // based on queue length and roundtrip length int @@ -48,17 +35,16 @@ var ( ErrLinkClosed = errors.New("link closed") ) -func newLink(n *node, sock transport.Socket, lease *pb.Lease) *link { - return &link{ +func newLink(sock transport.Socket) *link { + l := &link{ id: uuid.New().String(), - closed: make(chan bool), - codec: &proto.Marshaler{}, - node: n, - lease: lease, socket: sock, + closed: make(chan bool), sendQueue: make(chan *Message, 128), recvQueue: make(chan *Message, 128), } + go l.process() + return l } // link methods @@ -69,13 +55,7 @@ func (l *link) process() { go func() { for { m := new(Message) - if err := l.recv(m, nil); err != nil { - return - } - - // check if it's an internal close method - if m.Header["Micro-Method"] == "close" { - l.Close() + if err := l.recv(m); err != nil { return } @@ -90,7 +70,7 @@ func (l *link) process() { for { select { case m := <-l.sendQueue: - if err := l.send(m, nil); err != nil { + if err := l.send(m); err != nil { return } case <-l.closed: @@ -99,169 +79,17 @@ func (l *link) process() { } } -// accept waits for the connect message from the remote end -// if it receives anything else it throws an error -func (l *link) accept() error { - for { - m := new(transport.Message) - err := l.socket.Recv(m) - if err == io.EOF { - return nil - } - if err != nil { - return err - } - - // TODO: pick a reliable header - event := m.Header["Micro-Method"] - - switch event { - // connect event - case "connect": - // process connect events from network.Connect() - // these are new connections to join the network - - // decode the connection event - conn := new(pb.Connect) - // expecting a connect message - if err := l.codec.Unmarshal(m.Body, conn); err != nil { - // skip error - continue - } - - // no micro id close the link - if len(conn.Muid) == 0 { - l.Close() - return errors.New("invalid muid " + conn.Muid) - } - - // get the existing lease if it exists - lease := conn.Lease - // if there's no lease create a new one - if lease == nil { - // create a new lease/node - lease = l.node.network.lease(conn.Muid) - } - - // check if we connected to ourself - if conn.Muid == l.node.muid { - // check our own leasae - l.node.Lock() - if l.node.lease == nil { - l.node.lease = lease - } - l.node.Unlock() - } - - // set the author to our own muid - lease.Author = l.node.muid - - // send back a lease offer for the node - if err := l.send(&Message{ - Header: map[string]string{ - "Micro-Method": "lease", - }, - }, lease); err != nil { - return err - } - - // the lease is saved - l.Lock() - l.lease = lease - l.Unlock() - - // we've connected - // start processing the messages - go l.process() - return nil - case "close": - l.Close() - return io.EOF - default: - return errors.New("unknown method: " + event) - } - } -} - -// connect sends a connect request and waits on a lease. -// this is for a new connection. in the event we send -// an existing lease, the same lease should be returned. -// if it differs then we assume our address for this link -// is different... -func (l *link) connect() error { - // get the current lease - l.RLock() - lease := l.lease - l.RUnlock() - - // send a lease request - if err := l.send(&Message{ - Header: map[string]string{ - "Micro-Method": "connect", - }, - }, &pb.Connect{Muid: l.node.muid, Lease: lease}); err != nil { - return err - } - - // create the new things - tm := new(Message) - newLease := new(pb.Lease) - - // wait for a response, hopefully a lease - if err := l.recv(tm, newLease); err != nil { - return err - } - - event := tm.Header["Micro-Method"] - - // check the method - switch event { - case "lease": - // save the lease - l.Lock() - l.lease = newLease - l.Unlock() - - // start processing the messages - go l.process() - case "close": - l.Close() - return io.EOF - default: - l.Close() - return errors.New("unable to attain lease") - } - - return nil -} - // send a message over the link -func (l *link) send(m *Message, v interface{}) error { +func (l *link) send(m *Message) error { tm := new(transport.Message) tm.Header = m.Header tm.Body = m.Body - - // set the body if not nil - // we're assuming this is network message - if v != nil { - // encode the data - b, err := l.codec.Marshal(v) - if err != nil { - return err - } - - // set the content type - tm.Header["Content-Type"] = "application/protobuf" - // set the marshalled body - tm.Body = b - } - // send via the transport socket return l.socket.Send(tm) } // recv a message on the link -func (l *link) recv(m *Message, v interface{}) error { +func (l *link) recv(m *Message) error { if m.Header == nil { m.Header = make(map[string]string) } @@ -277,19 +105,7 @@ func (l *link) recv(m *Message, v interface{}) error { m.Header = tm.Header m.Body = tm.Body - // bail early - if v == nil { - return nil - } - - // try unmarshal the body - // skip if there's no content-type - if tm.Header["Content-Type"] != "application/protobuf" { - return nil - } - - // return unmarshalled - return l.codec.Unmarshal(m.Body, v.(gproto.Message)) + return nil } // Close the link @@ -299,35 +115,27 @@ func (l *link) Close() error { return nil default: close(l.closed) + return l.socket.Close() } - - // send a final close message - return l.socket.Send(&transport.Message{ - Header: map[string]string{ - "Micro-Method": "close", - }, - }) } // returns the node id func (l *link) Id() string { l.RLock() defer l.RUnlock() - if l.lease == nil { - return "" - } - return l.lease.Node.Id + return l.id } -// Address of the node we're connected to -func (l *link) Address() string { +func (l *link) Remote() string { l.RLock() defer l.RUnlock() - if l.lease == nil { - return l.socket.Remote() - } - // the node in the lease - return l.lease.Node.Address + return l.socket.Remote() +} + +func (l *link) Local() string { + l.RLock() + defer l.RUnlock() + return l.socket.Local() } func (l *link) Length() int { @@ -341,15 +149,16 @@ func (l *link) Weight() int { } // Accept accepts a message on the socket -func (l *link) Accept() (*Message, error) { +func (l *link) Recv(m *Message) error { select { case <-l.closed: - return nil, io.EOF - case m := <-l.recvQueue: - return m, nil + return io.EOF + case rm := <-l.recvQueue: + *m = *rm + return nil } // never reach - return nil, nil + return nil } // Send sends a message on the socket immediately diff --git a/network/network.go b/network/network.go index f9b32090..12dc6b8c 100644 --- a/network/network.go +++ b/network/network.go @@ -10,46 +10,46 @@ import ( // is responsible for routing messages to the correct services. type Network interface { options.Options + // Create starts the network + Create() (*Node, error) // Name of the network Name() string - // Connect to the network - Connect() (Node, error) - // Peer with a neighboring network - Peer(Network) (Link, error) + // Connect to a node + Connect(*Node) (Conn, error) + // Listen for connections + Listen(*Node) (Listener, error) } -// Node represents a single node on a network -type Node interface { - // Id of the node - Id() string - // Address of the node +type Node struct { + Id string + Address string + Metadata map[string]string +} + +type Listener interface { Address() string - // The network of the node - Network() string - // Close the network connection Close() error - // Accept messages on the network - Accept() (*Message, error) - // Send a message to the network + Accept() (Conn, error) +} + +type Conn interface { + // Unique id of the connection + Id() string + // Close the connection + Close() error + // Send a message Send(*Message) error + // Receive a message + Recv(*Message) error + // The remote node + Remote() string + // The local node + Local() string } -// Link is a connection between one network and another -type Link interface { - // remote node the link is peered with - Node - // length defines the speed or distance of the link - Length() int - // weight defines the saturation or usage of the link - Weight() int -} - -// Message is the base type for opaque data type Message struct { - // Headers which provide local/remote info Header map[string]string - // The opaque data being sent - Body []byte + Body []byte } var ( diff --git a/network/transport/mucp/listener.go b/network/transport/mucp/listener.go deleted file mode 100644 index ceb7aae0..00000000 --- a/network/transport/mucp/listener.go +++ /dev/null @@ -1,44 +0,0 @@ -package mucp - -import ( - "github.com/micro/go-micro/network/transport" -) - -type listener struct { - // stream id - id string - // address of the listener - addr string - // close channel - closed chan bool - // accept socket - accept chan *socket -} - -func (n *listener) Addr() string { - return n.addr -} - -func (n *listener) Close() error { - select { - case <-n.closed: - default: - close(n.closed) - } - return nil -} - -func (n *listener) Accept(fn func(s transport.Socket)) error { - for { - select { - case <-n.closed: - return nil - case s, ok := <-n.accept: - if !ok { - return nil - } - go fn(s) - } - } - return nil -} diff --git a/network/transport/mucp/network.go b/network/transport/mucp/network.go deleted file mode 100644 index ae0046b9..00000000 --- a/network/transport/mucp/network.go +++ /dev/null @@ -1,342 +0,0 @@ -// Package mucp provides a mucp network transport -package mucp - -import ( - "context" - "crypto/sha256" - "errors" - "fmt" - "sync" - - "github.com/micro/go-micro/network" - "github.com/micro/go-micro/network/transport" -) - -type networkKey struct{} - -// Transport is a mucp transport. It should only -// be created with NewTransport and cast to -// *Transport if there's a need to close it. -type Transport struct { - options transport.Options - - // the network interface - network network.Network - - // protect all the things - sync.RWMutex - - // connect - connected bool - // connected node - node network.Node - // the send channel - send chan *message - // close channel - closed chan bool - - // sockets - sockets map[string]*socket - // listeners - listeners map[string]*listener -} - -func (n *Transport) newListener(addr string) *listener { - // hash the id - h := sha256.New() - h.Write([]byte(addr)) - id := fmt.Sprintf("%x", h.Sum(nil)) - - // create the listener - l := &listener{ - id: id, - addr: addr, - closed: make(chan bool), - accept: make(chan *socket, 128), - } - - // save it - n.Lock() - n.listeners[id] = l - n.Unlock() - - return l -} - -func (n *Transport) getListener(id string) (*listener, bool) { - // get the listener - n.RLock() - s, ok := n.listeners[id] - n.RUnlock() - return s, ok -} - -func (n *Transport) getSocket(id string) (*socket, bool) { - // get the socket - n.RLock() - s, ok := n.sockets[id] - n.RUnlock() - return s, ok -} - -func (n *Transport) newSocket(id string) *socket { - // hash the id - h := sha256.New() - h.Write([]byte(id)) - id = fmt.Sprintf("%x", h.Sum(nil)) - - // new socket - s := &socket{ - id: id, - closed: make(chan bool), - recv: make(chan *message, 128), - send: n.send, - } - - // save socket - n.Lock() - n.sockets[id] = s - n.Unlock() - - // return socket - return s -} - -// process outgoing messages -func (n *Transport) process() { - // manage the send buffer - // all pseudo sockets throw everything down this - for { - select { - case msg := <-n.send: - netmsg := &network.Message{ - Header: msg.data.Header, - Body: msg.data.Body, - } - - // set the stream id on the outgoing message - netmsg.Header["Micro-Stream"] = msg.id - - // send the message via the interface - if err := n.node.Send(netmsg); err != nil { - // no op - // TODO: do something - } - case <-n.closed: - return - } - } -} - -// process incoming messages -func (n *Transport) listen() { - for { - // process anything via the net interface - msg, err := n.node.Accept() - if err != nil { - return - } - - // a stream id - id := msg.Header["Micro-Stream"] - - // get the socket - s, exists := n.getSocket(id) - if !exists { - // get the listener - l, ok := n.getListener(id) - // there's no socket and there's no listener - if !ok { - continue - } - - // listener is closed - select { - case <-l.closed: - // delete it - n.Lock() - delete(n.listeners, l.id) - n.Unlock() - continue - default: - } - - // no socket, create one - s = n.newSocket(id) - // set remote address - s.remote = msg.Header["Remote"] - - // drop that to the listener - // TODO: non blocking - l.accept <- s - } - - // is the socket closed? - select { - case <-s.closed: - // closed - delete(n.sockets, id) - continue - default: - // process - } - - tmsg := &transport.Message{ - Header: msg.Header, - Body: msg.Body, - } - - // TODO: don't block on queuing - // append to recv backlog - s.recv <- &message{id: id, data: tmsg} - } -} - -func (n *Transport) Init(opts ...transport.Option) error { - for _, o := range opts { - o(&n.options) - } - return nil -} - -func (n *Transport) Options() transport.Options { - return n.options -} - -// Close the tunnel -func (n *Transport) Close() error { - n.Lock() - defer n.Unlock() - - if !n.connected { - return nil - } - - select { - case <-n.closed: - return nil - default: - // close all the sockets - for _, s := range n.sockets { - s.Close() - } - for _, l := range n.listeners { - l.Close() - } - // close the connection - close(n.closed) - // close node connection - n.node.Close() - // reset connected - n.connected = false - } - - return nil -} - -// Connect the tunnel -func (n *Transport) Connect() error { - n.Lock() - defer n.Unlock() - - // already connected - if n.connected { - return nil - } - - // get a new node - node, err := n.network.Connect() - if err != nil { - return err - } - - // set as connected - n.connected = true - // create new close channel - n.closed = make(chan bool) - // save node - n.node = node - - // process messages to be sent - go n.process() - // process incoming messages - go n.listen() - - return nil -} - -// Dial an address -func (n *Transport) Dial(addr string, opts ...transport.DialOption) (transport.Client, error) { - if err := n.Connect(); err != nil { - return nil, err - } - - // create new socket - s := n.newSocket(addr) - // set remote - s.remote = addr - // set local - n.RLock() - s.local = n.node.Address() - n.RUnlock() - - return s, nil -} - -func (n *Transport) Listen(addr string, opts ...transport.ListenOption) (transport.Listener, error) { - // check existing listeners - n.RLock() - for _, l := range n.listeners { - if l.addr == addr { - n.RUnlock() - return nil, errors.New("already listening on " + addr) - } - } - n.RUnlock() - - // try to connect to the network - if err := n.Connect(); err != nil { - return nil, err - } - - return n.newListener(addr), nil -} - -func (n *Transport) String() string { - return "network" -} - -// NewTransport creates a new network transport -func NewTransport(opts ...transport.Option) transport.Transport { - options := transport.Options{ - Context: context.Background(), - } - - for _, o := range opts { - o(&options) - } - - // get the network interface - n, ok := options.Context.Value(networkKey{}).(network.Network) - if !ok { - n = network.DefaultNetwork - } - - return &Transport{ - options: options, - network: n, - send: make(chan *message, 128), - closed: make(chan bool), - sockets: make(map[string]*socket), - } -} - -// WithNetwork sets the network interface -func WithNetwork(n network.Network) transport.Option { - return func(o *transport.Options) { - if o.Context == nil { - o.Context = context.Background() - } - o.Context = context.WithValue(o.Context, networkKey{}, n) - } -} diff --git a/network/transport/mucp/socket.go b/network/transport/mucp/socket.go deleted file mode 100644 index 862da50a..00000000 --- a/network/transport/mucp/socket.go +++ /dev/null @@ -1,80 +0,0 @@ -package mucp - -import ( - "errors" - - "github.com/micro/go-micro/network/transport" -) - -// socket is our pseudo socket for transport.Socket -type socket struct { - // socket id based on Micro-Stream - id string - // closed - closed chan bool - // remote addr - remote string - // local addr - local string - // send chan - send chan *message - // recv chan - recv chan *message -} - -// message is sent over the send channel -type message struct { - // socket id - id string - // transport data - data *transport.Message -} - -func (s *socket) Remote() string { - return s.remote -} - -func (s *socket) Local() string { - return s.local -} - -func (s *socket) Id() string { - return s.id -} - -func (s *socket) Send(m *transport.Message) error { - select { - case <-s.closed: - return errors.New("socket is closed") - default: - // no op - } - // append to backlog - s.send <- &message{id: s.id, data: m} - return nil -} - -func (s *socket) Recv(m *transport.Message) error { - select { - case <-s.closed: - return errors.New("socket is closed") - default: - // no op - } - // recv from backlog - msg := <-s.recv - // set message - *m = *msg.data - // return nil - return nil -} - -func (s *socket) Close() error { - select { - case <-s.closed: - // no op - default: - close(s.closed) - } - return nil -} diff --git a/network/transport/mucp/socket_test.go b/network/transport/mucp/socket_test.go deleted file mode 100644 index a9dfbd5a..00000000 --- a/network/transport/mucp/socket_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package mucp - -import ( - "testing" - - "github.com/micro/go-micro/network/transport" -) - -func TestTunnelSocket(t *testing.T) { - s := &socket{ - id: "1", - closed: make(chan bool), - remote: "remote", - local: "local", - send: make(chan *message, 1), - recv: make(chan *message, 1), - } - - // check addresses local and remote - if s.Local() != s.local { - t.Fatalf("Expected s.Local %s got %s", s.local, s.Local()) - } - if s.Remote() != s.remote { - t.Fatalf("Expected s.Remote %s got %s", s.remote, s.Remote()) - } - - // send a message - s.Send(&transport.Message{Header: map[string]string{}}) - - // get sent message - msg := <-s.send - - if msg.id != s.id { - t.Fatalf("Expected sent message id %s got %s", s.id, msg.id) - } - - // recv a message - msg.data.Header["Foo"] = "bar" - s.recv <- msg - - m := new(transport.Message) - s.Recv(m) - - // check header - if m.Header["Foo"] != "bar" { - t.Fatalf("Did not receive correct message %+v", m) - } - - // close the connection - s.Close() - - // check connection - err := s.Send(m) - if err == nil { - t.Fatal("Expected closed connection") - } - err = s.Recv(m) - if err == nil { - t.Fatal("Expected closed connection") - } -} From 608a1f8add890f3ddbd82900a7141648a4c64b7b Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 8 Jul 2019 16:25:04 +0100 Subject: [PATCH 115/287] remove node code --- network/node.go | 529 ------------------------------------------------ 1 file changed, 529 deletions(-) delete mode 100644 network/node.go diff --git a/network/node.go b/network/node.go deleted file mode 100644 index 93372c7d..00000000 --- a/network/node.go +++ /dev/null @@ -1,529 +0,0 @@ -package network - -import ( - "errors" - "fmt" - "io" - "net" - "runtime/debug" - "sort" - "strconv" - "sync" - "time" - - "github.com/google/uuid" - "github.com/micro/go-micro/network/transport" - "github.com/micro/go-micro/registry" - "github.com/micro/go-micro/util/addr" - "github.com/micro/go-micro/util/log" - - pb "github.com/micro/go-micro/network/proto" -) - -type node struct { - *network - - // closed channel to close our connection to the network - closed chan bool - - sync.RWMutex - - // the nodes unique micro assigned mac address - muid string - - // the node id registered in registry - id string - - // address of this node registered in registry - address string - - // our network lease with our network id/address - lease *pb.Lease - - // the node registry - registry registry.Registry - - // the base level transport - transport transport.Transport - - // the listener - listener transport.Listener - - // connected records - // record.Address:true - connected map[string]bool - - // leases for connections to us - // link remote node:link - links map[string][]*link - - // messages received over links - recv chan *Message - // messages received over links - send chan *Message -} - -// network methods - -func newNode(n *network) (*node, error) { - // create a new node - node := &node{ - // this nodes unique micro assigned mac address - muid: fmt.Sprintf("%s-%s", n.name, uuid.New().String()), - // map of connected records - connected: make(map[string]bool), - // the links - links: make(map[string][]*link), - // closed channel - closed: make(chan bool), - // set the nodes network - network: n, - // set the default transport - transport: transport.DefaultTransport, - // set the default registry - registry: registry.DefaultRegistry, - // receive channel for accepted connections - recv: make(chan *Message, 128), - // send channel for accepted connections - send: make(chan *Message, 128), - } - - // get the transport we're going to use for our tunnels - // TODO: set to quic or tunnel or something else - t, ok := n.Options.Values().Get("network.transport") - if ok { - node.transport = t.(transport.Transport) - } - - // register the node with the registry for the network - // TODO: use a registrar or something else for local things - r, ok := n.Options.Values().Get("network.registry") - if ok { - node.registry = r.(registry.Registry) - } - - // we listen on a random address, this is not advertised - // TODO: use util/addr to get something anyone in the same private network can talk to - l, err := node.transport.Listen(":0") - if err != nil { - return nil, err - } - // set the listener - node.listener = l - - node.address = l.Addr() - - // TODO: start the router and broadcast advertisements - // receive updates and push them to the network in accept(l) below - // chan, err := n.router.Advertise() - // u <- chan - // socket.send("route", u) - // u := socket.recv() => r.router.Update(u) - - // process any incoming messages on the listener - // this is our inbound network connection - go node.accept(l) - - // process any messages being sent by node.Send - // forwards to every link we have - go node.process() - - var port int - // TODO: this should be an overlay address - // ideally received via some dhcp style broadcast - host, pp, err := net.SplitHostPort(l.Addr()) - if err == nil { - pt, _ := strconv.Atoi(pp) - port = pt - } - - // some horrible things are happening - if host == "::" { - host = "" - } - // set the address - addr, _ := addr.Extract(host) - - // used to register in registry for network resolution - // separate to our lease on the network itself - node.id = uuid.New().String() - node.address = fmt.Sprintf("%s:%d", addr, port) - - // register self with the registry using network: prefix - // this is a local registry of nodes separate to the resolver - // maybe consolidate registry/resolver - // TODO: find a way to do this via gossip or something like - // a registrar or tld or whatever - if err := node.registry.Register(®istry.Service{ - // register with the network id - Name: n.Name(), - Nodes: []*registry.Node{ - {Id: node.id, Address: node.address}, - }, - }); err != nil { - node.Close() - return nil, err - } - - // create a channel to get links - linkChan := make(chan *link, 1) - - // we're going to wait for the first connection - go node.connect(linkChan) - - // wait forever to connect - // TODO: do something with the links we receive - link := <-linkChan - - // process this link - log.Debugf("connect managing link %s", link.id) - go node.manage(link) - - go func() { - for { - // process any further new links - select { - case l := <-linkChan: - log.Debugf("Managing new link %s", l.id) - go node.manage(l) - case <-node.closed: - return - } - } - }() - - return node, nil -} - -// node methods - -// Accept processes the incoming messages on its listener. -// This listener was created with the first call to network.Connect. -// Any inbound new socket here is essentially something else attempting -// to connect to the network. So we turn it into a socket, then process it. -func (n *node) accept(l transport.Listener) error { - return l.Accept(func(sock transport.Socket) { - defer func() { - // close socket - sock.Close() - - if r := recover(); r != nil { - log.Log("panic recovered: ", r) - log.Log(string(debug.Stack())) - } - }() - - // create a new link - link := newLink(n, sock, nil) - - log.Debugf("Accepting connection from %s", link.socket.Remote()) - - // wait for the link to be connected - // the remote end will send "Connect" - // and we will return a "Lease" - if err := link.accept(); err != nil { - log.Debugf("Error accepting connection %v", err) - return - } - - log.Debugf("Accepted link from %s", link.socket.Remote()) - - // save with the muid as the key - // where we attempt to connect to nodes - // we do not connect to the same thing - - // TODO: figure out why this is an issue - // When we receive a connection from ourself - // we can't maintain the two links separately - // so we don't save it. It's basically some - // weird loopback issue because its our own socket. - if n.muid != link.lease.Node.Muid { - n.Lock() - // get the links - - links := n.links[link.lease.Node.Muid] - // append to the current links - links = append(links, link) - // save the links with muid as the key - n.links[link.lease.Node.Muid] = links - n.Unlock() - } - - // manage the link for its lifetime - log.Debugf("managing the link now %s", link.id) - n.manage(link) - }) -} - -// processes the sends the messages from n.Send into the queue of -// each link. If multiple links exist for a muid it should only -// send on link to figure it out. -// If we connected to a record and that link goes down we should -// also remove it from the n.connected map. -func (n *node) process() { - for { - select { - case <-n.closed: - return - // process outbound messages on the send queue - // these messages are received from n.Send - case m := <-n.send: - // queue the message on each link - // TODO: more than likely use proxy - n.RLock() - // range over all the links - for _, links := range n.links { - if len(links) == 0 { - continue - } - - // sort the links by weight - sort.Slice(links, func(i, j int) bool { - return links[i].Weight() < links[j].Weight() - }) - - // queue the message - links[0].Send(m) - } - n.RUnlock() - } - } -} - -// Manage manages the link for its lifetime. It should ideally throw -// away the link in the n.links map if there's any issues or total disconnection -// it should look at link.Status. -// If we connected to a record and that link goes down we should -// also remove it from the n.connected map. -func (n *node) manage(l *link) { - // now process inbound messages on the link - // assumption is this handles everything else - for { - // the send side uses a link queue but the receive side immediately sends it - // ideally we should probably have an internal queue on that side as well - // so we can judge link saturation both ways. - - m, err := l.Accept() - if err == io.EOF { - return - } - if err != nil { - log.Debugf("Error accepting message on link %s: %v", l.id, err) - // ??? - return - } - - // if the node connection is closed bail out - select { - case <-n.closed: - return - // send to the network recv channel e.g node.Accept() - case n.recv <- m: - } - } -} - -// connect attempts to periodically connect to new nodes in the network. -// It will only do this if it has less than 3 connections. this method -// is called by network.Connect and fired in a go routine after establishing -// the first connection and creating a node. The node attempts to maintain -// its connection to the network via multiple links. -func (n *node) connect(linkChan chan *link) { - // TODO: adjustable ticker - t := time.NewTicker(time.Second) - - var lease *pb.Lease - - for { - select { - // exit when told to do so - case <-n.closed: - return - // on every tick check the number of links and then attempt - // to connect to new nodes if we don't have sufficient links - case <-t.C: - n.RLock() - - // only start processing if we have less than 3 links - conns := len(n.links) - if conns > 2 { - n.RUnlock() - continue - } - - // get a list of link addresses so we don't reconnect - // to the ones we're already connected to - connected := n.connected - - // unlock our read lock - n.RUnlock() - - // lookup records for our network - records := n.network.lookup(n.registry) - - // for each record check we haven't already got a connection - // attempt to dial it, create a new socket and call - // connect with our existing network lease. - // if its the first call we don't actually have a lease - - // TODO: determine how to prioritise local records - // while still connecting to the global network - for _, record := range records { - // skip existing connections - if connected[record.Address] { - log.Tracef("Skipping connection to %s", record.Address) - continue - } - - // check how many connections we have - if conns > 2 { - log.Debugf("Made enough connections") - break - } - - // attempt to connect and create a link - - log.Debugf("Dialing connection to %s", record.Address) - - // connect to the node - sock, err := n.transport.Dial(record.Address) - if err != nil { - log.Debugf("Dialing connection error %v", err) - continue - } - - // create a new link with the lease and socket - link := newLink(n, sock, lease) - - log.Debugf("Connecting link to %s", record.Address) - - // connect the link: - // this broadcasts a "connect" request and gets back a "lease" - // this is the tunnel to the outside world and to the network - // then push updates and messages over this link - // first connect will not have a lease so we get one with node id/address - if err := link.connect(); err != nil { - // shit - continue - } - - log.Debugf("Connected link to %s", record.Address) - - n.Lock() - // set lease for next time we connect to anything else - // we want to use the same lease for that. in future - // we may have to expire the lease - lease = link.lease - // save the new link - // get existing links using the lease author - links := n.links[lease.Author] - // append to the links - links = append(links, link) - // save the links using the author - n.links[lease.Author] = links - n.Unlock() - - // update number of connections - conns++ - - // save the connection - n.Lock() - n.connected[record.Address] = true - n.Unlock() - - // drop this down the link channel to the network - // so it can manage the links - linkChan <- link - } - } - } -} - -func (n *node) Address() string { - n.RLock() - defer n.RUnlock() - // we have no address yet - if n.lease == nil { - return "" - } - // return node address in the lease - return n.lease.Node.Address -} - -// Close shutdowns all the links and closes the listener -func (n *node) Close() error { - select { - case <-n.closed: - return nil - default: - // mark as closed, we're now useless and there's no coming back - close(n.closed) - - // shutdown all the links - n.Lock() - for muid, links := range n.links { - for _, link := range links { - link.Close() - } - delete(n.links, muid) - } - // reset connected - n.connected = nil - n.Unlock() - - // deregister self - n.registry.Deregister(®istry.Service{ - Name: n.network.Name(), - Nodes: []*registry.Node{ - {Id: n.id, Address: n.address}, - }, - }) - - // shutdown the listener - return n.listener.Close() - } - return nil -} - -// Accept receives the incoming messages from all links -func (n *node) Accept() (*Message, error) { - // process the inbound cruft - for { - select { - case m, ok := <-n.recv: - if !ok { - return nil, errors.New("connection closed") - } - // return the message - return m, nil - case <-n.closed: - return nil, errors.New("connection closed") - } - } - // we never get here - return nil, nil -} - -func (n *node) Id() string { - n.RLock() - defer n.RUnlock() - if n.lease == nil { - return "" - } - return n.lease.Node.Id -} - -func (n *node) Network() string { - return n.network.Name() -} - -// Send propagates a message over all links. This should probably use its proxy. -func (n *node) Send(m *Message) error { - select { - case <-n.closed: - return errors.New("connection closed") - case n.send <- m: - // send the message - } - return nil -} From fa54db5ba55119146dad6e750534aa631d68cb3a Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 8 Jul 2019 16:27:02 +0100 Subject: [PATCH 116/287] rename network name to go.micro --- network/network.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network/network.go b/network/network.go index 12dc6b8c..a1439948 100644 --- a/network/network.go +++ b/network/network.go @@ -54,7 +54,7 @@ type Message struct { var ( // The default network name is local - DefaultName = "local" + DefaultName = "go.micro" // just the standard network element DefaultNetwork = NewNetwork() From 6bdc23a3aa305e527e79ac59236bf4ae21a74e01 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 8 Jul 2019 16:32:12 +0100 Subject: [PATCH 117/287] add comments --- network/default.go | 1 + network/network.go | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/network/default.go b/network/default.go index bc4024f6..626f9281 100644 --- a/network/default.go +++ b/network/default.go @@ -43,6 +43,7 @@ func (n *network) Create() (*Node, error) { Address: ip, Metadata: map[string]string{ "network": n.Name(), + "transport": n.transport.String(), }, }, nil } diff --git a/network/network.go b/network/network.go index a1439948..3198bf3f 100644 --- a/network/network.go +++ b/network/network.go @@ -10,28 +10,32 @@ import ( // is responsible for routing messages to the correct services. type Network interface { options.Options - // Create starts the network + // Create starts the network and creates a new node Create() (*Node, error) // Name of the network Name() string - // Connect to a node + // Connect to a node on the network Connect(*Node) (Conn, error) - // Listen for connections + // Listen for connections for this node Listen(*Node) (Listener, error) } +// Node is a network node represented with id/address and +// metadata which includes the network name, transport, etc type Node struct { Id string Address string Metadata map[string]string } +// A network node listener which can be used to receive messages type Listener interface { Address() string Close() error Accept() (Conn, error) } +// A connection from another node on the network type Conn interface { // Unique id of the connection Id() string @@ -47,6 +51,7 @@ type Conn interface { Local() string } +// The message type sent over the network type Message struct { Header map[string]string Body []byte From ea872f6900b957bb815b0bcf9d78ecce714a68d6 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Wed, 3 Jul 2019 19:50:07 +0100 Subject: [PATCH 118/287] Updated error statements; Update ships list of events. --- network/router/default_router.go | 62 ++++++++++++++++++++++---------- network/router/default_table.go | 1 + network/router/router.go | 46 +++++++++++++++++------- network/router/table_watcher.go | 15 ++++---- 4 files changed, 86 insertions(+), 38 deletions(-) diff --git a/network/router/default_router.go b/network/router/default_router.go index 9a7b933e..340c63f5 100644 --- a/network/router/default_router.go +++ b/network/router/default_router.go @@ -2,6 +2,7 @@ package router import ( "fmt" + "sort" "strings" "sync" "time" @@ -10,6 +11,15 @@ import ( "github.com/olekukonko/tablewriter" ) +const ( + // UpdateRoutePenalty penalises route updates + UpdateRoutePenalty = 500 + // DeleteRoutePenalty penalises route deletes + DeleteRoutePenalty = 1000 + // AdvertiseTick is time interval in which we advertise route updates + AdvertiseTick = 5 * time.Second +) + // router provides default router implementation type router struct { opts Options @@ -79,7 +89,7 @@ func (r *router) Network() string { func (r *router) addServiceRoutes(reg registry.Registry, network string, metric int) error { services, err := reg.ListServices() if err != nil { - return fmt.Errorf("failed to list services: %v", err) + return fmt.Errorf("failed listing services: %v", err) } // add each service node as a separate route @@ -148,12 +158,12 @@ func (r *router) manageServiceRoutes(w registry.Watcher, metric int) error { case "create": // only return error if the route is not duplicate, but something else has failed if err := r.opts.Table.Add(route); err != nil && err != ErrDuplicateRoute { - return fmt.Errorf("failed to add route for service %v: %s", res.Service.Name, err) + return fmt.Errorf("failed adding route for service %v: %s", res.Service.Name, err) } case "delete": // only return error if the route is not in the table, but something else has failed if err := r.opts.Table.Delete(route); err != nil && err != ErrRouteNotFound { - return fmt.Errorf("failed to delete route for service %v: %s", res.Service.Name, err) + return fmt.Errorf("failed adding route for service %v: %s", res.Service.Name, err) } } } @@ -175,7 +185,6 @@ func (r *router) watchTable(w Watcher) error { var watchErr error -exit: for { event, err := w.Next() if err != nil { @@ -188,12 +197,13 @@ exit: u := &Update{ ID: r.ID(), Timestamp: time.Now(), - Event: event, + Events: []*Event{event}, } select { case <-r.exit: - break exit + close(r.advertChan) + return watchErr case r.advertChan <- u: } } @@ -258,7 +268,7 @@ func (r *router) Advertise() (<-chan *Update, error) { Metric: DefaultLocalMetric, } if err := r.opts.Table.Add(route); err != nil { - return nil, fmt.Errorf("error to add default gateway route: %s", err) + return nil, fmt.Errorf("failed adding default gateway route: %s", err) } } @@ -271,12 +281,12 @@ func (r *router) Advertise() (<-chan *Update, error) { // routing table watcher which watches all routes i.e. to every destination tableWatcher, err := r.opts.Table.Watch(WatchDestination("*")) if err != nil { - return nil, fmt.Errorf("failed to create routing table watcher: %v", err) + return nil, fmt.Errorf("failed creating routing table watcher: %v", err) } // registry watcher regWatcher, err := r.opts.Registry.Watch() if err != nil { - return nil, fmt.Errorf("failed to create registry watcher: %v", err) + return nil, fmt.Errorf("failed creating registry watcher: %v", err) } // error channel collecting goroutine errors @@ -311,18 +321,32 @@ func (r *router) Advertise() (<-chan *Update, error) { } // Update updates the routing table using the advertised values -func (r *router) Update(a *Update) error { - // we extract the route from advertisement and update the routing table - route := Route{ - Destination: a.Event.Route.Destination, - Gateway: a.Event.Route.Gateway, - Router: a.Event.Route.Router, - Network: a.Event.Route.Network, - Metric: a.Event.Route.Metric, - Policy: AddIfNotExists, +func (r *router) Update(u *Update) error { + // NOTE: event sorting might not be necessary + // copy update events intp new slices + events := make([]*Event, len(u.Events)) + copy(events, u.Events) + // sort events by timestamp + sort.Slice(events, func(i, j int) bool { + return events[i].Timestamp.Before(events[j].Timestamp) + }) + + for _, event := range events { + // we extract the route from advertisement and update the routing table + route := Route{ + Destination: event.Route.Destination, + Gateway: event.Route.Gateway, + Router: event.Route.Router, + Network: event.Route.Network, + Metric: event.Route.Metric, + Policy: AddIfNotExists, + } + if err := r.opts.Table.Update(route); err != nil { + return fmt.Errorf("failed updating routing table: %v", err) + } } - return r.opts.Table.Update(route) + return nil } // Status returns router status diff --git a/network/router/default_table.go b/network/router/default_table.go index 3297c028..bf4e9646 100644 --- a/network/router/default_table.go +++ b/network/router/default_table.go @@ -138,6 +138,7 @@ func (t *table) Update(r Route) error { return ErrRouteNotFound } + // check if destination has this particular router in the table if _, ok := t.m[destAddr][sum]; !ok && r.Policy == AddIfNotExists { t.m[destAddr][sum] = r go t.sendEvent(&Event{Type: CreateEvent, Route: r}) diff --git a/network/router/router.go b/network/router/router.go index e45c0baa..e5ff9a18 100644 --- a/network/router/router.go +++ b/network/router/router.go @@ -34,14 +34,39 @@ type Router interface { String() string } +// Option used by the router +type Option func(*Options) + +// UpdateType is route advertisement update type +type UpdateType int + +const ( + // Announce is advertised when the router announces itself + Announce UpdateType = iota + // RouteEvent advertises route events + RouteEvent +) + +// String returns string representation of update event +func (ut UpdateType) String() string { + switch ut { + case Announce: + return "ANNOUNCE" + case RouteEvent: + return "ROUTE" + default: + return "UNKNOWN" + } +} + // Update is sent by the router to the network type Update struct { // ID is the router ID ID string - // Timestamp marks the time when update is sent + // Timestamp marks the time when the update is sent Timestamp time.Time - // Event defines advertisement even - Event *Event + // Events is a list of events to advertise + Events []*Event } // StatusCode defines router status @@ -58,12 +83,12 @@ type Status struct { const ( // Init means the rotuer has just been initialized Init StatusCode = iota - // Running means the router is running + // Running means the router is up and running Running - // Error means the router has crashed with error - Error - // Stopped means the router has stopped + // Stopped means the router has been stopped Stopped + // Error means the router has encountered error + Error ) // String returns human readable status code @@ -73,18 +98,15 @@ func (sc StatusCode) String() string { return "INITIALIZED" case Running: return "RUNNING" - case Error: - return "ERROR" case Stopped: return "STOPPED" + case Error: + return "ERROR" default: return "UNKNOWN" } } -// Option used by the router -type Option func(*Options) - // NewRouter creates new Router and returns it func NewRouter(opts ...Option) Router { return newRouter(opts...) diff --git a/network/router/table_watcher.go b/network/router/table_watcher.go index 91411247..976fa8af 100644 --- a/network/router/table_watcher.go +++ b/network/router/table_watcher.go @@ -3,6 +3,7 @@ package router import ( "errors" "strings" + "time" "github.com/olekukonko/tablewriter" ) @@ -16,11 +17,11 @@ var ( type EventType int const ( - // CreateEvent is emitted when new route has been created + // CreateEvent is emitted when a new route has been created CreateEvent EventType = iota // DeleteEvent is emitted when an existing route has been deleted DeleteEvent - // UpdateEvent is emitted when a routing table has been updated + // UpdateEvent is emitted when an existing route has been updated UpdateEvent ) @@ -42,6 +43,8 @@ func (et EventType) String() string { type Event struct { // Type defines type of event Type EventType + // Timestamp is event timestamp + Timestamp time.Time // Route is table rout Route Route } @@ -81,18 +84,16 @@ type tableWatcher struct { } // Next returns the next noticed action taken on table -// TODO: this needs to be thought through properly; we only allow watching particular route destination for now +// TODO: this needs to be thought through properly; +// right now we only allow to watch destination func (w *tableWatcher) Next() (*Event, error) { for { select { case res := <-w.resChan: switch w.opts.Destination { - case "*", "": + case res.Route.Destination, "*": return res, nil default: - if w.opts.Destination == res.Route.Destination { - return res, nil - } continue } case <-w.done: From d6c07dfb166e7b1801bd8104bd4ecb215b1c3e10 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Thu, 4 Jul 2019 02:06:59 +0100 Subject: [PATCH 119/287] Update is now Advert --- network/router/default_router.go | 16 ++++++++-------- network/router/router.go | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/network/router/default_router.go b/network/router/default_router.go index 340c63f5..e1c97ccf 100644 --- a/network/router/default_router.go +++ b/network/router/default_router.go @@ -24,7 +24,7 @@ const ( type router struct { opts Options status Status - advertChan chan *Update + advertChan chan *Advert exit chan struct{} wg *sync.WaitGroup sync.RWMutex @@ -43,7 +43,7 @@ func newRouter(opts ...Option) Router { return &router{ opts: options, status: Status{Error: nil, Code: Init}, - advertChan: make(chan *Update), + advertChan: make(chan *Advert), exit: make(chan struct{}), wg: &sync.WaitGroup{}, } @@ -194,7 +194,7 @@ func (r *router) watchTable(w Watcher) error { break } - u := &Update{ + u := &Advert{ ID: r.ID(), Timestamp: time.Now(), Events: []*Event{event}, @@ -248,7 +248,7 @@ func (r *router) watchError(errChan <-chan error) { // Advertise advertises the routes to the network. // It returns error if any of the launched goroutines fail with error. -func (r *router) Advertise() (<-chan *Update, error) { +func (r *router) Advertise() (<-chan *Advert, error) { r.Lock() defer r.Unlock() @@ -275,7 +275,7 @@ func (r *router) Advertise() (<-chan *Update, error) { // NOTE: we only need to recreate the exit/advertChan if the router errored or was stopped if r.status.Code == Error || r.status.Code == Stopped { r.exit = make(chan struct{}) - r.advertChan = make(chan *Update) + r.advertChan = make(chan *Advert) } // routing table watcher which watches all routes i.e. to every destination @@ -321,11 +321,11 @@ func (r *router) Advertise() (<-chan *Update, error) { } // Update updates the routing table using the advertised values -func (r *router) Update(u *Update) error { +func (r *router) Update(a *Advert) error { // NOTE: event sorting might not be necessary // copy update events intp new slices - events := make([]*Event, len(u.Events)) - copy(events, u.Events) + events := make([]*Event, len(a.Events)) + copy(events, a.Events) // sort events by timestamp sort.Slice(events, func(i, j int) bool { return events[i].Timestamp.Before(events[j].Timestamp) diff --git a/network/router/router.go b/network/router/router.go index e5ff9a18..20c05fa0 100644 --- a/network/router/router.go +++ b/network/router/router.go @@ -23,9 +23,9 @@ type Router interface { // Network returns the network address of the router Network() string // Advertise starts advertising routes to the network - Advertise() (<-chan *Update, error) + Advertise() (<-chan *Advert, error) // Update updates the routing table - Update(*Update) error + Update(*Advert) error // Status returns router status Status() Status // Stop stops the router @@ -43,8 +43,8 @@ type UpdateType int const ( // Announce is advertised when the router announces itself Announce UpdateType = iota - // RouteEvent advertises route events - RouteEvent + // Update advertises route updates + Update ) // String returns string representation of update event @@ -52,15 +52,15 @@ func (ut UpdateType) String() string { switch ut { case Announce: return "ANNOUNCE" - case RouteEvent: - return "ROUTE" + case Update: + return "UPDATE" default: return "UNKNOWN" } } -// Update is sent by the router to the network -type Update struct { +// Advert is sent by the router to the network +type Advert struct { // ID is the router ID ID string // Timestamp marks the time when the update is sent From 72ef0321626606d53291a6190004bcb263d96d55 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Fri, 5 Jul 2019 19:15:32 +0100 Subject: [PATCH 120/287] First shot at flapping detection and event advertising. This commit also adds Route hash function, lots of debug messages for now and String() methods for various API objects. --- network/router/default_router.go | 241 +++++++++++++++++++++++++++---- network/router/default_table.go | 6 + network/router/route.go | 12 +- network/router/table_watcher.go | 10 +- 4 files changed, 239 insertions(+), 30 deletions(-) diff --git a/network/router/default_router.go b/network/router/default_router.go index e1c97ccf..7ad1197c 100644 --- a/network/router/default_router.go +++ b/network/router/default_router.go @@ -2,11 +2,13 @@ package router import ( "fmt" + "math" "sort" "strings" "sync" "time" + "github.com/micro/go-log" "github.com/micro/go-micro/registry" "github.com/olekukonko/tablewriter" ) @@ -18,14 +20,21 @@ const ( DeleteRoutePenalty = 1000 // AdvertiseTick is time interval in which we advertise route updates AdvertiseTick = 5 * time.Second + // AdvertSuppress is advert suppression threshold + AdvertSuppress = 2000 + // AdvertRecover is advert suppression recovery threshold + AdvertRecover = 750 + // PenaltyDecay is the "half-life" of the penalty + PenaltyDecay = 1.15 ) // router provides default router implementation type router struct { opts Options status Status - advertChan chan *Advert exit chan struct{} + eventChan chan *Event + advertChan chan *Advert wg *sync.WaitGroup sync.RWMutex } @@ -43,8 +52,9 @@ func newRouter(opts ...Option) Router { return &router{ opts: options, status: Status{Error: nil, Code: Init}, - advertChan: make(chan *Advert), exit: make(chan struct{}), + eventChan: make(chan *Event), + advertChan: make(chan *Advert), wg: &sync.WaitGroup{}, } } @@ -83,9 +93,9 @@ func (r *router) Network() string { } // addServiceRoutes adds all services in given registry to the routing table. -// NOTE: this is a one-off operation done when bootstrapping the routing table +// NOTE: this is a one-off operation done when bootstrapping the router // It returns error if either the services failed to be listed or -// if any of the the routes could not be added to the routing table. +// if any of the the routes failed to be added to the routing table. func (r *router) addServiceRoutes(reg registry.Registry, network string, metric int) error { services, err := reg.ListServices() if err != nil { @@ -124,9 +134,9 @@ func (r *router) addServiceRoutes(reg registry.Registry, network string, metric return nil } -// manageServiceRoutes watches services in given registry and updates the routing table accordingly. -// It returns error if the service registry watcher has stopped or if the routing table failed to be updated. -func (r *router) manageServiceRoutes(w registry.Watcher, metric int) error { +// watchServices watches services in given registry and updates the routing table accordingly. +// It returns error if the service registry watcher stops or if the routing table can't be updated. +func (r *router) watchServices(w registry.Watcher) error { // wait in the background for the router to stop // when the router stops, stop the watcher and exit r.wg.Add(1) @@ -151,7 +161,7 @@ func (r *router) manageServiceRoutes(w registry.Watcher, metric int) error { Destination: res.Service.Name, Router: r.opts.Address, Network: r.opts.Network, - Metric: metric, + Metric: DefaultLocalMetric, } switch res.Action { @@ -193,31 +203,173 @@ func (r *router) watchTable(w Watcher) error { } break } - - u := &Advert{ - ID: r.ID(), - Timestamp: time.Now(), - Events: []*Event{event}, - } - select { case <-r.exit: - close(r.advertChan) - return watchErr - case r.advertChan <- u: + close(r.eventChan) + return nil + case r.eventChan <- event: } } - // close the advertisement channel - close(r.advertChan) + // close event channel on error + close(r.eventChan) return watchErr } -// watchError watches router errors -func (r *router) watchError(errChan <-chan error) { +func eventFlap(curr, prev *Event) bool { + if curr.Type == UpdateEvent && prev.Type == UpdateEvent { + // update flap: this can be either metric or whatnot + log.Logf("eventFlap(): Update flap") + return true + } + + if curr.Type == CreateEvent && prev.Type == DeleteEvent || curr.Type == DeleteEvent && prev.Type == CreateEvent { + log.Logf("eventFlap(): Create/Delete flap") + return true + } + + return false +} + +// processEvents processes routing table events. +// It suppresses unhealthy flapping events and advertises healthy events upstream. +func (r *router) processEvents() error { + // ticker to periodically scan event for advertising + ticker := time.NewTicker(AdvertiseTick) + + // TODO: Need to flag already advertised events otherwise we'll keep on advertising them + // as they keep getting advertised unless deleted and are only deleted when received by upstream + + // advertEvent is a table event enriched with advert data + type advertEvent struct { + *Event + timestamp time.Time + penalty float64 + isSuppressed bool + isFlapping bool + } + + // eventMap is a map of advert events that might end up being advertised + eventMap := make(map[uint64]*advertEvent) + // lock to protect access to eventMap + mu := &sync.RWMutex{} + // waitgroup to manage advertisement goroutines + var wg sync.WaitGroup + +process: + for { + select { + case <-ticker.C: + var events []*Event + // decay the penalties of existing events + mu.RLock() + for _, event := range eventMap { + delta := time.Since(event.timestamp).Seconds() + event.penalty = event.penalty * math.Exp(delta) + // suppress or recover the event based on its current penalty + if !event.isSuppressed && event.penalty > AdvertSuppress { + event.isSuppressed = true + } else if event.penalty < AdvertRecover { + event.isSuppressed = false + event.isFlapping = false + } + if !event.isFlapping { + e := new(Event) + *e = *event.Event + events = append(events, e) + } + } + mu.RUnlock() + + if len(events) > 0 { + wg.Add(1) + go func(events []*Event) { + defer wg.Done() + + log.Logf("go advertise(): start") + + a := &Advert{ + ID: r.ID(), + Timestamp: time.Now(), + Events: events, + } + + select { + case r.advertChan <- a: + mu.Lock() + // once we've advertised the events, we need to delete them + for _, event := range a.Events { + delete(eventMap, event.Route.Hash()) + } + mu.Unlock() + case <-r.exit: + log.Logf("go advertise(): exit") + return + } + log.Logf("go advertise(): exit") + }(events) + } + case e := <-r.eventChan: + // if event is nil, break + if e == nil { + continue + } + log.Logf("r.processEvents(): event received:\n%s", e) + // determine the event penalty + var penalty float64 + switch e.Type { + case UpdateEvent: + penalty = UpdateRoutePenalty + case CreateEvent, DeleteEvent: + penalty = DeleteRoutePenalty + } + // we use route hash as eventMap key + hash := e.Route.Hash() + event, ok := eventMap[hash] + if !ok { + event = &advertEvent{ + Event: e, + penalty: penalty, + timestamp: time.Now(), + } + eventMap[hash] = event + continue + } + // update penalty for existing event: decay existing and add new penalty + delta := time.Since(event.timestamp).Seconds() + event.penalty = event.penalty*math.Exp(delta) + penalty + event.timestamp = time.Now() + // suppress or recover the event based on its current penalty + if !event.isSuppressed && event.penalty > AdvertSuppress { + event.isSuppressed = true + } else if event.penalty < AdvertRecover { + event.isSuppressed = false + } + // if not suppressed decide if if its flapping + if !event.isSuppressed { + // detect if its flapping + event.isFlapping = eventFlap(e, event.Event) + } + case <-r.exit: + break process + } + } + + wg.Wait() + close(r.advertChan) + + log.Logf("r.processEvents(): event processor stopped") + + return nil +} + +// manage watches router errors and takes appropriate actions +func (r *router) manage(errChan <-chan error) { defer r.wg.Done() + log.Logf("r.manage(): manage start") + var code StatusCode var err error @@ -228,6 +380,8 @@ func (r *router) watchError(errChan <-chan error) { code = Error } + log.Logf("r.manage(): manage exiting") + r.Lock() defer r.Unlock() status := Status{ @@ -236,6 +390,8 @@ func (r *router) watchError(errChan <-chan error) { } r.status = status + log.Logf("r.manage(): router status: %v", r.status) + // stop the router if some error happened if err != nil && code != Stopped { // this will stop watchers which will close r.advertChan @@ -243,7 +399,12 @@ func (r *router) watchError(errChan <-chan error) { // drain the advertise channel for range r.advertChan { } + // drain the event channel + for range r.eventChan { + } } + + log.Logf("r.manage(): manage exit") } // Advertise advertises the routes to the network. @@ -257,6 +418,7 @@ func (r *router) Advertise() (<-chan *Advert, error) { if err := r.addServiceRoutes(r.opts.Registry, "local", DefaultLocalMetric); err != nil { return nil, fmt.Errorf("failed adding routes: %v", err) } + log.Logf("Routing table:\n%s", r.opts.Table) // add default gateway into routing table if r.opts.Gateway != "" { // note, the only non-default value is the gateway @@ -273,8 +435,10 @@ func (r *router) Advertise() (<-chan *Advert, error) { } // NOTE: we only need to recreate the exit/advertChan if the router errored or was stopped + // TODO: these channels most likely won't have to be the struct fields if r.status.Code == Error || r.status.Code == Stopped { r.exit = make(chan struct{}) + r.eventChan = make(chan *Event) r.advertChan = make(chan *Advert) } @@ -283,31 +447,44 @@ func (r *router) Advertise() (<-chan *Advert, error) { if err != nil { return nil, fmt.Errorf("failed creating routing table watcher: %v", err) } - // registry watcher - regWatcher, err := r.opts.Registry.Watch() + // service registry watcher + svcWatcher, err := r.opts.Registry.Watch() if err != nil { - return nil, fmt.Errorf("failed creating registry watcher: %v", err) + return nil, fmt.Errorf("failed creating service registry watcher: %v", err) } // error channel collecting goroutine errors - errChan := make(chan error, 2) + errChan := make(chan error, 3) r.wg.Add(1) go func() { defer r.wg.Done() + log.Logf("r.Advertise(): r.watchServices() start") // watch local registry and register routes in routine table - errChan <- r.manageServiceRoutes(regWatcher, DefaultLocalMetric) + errChan <- r.watchServices(svcWatcher) + log.Logf("r.Advertise(): r.watchServices() exit") }() r.wg.Add(1) go func() { defer r.wg.Done() + log.Logf("r.Advertise(): r.watchTable() start") // watch local registry and register routes in routing table errChan <- r.watchTable(tableWatcher) + log.Logf("r.Advertise(): r.watchTable() exit") }() r.wg.Add(1) - go r.watchError(errChan) + go func() { + defer r.wg.Done() + log.Logf("r.Advertise(): r.processEvents() start") + // listen to routing table events and process them + errChan <- r.processEvents() + log.Logf("r.Advertise(): r.processEvents() exit") + }() + + r.wg.Add(1) + go r.manage(errChan) // mark router as running and set its Error to nil status := Status{ @@ -362,20 +539,28 @@ func (r *router) Status() Status { // Stop stops the router func (r *router) Stop() error { + log.Logf("r.Stop(): Stopping router") r.RLock() // only close the channel if the router is running if r.status.Code == Running { // notify all goroutines to finish close(r.exit) + log.Logf("r.Stop(): exit closed") // drain the advertise channel for range r.advertChan { } + log.Logf("r.Stop(): advert channel drained") + // drain the event channel + for range r.eventChan { + } + log.Logf("r.Stop(): event channel drained") } r.RUnlock() // wait for all goroutines to finish r.wg.Wait() + log.Logf("r.Stop(): Router stopped") return nil } diff --git a/network/router/default_table.go b/network/router/default_table.go index bf4e9646..28659cbd 100644 --- a/network/router/default_table.go +++ b/network/router/default_table.go @@ -8,6 +8,7 @@ import ( "sync" "github.com/google/uuid" + "github.com/micro/go-log" "github.com/olekukonko/tablewriter" ) @@ -19,6 +20,7 @@ type TableOptions struct{} type table struct { // opts are table options opts TableOptions + // TODO: we should stop key-ing on destination // m stores routing table map m map[string]map[uint64]Route // h hashes route entries @@ -242,12 +244,16 @@ func (t *table) sendEvent(r *Event) { t.RLock() defer t.RUnlock() + log.Logf("sending event to %d registered table watchers", len(t.w)) + for _, w := range t.w { select { case w.resChan <- r: case <-w.done: } } + + log.Logf("sending event done") } // Size returns the size of the routing table diff --git a/network/router/route.go b/network/router/route.go index 7ee3559c..5e3cd8e5 100644 --- a/network/router/route.go +++ b/network/router/route.go @@ -2,6 +2,7 @@ package router import ( "fmt" + "hash/fnv" "strings" "github.com/olekukonko/tablewriter" @@ -56,8 +57,17 @@ type Route struct { Policy RoutePolicy } +// Hash returns route hash sum. +func (r *Route) Hash() uint64 { + h := fnv.New64() + h.Reset() + h.Write([]byte(r.Destination + r.Gateway + r.Network)) + + return h.Sum64() +} + // String allows to print the route -func (r *Route) String() string { +func (r Route) String() string { // this will help us build routing table string sb := &strings.Builder{} diff --git a/network/router/table_watcher.go b/network/router/table_watcher.go index 976fa8af..2c5d8989 100644 --- a/network/router/table_watcher.go +++ b/network/router/table_watcher.go @@ -2,9 +2,11 @@ package router import ( "errors" + "fmt" "strings" "time" + "github.com/micro/go-log" "github.com/olekukonko/tablewriter" ) @@ -45,10 +47,15 @@ type Event struct { Type EventType // Timestamp is event timestamp Timestamp time.Time - // Route is table rout + // Route is table route Route Route } +// String prints human readable Event +func (e Event) String() string { + return fmt.Sprintf("[EVENT] Type: %s\nRoute:\n%s", e.Type, e.Route) +} + // WatchOption is used to define what routes to watch in the table type WatchOption func(*WatchOptions) @@ -94,6 +101,7 @@ func (w *tableWatcher) Next() (*Event, error) { case res.Route.Destination, "*": return res, nil default: + log.Logf("no table watcher available to receive the event") continue } case <-w.done: From b68f0e237f39fa9f810e331bbf19f57020d81fdf Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Sat, 6 Jul 2019 00:36:15 +0100 Subject: [PATCH 121/287] Removed event from eventMap once sent to be advertised --- network/router/default_router.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/network/router/default_router.go b/network/router/default_router.go index 7ad1197c..e5dff063 100644 --- a/network/router/default_router.go +++ b/network/router/default_router.go @@ -107,6 +107,7 @@ func (r *router) addServiceRoutes(reg registry.Registry, network string, metric // get the service to retrieve all its info srvs, err := reg.GetService(service.Name) if err != nil { + log.Logf("r.addServiceRoutes() GetService() error: %v", err) continue } @@ -157,6 +158,8 @@ func (r *router) watchServices(w registry.Watcher) error { break } + log.Logf("r.watchServices() new service event: %s", res.Service.Name) + route := Route{ Destination: res.Service.Name, Router: r.opts.Address, @@ -238,9 +241,6 @@ func (r *router) processEvents() error { // ticker to periodically scan event for advertising ticker := time.NewTicker(AdvertiseTick) - // TODO: Need to flag already advertised events otherwise we'll keep on advertising them - // as they keep getting advertised unless deleted and are only deleted when received by upstream - // advertEvent is a table event enriched with advert data type advertEvent struct { *Event @@ -263,8 +263,8 @@ process: case <-ticker.C: var events []*Event // decay the penalties of existing events - mu.RLock() - for _, event := range eventMap { + mu.Lock() + for advert, event := range eventMap { delta := time.Since(event.timestamp).Seconds() event.penalty = event.penalty * math.Exp(delta) // suppress or recover the event based on its current penalty @@ -278,9 +278,11 @@ process: e := new(Event) *e = *event.Event events = append(events, e) + // this deletes the advertised event from the map + delete(eventMap, advert) } } - mu.RUnlock() + mu.Unlock() if len(events) > 0 { wg.Add(1) @@ -356,7 +358,9 @@ process: } } + // first wait for the advertiser to finish wg.Wait() + // close the advert channel close(r.advertChan) log.Logf("r.processEvents(): event processor stopped") @@ -390,8 +394,6 @@ func (r *router) manage(errChan <-chan error) { } r.status = status - log.Logf("r.manage(): router status: %v", r.status) - // stop the router if some error happened if err != nil && code != Stopped { // this will stop watchers which will close r.advertChan From 30d05e34a94efcc1f183184c001fc6fec08116a0 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Sat, 6 Jul 2019 01:31:59 +0100 Subject: [PATCH 122/287] Read and remove routes based on registry event deltas --- network/router/default_router.go | 43 +++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/network/router/default_router.go b/network/router/default_router.go index e5dff063..872dfc93 100644 --- a/network/router/default_router.go +++ b/network/router/default_router.go @@ -158,25 +158,40 @@ func (r *router) watchServices(w registry.Watcher) error { break } - log.Logf("r.watchServices() new service event: %s", res.Service.Name) - - route := Route{ - Destination: res.Service.Name, - Router: r.opts.Address, - Network: r.opts.Network, - Metric: DefaultLocalMetric, - } + log.Logf("r.watchServices() new service event: Action: %s Service: %v", res.Action, res.Service) switch res.Action { case "create": - // only return error if the route is not duplicate, but something else has failed - if err := r.opts.Table.Add(route); err != nil && err != ErrDuplicateRoute { - return fmt.Errorf("failed adding route for service %v: %s", res.Service.Name, err) + // range over the flat slice of nodes + for _, node := range res.Service.Nodes { + gateway := node.Address + if node.Port > 0 { + gateway = fmt.Sprintf("%s:%d", node.Address, node.Port) + } + route := Route{ + Destination: res.Service.Name, + Gateway: gateway, + Router: r.opts.Address, + Network: r.opts.Network, + Metric: DefaultLocalMetric, + } + if err := r.opts.Table.Add(route); err != nil && err != ErrDuplicateRoute { + return fmt.Errorf("error adding route for service %s: %s", res.Service.Name, err) + } } case "delete": - // only return error if the route is not in the table, but something else has failed - if err := r.opts.Table.Delete(route); err != nil && err != ErrRouteNotFound { - return fmt.Errorf("failed adding route for service %v: %s", res.Service.Name, err) + for _, node := range res.Service.Nodes { + route := Route{ + Destination: res.Service.Name, + Gateway: node.Address, + Router: r.opts.Address, + Network: r.opts.Network, + Metric: DefaultLocalMetric, + } + // only return error if the route is not in the table, but something else has failed + if err := r.opts.Table.Delete(route); err != nil && err != ErrRouteNotFound { + return fmt.Errorf("failed adding route for service %v: %s", res.Service.Name, err) + } } } } From 0c1a28a9b615f4ce0ca780865d2322a636295f43 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Mon, 8 Jul 2019 16:16:50 +0100 Subject: [PATCH 123/287] Router routing table management. Table route hashes. Status codes changed. We now manage routing table actions using dedicated functions run on either registry or services in the registry. Routing table now uses Route.Hash() instead of maintaining its own hash struct filed which previously performed these operations. Various names of variables have been changed to make them more concise. --- network/router/default_router.go | 105 +++++++++++---------------- network/router/default_table.go | 54 +++++--------- network/router/default_table_test.go | 23 +++--- network/router/options.go | 2 +- network/router/route.go | 36 ++++----- network/router/router.go | 12 +-- 6 files changed, 96 insertions(+), 136 deletions(-) diff --git a/network/router/default_router.go b/network/router/default_router.go index 872dfc93..a9517f9d 100644 --- a/network/router/default_router.go +++ b/network/router/default_router.go @@ -39,7 +39,7 @@ type router struct { sync.RWMutex } -// newRouter creates new router and returns it +// newRouter creates a new router and returns it func newRouter(opts ...Option) Router { // get default options options := DefaultOptions() @@ -51,7 +51,7 @@ func newRouter(opts ...Option) Router { return &router{ opts: options, - status: Status{Error: nil, Code: Init}, + status: Status{Error: nil, Code: Stopped}, exit: make(chan struct{}), eventChan: make(chan *Event), advertChan: make(chan *Advert), @@ -92,11 +92,39 @@ func (r *router) Network() string { return r.opts.Network } -// addServiceRoutes adds all services in given registry to the routing table. -// NOTE: this is a one-off operation done when bootstrapping the router -// It returns error if either the services failed to be listed or -// if any of the the routes failed to be added to the routing table. -func (r *router) addServiceRoutes(reg registry.Registry, network string, metric int) error { +// manageServiceRoutes manages the routes for a given service. +// It returns error of the routing table action fails with error. +func (r *router) manageServiceRoutes(service *registry.Service, action string, metric int) error { + // action is the routing table action + action = strings.ToLower(action) + // take route action on each service node + for _, node := range service.Nodes { + route := Route{ + Destination: service.Name, + Gateway: node.Address, + Router: r.opts.Address, + Network: r.opts.Network, + Metric: metric, + } + switch action { + case "insert", "create": + if err := r.opts.Table.Add(route); err != nil && err != ErrDuplicateRoute { + return fmt.Errorf("failed adding route for service %s: %s", service.Name, err) + } + case "delete": + if err := r.opts.Table.Delete(route); err != nil && err != ErrRouteNotFound { + return fmt.Errorf("failed deleting route for service %v: %s", service.Name, err) + } + default: + return fmt.Errorf("failed to manage route for service %v. Unknown action: %s", service.Name, action) + } + } + return nil +} + +// manageRegistryRoutes manages routes for each service found in the registry. +// It returns error if either the services failed to be listed or if the routing table action fails wirh error +func (r *router) manageRegistryRoutes(reg registry.Registry, action string, metric int) error { services, err := reg.ListServices() if err != nil { return fmt.Errorf("failed listing services: %v", err) @@ -107,27 +135,13 @@ func (r *router) addServiceRoutes(reg registry.Registry, network string, metric // get the service to retrieve all its info srvs, err := reg.GetService(service.Name) if err != nil { - log.Logf("r.addServiceRoutes() GetService() error: %v", err) + log.Logf("r.manageRegistryRoutes() GetService() error: %v", err) continue } - - // create a flat slide of nodes - var nodes []*registry.Node + // manage the routes for all return services for _, s := range srvs { - nodes = append(nodes, s.Nodes...) - } - - // range over the flat slice of nodes - for _, node := range nodes { - route := Route{ - Destination: service.Name, - Gateway: node.Address, - Router: r.opts.Address, - Network: r.opts.Network, - Metric: metric, - } - if err := r.opts.Table.Add(route); err != nil && err != ErrDuplicateRoute { - return fmt.Errorf("error adding route for service %s: %s", service.Name, err) + if err := r.manageServiceRoutes(s, action, metric); err != nil { + return err } } } @@ -160,39 +174,8 @@ func (r *router) watchServices(w registry.Watcher) error { log.Logf("r.watchServices() new service event: Action: %s Service: %v", res.Action, res.Service) - switch res.Action { - case "create": - // range over the flat slice of nodes - for _, node := range res.Service.Nodes { - gateway := node.Address - if node.Port > 0 { - gateway = fmt.Sprintf("%s:%d", node.Address, node.Port) - } - route := Route{ - Destination: res.Service.Name, - Gateway: gateway, - Router: r.opts.Address, - Network: r.opts.Network, - Metric: DefaultLocalMetric, - } - if err := r.opts.Table.Add(route); err != nil && err != ErrDuplicateRoute { - return fmt.Errorf("error adding route for service %s: %s", res.Service.Name, err) - } - } - case "delete": - for _, node := range res.Service.Nodes { - route := Route{ - Destination: res.Service.Name, - Gateway: node.Address, - Router: r.opts.Address, - Network: r.opts.Network, - Metric: DefaultLocalMetric, - } - // only return error if the route is not in the table, but something else has failed - if err := r.opts.Table.Delete(route); err != nil && err != ErrRouteNotFound { - return fmt.Errorf("failed adding route for service %v: %s", res.Service.Name, err) - } - } + if err := r.manageServiceRoutes(res.Service, res.Action, DefaultLocalMetric); err != nil { + return err } } @@ -431,8 +414,8 @@ func (r *router) Advertise() (<-chan *Advert, error) { defer r.Unlock() if r.status.Code != Running { - // add local service routes into the routing table - if err := r.addServiceRoutes(r.opts.Registry, "local", DefaultLocalMetric); err != nil { + // add all local service routes into the routing table + if err := r.manageRegistryRoutes(r.opts.Registry, "insert", DefaultLocalMetric); err != nil { return nil, fmt.Errorf("failed adding routes: %v", err) } log.Logf("Routing table:\n%s", r.opts.Table) @@ -533,7 +516,7 @@ func (r *router) Update(a *Advert) error { Router: event.Route.Router, Network: event.Route.Network, Metric: event.Route.Metric, - Policy: AddIfNotExists, + Policy: Insert, } if err := r.opts.Table.Update(route); err != nil { return fmt.Errorf("failed updating routing table: %v", err) diff --git a/network/router/default_table.go b/network/router/default_table.go index 28659cbd..9ae35e41 100644 --- a/network/router/default_table.go +++ b/network/router/default_table.go @@ -2,8 +2,6 @@ package router import ( "fmt" - "hash" - "hash/fnv" "strings" "sync" @@ -12,25 +10,22 @@ import ( "github.com/olekukonko/tablewriter" ) -// TableOptions are routing table options +// TableOptions specify routing table options // TODO: table options TBD in the future type TableOptions struct{} -// table is in memory routing table +// table is an in memory routing table type table struct { // opts are table options opts TableOptions - // TODO: we should stop key-ing on destination // m stores routing table map m map[string]map[uint64]Route - // h hashes route entries - h hash.Hash64 // w is a list of table watchers w map[string]*tableWatcher sync.RWMutex } -// newTable creates in memory routing table and returns it +// newTable creates a new routing table and returns it func newTable(opts ...TableOption) Table { // default options var options TableOptions @@ -40,14 +35,10 @@ func newTable(opts ...TableOption) Table { o(&options) } - h := fnv.New64() - h.Reset() - return &table{ opts: options, m: make(map[string]map[uint64]Route), w: make(map[string]*tableWatcher), - h: h, } } @@ -67,12 +58,12 @@ func (t *table) Options() TableOptions { // Add adds a route to the routing table func (t *table) Add(r Route) error { destAddr := r.Destination - sum := t.hash(r) + sum := r.Hash() t.Lock() defer t.Unlock() - // check if the destination has any routes in the table + // check if there are any routes in the table for the route destination if _, ok := t.m[destAddr]; !ok { t.m[destAddr] = make(map[uint64]Route) t.m[destAddr][sum] = r @@ -80,7 +71,7 @@ func (t *table) Add(r Route) error { return nil } - // add new route to the table for the given destination + // add new route to the table for the route destination if _, ok := t.m[destAddr][sum]; !ok { t.m[destAddr][sum] = r go t.sendEvent(&Event{Type: CreateEvent, Route: r}) @@ -88,15 +79,15 @@ func (t *table) Add(r Route) error { } // only add the route if the route override is explicitly requested - if _, ok := t.m[destAddr][sum]; ok && r.Policy == OverrideIfExists { + if _, ok := t.m[destAddr][sum]; ok && r.Policy == Override { t.m[destAddr][sum] = r go t.sendEvent(&Event{Type: UpdateEvent, Route: r}) return nil } - // if we reached this point without already returning the route already exists + // if we reached this point the route must already exist // we return nil only if explicitly requested by the client - if r.Policy == IgnoreIfExists { + if r.Policy == Skip { return nil } @@ -105,12 +96,12 @@ func (t *table) Add(r Route) error { // Delete deletes the route from the routing table func (t *table) Delete(r Route) error { + destAddr := r.Destination + sum := r.Hash() + t.Lock() defer t.Unlock() - destAddr := r.Destination - sum := t.hash(r) - if _, ok := t.m[destAddr]; !ok { return ErrRouteNotFound } @@ -121,17 +112,17 @@ func (t *table) Delete(r Route) error { return nil } -// Update updates routing table with new route +// Update updates routing table with the new route func (t *table) Update(r Route) error { destAddr := r.Destination - sum := t.hash(r) + sum := r.Hash() t.Lock() defer t.Unlock() - // check if the destAddr has ANY routes in the table + // check if the route destination has any routes in the table if _, ok := t.m[destAddr]; !ok { - if r.Policy == AddIfNotExists { + if r.Policy == Insert { t.m[destAddr] = make(map[uint64]Route) t.m[destAddr][sum] = r go t.sendEvent(&Event{Type: CreateEvent, Route: r}) @@ -140,8 +131,9 @@ func (t *table) Update(r Route) error { return ErrRouteNotFound } - // check if destination has this particular router in the table - if _, ok := t.m[destAddr][sum]; !ok && r.Policy == AddIfNotExists { + // check if the route for the route destination already exists + // NOTE: We only insert the route if explicitly requested by the client + if _, ok := t.m[destAddr][sum]; !ok && r.Policy == Insert { t.m[destAddr][sum] = r go t.sendEvent(&Event{Type: CreateEvent, Route: r}) return nil @@ -299,11 +291,3 @@ func (t *table) String() string { return sb.String() } - -// hash hashes the route using router gateway and network address -func (t *table) hash(r Route) uint64 { - t.h.Reset() - t.h.Write([]byte(r.Destination + r.Gateway + r.Network)) - - return t.h.Sum64() -} diff --git a/network/router/default_table_test.go b/network/router/default_table_test.go index 9098e5ad..46b8b034 100644 --- a/network/router/default_table_test.go +++ b/network/router/default_table_test.go @@ -2,7 +2,6 @@ package router import "testing" -// creates routing table and test route func testSetup() (Table, Route) { table := NewTable() @@ -35,32 +34,32 @@ func TestAdd(t *testing.T) { testTableSize += 1 // overrides an existing route - // NOTE: the size of the table should not change route.Metric = 100 - route.Policy = OverrideIfExists + route.Policy = Override if err := table.Add(route); err != nil { t.Errorf("error adding route: %s", err) } + // the size of the table should not change when Override policy is used if table.Size() != testTableSize { t.Errorf("invalid number of routes. expected: %d, given: %d", testTableSize, table.Size()) } // dont add new route if it already exists - // NOTE: The size of the table should not change - route.Policy = IgnoreIfExists + route.Policy = Skip if err := table.Add(route); err != nil { t.Errorf("error adding route: %s", err) } + // the size of the table should not change if Skip policy is used if table.Size() != testTableSize { t.Errorf("invalid number of routes. expected: %d, given: %d", testTableSize, table.Size()) } - // adding the same route under AddIfNotExists policy must error - route.Policy = AddIfNotExists + // adding the same route under Insert policy must error + route.Policy = Insert if err := table.Add(route); err != ErrDuplicateRoute { t.Errorf("error adding route. Expected error: %s, Given: %s", ErrDuplicateRoute, err) @@ -107,18 +106,17 @@ func TestUpdate(t *testing.T) { testTableSize += 1 // change the metric of the original route - // NOTE: this should NOT change the size of the table route.Metric = 200 if err := table.Update(route); err != nil { t.Errorf("error updating route: %s", err) } + // the size of the table should not change as we're only updating the metric of an existing route if table.Size() != testTableSize { t.Errorf("invalid number of routes. expected: %d, given: %d", testTableSize, table.Size()) } - // NOTE: routing table routes on // this should add a new route route.Destination = "new.dest" @@ -127,12 +125,11 @@ func TestUpdate(t *testing.T) { } testTableSize += 1 - // NOTE: default policy is AddIfNotExists so the new route will be added here + // Default policy is Insert so the new route will be added here since the route does not exist if table.Size() != testTableSize { t.Errorf("invalid number of routes. expected: %d, given: %d", testTableSize, table.Size()) } - // NOTE: we are hashing routes on // this should add a new route route.Gateway = "new.gw" @@ -145,9 +142,9 @@ func TestUpdate(t *testing.T) { t.Errorf("invalid number of routes. expected: %d, given: %d", testTableSize, table.Size()) } - // this should NOT add a new route as we are setting the policy to IgnoreIfExists + // this should NOT add a new route as we are setting the policy to Skip route.Destination = "rand.dest" - route.Policy = IgnoreIfExists + route.Policy = Skip if err := table.Update(route); err != ErrRouteNotFound { t.Errorf("error updating route. Expected error: %s, given: %s", ErrRouteNotFound, err) diff --git a/network/router/options.go b/network/router/options.go index 2426fa32..f6413a53 100644 --- a/network/router/options.go +++ b/network/router/options.go @@ -9,7 +9,7 @@ var ( // DefaultAddress is default router address DefaultAddress = ":9093" // DefaultNetwork is default micro network - DefaultNetwork = "local" + DefaultNetwork = "micro.mu" ) // Options are router options diff --git a/network/router/route.go b/network/router/route.go index 5e3cd8e5..f995d9d4 100644 --- a/network/router/route.go +++ b/network/router/route.go @@ -9,33 +9,33 @@ import ( ) var ( - // DefaultLocalMetric is default route cost for local network + // DefaultLocalMetric is default route cost metric for the local network DefaultLocalMetric = 1 - // DefaultNetworkMetric is default route cost for micro network + // DefaultNetworkMetric is default route cost metric for the micro network DefaultNetworkMetric = 10 ) -// RoutePolicy defines routing table addition policy +// RoutePolicy defines routing table policy type RoutePolicy int const ( - // AddIfNotExist adds the route if it does not exist - AddIfNotExists RoutePolicy = iota - // OverrideIfExists overrides route if it already exists - OverrideIfExists - // IgnoreIfExists instructs to not modify existing route - IgnoreIfExists + // Insert inserts a new route if it does not already exist + Insert RoutePolicy = iota + // Override overrides the route if it already exists + Override + // Skip skips modifying the route if it already exists + Skip ) // String returns human reprensentation of policy func (p RoutePolicy) String() string { switch p { - case AddIfNotExists: - return "ADD_IF_NOT_EXISTS" - case OverrideIfExists: - return "OVERRIDE_IF_EXISTS" - case IgnoreIfExists: - return "IGNORE_IF_EXISTS" + case Insert: + return "INSERT" + case Override: + return "OVERRIDE" + case Skip: + return "SKIP" default: return "UNKNOWN" } @@ -47,9 +47,9 @@ type Route struct { Destination string // Gateway is route gateway Gateway string - // Router is the network router address + // Router is the router address Router string - // Network is micro network address + // Network is network address Network string // Metric is the route cost metric Metric int @@ -66,7 +66,7 @@ func (r *Route) Hash() uint64 { return h.Sum64() } -// String allows to print the route +// String returns human readable route func (r Route) String() string { // this will help us build routing table string sb := &strings.Builder{} diff --git a/network/router/router.go b/network/router/router.go index 20c05fa0..ea91538c 100644 --- a/network/router/router.go +++ b/network/router/router.go @@ -14,7 +14,7 @@ type Router interface { Init(...Option) error // Options returns the router options Options() Options - // ID returns the id of the router + // ID returns the ID of the router ID() string // Table returns the routing table Table() Table @@ -22,7 +22,7 @@ type Router interface { Address() string // Network returns the network address of the router Network() string - // Advertise starts advertising routes to the network + // Advertise advertises routes to the network Advertise() (<-chan *Advert, error) // Update updates the routing table Update(*Advert) error @@ -59,7 +59,7 @@ func (ut UpdateType) String() string { } } -// Advert is sent by the router to the network +// Advert contains a list of events advertised by the router to the network type Advert struct { // ID is the router ID ID string @@ -81,10 +81,8 @@ type Status struct { } const ( - // Init means the rotuer has just been initialized - Init StatusCode = iota // Running means the router is up and running - Running + Running StatusCode = iota // Stopped means the router has been stopped Stopped // Error means the router has encountered error @@ -94,8 +92,6 @@ const ( // String returns human readable status code func (sc StatusCode) String() string { switch sc { - case Init: - return "INITIALIZED" case Running: return "RUNNING" case Stopped: From cc590f5f2c8a63a55876604d6f19103eb61b839c Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Mon, 8 Jul 2019 16:51:55 +0100 Subject: [PATCH 124/287] Table now has a dedicated package inside router package. --- .../router/{default_router.go => default.go} | 68 ++++++++++--------- network/router/options.go | 7 +- network/router/router.go | 12 ++-- .../{default_table.go => table/default.go} | 16 ++--- .../default_test.go} | 2 +- network/router/{ => table}/query.go | 2 +- network/router/{ => table}/route.go | 2 +- network/router/{ => table}/table.go | 2 +- .../{table_watcher.go => table/watcher.go} | 22 +++--- 9 files changed, 71 insertions(+), 62 deletions(-) rename network/router/{default_router.go => default.go} (89%) rename network/router/{default_table.go => table/default.go} (93%) rename network/router/{default_table_test.go => table/default_test.go} (99%) rename network/router/{ => table}/query.go (99%) rename network/router/{ => table}/route.go (99%) rename network/router/{ => table}/table.go (98%) rename network/router/{table_watcher.go => table/watcher.go} (87%) diff --git a/network/router/default_router.go b/network/router/default.go similarity index 89% rename from network/router/default_router.go rename to network/router/default.go index a9517f9d..44e07108 100644 --- a/network/router/default_router.go +++ b/network/router/default.go @@ -9,6 +9,7 @@ import ( "time" "github.com/micro/go-log" + "github.com/micro/go-micro/network/router/table" "github.com/micro/go-micro/registry" "github.com/olekukonko/tablewriter" ) @@ -33,7 +34,7 @@ type router struct { opts Options status Status exit chan struct{} - eventChan chan *Event + eventChan chan *table.Event advertChan chan *Advert wg *sync.WaitGroup sync.RWMutex @@ -53,7 +54,7 @@ func newRouter(opts ...Option) Router { opts: options, status: Status{Error: nil, Code: Stopped}, exit: make(chan struct{}), - eventChan: make(chan *Event), + eventChan: make(chan *table.Event), advertChan: make(chan *Advert), wg: &sync.WaitGroup{}, } @@ -78,7 +79,7 @@ func (r *router) ID() string { } // Table returns routing table -func (r *router) Table() Table { +func (r *router) Table() table.Table { return r.opts.Table } @@ -99,7 +100,7 @@ func (r *router) manageServiceRoutes(service *registry.Service, action string, m action = strings.ToLower(action) // take route action on each service node for _, node := range service.Nodes { - route := Route{ + route := table.Route{ Destination: service.Name, Gateway: node.Address, Router: r.opts.Address, @@ -108,11 +109,11 @@ func (r *router) manageServiceRoutes(service *registry.Service, action string, m } switch action { case "insert", "create": - if err := r.opts.Table.Add(route); err != nil && err != ErrDuplicateRoute { + if err := r.opts.Table.Add(route); err != nil && err != table.ErrDuplicateRoute { return fmt.Errorf("failed adding route for service %s: %s", service.Name, err) } case "delete": - if err := r.opts.Table.Delete(route); err != nil && err != ErrRouteNotFound { + if err := r.opts.Table.Delete(route); err != nil && err != table.ErrRouteNotFound { return fmt.Errorf("failed deleting route for service %v: %s", service.Name, err) } default: @@ -138,7 +139,7 @@ func (r *router) manageRegistryRoutes(reg registry.Registry, action string, metr log.Logf("r.manageRegistryRoutes() GetService() error: %v", err) continue } - // manage the routes for all return services + // manage the routes for all returned services for _, s := range srvs { if err := r.manageServiceRoutes(s, action, metric); err != nil { return err @@ -174,7 +175,7 @@ func (r *router) watchServices(w registry.Watcher) error { log.Logf("r.watchServices() new service event: Action: %s Service: %v", res.Action, res.Service) - if err := r.manageServiceRoutes(res.Service, res.Action, DefaultLocalMetric); err != nil { + if err := r.manageServiceRoutes(res.Service, res.Action, table.DefaultLocalMetric); err != nil { return err } } @@ -184,7 +185,7 @@ func (r *router) watchServices(w registry.Watcher) error { // watchTable watches routing table entries and either adds or deletes locally registered service to/from network registry // It returns error if the locally registered services either fails to be added/deleted to/from network registry. -func (r *router) watchTable(w Watcher) error { +func (r *router) watchTable(w table.Watcher) error { // wait in the background for the router to stop // when the router stops, stop the watcher and exit r.wg.Add(1) @@ -199,11 +200,14 @@ func (r *router) watchTable(w Watcher) error { for { event, err := w.Next() if err != nil { - if err != ErrWatcherStopped { + if err != table.ErrWatcherStopped { watchErr = err } break } + + log.Logf("r.watchTable() new table event: %s", event) + select { case <-r.exit: close(r.eventChan) @@ -218,14 +222,14 @@ func (r *router) watchTable(w Watcher) error { return watchErr } -func eventFlap(curr, prev *Event) bool { - if curr.Type == UpdateEvent && prev.Type == UpdateEvent { +func eventFlap(curr, prev *table.Event) bool { + if curr.Type == table.Update && prev.Type == table.Update { // update flap: this can be either metric or whatnot log.Logf("eventFlap(): Update flap") return true } - if curr.Type == CreateEvent && prev.Type == DeleteEvent || curr.Type == DeleteEvent && prev.Type == CreateEvent { + if curr.Type == table.Create && prev.Type == table.Delete || curr.Type == table.Delete && prev.Type == table.Create { log.Logf("eventFlap(): Create/Delete flap") return true } @@ -241,7 +245,7 @@ func (r *router) processEvents() error { // advertEvent is a table event enriched with advert data type advertEvent struct { - *Event + *table.Event timestamp time.Time penalty float64 isSuppressed bool @@ -259,7 +263,7 @@ process: for { select { case <-ticker.C: - var events []*Event + var events []*table.Event // decay the penalties of existing events mu.Lock() for advert, event := range eventMap { @@ -273,7 +277,7 @@ process: event.isFlapping = false } if !event.isFlapping { - e := new(Event) + e := new(table.Event) *e = *event.Event events = append(events, e) // this deletes the advertised event from the map @@ -284,7 +288,7 @@ process: if len(events) > 0 { wg.Add(1) - go func(events []*Event) { + go func(events []*table.Event) { defer wg.Done() log.Logf("go advertise(): start") @@ -319,9 +323,9 @@ process: // determine the event penalty var penalty float64 switch e.Type { - case UpdateEvent: + case table.Update: penalty = UpdateRoutePenalty - case CreateEvent, DeleteEvent: + case table.Create, table.Delete: penalty = DeleteRoutePenalty } // we use route hash as eventMap key @@ -366,8 +370,8 @@ process: return nil } -// manage watches router errors and takes appropriate actions -func (r *router) manage(errChan <-chan error) { +// watchErrors watches router errors and takes appropriate actions +func (r *router) watchErrors(errChan <-chan error) { defer r.wg.Done() log.Logf("r.manage(): manage start") @@ -382,7 +386,7 @@ func (r *router) manage(errChan <-chan error) { code = Error } - log.Logf("r.manage(): manage exiting") + log.Logf("r.watchErrors(): watchErrors exiting") r.Lock() defer r.Unlock() @@ -404,7 +408,7 @@ func (r *router) manage(errChan <-chan error) { } } - log.Logf("r.manage(): manage exit") + log.Logf("r.watchErrors(): watchErrors exit") } // Advertise advertises the routes to the network. @@ -415,19 +419,19 @@ func (r *router) Advertise() (<-chan *Advert, error) { if r.status.Code != Running { // add all local service routes into the routing table - if err := r.manageRegistryRoutes(r.opts.Registry, "insert", DefaultLocalMetric); err != nil { + if err := r.manageRegistryRoutes(r.opts.Registry, "insert", table.DefaultLocalMetric); err != nil { return nil, fmt.Errorf("failed adding routes: %v", err) } log.Logf("Routing table:\n%s", r.opts.Table) // add default gateway into routing table if r.opts.Gateway != "" { // note, the only non-default value is the gateway - route := Route{ + route := table.Route{ Destination: "*", Gateway: r.opts.Gateway, Router: "*", Network: "*", - Metric: DefaultLocalMetric, + Metric: table.DefaultLocalMetric, } if err := r.opts.Table.Add(route); err != nil { return nil, fmt.Errorf("failed adding default gateway route: %s", err) @@ -438,12 +442,12 @@ func (r *router) Advertise() (<-chan *Advert, error) { // TODO: these channels most likely won't have to be the struct fields if r.status.Code == Error || r.status.Code == Stopped { r.exit = make(chan struct{}) - r.eventChan = make(chan *Event) + r.eventChan = make(chan *table.Event) r.advertChan = make(chan *Advert) } // routing table watcher which watches all routes i.e. to every destination - tableWatcher, err := r.opts.Table.Watch(WatchDestination("*")) + tableWatcher, err := r.opts.Table.Watch(table.WatchDestination("*")) if err != nil { return nil, fmt.Errorf("failed creating routing table watcher: %v", err) } @@ -484,7 +488,7 @@ func (r *router) Advertise() (<-chan *Advert, error) { }() r.wg.Add(1) - go r.manage(errChan) + go r.watchErrors(errChan) // mark router as running and set its Error to nil status := Status{ @@ -501,7 +505,7 @@ func (r *router) Advertise() (<-chan *Advert, error) { func (r *router) Update(a *Advert) error { // NOTE: event sorting might not be necessary // copy update events intp new slices - events := make([]*Event, len(a.Events)) + events := make([]*table.Event, len(a.Events)) copy(events, a.Events) // sort events by timestamp sort.Slice(events, func(i, j int) bool { @@ -510,13 +514,13 @@ func (r *router) Update(a *Advert) error { for _, event := range events { // we extract the route from advertisement and update the routing table - route := Route{ + route := table.Route{ Destination: event.Route.Destination, Gateway: event.Route.Gateway, Router: event.Route.Router, Network: event.Route.Network, Metric: event.Route.Metric, - Policy: Insert, + Policy: table.Insert, } if err := r.opts.Table.Update(route); err != nil { return fmt.Errorf("failed updating routing table: %v", err) diff --git a/network/router/options.go b/network/router/options.go index f6413a53..eb287075 100644 --- a/network/router/options.go +++ b/network/router/options.go @@ -2,6 +2,7 @@ package router import ( "github.com/google/uuid" + "github.com/micro/go-micro/network/router/table" "github.com/micro/go-micro/registry" ) @@ -25,7 +26,7 @@ type Options struct { // Registry is the local registry Registry registry.Registry // Table is routing table - Table Table + Table table.Table } // ID sets Router ID @@ -57,7 +58,7 @@ func Gateway(g string) Option { } // RoutingTable sets the routing table -func RoutingTable(t Table) Option { +func RoutingTable(t table.Table) Option { return func(o *Options) { o.Table = t } @@ -77,6 +78,6 @@ func DefaultOptions() Options { Address: DefaultAddress, Network: DefaultNetwork, Registry: registry.DefaultRegistry, - Table: NewTable(), + Table: table.NewTable(), } } diff --git a/network/router/router.go b/network/router/router.go index ea91538c..e0f7d676 100644 --- a/network/router/router.go +++ b/network/router/router.go @@ -1,7 +1,11 @@ // Package router provides a network routing control plane package router -import "time" +import ( + "time" + + "github.com/micro/go-micro/network/router/table" +) var ( // DefaultRouter is default network router @@ -17,7 +21,7 @@ type Router interface { // ID returns the ID of the router ID() string // Table returns the routing table - Table() Table + Table() table.Table // Address returns the router adddress Address() string // Network returns the network address of the router @@ -65,8 +69,8 @@ type Advert struct { ID string // Timestamp marks the time when the update is sent Timestamp time.Time - // Events is a list of events to advertise - Events []*Event + // Events is a list of routing table events to advertise + Events []*table.Event } // StatusCode defines router status diff --git a/network/router/default_table.go b/network/router/table/default.go similarity index 93% rename from network/router/default_table.go rename to network/router/table/default.go index 9ae35e41..3480183e 100644 --- a/network/router/default_table.go +++ b/network/router/table/default.go @@ -1,4 +1,4 @@ -package router +package table import ( "fmt" @@ -67,21 +67,21 @@ func (t *table) Add(r Route) error { if _, ok := t.m[destAddr]; !ok { t.m[destAddr] = make(map[uint64]Route) t.m[destAddr][sum] = r - go t.sendEvent(&Event{Type: CreateEvent, Route: r}) + go t.sendEvent(&Event{Type: Create, Route: r}) return nil } // add new route to the table for the route destination if _, ok := t.m[destAddr][sum]; !ok { t.m[destAddr][sum] = r - go t.sendEvent(&Event{Type: CreateEvent, Route: r}) + go t.sendEvent(&Event{Type: Create, Route: r}) return nil } // only add the route if the route override is explicitly requested if _, ok := t.m[destAddr][sum]; ok && r.Policy == Override { t.m[destAddr][sum] = r - go t.sendEvent(&Event{Type: UpdateEvent, Route: r}) + go t.sendEvent(&Event{Type: Update, Route: r}) return nil } @@ -107,7 +107,7 @@ func (t *table) Delete(r Route) error { } delete(t.m[destAddr], sum) - go t.sendEvent(&Event{Type: DeleteEvent, Route: r}) + go t.sendEvent(&Event{Type: Delete, Route: r}) return nil } @@ -125,7 +125,7 @@ func (t *table) Update(r Route) error { if r.Policy == Insert { t.m[destAddr] = make(map[uint64]Route) t.m[destAddr][sum] = r - go t.sendEvent(&Event{Type: CreateEvent, Route: r}) + go t.sendEvent(&Event{Type: Create, Route: r}) return nil } return ErrRouteNotFound @@ -135,14 +135,14 @@ func (t *table) Update(r Route) error { // NOTE: We only insert the route if explicitly requested by the client if _, ok := t.m[destAddr][sum]; !ok && r.Policy == Insert { t.m[destAddr][sum] = r - go t.sendEvent(&Event{Type: CreateEvent, Route: r}) + go t.sendEvent(&Event{Type: Create, Route: r}) return nil } // if the route has been found update it if _, ok := t.m[destAddr][sum]; ok { t.m[destAddr][sum] = r - go t.sendEvent(&Event{Type: UpdateEvent, Route: r}) + go t.sendEvent(&Event{Type: Update, Route: r}) return nil } diff --git a/network/router/default_table_test.go b/network/router/table/default_test.go similarity index 99% rename from network/router/default_table_test.go rename to network/router/table/default_test.go index 46b8b034..a0c364b7 100644 --- a/network/router/default_table_test.go +++ b/network/router/table/default_test.go @@ -1,4 +1,4 @@ -package router +package table import "testing" diff --git a/network/router/query.go b/network/router/table/query.go similarity index 99% rename from network/router/query.go rename to network/router/table/query.go index befdd1d9..ccb7d396 100644 --- a/network/router/query.go +++ b/network/router/table/query.go @@ -1,4 +1,4 @@ -package router +package table import ( "fmt" diff --git a/network/router/route.go b/network/router/table/route.go similarity index 99% rename from network/router/route.go rename to network/router/table/route.go index f995d9d4..3d9c3bcb 100644 --- a/network/router/route.go +++ b/network/router/table/route.go @@ -1,4 +1,4 @@ -package router +package table import ( "fmt" diff --git a/network/router/table.go b/network/router/table/table.go similarity index 98% rename from network/router/table.go rename to network/router/table/table.go index c00484cd..9d353a54 100644 --- a/network/router/table.go +++ b/network/router/table/table.go @@ -1,4 +1,4 @@ -package router +package table import ( "errors" diff --git a/network/router/table_watcher.go b/network/router/table/watcher.go similarity index 87% rename from network/router/table_watcher.go rename to network/router/table/watcher.go index 2c5d8989..850a9089 100644 --- a/network/router/table_watcher.go +++ b/network/router/table/watcher.go @@ -1,4 +1,4 @@ -package router +package table import ( "errors" @@ -19,22 +19,22 @@ var ( type EventType int const ( - // CreateEvent is emitted when a new route has been created - CreateEvent EventType = iota - // DeleteEvent is emitted when an existing route has been deleted - DeleteEvent - // UpdateEvent is emitted when an existing route has been updated - UpdateEvent + // Create is emitted when a new route has been created + Create EventType = iota + // Delete is emitted when an existing route has been deleted + Delete + // Update is emitted when an existing route has been updated + Update ) // String returns string representation of the event func (et EventType) String() string { switch et { - case CreateEvent: + case Create: return "CREATE" - case DeleteEvent: + case Delete: return "DELETE" - case UpdateEvent: + case Update: return "UPDATE" default: return "UNKNOWN" @@ -53,7 +53,7 @@ type Event struct { // String prints human readable Event func (e Event) String() string { - return fmt.Sprintf("[EVENT] Type: %s\nRoute:\n%s", e.Type, e.Route) + return fmt.Sprintf("[EVENT] %s:\nRoute:\n%s", e.Type, e.Route) } // WatchOption is used to define what routes to watch in the table From b82245429eb158eee541223bc32f257d5d714e0f Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Mon, 8 Jul 2019 21:03:54 +0100 Subject: [PATCH 125/287] Simplified table logic. Lookup tests. mucp/cient update --- client/selector/router/router.go | 11 +- network/proxy/mucp/mucp.go | 11 +- network/router/default.go | 111 +++++++++--------- network/router/router.go | 7 +- network/router/table/default.go | 31 +---- network/router/table/default_test.go | 163 +++++++++++++++++---------- network/router/table/query.go | 1 + network/router/table/route.go | 32 +----- network/router/table/watcher.go | 10 +- 9 files changed, 183 insertions(+), 194 deletions(-) diff --git a/client/selector/router/router.go b/client/selector/router/router.go index 4bcdecd1..65e69702 100644 --- a/client/selector/router/router.go +++ b/client/selector/router/router.go @@ -11,6 +11,7 @@ import ( "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/network/router" pb "github.com/micro/go-micro/network/router/proto" + "github.com/micro/go-micro/network/router/table" "github.com/micro/go-micro/registry" ) @@ -40,11 +41,11 @@ type clientKey struct{} type routerKey struct{} // getRoutes returns the routes whether they are remote or local -func (r *routerSelector) getRoutes(service string) ([]router.Route, error) { +func (r *routerSelector) getRoutes(service string) ([]table.Route, error) { if !r.remote { // lookup router for routes for the service - return r.r.Table().Lookup(router.NewQuery( - router.QueryDestination(service), + return r.r.Table().Lookup(table.NewQuery( + table.QueryDestination(service), )) } @@ -101,11 +102,11 @@ func (r *routerSelector) getRoutes(service string) ([]router.Route, error) { return nil, selector.ErrNoneAvailable } - var routes []router.Route + var routes []table.Route // convert from pb to []*router.Route for _, r := range pbRoutes.Routes { - routes = append(routes, router.Route{ + routes = append(routes, table.Route{ Destination: r.Destination, Gateway: r.Gateway, Router: r.Router, diff --git a/network/proxy/mucp/mucp.go b/network/proxy/mucp/mucp.go index 1abe976b..d0ecb81f 100644 --- a/network/proxy/mucp/mucp.go +++ b/network/proxy/mucp/mucp.go @@ -18,6 +18,7 @@ import ( "github.com/micro/go-micro/server" pb "github.com/micro/go-micro/network/router/proto" + "github.com/micro/go-micro/network/router/table" ) // Proxy will transparently proxy requests to an endpoint. @@ -40,7 +41,7 @@ type Proxy struct { // A fib of routes service:address sync.RWMutex - Routes map[string][]router.Route + Routes map[string][]table.Route } // read client request and write to server @@ -80,7 +81,7 @@ func readLoop(r server.Request, s client.Stream) error { func (p *Proxy) getRoute(service string) ([]string, error) { // converts routes to just addresses - toNodes := func(routes []router.Route) []string { + toNodes := func(routes []table.Route) []string { var nodes []string for _, node := range routes { nodes = append(nodes, node.Gateway) @@ -106,7 +107,7 @@ func (p *Proxy) getRoute(service string) ([]string, error) { if p.Router != nil { // lookup the router routes, err := p.Router.Table().Lookup( - router.NewQuery(router.QueryDestination(service)), + table.NewQuery(table.QueryDestination(service)), ) if err != nil { return nil, err @@ -114,7 +115,7 @@ func (p *Proxy) getRoute(service string) ([]string, error) { p.Lock() if p.Routes == nil { - p.Routes = make(map[string][]router.Route) + p.Routes = make(map[string][]table.Route) } p.Routes[service] = routes p.Unlock() @@ -203,7 +204,7 @@ func (p *Proxy) getRoute(service string) ([]string, error) { // convert from pb to []*router.Route for _, r := range pbRoutes.Routes { - routes = append(routes, router.Route{ + routes = append(routes, table.Route{ Destination: r.Destination, Gateway: r.Gateway, Router: r.Router, diff --git a/network/router/default.go b/network/router/default.go index 44e07108..b77b40fe 100644 --- a/network/router/default.go +++ b/network/router/default.go @@ -15,18 +15,20 @@ import ( ) const ( - // UpdateRoutePenalty penalises route updates - UpdateRoutePenalty = 500 - // DeleteRoutePenalty penalises route deletes - DeleteRoutePenalty = 1000 // AdvertiseTick is time interval in which we advertise route updates AdvertiseTick = 5 * time.Second // AdvertSuppress is advert suppression threshold AdvertSuppress = 2000 - // AdvertRecover is advert suppression recovery threshold + // AdvertRecover is advert recovery threshold AdvertRecover = 750 - // PenaltyDecay is the "half-life" of the penalty + // DefaultAdvertTTL is default advertisement TTL + DefaultAdvertTTL = time.Minute + // PenaltyDecay is the penalty decay PenaltyDecay = 1.15 + // Delete penalises route addition and deletion + Delete = 1000 + // UpdatePenalty penalises route updates + UpdatePenalty = 500 ) // router provides default router implementation @@ -93,8 +95,8 @@ func (r *router) Network() string { return r.opts.Network } -// manageServiceRoutes manages the routes for a given service. -// It returns error of the routing table action fails with error. +// manageServiceRoutes manages routes for a given service. +// It returns error of the routing table action fails. func (r *router) manageServiceRoutes(service *registry.Service, action string, metric int) error { // action is the routing table action action = strings.ToLower(action) @@ -124,7 +126,7 @@ func (r *router) manageServiceRoutes(service *registry.Service, action string, m } // manageRegistryRoutes manages routes for each service found in the registry. -// It returns error if either the services failed to be listed or if the routing table action fails wirh error +// It returns error if either the services failed to be listed or the routing table action fails. func (r *router) manageRegistryRoutes(reg registry.Registry, action string, metric int) error { services, err := reg.ListServices() if err != nil { @@ -222,66 +224,60 @@ func (r *router) watchTable(w table.Watcher) error { return watchErr } -func eventFlap(curr, prev *table.Event) bool { +// isFlapping detects if the event is flapping based on the current and previous event status. +func isFlapping(curr, prev *table.Event) bool { if curr.Type == table.Update && prev.Type == table.Update { - // update flap: this can be either metric or whatnot - log.Logf("eventFlap(): Update flap") + log.Logf("isFlapping(): Update flap") return true } - if curr.Type == table.Create && prev.Type == table.Delete || curr.Type == table.Delete && prev.Type == table.Create { - log.Logf("eventFlap(): Create/Delete flap") + if curr.Type == table.Insert && prev.Type == table.Delete || curr.Type == table.Delete && prev.Type == table.Insert { + log.Logf("isFlapping(): Create/Delete flap") return true } return false } +// updateEvent is a table event enriched with advertisement data +type updateEvent struct { + *table.Event + // timestamp marks the time the event has been received + timestamp time.Time + // penalty is current event penalty + penalty float64 + // isSuppressed flags if the event should be considered for flap detection + isSuppressed bool + // isFlapping marks the event as flapping event + isFlapping bool +} + // processEvents processes routing table events. // It suppresses unhealthy flapping events and advertises healthy events upstream. func (r *router) processEvents() error { // ticker to periodically scan event for advertising ticker := time.NewTicker(AdvertiseTick) - - // advertEvent is a table event enriched with advert data - type advertEvent struct { - *table.Event - timestamp time.Time - penalty float64 - isSuppressed bool - isFlapping bool - } - - // eventMap is a map of advert events that might end up being advertised - eventMap := make(map[uint64]*advertEvent) + // eventMap is a map of advert events + eventMap := make(map[uint64]*updateEvent) // lock to protect access to eventMap mu := &sync.RWMutex{} // waitgroup to manage advertisement goroutines var wg sync.WaitGroup -process: +processLoop: for { select { case <-ticker.C: var events []*table.Event - // decay the penalties of existing events + // collect all events which are not flapping mu.Lock() - for advert, event := range eventMap { - delta := time.Since(event.timestamp).Seconds() - event.penalty = event.penalty * math.Exp(delta) - // suppress or recover the event based on its current penalty - if !event.isSuppressed && event.penalty > AdvertSuppress { - event.isSuppressed = true - } else if event.penalty < AdvertRecover { - event.isSuppressed = false - event.isFlapping = false - } - if !event.isFlapping { + for key, event := range eventMap { + if !event.isFlapping && !event.isSuppressed { e := new(table.Event) *e = *event.Event events = append(events, e) // this deletes the advertised event from the map - delete(eventMap, advert) + delete(eventMap, key) } } mu.Unlock() @@ -301,12 +297,6 @@ process: select { case r.advertChan <- a: - mu.Lock() - // once we've advertised the events, we need to delete them - for _, event := range a.Events { - delete(eventMap, event.Route.Hash()) - } - mu.Unlock() case <-r.exit: log.Logf("go advertise(): exit") return @@ -315,7 +305,9 @@ process: }(events) } case e := <-r.eventChan: - // if event is nil, break + // event timestamp + now := time.Now() + // if event is nil, continue if e == nil { continue } @@ -324,15 +316,15 @@ process: var penalty float64 switch e.Type { case table.Update: - penalty = UpdateRoutePenalty - case table.Create, table.Delete: - penalty = DeleteRoutePenalty + penalty = UpdatePenalty + case table.Delete: + penalty = Delete } // we use route hash as eventMap key hash := e.Route.Hash() event, ok := eventMap[hash] if !ok { - event = &advertEvent{ + event = &updateEvent{ Event: e, penalty: penalty, timestamp: time.Now(), @@ -342,8 +334,8 @@ process: } // update penalty for existing event: decay existing and add new penalty delta := time.Since(event.timestamp).Seconds() - event.penalty = event.penalty*math.Exp(delta) + penalty - event.timestamp = time.Now() + event.penalty = event.penalty*math.Exp(-delta) + penalty + event.timestamp = now // suppress or recover the event based on its current penalty if !event.isSuppressed && event.penalty > AdvertSuppress { event.isSuppressed = true @@ -352,11 +344,11 @@ process: } // if not suppressed decide if if its flapping if !event.isSuppressed { - // detect if its flapping - event.isFlapping = eventFlap(e, event.Event) + // detect if its flapping by comparing current and previous event + event.isFlapping = isFlapping(e, event.Event) } case <-r.exit: - break process + break processLoop } } @@ -438,8 +430,7 @@ func (r *router) Advertise() (<-chan *Advert, error) { } } - // NOTE: we only need to recreate the exit/advertChan if the router errored or was stopped - // TODO: these channels most likely won't have to be the struct fields + // NOTE: we only need to recreate these if the router errored or was stopped if r.status.Code == Error || r.status.Code == Stopped { r.exit = make(chan struct{}) r.eventChan = make(chan *table.Event) @@ -490,6 +481,9 @@ func (r *router) Advertise() (<-chan *Advert, error) { r.wg.Add(1) go r.watchErrors(errChan) + // TODO: send router announcement update comes here + // the announcement update contains routes from routing table + // mark router as running and set its Error to nil status := Status{ Code: Running, @@ -520,7 +514,6 @@ func (r *router) Update(a *Advert) error { Router: event.Route.Router, Network: event.Route.Network, Metric: event.Route.Metric, - Policy: table.Insert, } if err := r.opts.Table.Update(route); err != nil { return fmt.Errorf("failed updating routing table: %v", err) diff --git a/network/router/router.go b/network/router/router.go index e0f7d676..4fd53c07 100644 --- a/network/router/router.go +++ b/network/router/router.go @@ -20,12 +20,12 @@ type Router interface { Options() Options // ID returns the ID of the router ID() string - // Table returns the routing table - Table() table.Table // Address returns the router adddress Address() string // Network returns the network address of the router Network() string + // Table returns the routing table + Table() table.Table // Advertise advertises routes to the network Advertise() (<-chan *Advert, error) // Update updates the routing table @@ -69,6 +69,9 @@ type Advert struct { ID string // Timestamp marks the time when the update is sent Timestamp time.Time + // TTL is Advert TTL + // TODO: not used + TTL time.Time // Events is a list of routing table events to advertise Events []*table.Event } diff --git a/network/router/table/default.go b/network/router/table/default.go index 3480183e..7a95716c 100644 --- a/network/router/table/default.go +++ b/network/router/table/default.go @@ -67,27 +67,14 @@ func (t *table) Add(r Route) error { if _, ok := t.m[destAddr]; !ok { t.m[destAddr] = make(map[uint64]Route) t.m[destAddr][sum] = r - go t.sendEvent(&Event{Type: Create, Route: r}) + go t.sendEvent(&Event{Type: Insert, Route: r}) return nil } // add new route to the table for the route destination if _, ok := t.m[destAddr][sum]; !ok { t.m[destAddr][sum] = r - go t.sendEvent(&Event{Type: Create, Route: r}) - return nil - } - - // only add the route if the route override is explicitly requested - if _, ok := t.m[destAddr][sum]; ok && r.Policy == Override { - t.m[destAddr][sum] = r - go t.sendEvent(&Event{Type: Update, Route: r}) - return nil - } - - // if we reached this point the route must already exist - // we return nil only if explicitly requested by the client - if r.Policy == Skip { + go t.sendEvent(&Event{Type: Insert, Route: r}) return nil } @@ -122,23 +109,9 @@ func (t *table) Update(r Route) error { // check if the route destination has any routes in the table if _, ok := t.m[destAddr]; !ok { - if r.Policy == Insert { - t.m[destAddr] = make(map[uint64]Route) - t.m[destAddr][sum] = r - go t.sendEvent(&Event{Type: Create, Route: r}) - return nil - } return ErrRouteNotFound } - // check if the route for the route destination already exists - // NOTE: We only insert the route if explicitly requested by the client - if _, ok := t.m[destAddr][sum]; !ok && r.Policy == Insert { - t.m[destAddr][sum] = r - go t.sendEvent(&Event{Type: Create, Route: r}) - return nil - } - // if the route has been found update it if _, ok := t.m[destAddr][sum]; ok { t.m[destAddr][sum] = r diff --git a/network/router/table/default_test.go b/network/router/table/default_test.go index a0c364b7..6447cf03 100644 --- a/network/router/table/default_test.go +++ b/network/router/table/default_test.go @@ -33,36 +33,13 @@ func TestAdd(t *testing.T) { } testTableSize += 1 - // overrides an existing route - route.Metric = 100 - route.Policy = Override - - if err := table.Add(route); err != nil { - t.Errorf("error adding route: %s", err) - } - - // the size of the table should not change when Override policy is used if table.Size() != testTableSize { - t.Errorf("invalid number of routes. expected: %d, given: %d", testTableSize, table.Size()) - } - - // dont add new route if it already exists - route.Policy = Skip - - if err := table.Add(route); err != nil { - t.Errorf("error adding route: %s", err) - } - - // the size of the table should not change if Skip policy is used - if table.Size() != testTableSize { - t.Errorf("invalid number of routes. expected: %d, given: %d", testTableSize, table.Size()) + t.Errorf("invalid number of routes. expected: %d, found: %d", testTableSize, table.Size()) } // adding the same route under Insert policy must error - route.Policy = Insert - if err := table.Add(route); err != ErrDuplicateRoute { - t.Errorf("error adding route. Expected error: %s, Given: %s", ErrDuplicateRoute, err) + t.Errorf("error adding route. Expected error: %s, found: %s", ErrDuplicateRoute, err) } } @@ -80,7 +57,7 @@ func TestDelete(t *testing.T) { route.Destination = "randDest" if err := table.Delete(route); err != ErrRouteNotFound { - t.Errorf("error deleting route. Expected error: %s, given: %s", ErrRouteNotFound, err) + t.Errorf("error deleting route. Expected error: %s, found: %s", ErrRouteNotFound, err) } // we should be able to delete the existing route @@ -92,7 +69,7 @@ func TestDelete(t *testing.T) { testTableSize -= 1 if table.Size() != testTableSize { - t.Errorf("invalid number of routes. expected: %d, given: %d", testTableSize, table.Size()) + t.Errorf("invalid number of routes. expected: %d, found: %d", testTableSize, table.Size()) } } @@ -114,44 +91,18 @@ func TestUpdate(t *testing.T) { // the size of the table should not change as we're only updating the metric of an existing route if table.Size() != testTableSize { - t.Errorf("invalid number of routes. expected: %d, given: %d", testTableSize, table.Size()) + t.Errorf("invalid number of routes. expected: %d, found: %d", testTableSize, table.Size()) } - // this should add a new route - route.Destination = "new.dest" - - if err := table.Update(route); err != nil { - t.Errorf("error updating route: %s", err) - } - testTableSize += 1 - - // Default policy is Insert so the new route will be added here since the route does not exist - if table.Size() != testTableSize { - t.Errorf("invalid number of routes. expected: %d, given: %d", testTableSize, table.Size()) - } - - // this should add a new route - route.Gateway = "new.gw" - - if err := table.Update(route); err != nil { - t.Errorf("error updating route: %s", err) - } - testTableSize += 1 - - if table.Size() != testTableSize { - t.Errorf("invalid number of routes. expected: %d, given: %d", testTableSize, table.Size()) - } - - // this should NOT add a new route as we are setting the policy to Skip + // this should error as the destination does not exist route.Destination = "rand.dest" - route.Policy = Skip if err := table.Update(route); err != ErrRouteNotFound { - t.Errorf("error updating route. Expected error: %s, given: %s", ErrRouteNotFound, err) + t.Errorf("error updating route. Expected error: %s, found: %s", ErrRouteNotFound, err) } - if table.Size() != 3 { - t.Errorf("invalid number of routes. expected: %d, given: %d", testTableSize, table.Size()) + if table.Size() != testTableSize { + t.Errorf("invalid number of routes. expected: %d, found: %d", testTableSize, table.Size()) } } @@ -173,10 +124,104 @@ func TestList(t *testing.T) { } if len(routes) != len(dest) { - t.Errorf("incorrect number of routes listed. Expected: %d, Given: %d", len(dest), len(routes)) + t.Errorf("incorrect number of routes listed. Expected: %d, found: %d", len(dest), len(routes)) } if len(routes) != table.Size() { t.Errorf("mismatch number of routes and table size. Routes: %d, Size: %d", len(routes), table.Size()) } } + +func TestLookup(t *testing.T) { + table, route := testSetup() + + dest := []string{"svc1", "svc2", "svc3"} + net := []string{"net1", "net2", "net1"} + rtr := []string{"router1", "router2", "router3"} + + for i := 0; i < len(dest); i++ { + route.Destination = dest[i] + route.Network = net[i] + route.Router = rtr[i] + if err := table.Add(route); err != nil { + t.Errorf("error adding route: %s", err) + } + } + + // return all routes + query := NewQuery() + + routes, err := table.Lookup(query) + if err != nil { + t.Errorf("error looking up routes: %s", err) + } + + if len(routes) != table.Size() { + t.Errorf("incorrect number of routes returned. expected: %d, found: %d", table.Size(), len(routes)) + } + + // query particular net + query = NewQuery(QueryNetwork("net1")) + + routes, err = table.Lookup(query) + if err != nil { + t.Errorf("error looking up routes: %s", err) + } + + if len(routes) != 2 { + t.Errorf("incorrect number of routes returned. expected: %d, found: %d", 2, len(routes)) + } + + // query particular router + router := "router1" + query = NewQuery(QueryRouter(router)) + + routes, err = table.Lookup(query) + if err != nil { + t.Errorf("error looking up routes: %s", err) + } + + if len(routes) != 1 { + t.Errorf("incorrect number of routes returned. expected: %d, found: %d", 1, len(routes)) + } + + if routes[0].Router != router { + t.Errorf("incorrect route returned. Expected router: %s, found: %s", router, routes[0].Router) + } + + // query particular route + network := "net1" + query = NewQuery( + QueryRouter(router), + QueryNetwork(network), + ) + + routes, err = table.Lookup(query) + if err != nil { + t.Errorf("error looking up routes: %s", err) + } + + if len(routes) != 1 { + t.Errorf("incorrect number of routes returned. expected: %d, found: %d", 1, len(routes)) + } + + if routes[0].Router != router { + t.Errorf("incorrect route returned. Expected router: %s, found: %s", router, routes[0].Router) + } + + if routes[0].Network != network { + t.Errorf("incorrect network returned. Expected network: %s, found: %s", network, routes[0].Network) + } + + // bullshit route query + query = NewQuery(QueryDestination("foobar")) + + routes, err = table.Lookup(query) + if err != nil { + t.Errorf("error looking up routes: %s", err) + } + + if len(routes) != 0 { + t.Errorf("incorrect number of routes returned. expected: %d, found: %d", 0, len(routes)) + } +} diff --git a/network/router/table/query.go b/network/router/table/query.go index ccb7d396..42b44db6 100644 --- a/network/router/table/query.go +++ b/network/router/table/query.go @@ -90,6 +90,7 @@ func NewQuery(opts ...QueryOption) Query { // NOTE: by default we use DefaultNetworkMetric qopts := QueryOptions{ Destination: "*", + Router: "*", Network: "*", Policy: DiscardIfNone, } diff --git a/network/router/table/route.go b/network/router/table/route.go index 3d9c3bcb..cbb32bf1 100644 --- a/network/router/table/route.go +++ b/network/router/table/route.go @@ -15,46 +15,18 @@ var ( DefaultNetworkMetric = 10 ) -// RoutePolicy defines routing table policy -type RoutePolicy int - -const ( - // Insert inserts a new route if it does not already exist - Insert RoutePolicy = iota - // Override overrides the route if it already exists - Override - // Skip skips modifying the route if it already exists - Skip -) - -// String returns human reprensentation of policy -func (p RoutePolicy) String() string { - switch p { - case Insert: - return "INSERT" - case Override: - return "OVERRIDE" - case Skip: - return "SKIP" - default: - return "UNKNOWN" - } -} - // Route is network route type Route struct { // Destination is destination address Destination string // Gateway is route gateway Gateway string - // Router is the router address - Router string // Network is network address Network string + // Router is the router address + Router string // Metric is the route cost metric Metric int - // Policy defines route policy - Policy RoutePolicy } // Hash returns route hash sum. diff --git a/network/router/table/watcher.go b/network/router/table/watcher.go index 850a9089..90e46360 100644 --- a/network/router/table/watcher.go +++ b/network/router/table/watcher.go @@ -19,8 +19,8 @@ var ( type EventType int const ( - // Create is emitted when a new route has been created - Create EventType = iota + // Insert is emitted when a new route has been inserted + Insert EventType = iota // Delete is emitted when an existing route has been deleted Delete // Update is emitted when an existing route has been updated @@ -30,8 +30,8 @@ const ( // String returns string representation of the event func (et EventType) String() string { switch et { - case Create: - return "CREATE" + case Insert: + return "INSERT" case Delete: return "DELETE" case Update: @@ -126,7 +126,7 @@ func (w *tableWatcher) Stop() { } // String prints debug information -func (w *tableWatcher) String() string { +func (w tableWatcher) String() string { sb := &strings.Builder{} table := tablewriter.NewWriter(sb) From 265271008e75677fb522efd44d1fb35fd918778e Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Tue, 9 Jul 2019 12:46:15 +0100 Subject: [PATCH 126/287] Simplified processEvents loop; Added router Announcement. --- network/router/default.go | 110 +++++++++++++++++++++++--------------- network/router/router.go | 12 +++-- 2 files changed, 73 insertions(+), 49 deletions(-) diff --git a/network/router/default.go b/network/router/default.go index b77b40fe..34462e6d 100644 --- a/network/router/default.go +++ b/network/router/default.go @@ -38,6 +38,7 @@ type router struct { exit chan struct{} eventChan chan *table.Event advertChan chan *Advert + advertWg *sync.WaitGroup wg *sync.WaitGroup sync.RWMutex } @@ -58,6 +59,7 @@ func newRouter(opts ...Option) Router { exit: make(chan struct{}), eventChan: make(chan *table.Event), advertChan: make(chan *Advert), + advertWg: &sync.WaitGroup{}, wg: &sync.WaitGroup{}, } } @@ -97,7 +99,7 @@ func (r *router) Network() string { // manageServiceRoutes manages routes for a given service. // It returns error of the routing table action fails. -func (r *router) manageServiceRoutes(service *registry.Service, action string, metric int) error { +func (r *router) manageServiceRoutes(service *registry.Service, action string) error { // action is the routing table action action = strings.ToLower(action) // take route action on each service node @@ -107,7 +109,7 @@ func (r *router) manageServiceRoutes(service *registry.Service, action string, m Gateway: node.Address, Router: r.opts.Address, Network: r.opts.Network, - Metric: metric, + Metric: table.DefaultLocalMetric, } switch action { case "insert", "create": @@ -127,7 +129,7 @@ func (r *router) manageServiceRoutes(service *registry.Service, action string, m // manageRegistryRoutes manages routes for each service found in the registry. // It returns error if either the services failed to be listed or the routing table action fails. -func (r *router) manageRegistryRoutes(reg registry.Registry, action string, metric int) error { +func (r *router) manageRegistryRoutes(reg registry.Registry, action string) error { services, err := reg.ListServices() if err != nil { return fmt.Errorf("failed listing services: %v", err) @@ -143,7 +145,7 @@ func (r *router) manageRegistryRoutes(reg registry.Registry, action string, metr } // manage the routes for all returned services for _, s := range srvs { - if err := r.manageServiceRoutes(s, action, metric); err != nil { + if err := r.manageServiceRoutes(s, action); err != nil { return err } } @@ -177,7 +179,7 @@ func (r *router) watchServices(w registry.Watcher) error { log.Logf("r.watchServices() new service event: Action: %s Service: %v", res.Action, res.Service) - if err := r.manageServiceRoutes(res.Service, res.Action, table.DefaultLocalMetric); err != nil { + if err := r.manageServiceRoutes(res.Service, res.Action); err != nil { return err } } @@ -224,6 +226,29 @@ func (r *router) watchTable(w table.Watcher) error { return watchErr } +func (r *router) advertEvents(advType AdvertType, events []*table.Event) { + defer r.advertWg.Done() + + log.Logf("r.advertEvents(): start event: %s", advType) + + a := &Advert{ + ID: r.ID(), + Type: advType, + Timestamp: time.Now(), + Events: events, + } + + select { + case r.advertChan <- a: + log.Logf("r.advertEvents(): advertised event: %s", advType) + case <-r.exit: + log.Logf("r.advertEvents(): DONE exit") + return + } + + log.Logf("r.advertEvents(): REGULAR exit") +} + // isFlapping detects if the event is flapping based on the current and previous event status. func isFlapping(curr, prev *table.Event) bool { if curr.Type == table.Update && prev.Type == table.Update { @@ -259,18 +284,12 @@ func (r *router) processEvents() error { ticker := time.NewTicker(AdvertiseTick) // eventMap is a map of advert events eventMap := make(map[uint64]*updateEvent) - // lock to protect access to eventMap - mu := &sync.RWMutex{} - // waitgroup to manage advertisement goroutines - var wg sync.WaitGroup -processLoop: for { select { case <-ticker.C: var events []*table.Event // collect all events which are not flapping - mu.Lock() for key, event := range eventMap { if !event.isFlapping && !event.isSuppressed { e := new(table.Event) @@ -280,29 +299,10 @@ processLoop: delete(eventMap, key) } } - mu.Unlock() if len(events) > 0 { - wg.Add(1) - go func(events []*table.Event) { - defer wg.Done() - - log.Logf("go advertise(): start") - - a := &Advert{ - ID: r.ID(), - Timestamp: time.Now(), - Events: events, - } - - select { - case r.advertChan <- a: - case <-r.exit: - log.Logf("go advertise(): exit") - return - } - log.Logf("go advertise(): exit") - }(events) + r.advertWg.Add(1) + go r.advertEvents(Update, events) } case e := <-r.eventChan: // event timestamp @@ -348,15 +348,16 @@ processLoop: event.isFlapping = isFlapping(e, event.Event) } case <-r.exit: - break processLoop + // first wait for the advertiser to finish + r.advertWg.Wait() + // close the advert channel + close(r.advertChan) + log.Logf("r.processEvents(): event processor stopped") + return nil } } - // first wait for the advertiser to finish - wg.Wait() - // close the advert channel - close(r.advertChan) - + // we probably never reach this place log.Logf("r.processEvents(): event processor stopped") return nil @@ -395,9 +396,11 @@ func (r *router) watchErrors(errChan <-chan error) { // drain the advertise channel for range r.advertChan { } + log.Logf("r.watchErrors(): advert channel drained") // drain the event channel for range r.eventChan { } + log.Logf("r.watchErrors(): event channel drained") } log.Logf("r.watchErrors(): watchErrors exit") @@ -411,10 +414,15 @@ func (r *router) Advertise() (<-chan *Advert, error) { if r.status.Code != Running { // add all local service routes into the routing table - if err := r.manageRegistryRoutes(r.opts.Registry, "insert", table.DefaultLocalMetric); err != nil { - return nil, fmt.Errorf("failed adding routes: %v", err) + if err := r.manageRegistryRoutes(r.opts.Registry, "insert"); err != nil { + return nil, fmt.Errorf("failed adding routes: %s", err) } log.Logf("Routing table:\n%s", r.opts.Table) + // list routing table routes to announce + routes, err := r.opts.Table.List() + if err != nil { + return nil, fmt.Errorf("failed listing routes: %s", err) + } // add default gateway into routing table if r.opts.Gateway != "" { // note, the only non-default value is the gateway @@ -431,14 +439,15 @@ func (r *router) Advertise() (<-chan *Advert, error) { } // NOTE: we only need to recreate these if the router errored or was stopped + // TODO: These probably dont need to be struct members if r.status.Code == Error || r.status.Code == Stopped { r.exit = make(chan struct{}) r.eventChan = make(chan *table.Event) r.advertChan = make(chan *Advert) } - // routing table watcher which watches all routes i.e. to every destination - tableWatcher, err := r.opts.Table.Watch(table.WatchDestination("*")) + // routing table watcher + tableWatcher, err := r.opts.Table.Watch() if err != nil { return nil, fmt.Errorf("failed creating routing table watcher: %v", err) } @@ -478,11 +487,24 @@ func (r *router) Advertise() (<-chan *Advert, error) { log.Logf("r.Advertise(): r.processEvents() exit") }() + // watch for errors and cleanup r.wg.Add(1) go r.watchErrors(errChan) - // TODO: send router announcement update comes here - // the announcement update contains routes from routing table + // announce yourself with all the existing routes + events := make([]*table.Event, len(routes)) + for i, route := range routes { + event := &table.Event{ + Type: table.Insert, + Timestamp: time.Now(), + Route: route, + } + events[i] = event + } + + // advertise your presence + r.advertWg.Add(1) + go r.advertEvents(Announce, events) // mark router as running and set its Error to nil status := Status{ diff --git a/network/router/router.go b/network/router/router.go index 4fd53c07..715bcc56 100644 --- a/network/router/router.go +++ b/network/router/router.go @@ -41,19 +41,19 @@ type Router interface { // Option used by the router type Option func(*Options) -// UpdateType is route advertisement update type -type UpdateType int +// AdvertType is route advertisement type +type AdvertType int const ( // Announce is advertised when the router announces itself - Announce UpdateType = iota + Announce AdvertType = iota // Update advertises route updates Update ) // String returns string representation of update event -func (ut UpdateType) String() string { - switch ut { +func (at AdvertType) String() string { + switch at { case Announce: return "ANNOUNCE" case Update: @@ -67,6 +67,8 @@ func (ut UpdateType) String() string { type Advert struct { // ID is the router ID ID string + // Type is type of advert + Type AdvertType // Timestamp marks the time when the update is sent Timestamp time.Time // TTL is Advert TTL From 449aa0a3395b27f7d2de3b1a834e10e097ef0fb9 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Tue, 9 Jul 2019 15:01:52 +0100 Subject: [PATCH 127/287] Collect ANNOUNCE mesage events before adding default gateway. --- network/router/default.go | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/network/router/default.go b/network/router/default.go index 34462e6d..bcdca8e3 100644 --- a/network/router/default.go +++ b/network/router/default.go @@ -418,11 +418,23 @@ func (r *router) Advertise() (<-chan *Advert, error) { return nil, fmt.Errorf("failed adding routes: %s", err) } log.Logf("Routing table:\n%s", r.opts.Table) + // list routing table routes to announce routes, err := r.opts.Table.List() if err != nil { return nil, fmt.Errorf("failed listing routes: %s", err) } + // collect all the added routes before we attempt to add default gateway + events := make([]*table.Event, len(routes)) + for i, route := range routes { + event := &table.Event{ + Type: table.Insert, + Timestamp: time.Now(), + Route: route, + } + events[i] = event + } + // add default gateway into routing table if r.opts.Gateway != "" { // note, the only non-default value is the gateway @@ -491,17 +503,6 @@ func (r *router) Advertise() (<-chan *Advert, error) { r.wg.Add(1) go r.watchErrors(errChan) - // announce yourself with all the existing routes - events := make([]*table.Event, len(routes)) - for i, route := range routes { - event := &table.Event{ - Type: table.Insert, - Timestamp: time.Now(), - Route: route, - } - events[i] = event - } - // advertise your presence r.advertWg.Add(1) go r.advertEvents(Announce, events) From 70665e5a7de1b7c8b9a1aac81466928239843180 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Tue, 9 Jul 2019 15:45:42 +0100 Subject: [PATCH 128/287] Route has changed to accomodate Link, Service and Address --- network/router/default.go | 31 +++++------ network/router/options.go | 20 +++---- network/router/table/default.go | 45 ++++++++-------- network/router/table/default_test.go | 78 ++++++++++++++-------------- network/router/table/query.go | 46 ++++++++-------- network/router/table/route.go | 21 +++++--- network/router/table/watcher.go | 22 ++++---- 7 files changed, 132 insertions(+), 131 deletions(-) diff --git a/network/router/default.go b/network/router/default.go index bcdca8e3..82e24aba 100644 --- a/network/router/default.go +++ b/network/router/default.go @@ -105,11 +105,12 @@ func (r *router) manageServiceRoutes(service *registry.Service, action string) e // take route action on each service node for _, node := range service.Nodes { route := table.Route{ - Destination: service.Name, - Gateway: node.Address, - Router: r.opts.Address, - Network: r.opts.Network, - Metric: table.DefaultLocalMetric, + Service: service.Name, + Address: node.Address, + Gateway: "", + Network: r.opts.Network, + Link: table.DefaultLink, + Metric: table.DefaultLocalMetric, } switch action { case "insert", "create": @@ -439,11 +440,11 @@ func (r *router) Advertise() (<-chan *Advert, error) { if r.opts.Gateway != "" { // note, the only non-default value is the gateway route := table.Route{ - Destination: "*", - Gateway: r.opts.Gateway, - Router: "*", - Network: "*", - Metric: table.DefaultLocalMetric, + Service: "*", + Address: "*", + Gateway: r.opts.Gateway, + Network: "*", + Metric: table.DefaultLocalMetric, } if err := r.opts.Table.Add(route); err != nil { return nil, fmt.Errorf("failed adding default gateway route: %s", err) @@ -530,14 +531,8 @@ func (r *router) Update(a *Advert) error { }) for _, event := range events { - // we extract the route from advertisement and update the routing table - route := table.Route{ - Destination: event.Route.Destination, - Gateway: event.Route.Gateway, - Router: event.Route.Router, - Network: event.Route.Network, - Metric: event.Route.Metric, - } + // create a copy of the route + route := event.Route if err := r.opts.Table.Update(route); err != nil { return fmt.Errorf("failed updating routing table: %v", err) } diff --git a/network/router/options.go b/network/router/options.go index eb287075..96d956f6 100644 --- a/network/router/options.go +++ b/network/router/options.go @@ -10,7 +10,7 @@ var ( // DefaultAddress is default router address DefaultAddress = ":9093" // DefaultNetwork is default micro network - DefaultNetwork = "micro.mu" + DefaultNetwork = "go.micro" ) // Options are router options @@ -19,10 +19,10 @@ type Options struct { ID string // Address is router address Address string - // Network is micro network - Network string // Gateway is micro network gateway Gateway string + // Network is micro network + Network string // Registry is the local registry Registry registry.Registry // Table is routing table @@ -43,13 +43,6 @@ func Address(a string) Option { } } -// Network sets router network -func Network(n string) Option { - return func(o *Options) { - o.Network = n - } -} - // Gateway sets network gateway func Gateway(g string) Option { return func(o *Options) { @@ -57,6 +50,13 @@ func Gateway(g string) Option { } } +// Network sets router network +func Network(n string) Option { + return func(o *Options) { + o.Network = n + } +} + // RoutingTable sets the routing table func RoutingTable(t table.Table) Option { return func(o *Options) { diff --git a/network/router/table/default.go b/network/router/table/default.go index 7a95716c..54228404 100644 --- a/network/router/table/default.go +++ b/network/router/table/default.go @@ -57,23 +57,23 @@ func (t *table) Options() TableOptions { // Add adds a route to the routing table func (t *table) Add(r Route) error { - destAddr := r.Destination + service := r.Service sum := r.Hash() t.Lock() defer t.Unlock() // check if there are any routes in the table for the route destination - if _, ok := t.m[destAddr]; !ok { - t.m[destAddr] = make(map[uint64]Route) - t.m[destAddr][sum] = r + if _, ok := t.m[service]; !ok { + t.m[service] = make(map[uint64]Route) + t.m[service][sum] = r go t.sendEvent(&Event{Type: Insert, Route: r}) return nil } // add new route to the table for the route destination - if _, ok := t.m[destAddr][sum]; !ok { - t.m[destAddr][sum] = r + if _, ok := t.m[service][sum]; !ok { + t.m[service][sum] = r go t.sendEvent(&Event{Type: Insert, Route: r}) return nil } @@ -83,17 +83,17 @@ func (t *table) Add(r Route) error { // Delete deletes the route from the routing table func (t *table) Delete(r Route) error { - destAddr := r.Destination + service := r.Service sum := r.Hash() t.Lock() defer t.Unlock() - if _, ok := t.m[destAddr]; !ok { + if _, ok := t.m[service]; !ok { return ErrRouteNotFound } - delete(t.m[destAddr], sum) + delete(t.m[service], sum) go t.sendEvent(&Event{Type: Delete, Route: r}) return nil @@ -101,20 +101,20 @@ func (t *table) Delete(r Route) error { // Update updates routing table with the new route func (t *table) Update(r Route) error { - destAddr := r.Destination + service := r.Service sum := r.Hash() t.Lock() defer t.Unlock() // check if the route destination has any routes in the table - if _, ok := t.m[destAddr]; !ok { + if _, ok := t.m[service]; !ok { return ErrRouteNotFound } // if the route has been found update it - if _, ok := t.m[destAddr][sum]; ok { - t.m[destAddr][sum] = r + if _, ok := t.m[service][sum]; ok { + t.m[service][sum] = r go t.sendEvent(&Event{Type: Update, Route: r}) return nil } @@ -140,7 +140,7 @@ func (t *table) List() ([]Route, error) { // isMatch checks if the route matches given network and router func isMatch(route Route, network, router string) bool { if network == "*" || network == route.Network { - if router == "*" || router == route.Router { + if router == "*" || router == route.Gateway { return true } } @@ -163,18 +163,18 @@ func (t *table) Lookup(q Query) ([]Route, error) { t.RLock() defer t.RUnlock() - if q.Options().Destination != "*" { + if q.Options().Service != "*" { // no routes found for the destination and query policy is not a DiscardIfNone - if _, ok := t.m[q.Options().Destination]; !ok && q.Options().Policy != DiscardIfNone { + if _, ok := t.m[q.Options().Service]; !ok && q.Options().Policy != DiscardIfNone { return nil, ErrRouteNotFound } - return findRoutes(t.m[q.Options().Destination], q.Options().Network, q.Options().Router), nil + return findRoutes(t.m[q.Options().Service], q.Options().Network, q.Options().Gateway), nil } var results []Route // search through all destinations for _, routes := range t.m { - results = append(results, findRoutes(routes, q.Options().Network, q.Options().Router)...) + results = append(results, findRoutes(routes, q.Options().Network, q.Options().Gateway)...) } return results, nil @@ -184,7 +184,7 @@ func (t *table) Lookup(q Query) ([]Route, error) { func (t *table) Watch(opts ...WatchOption) (Watcher, error) { // by default watch everything wopts := WatchOptions{ - Destination: "*", + Service: "*", } for _, o := range opts { @@ -244,15 +244,16 @@ func (t *table) String() string { // create nice table printing structure table := tablewriter.NewWriter(sb) - table.SetHeader([]string{"Destination", "Gateway", "Router", "Network", "Metric"}) + table.SetHeader([]string{"Service", "Address", "Gateway", "Network", "Link", "Metric"}) for _, destRoute := range t.m { for _, route := range destRoute { strRoute := []string{ - route.Destination, + route.Service, + route.Address, route.Gateway, - route.Router, route.Network, + route.Link, fmt.Sprintf("%d", route.Metric), } table.Append(strRoute) diff --git a/network/router/table/default_test.go b/network/router/table/default_test.go index 6447cf03..3f7acdb6 100644 --- a/network/router/table/default_test.go +++ b/network/router/table/default_test.go @@ -6,11 +6,11 @@ func testSetup() (Table, Route) { table := NewTable() route := Route{ - Destination: "dest.svc", - Gateway: "dest.gw", - Router: "dest.router", - Network: "dest.network", - Metric: 10, + Service: "dest.svc", + Gateway: "dest.gw", + Network: "dest.network", + Link: "det.link", + Metric: 10, } return table, route @@ -34,7 +34,7 @@ func TestAdd(t *testing.T) { testTableSize += 1 if table.Size() != testTableSize { - t.Errorf("invalid number of routes. expected: %d, found: %d", testTableSize, table.Size()) + t.Errorf("invalid number of routes. Expected: %d, found: %d", testTableSize, table.Size()) } // adding the same route under Insert policy must error @@ -53,15 +53,15 @@ func TestDelete(t *testing.T) { testTableSize += 1 // should fail to delete non-existant route - prevDest := route.Destination - route.Destination = "randDest" + prevSvc := route.Service + route.Service = "randDest" if err := table.Delete(route); err != ErrRouteNotFound { - t.Errorf("error deleting route. Expected error: %s, found: %s", ErrRouteNotFound, err) + t.Errorf("error deleting route. Expected: %s, found: %s", ErrRouteNotFound, err) } // we should be able to delete the existing route - route.Destination = prevDest + route.Service = prevSvc if err := table.Delete(route); err != nil { t.Errorf("error deleting route: %s", err) @@ -69,7 +69,7 @@ func TestDelete(t *testing.T) { testTableSize -= 1 if table.Size() != testTableSize { - t.Errorf("invalid number of routes. expected: %d, found: %d", testTableSize, table.Size()) + t.Errorf("invalid number of routes. Expected: %d, found: %d", testTableSize, table.Size()) } } @@ -91,28 +91,28 @@ func TestUpdate(t *testing.T) { // the size of the table should not change as we're only updating the metric of an existing route if table.Size() != testTableSize { - t.Errorf("invalid number of routes. expected: %d, found: %d", testTableSize, table.Size()) + t.Errorf("invalid number of routes. Expected: %d, found: %d", testTableSize, table.Size()) } // this should error as the destination does not exist - route.Destination = "rand.dest" + route.Service = "rand.dest" if err := table.Update(route); err != ErrRouteNotFound { t.Errorf("error updating route. Expected error: %s, found: %s", ErrRouteNotFound, err) } if table.Size() != testTableSize { - t.Errorf("invalid number of routes. expected: %d, found: %d", testTableSize, table.Size()) + t.Errorf("invalid number of routes. Expected: %d, found: %d", testTableSize, table.Size()) } } func TestList(t *testing.T) { table, route := testSetup() - dest := []string{"one.svc", "two.svc", "three.svc"} + svc := []string{"one.svc", "two.svc", "three.svc"} - for i := 0; i < len(dest); i++ { - route.Destination = dest[i] + for i := 0; i < len(svc); i++ { + route.Service = svc[i] if err := table.Add(route); err != nil { t.Errorf("error adding route: %s", err) } @@ -123,26 +123,26 @@ func TestList(t *testing.T) { t.Errorf("error listing routes: %s", err) } - if len(routes) != len(dest) { - t.Errorf("incorrect number of routes listed. Expected: %d, found: %d", len(dest), len(routes)) + if len(routes) != len(svc) { + t.Errorf("incorrect number of routes listed. Expected: %d, found: %d", len(svc), len(routes)) } if len(routes) != table.Size() { - t.Errorf("mismatch number of routes and table size. Routes: %d, Size: %d", len(routes), table.Size()) + t.Errorf("mismatch number of routes and table size. Expected: %d, found: %d", len(routes), table.Size()) } } func TestLookup(t *testing.T) { table, route := testSetup() - dest := []string{"svc1", "svc2", "svc3"} + svc := []string{"svc1", "svc2", "svc3"} net := []string{"net1", "net2", "net1"} - rtr := []string{"router1", "router2", "router3"} + gw := []string{"gw1", "gw2", "gw3"} - for i := 0; i < len(dest); i++ { - route.Destination = dest[i] + for i := 0; i < len(svc); i++ { + route.Service = svc[i] route.Network = net[i] - route.Router = rtr[i] + route.Gateway = gw[i] if err := table.Add(route); err != nil { t.Errorf("error adding route: %s", err) } @@ -157,7 +157,7 @@ func TestLookup(t *testing.T) { } if len(routes) != table.Size() { - t.Errorf("incorrect number of routes returned. expected: %d, found: %d", table.Size(), len(routes)) + t.Errorf("incorrect number of routes returned. Expected: %d, found: %d", table.Size(), len(routes)) } // query particular net @@ -169,12 +169,12 @@ func TestLookup(t *testing.T) { } if len(routes) != 2 { - t.Errorf("incorrect number of routes returned. expected: %d, found: %d", 2, len(routes)) + t.Errorf("incorrect number of routes returned. Expected: %d, found: %d", 2, len(routes)) } - // query particular router - router := "router1" - query = NewQuery(QueryRouter(router)) + // query particular gateway + gateway := "gw1" + query = NewQuery(QueryGateway(gateway)) routes, err = table.Lookup(query) if err != nil { @@ -182,17 +182,17 @@ func TestLookup(t *testing.T) { } if len(routes) != 1 { - t.Errorf("incorrect number of routes returned. expected: %d, found: %d", 1, len(routes)) + t.Errorf("incorrect number of routes returned. Expected: %d, found: %d", 1, len(routes)) } - if routes[0].Router != router { - t.Errorf("incorrect route returned. Expected router: %s, found: %s", router, routes[0].Router) + if routes[0].Gateway != gateway { + t.Errorf("incorrect route returned. Expected gateway: %s, found: %s", gateway, routes[0].Gateway) } // query particular route network := "net1" query = NewQuery( - QueryRouter(router), + QueryGateway(gateway), QueryNetwork(network), ) @@ -202,11 +202,11 @@ func TestLookup(t *testing.T) { } if len(routes) != 1 { - t.Errorf("incorrect number of routes returned. expected: %d, found: %d", 1, len(routes)) + t.Errorf("incorrect number of routes returned. Expected: %d, found: %d", 1, len(routes)) } - if routes[0].Router != router { - t.Errorf("incorrect route returned. Expected router: %s, found: %s", router, routes[0].Router) + if routes[0].Gateway != gateway { + t.Errorf("incorrect route returned. Expected gateway: %s, found: %s", gateway, routes[0].Gateway) } if routes[0].Network != network { @@ -214,7 +214,7 @@ func TestLookup(t *testing.T) { } // bullshit route query - query = NewQuery(QueryDestination("foobar")) + query = NewQuery(QueryService("foobar")) routes, err = table.Lookup(query) if err != nil { @@ -222,6 +222,6 @@ func TestLookup(t *testing.T) { } if len(routes) != 0 { - t.Errorf("incorrect number of routes returned. expected: %d, found: %d", 0, len(routes)) + t.Errorf("incorrect number of routes returned. Expected: %d, found: %d", 0, len(routes)) } } diff --git a/network/router/table/query.go b/network/router/table/query.go index 42b44db6..82afd5ff 100644 --- a/network/router/table/query.go +++ b/network/router/table/query.go @@ -34,34 +34,34 @@ type QueryOption func(*QueryOptions) // QueryOptions are routing table query options type QueryOptions struct { - // Destination is destination address - Destination string + // Service is destination service name + Service string + // Gateway is route gateway + Gateway string // Network is network address Network string - // Router is router address - Router string // Policy is query lookup policy Policy LookupPolicy } -// QueryDestination sets destination address -func QueryDestination(d string) QueryOption { +// QueryService sets destination address +func QueryService(s string) QueryOption { return func(o *QueryOptions) { - o.Destination = d + o.Service = s + } +} + +// QueryGateway sets route gateway +func QueryGateway(g string) QueryOption { + return func(o *QueryOptions) { + o.Gateway = g } } // QueryNetwork sets route network address -func QueryNetwork(a string) QueryOption { +func QueryNetwork(n string) QueryOption { return func(o *QueryOptions) { - o.Network = a - } -} - -// QueryRouter sets route router address -func QueryRouter(r string) QueryOption { - return func(o *QueryOptions) { - o.Router = r + o.Network = n } } @@ -89,10 +89,10 @@ func NewQuery(opts ...QueryOption) Query { // default options // NOTE: by default we use DefaultNetworkMetric qopts := QueryOptions{ - Destination: "*", - Router: "*", - Network: "*", - Policy: DiscardIfNone, + Service: "*", + Gateway: "*", + Network: "*", + Policy: DiscardIfNone, } for _, o := range opts { @@ -116,12 +116,12 @@ func (q query) String() string { // create nice table printing structure table := tablewriter.NewWriter(sb) - table.SetHeader([]string{"Destination", "Network", "Router", "Policy"}) + table.SetHeader([]string{"Service", "Gateway", "Network", "Policy"}) strQuery := []string{ - q.opts.Destination, + q.opts.Service, + q.opts.Gateway, q.opts.Network, - q.opts.Router, fmt.Sprintf("%s", q.opts.Policy), } table.Append(strQuery) diff --git a/network/router/table/route.go b/network/router/table/route.go index cbb32bf1..0054b3b9 100644 --- a/network/router/table/route.go +++ b/network/router/table/route.go @@ -9,6 +9,8 @@ import ( ) var ( + // DefaultLink is default network link + DefaultLink = "local" // DefaultLocalMetric is default route cost metric for the local network DefaultLocalMetric = 1 // DefaultNetworkMetric is default route cost metric for the micro network @@ -17,14 +19,16 @@ var ( // Route is network route type Route struct { - // Destination is destination address - Destination string + // Service is destination service name + Service string + // Address is service node address + Address string // Gateway is route gateway Gateway string // Network is network address Network string - // Router is the router address - Router string + // Link is network link + Link string // Metric is the route cost metric Metric int } @@ -33,7 +37,7 @@ type Route struct { func (r *Route) Hash() uint64 { h := fnv.New64() h.Reset() - h.Write([]byte(r.Destination + r.Gateway + r.Network)) + h.Write([]byte(r.Service + r.Address + r.Gateway + r.Network + r.Link)) return h.Sum64() } @@ -45,13 +49,14 @@ func (r Route) String() string { // create nice table printing structure table := tablewriter.NewWriter(sb) - table.SetHeader([]string{"Destination", "Gateway", "Router", "Network", "Metric"}) + table.SetHeader([]string{"Service", "Address", "Gateway", "Network", "Link", "Metric"}) strRoute := []string{ - r.Destination, + r.Service, + r.Address, r.Gateway, - r.Router, r.Network, + r.Link, fmt.Sprintf("%d", r.Metric), } table.Append(strRoute) diff --git a/network/router/table/watcher.go b/network/router/table/watcher.go index 90e46360..391c0a0c 100644 --- a/network/router/table/watcher.go +++ b/network/router/table/watcher.go @@ -53,7 +53,7 @@ type Event struct { // String prints human readable Event func (e Event) String() string { - return fmt.Sprintf("[EVENT] %s:\nRoute:\n%s", e.Type, e.Route) + return fmt.Sprintf("[EVENT] time: %s type: %s", e.Timestamp, e.Type) } // WatchOption is used to define what routes to watch in the table @@ -72,15 +72,15 @@ type Watcher interface { // WatchOptions are table watcher options type WatchOptions struct { - // Specify destination address to watch - Destination string + // Service allows to watch specific service routes + Service string } -// WatchDestination sets what destination to watch -// Destination is usually microservice name -func WatchDestination(d string) WatchOption { +// WatchService sets what service routes to watch +// Service is the microservice name +func WatchService(s string) WatchOption { return func(o *WatchOptions) { - o.Destination = d + o.Service = s } } @@ -97,8 +97,8 @@ func (w *tableWatcher) Next() (*Event, error) { for { select { case res := <-w.resChan: - switch w.opts.Destination { - case res.Route.Destination, "*": + switch w.opts.Service { + case res.Route.Service, "*": return res, nil default: log.Logf("no table watcher available to receive the event") @@ -130,10 +130,10 @@ func (w tableWatcher) String() string { sb := &strings.Builder{} table := tablewriter.NewWriter(sb) - table.SetHeader([]string{"Destination"}) + table.SetHeader([]string{"Service"}) data := []string{ - w.opts.Destination, + w.opts.Service, } table.Append(data) From c5fb409760dc152f31881c5cfbca3223dc4c1f79 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Tue, 9 Jul 2019 15:55:39 +0100 Subject: [PATCH 129/287] Removed debug logs --- network/router/default.go | 37 ++------------------------------- network/router/table/default.go | 5 ----- network/router/table/watcher.go | 2 -- 3 files changed, 2 insertions(+), 42 deletions(-) diff --git a/network/router/default.go b/network/router/default.go index 82e24aba..d8ad3a60 100644 --- a/network/router/default.go +++ b/network/router/default.go @@ -8,7 +8,6 @@ import ( "sync" "time" - "github.com/micro/go-log" "github.com/micro/go-micro/network/router/table" "github.com/micro/go-micro/registry" "github.com/olekukonko/tablewriter" @@ -141,7 +140,6 @@ func (r *router) manageRegistryRoutes(reg registry.Registry, action string) erro // get the service to retrieve all its info srvs, err := reg.GetService(service.Name) if err != nil { - log.Logf("r.manageRegistryRoutes() GetService() error: %v", err) continue } // manage the routes for all returned services @@ -178,8 +176,6 @@ func (r *router) watchServices(w registry.Watcher) error { break } - log.Logf("r.watchServices() new service event: Action: %s Service: %v", res.Action, res.Service) - if err := r.manageServiceRoutes(res.Service, res.Action); err != nil { return err } @@ -211,8 +207,6 @@ func (r *router) watchTable(w table.Watcher) error { break } - log.Logf("r.watchTable() new table event: %s", event) - select { case <-r.exit: close(r.eventChan) @@ -230,8 +224,6 @@ func (r *router) watchTable(w table.Watcher) error { func (r *router) advertEvents(advType AdvertType, events []*table.Event) { defer r.advertWg.Done() - log.Logf("r.advertEvents(): start event: %s", advType) - a := &Advert{ ID: r.ID(), Type: advType, @@ -241,24 +233,19 @@ func (r *router) advertEvents(advType AdvertType, events []*table.Event) { select { case r.advertChan <- a: - log.Logf("r.advertEvents(): advertised event: %s", advType) case <-r.exit: - log.Logf("r.advertEvents(): DONE exit") return } - log.Logf("r.advertEvents(): REGULAR exit") } // isFlapping detects if the event is flapping based on the current and previous event status. func isFlapping(curr, prev *table.Event) bool { if curr.Type == table.Update && prev.Type == table.Update { - log.Logf("isFlapping(): Update flap") return true } if curr.Type == table.Insert && prev.Type == table.Delete || curr.Type == table.Delete && prev.Type == table.Insert { - log.Logf("isFlapping(): Create/Delete flap") return true } @@ -312,7 +299,7 @@ func (r *router) processEvents() error { if e == nil { continue } - log.Logf("r.processEvents(): event received:\n%s", e) + // determine the event penalty var penalty float64 switch e.Type { @@ -337,6 +324,7 @@ func (r *router) processEvents() error { delta := time.Since(event.timestamp).Seconds() event.penalty = event.penalty*math.Exp(-delta) + penalty event.timestamp = now + // suppress or recover the event based on its current penalty if !event.isSuppressed && event.penalty > AdvertSuppress { event.isSuppressed = true @@ -353,13 +341,11 @@ func (r *router) processEvents() error { r.advertWg.Wait() // close the advert channel close(r.advertChan) - log.Logf("r.processEvents(): event processor stopped") return nil } } // we probably never reach this place - log.Logf("r.processEvents(): event processor stopped") return nil } @@ -368,8 +354,6 @@ func (r *router) processEvents() error { func (r *router) watchErrors(errChan <-chan error) { defer r.wg.Done() - log.Logf("r.manage(): manage start") - var code StatusCode var err error @@ -380,8 +364,6 @@ func (r *router) watchErrors(errChan <-chan error) { code = Error } - log.Logf("r.watchErrors(): watchErrors exiting") - r.Lock() defer r.Unlock() status := Status{ @@ -397,14 +379,11 @@ func (r *router) watchErrors(errChan <-chan error) { // drain the advertise channel for range r.advertChan { } - log.Logf("r.watchErrors(): advert channel drained") // drain the event channel for range r.eventChan { } - log.Logf("r.watchErrors(): event channel drained") } - log.Logf("r.watchErrors(): watchErrors exit") } // Advertise advertises the routes to the network. @@ -418,7 +397,6 @@ func (r *router) Advertise() (<-chan *Advert, error) { if err := r.manageRegistryRoutes(r.opts.Registry, "insert"); err != nil { return nil, fmt.Errorf("failed adding routes: %s", err) } - log.Logf("Routing table:\n%s", r.opts.Table) // list routing table routes to announce routes, err := r.opts.Table.List() @@ -476,28 +454,22 @@ func (r *router) Advertise() (<-chan *Advert, error) { r.wg.Add(1) go func() { defer r.wg.Done() - log.Logf("r.Advertise(): r.watchServices() start") // watch local registry and register routes in routine table errChan <- r.watchServices(svcWatcher) - log.Logf("r.Advertise(): r.watchServices() exit") }() r.wg.Add(1) go func() { defer r.wg.Done() - log.Logf("r.Advertise(): r.watchTable() start") // watch local registry and register routes in routing table errChan <- r.watchTable(tableWatcher) - log.Logf("r.Advertise(): r.watchTable() exit") }() r.wg.Add(1) go func() { defer r.wg.Done() - log.Logf("r.Advertise(): r.processEvents() start") // listen to routing table events and process them errChan <- r.processEvents() - log.Logf("r.Advertise(): r.processEvents() exit") }() // watch for errors and cleanup @@ -554,28 +526,23 @@ func (r *router) Status() Status { // Stop stops the router func (r *router) Stop() error { - log.Logf("r.Stop(): Stopping router") r.RLock() // only close the channel if the router is running if r.status.Code == Running { // notify all goroutines to finish close(r.exit) - log.Logf("r.Stop(): exit closed") // drain the advertise channel for range r.advertChan { } - log.Logf("r.Stop(): advert channel drained") // drain the event channel for range r.eventChan { } - log.Logf("r.Stop(): event channel drained") } r.RUnlock() // wait for all goroutines to finish r.wg.Wait() - log.Logf("r.Stop(): Router stopped") return nil } diff --git a/network/router/table/default.go b/network/router/table/default.go index 54228404..79416dc1 100644 --- a/network/router/table/default.go +++ b/network/router/table/default.go @@ -6,7 +6,6 @@ import ( "sync" "github.com/google/uuid" - "github.com/micro/go-log" "github.com/olekukonko/tablewriter" ) @@ -209,16 +208,12 @@ func (t *table) sendEvent(r *Event) { t.RLock() defer t.RUnlock() - log.Logf("sending event to %d registered table watchers", len(t.w)) - for _, w := range t.w { select { case w.resChan <- r: case <-w.done: } } - - log.Logf("sending event done") } // Size returns the size of the routing table diff --git a/network/router/table/watcher.go b/network/router/table/watcher.go index 391c0a0c..773593e4 100644 --- a/network/router/table/watcher.go +++ b/network/router/table/watcher.go @@ -6,7 +6,6 @@ import ( "strings" "time" - "github.com/micro/go-log" "github.com/olekukonko/tablewriter" ) @@ -101,7 +100,6 @@ func (w *tableWatcher) Next() (*Event, error) { case res.Route.Service, "*": return res, nil default: - log.Logf("no table watcher available to receive the event") continue } case <-w.done: From 23cb811f60e9a84199e03f65422e14a37e3f96e0 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Tue, 9 Jul 2019 16:17:18 +0100 Subject: [PATCH 130/287] Removed fmt.Stringer artistry from all roouter and table structs --- network/router/default.go | 22 ++------------------- network/router/table/default.go | 34 ++------------------------------- network/router/table/query.go | 27 +------------------------- network/router/table/route.go | 26 +------------------------ network/router/table/watcher.go | 18 +---------------- 5 files changed, 7 insertions(+), 120 deletions(-) diff --git a/network/router/default.go b/network/router/default.go index d8ad3a60..c37fd49d 100644 --- a/network/router/default.go +++ b/network/router/default.go @@ -10,7 +10,6 @@ import ( "github.com/micro/go-micro/network/router/table" "github.com/micro/go-micro/registry" - "github.com/olekukonko/tablewriter" ) const ( @@ -547,23 +546,6 @@ func (r *router) Stop() error { } // String prints debugging information about router -func (r *router) String() string { - sb := &strings.Builder{} - - table := tablewriter.NewWriter(sb) - table.SetHeader([]string{"ID", "Address", "Network", "Table", "Status"}) - - data := []string{ - r.opts.ID, - r.opts.Address, - r.opts.Network, - fmt.Sprintf("%d", r.opts.Table.Size()), - r.status.Code.String(), - } - table.Append(data) - - // render table into sb - table.Render() - - return sb.String() +func (r router) String() string { + return "router" } diff --git a/network/router/table/default.go b/network/router/table/default.go index 79416dc1..76de3f97 100644 --- a/network/router/table/default.go +++ b/network/router/table/default.go @@ -1,12 +1,9 @@ package table import ( - "fmt" - "strings" "sync" "github.com/google/uuid" - "github.com/olekukonko/tablewriter" ) // TableOptions specify routing table options @@ -230,33 +227,6 @@ func (t *table) Size() int { } // String returns debug information -func (t *table) String() string { - t.RLock() - defer t.RUnlock() - - // this will help us build routing table string - sb := &strings.Builder{} - - // create nice table printing structure - table := tablewriter.NewWriter(sb) - table.SetHeader([]string{"Service", "Address", "Gateway", "Network", "Link", "Metric"}) - - for _, destRoute := range t.m { - for _, route := range destRoute { - strRoute := []string{ - route.Service, - route.Address, - route.Gateway, - route.Network, - route.Link, - fmt.Sprintf("%d", route.Metric), - } - table.Append(strRoute) - } - } - - // render table into sb - table.Render() - - return sb.String() +func (t table) String() string { + return "table" } diff --git a/network/router/table/query.go b/network/router/table/query.go index 82afd5ff..7703e3b3 100644 --- a/network/router/table/query.go +++ b/network/router/table/query.go @@ -1,12 +1,5 @@ package table -import ( - "fmt" - "strings" - - "github.com/olekukonko/tablewriter" -) - // LookupPolicy defines query policy type LookupPolicy int @@ -111,23 +104,5 @@ func (q *query) Options() QueryOptions { // String prints routing table query in human readable form func (q query) String() string { - // this will help us build routing table string - sb := &strings.Builder{} - - // create nice table printing structure - table := tablewriter.NewWriter(sb) - table.SetHeader([]string{"Service", "Gateway", "Network", "Policy"}) - - strQuery := []string{ - q.opts.Service, - q.opts.Gateway, - q.opts.Network, - fmt.Sprintf("%s", q.opts.Policy), - } - table.Append(strQuery) - - // render table into sb - table.Render() - - return sb.String() + return "query" } diff --git a/network/router/table/route.go b/network/router/table/route.go index 0054b3b9..652abd28 100644 --- a/network/router/table/route.go +++ b/network/router/table/route.go @@ -1,11 +1,7 @@ package table import ( - "fmt" "hash/fnv" - "strings" - - "github.com/olekukonko/tablewriter" ) var ( @@ -44,25 +40,5 @@ func (r *Route) Hash() uint64 { // String returns human readable route func (r Route) String() string { - // this will help us build routing table string - sb := &strings.Builder{} - - // create nice table printing structure - table := tablewriter.NewWriter(sb) - table.SetHeader([]string{"Service", "Address", "Gateway", "Network", "Link", "Metric"}) - - strRoute := []string{ - r.Service, - r.Address, - r.Gateway, - r.Network, - r.Link, - fmt.Sprintf("%d", r.Metric), - } - table.Append(strRoute) - - // render table into sb - table.Render() - - return sb.String() + return "route" } diff --git a/network/router/table/watcher.go b/network/router/table/watcher.go index 773593e4..c089ddfc 100644 --- a/network/router/table/watcher.go +++ b/network/router/table/watcher.go @@ -3,10 +3,7 @@ package table import ( "errors" "fmt" - "strings" "time" - - "github.com/olekukonko/tablewriter" ) var ( @@ -125,18 +122,5 @@ func (w *tableWatcher) Stop() { // String prints debug information func (w tableWatcher) String() string { - sb := &strings.Builder{} - - table := tablewriter.NewWriter(sb) - table.SetHeader([]string{"Service"}) - - data := []string{ - w.opts.Service, - } - table.Append(data) - - // render table into sb - table.Render() - - return sb.String() + return "watcher" } From d725980444c7ee44828dba5d1f24c610cf365013 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 9 Jul 2019 16:37:59 +0100 Subject: [PATCH 131/287] add some initialisers --- network/default.go | 14 ++++++++++++-- network/network.go | 17 +++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/network/default.go b/network/default.go index 626f9281..c8ab8fc2 100644 --- a/network/default.go +++ b/network/default.go @@ -18,6 +18,9 @@ type network struct { // name of the network name string + // network address used where one is specified + address string + // transport transport transport.Transport } @@ -34,15 +37,16 @@ type listener struct { } func (n *network) Create() (*Node, error) { - ip, err := addr.Extract("") + ip, err := addr.Extract(n.address) if err != nil { return nil, err } return &Node{ Id: fmt.Sprintf("%s-%s", n.name, uuid.New().String()), Address: ip, + Network: n.Name(), Metadata: map[string]string{ - "network": n.Name(), + "network": n.String(), "transport": n.transport.String(), }, }, nil @@ -140,6 +144,12 @@ func newNetwork(opts ...options.Option) *network { net.name = name.(string) } + // get network name + address, ok := options.Values().Get("network.address") + if ok { + net.address = address.(string) + } + // get network transport t, ok := options.Values().Get("network.transport") if ok { diff --git a/network/network.go b/network/network.go index 3198bf3f..b7f7357c 100644 --- a/network/network.go +++ b/network/network.go @@ -3,6 +3,7 @@ package network import ( "github.com/micro/go-micro/config/options" + "github.com/micro/go-micro/network/transport" ) // Network defines a network interface. The network is a single @@ -25,6 +26,7 @@ type Network interface { type Node struct { Id string Address string + Network string Metadata map[string]string } @@ -69,3 +71,18 @@ var ( func NewNetwork(opts ...options.Option) Network { return newNetwork(opts...) } + +// Name sets the network name +func Name(n string) options.Option { + return options.WithValue("network.name", n) +} + +// Address sets the network address +func Address(a string) options.Option { + return options.WithValue("network.address", a) +} + +// Transport sets the network transport +func Transport(t transport.Transport) options.Option { + return options.WithValue("network.transport", t) +} From c5214c931f4f3239f13b70edf29cad7f474980fb Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 9 Jul 2019 16:38:44 +0100 Subject: [PATCH 132/287] reorder and reword --- network/network.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/network/network.go b/network/network.go index b7f7357c..164c8a98 100644 --- a/network/network.go +++ b/network/network.go @@ -11,10 +11,10 @@ import ( // is responsible for routing messages to the correct services. type Network interface { options.Options - // Create starts the network and creates a new node - Create() (*Node, error) // Name of the network Name() string + // Create returns a new network node id/address + Create() (*Node, error) // Connect to a node on the network Connect(*Node) (Conn, error) // Listen for connections for this node From 327029beffa447a0226be109345ee562fba4d545 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 9 Jul 2019 16:44:43 +0100 Subject: [PATCH 133/287] fix string method --- network/default.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/network/default.go b/network/default.go index c8ab8fc2..494ecbd2 100644 --- a/network/default.go +++ b/network/default.go @@ -56,6 +56,10 @@ func (n *network) Name() string { return n.name } +func (n *network) String() string { + return "local" +} + func (n *network) Connect(node *Node) (Conn, error) { c, err := n.transport.Dial(node.Address) if err != nil { From 6cf8bde6128ada66986effa8887c245568a8480d Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Tue, 9 Jul 2019 16:45:31 +0100 Subject: [PATCH 134/287] Router selector and proxy modifications due to Route struct changes. --- client/selector/router/router.go | 15 +-- network/proxy/mucp/mucp.go | 15 +-- network/router/proto/router.micro.go | 2 +- network/router/proto/router.pb.go | 164 ++++++++------------------- network/router/proto/router.proto | 16 +-- 5 files changed, 74 insertions(+), 138 deletions(-) diff --git a/client/selector/router/router.go b/client/selector/router/router.go index 65e69702..14146fba 100644 --- a/client/selector/router/router.go +++ b/client/selector/router/router.go @@ -45,7 +45,7 @@ func (r *routerSelector) getRoutes(service string) ([]table.Route, error) { if !r.remote { // lookup router for routes for the service return r.r.Table().Lookup(table.NewQuery( - table.QueryDestination(service), + table.QueryService(service), )) } @@ -83,7 +83,7 @@ func (r *routerSelector) getRoutes(service string) ([]table.Route, error) { // call the router pbRoutes, err = r.rs.Lookup(context.Background(), &pb.LookupRequest{ Query: &pb.Query{ - Destination: service, + Service: service, }, }, client.WithAddress(addr)) if err != nil { @@ -107,11 +107,12 @@ func (r *routerSelector) getRoutes(service string) ([]table.Route, error) { // convert from pb to []*router.Route for _, r := range pbRoutes.Routes { routes = append(routes, table.Route{ - Destination: r.Destination, - Gateway: r.Gateway, - Router: r.Router, - Network: r.Network, - Metric: int(r.Metric), + Service: r.Service, + Address: r.Address, + Gateway: r.Gateway, + Network: r.Network, + Link: r.Link, + Metric: int(r.Metric), }) } diff --git a/network/proxy/mucp/mucp.go b/network/proxy/mucp/mucp.go index d0ecb81f..05880fc9 100644 --- a/network/proxy/mucp/mucp.go +++ b/network/proxy/mucp/mucp.go @@ -107,7 +107,7 @@ func (p *Proxy) getRoute(service string) ([]string, error) { if p.Router != nil { // lookup the router routes, err := p.Router.Table().Lookup( - table.NewQuery(table.QueryDestination(service)), + table.NewQuery(table.QueryService(service)), ) if err != nil { return nil, err @@ -180,7 +180,7 @@ func (p *Proxy) getRoute(service string) ([]string, error) { // call the router proutes, err := p.RouterService.Lookup(context.Background(), &pb.LookupRequest{ Query: &pb.Query{ - Destination: service, + Service: service, }, }, client.WithAddress(addr)) if err != nil { @@ -205,11 +205,12 @@ func (p *Proxy) getRoute(service string) ([]string, error) { // convert from pb to []*router.Route for _, r := range pbRoutes.Routes { routes = append(routes, table.Route{ - Destination: r.Destination, - Gateway: r.Gateway, - Router: r.Router, - Network: r.Network, - Metric: int(r.Metric), + Service: r.Service, + Address: r.Address, + Gateway: r.Gateway, + Network: r.Network, + Link: r.Link, + Metric: int(r.Metric), }) } diff --git a/network/router/proto/router.micro.go b/network/router/proto/router.micro.go index 06736f82..9c4fdb1e 100644 --- a/network/router/proto/router.micro.go +++ b/network/router/proto/router.micro.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-micro. DO NOT EDIT. -// source: go-micro/network/router/proto/router.proto +// source: router.proto package router diff --git a/network/router/proto/router.pb.go b/network/router/proto/router.pb.go index d0aff457..d7d7a520 100644 --- a/network/router/proto/router.pb.go +++ b/network/router/proto/router.pb.go @@ -1,13 +1,11 @@ // Code generated by protoc-gen-go. DO NOT EDIT. -// source: go-micro/network/router/proto/router.proto +// source: router.proto package router import ( - context "context" fmt "fmt" proto "github.com/golang/protobuf/proto" - grpc "google.golang.org/grpc" math "math" ) @@ -34,7 +32,7 @@ func (m *LookupRequest) Reset() { *m = LookupRequest{} } func (m *LookupRequest) String() string { return proto.CompactTextString(m) } func (*LookupRequest) ProtoMessage() {} func (*LookupRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{0} + return fileDescriptor_367072455c71aedc, []int{0} } func (m *LookupRequest) XXX_Unmarshal(b []byte) error { @@ -74,7 +72,7 @@ func (m *LookupResponse) Reset() { *m = LookupResponse{} } func (m *LookupResponse) String() string { return proto.CompactTextString(m) } func (*LookupResponse) ProtoMessage() {} func (*LookupResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{1} + return fileDescriptor_367072455c71aedc, []int{1} } func (m *LookupResponse) XXX_Unmarshal(b []byte) error { @@ -104,8 +102,8 @@ func (m *LookupResponse) GetRoutes() []*Route { // Query is passed in a LookupRequest type Query struct { - // destination to lookup - Destination string `protobuf:"bytes,1,opt,name=destination,proto3" json:"destination,omitempty"` + // service to lookup + Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -115,7 +113,7 @@ func (m *Query) Reset() { *m = Query{} } func (m *Query) String() string { return proto.CompactTextString(m) } func (*Query) ProtoMessage() {} func (*Query) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{2} + return fileDescriptor_367072455c71aedc, []int{2} } func (m *Query) XXX_Unmarshal(b []byte) error { @@ -136,9 +134,9 @@ func (m *Query) XXX_DiscardUnknown() { var xxx_messageInfo_Query proto.InternalMessageInfo -func (m *Query) GetDestination() string { +func (m *Query) GetService() string { if m != nil { - return m.Destination + return m.Service } return "" } @@ -146,15 +144,17 @@ func (m *Query) GetDestination() string { // Route is a service route type Route struct { // service for the route - Destination string `protobuf:"bytes,1,opt,name=destination,proto3" json:"destination,omitempty"` + Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` + // the address that advertise this route + Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` // gateway as the next hop - Gateway string `protobuf:"bytes,2,opt,name=gateway,proto3" json:"gateway,omitempty"` - // the router that advertise this route - Router string `protobuf:"bytes,3,opt,name=router,proto3" json:"router,omitempty"` + Gateway string `protobuf:"bytes,3,opt,name=gateway,proto3" json:"gateway,omitempty"` // the network for this destination Network string `protobuf:"bytes,4,opt,name=network,proto3" json:"network,omitempty"` + // the network link + Link string `protobuf:"bytes,5,opt,name=link,proto3" json:"link,omitempty"` // the metric / score of this route - Metric int64 `protobuf:"varint,5,opt,name=metric,proto3" json:"metric,omitempty"` + Metric int64 `protobuf:"varint,6,opt,name=metric,proto3" json:"metric,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -164,7 +164,7 @@ func (m *Route) Reset() { *m = Route{} } func (m *Route) String() string { return proto.CompactTextString(m) } func (*Route) ProtoMessage() {} func (*Route) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{3} + return fileDescriptor_367072455c71aedc, []int{3} } func (m *Route) XXX_Unmarshal(b []byte) error { @@ -185,9 +185,16 @@ func (m *Route) XXX_DiscardUnknown() { var xxx_messageInfo_Route proto.InternalMessageInfo -func (m *Route) GetDestination() string { +func (m *Route) GetService() string { if m != nil { - return m.Destination + return m.Service + } + return "" +} + +func (m *Route) GetAddress() string { + if m != nil { + return m.Address } return "" } @@ -199,16 +206,16 @@ func (m *Route) GetGateway() string { return "" } -func (m *Route) GetRouter() string { +func (m *Route) GetNetwork() string { if m != nil { - return m.Router + return m.Network } return "" } -func (m *Route) GetNetwork() string { +func (m *Route) GetLink() string { if m != nil { - return m.Network + return m.Link } return "" } @@ -227,98 +234,23 @@ func init() { proto.RegisterType((*Route)(nil), "Route") } -func init() { - proto.RegisterFile("go-micro/network/router/proto/router.proto", fileDescriptor_fc08514fc6dadd29) -} - -var fileDescriptor_fc08514fc6dadd29 = []byte{ - // 242 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x90, 0xc1, 0x4a, 0xc3, 0x40, - 0x10, 0x86, 0x5d, 0x63, 0x56, 0x9c, 0x62, 0x85, 0x3d, 0xc8, 0x22, 0x22, 0x61, 0x4f, 0x55, 0x69, - 0x22, 0x15, 0xdf, 0xc2, 0x8b, 0xfb, 0x06, 0xb1, 0x0e, 0x25, 0x94, 0x66, 0xd2, 0xdd, 0x09, 0xa5, - 0x0f, 0xe1, 0x3b, 0x4b, 0x26, 0x5b, 0x30, 0xa7, 0x1e, 0xbf, 0x99, 0xf9, 0x7e, 0x76, 0x7f, 0x78, - 0xd9, 0xd0, 0x72, 0xd7, 0xac, 0x03, 0x55, 0x2d, 0xf2, 0x81, 0xc2, 0xb6, 0x0a, 0xd4, 0x33, 0x86, - 0xaa, 0x0b, 0xc4, 0x94, 0xa0, 0x14, 0x70, 0x4b, 0xb8, 0xfd, 0x24, 0xda, 0xf6, 0x9d, 0xc7, 0x7d, - 0x8f, 0x91, 0xcd, 0x23, 0xe4, 0xfb, 0x1e, 0xc3, 0xd1, 0xaa, 0x42, 0x2d, 0x66, 0x2b, 0x5d, 0x7e, - 0x0d, 0xe4, 0xc7, 0xa1, 0x7b, 0x83, 0xf9, 0xe9, 0x3c, 0x76, 0xd4, 0x46, 0x34, 0x4f, 0xa0, 0x25, - 0x30, 0x5a, 0x55, 0x64, 0x22, 0xf8, 0x01, 0x7d, 0x9a, 0xba, 0x67, 0xc8, 0x25, 0xc1, 0x14, 0x30, - 0xfb, 0xc1, 0xc8, 0x4d, 0x5b, 0x73, 0x43, 0xad, 0xc4, 0xdf, 0xf8, 0xff, 0x23, 0xf7, 0xab, 0x20, - 0x17, 0xf9, 0xfc, 0xad, 0xb1, 0x70, 0xbd, 0xa9, 0x19, 0x0f, 0xf5, 0xd1, 0x5e, 0xca, 0xf6, 0x84, - 0xe6, 0x3e, 0x3d, 0x28, 0xd8, 0x4c, 0x16, 0x89, 0x06, 0x23, 0xd5, 0x61, 0xaf, 0x46, 0x23, 0xe1, - 0x60, 0xec, 0x90, 0x43, 0xb3, 0xb6, 0x79, 0xa1, 0x16, 0x99, 0x4f, 0xb4, 0xfa, 0x00, 0xed, 0x47, - 0xf7, 0x15, 0xf4, 0xf8, 0x6d, 0x33, 0x2f, 0x27, 0x75, 0x3d, 0xdc, 0x95, 0xd3, 0x3e, 0xdc, 0xc5, - 0xb7, 0x96, 0x66, 0xdf, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0x4d, 0x73, 0x18, 0x9e, 0x87, 0x01, - 0x00, 0x00, -} - -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConn - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 - -// RouterClient is the client API for Router service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type RouterClient interface { - Lookup(ctx context.Context, in *LookupRequest, opts ...grpc.CallOption) (*LookupResponse, error) -} - -type routerClient struct { - cc *grpc.ClientConn -} - -func NewRouterClient(cc *grpc.ClientConn) RouterClient { - return &routerClient{cc} -} - -func (c *routerClient) Lookup(ctx context.Context, in *LookupRequest, opts ...grpc.CallOption) (*LookupResponse, error) { - out := new(LookupResponse) - err := c.cc.Invoke(ctx, "/Router/Lookup", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// RouterServer is the server API for Router service. -type RouterServer interface { - Lookup(context.Context, *LookupRequest) (*LookupResponse, error) -} - -func RegisterRouterServer(s *grpc.Server, srv RouterServer) { - s.RegisterService(&_Router_serviceDesc, srv) -} - -func _Router_Lookup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(LookupRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(RouterServer).Lookup(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/Router/Lookup", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(RouterServer).Lookup(ctx, req.(*LookupRequest)) - } - return interceptor(ctx, in, info, handler) -} - -var _Router_serviceDesc = grpc.ServiceDesc{ - ServiceName: "Router", - HandlerType: (*RouterServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Lookup", - Handler: _Router_Lookup_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "go-micro/network/router/proto/router.proto", +func init() { proto.RegisterFile("router.proto", fileDescriptor_367072455c71aedc) } + +var fileDescriptor_367072455c71aedc = []byte{ + // 238 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x90, 0xc1, 0x4a, 0xc4, 0x30, + 0x10, 0x86, 0x8d, 0xdd, 0x46, 0x1c, 0x75, 0x85, 0x1c, 0x24, 0x88, 0x48, 0xcd, 0x69, 0x41, 0x2c, + 0xb2, 0xe2, 0x5b, 0x78, 0x31, 0x6f, 0x50, 0x77, 0x07, 0x29, 0xd5, 0xa6, 0x3b, 0x49, 0x5c, 0xf6, + 0x59, 0x7c, 0x59, 0xc9, 0x24, 0x7b, 0xe8, 0xc1, 0x5b, 0xbf, 0xf9, 0x66, 0x7e, 0x9a, 0x1f, 0x2e, + 0xc9, 0xc5, 0x80, 0xd4, 0x4e, 0xe4, 0x82, 0x33, 0x4f, 0x70, 0xf5, 0xe6, 0xdc, 0x10, 0x27, 0x8b, + 0xbb, 0x88, 0x3e, 0xa8, 0x3b, 0xa8, 0x77, 0x11, 0xe9, 0xa0, 0x45, 0x23, 0x56, 0x17, 0x6b, 0xd9, + 0xbe, 0x27, 0xb2, 0x79, 0x68, 0x9e, 0x61, 0x79, 0x5c, 0xf7, 0x93, 0x1b, 0x3d, 0xaa, 0x7b, 0x90, + 0x1c, 0xe8, 0xb5, 0x68, 0x2a, 0x3e, 0xb0, 0x09, 0x6d, 0x99, 0x9a, 0x07, 0xa8, 0x39, 0x41, 0x69, + 0x38, 0xf3, 0x48, 0x3f, 0xfd, 0x06, 0x39, 0xfa, 0xdc, 0x1e, 0xd1, 0xfc, 0x0a, 0xa8, 0xf9, 0xe8, + 0xff, 0x9d, 0x64, 0xba, 0xed, 0x96, 0xd0, 0x7b, 0x7d, 0x9a, 0x4d, 0xc1, 0x64, 0x3e, 0xbb, 0x80, + 0xfb, 0xee, 0xa0, 0xab, 0x6c, 0x0a, 0x26, 0x33, 0x62, 0xd8, 0x3b, 0x1a, 0xf4, 0x22, 0x9b, 0x82, + 0x4a, 0xc1, 0xe2, 0xab, 0x1f, 0x07, 0x5d, 0xf3, 0x98, 0xbf, 0xd5, 0x0d, 0xc8, 0x6f, 0x0c, 0xd4, + 0x6f, 0xb4, 0x6c, 0xc4, 0xaa, 0xb2, 0x85, 0xd6, 0xaf, 0x20, 0xf9, 0xe7, 0x48, 0x3d, 0x82, 0xcc, + 0x8f, 0x57, 0xcb, 0x76, 0x56, 0xda, 0xed, 0x75, 0x3b, 0x6f, 0xc5, 0x9c, 0x7c, 0x48, 0xee, 0xf7, + 0xe5, 0x2f, 0x00, 0x00, 0xff, 0xff, 0xd3, 0x99, 0xfb, 0x2d, 0x6f, 0x01, 0x00, 0x00, } diff --git a/network/router/proto/router.proto b/network/router/proto/router.proto index 6f9e7323..4d278d0f 100644 --- a/network/router/proto/router.proto +++ b/network/router/proto/router.proto @@ -17,20 +17,22 @@ message LookupResponse { // Query is passed in a LookupRequest message Query { - // destination to lookup - string destination = 1; + // service to lookup + string service = 1; } // Route is a service route message Route { // service for the route - string destination = 1; + string service = 1; + // the address that advertise this route + string address = 2; // gateway as the next hop - string gateway = 2; - // the router that advertise this route - string router = 3; + string gateway = 3; // the network for this destination string network = 4; + // the network link + string link = 5; // the metric / score of this route - int64 metric = 5; + int64 metric = 6; } From c5a282ddd3a3ce923d7ddea2bf4775be8a715b2f Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 9 Jul 2019 16:52:44 +0100 Subject: [PATCH 135/287] remove the tunnel --- network/tunnel/default.go | 229 ---------------------------------- network/tunnel/socket.go | 82 ------------ network/tunnel/socket_test.go | 62 --------- network/tunnel/tunnel.go | 64 ---------- 4 files changed, 437 deletions(-) delete mode 100644 network/tunnel/default.go delete mode 100644 network/tunnel/socket.go delete mode 100644 network/tunnel/socket_test.go delete mode 100644 network/tunnel/tunnel.go diff --git a/network/tunnel/default.go b/network/tunnel/default.go deleted file mode 100644 index c417d935..00000000 --- a/network/tunnel/default.go +++ /dev/null @@ -1,229 +0,0 @@ -package tunnel - -import ( - "crypto/sha256" - "errors" - "fmt" - "sync" - - "github.com/google/uuid" - "github.com/micro/go-micro/network/transport" -) - -// tun represents a network tunnel -type tun struct { - // interface to use - net Interface - - // connect - mtx sync.RWMutex - connected bool - - // the send channel - send chan *message - // close channel - closed chan bool - - // sockets - sockets map[string]*socket -} - -// create new tunnel -func newTunnel(net Interface) *tun { - return &tun{ - net: net, - send: make(chan *message, 128), - closed: make(chan bool), - sockets: make(map[string]*socket), - } -} - -func (t *tun) getSocket(id string) (*socket, bool) { - // get the socket - t.mtx.RLock() - s, ok := t.sockets[id] - t.mtx.RUnlock() - return s, ok -} - -func (t *tun) newSocket(id string) *socket { - // new id if it doesn't exist - if len(id) == 0 { - id = uuid.New().String() - } - - // hash the id - h := sha256.New() - h.Write([]byte(id)) - id = fmt.Sprintf("%x", h.Sum(nil)) - - // new socket - s := &socket{ - id: id, - closed: make(chan bool), - recv: make(chan *message, 128), - send: t.send, - } - - // save socket - t.mtx.Lock() - t.sockets[id] = s - t.mtx.Unlock() - - // return socket - return s -} - -// process outgoing messages -func (t *tun) process() { - // manage the send buffer - // all pseudo sockets throw everything down this - for { - select { - case msg := <-t.send: - nmsg := &Message{ - Header: msg.data.Header, - Body: msg.data.Body, - } - - // set the stream id on the outgoing message - nmsg.Header["Micro-Stream"] = msg.id - - // send the message via the interface - if err := t.net.Send(nmsg); err != nil { - // no op - // TODO: do something - } - case <-t.closed: - return - } - } -} - -// process incoming messages -func (t *tun) listen() { - for { - // process anything via the net interface - msg, err := t.net.Recv() - if err != nil { - return - } - - // a stream id - id := msg.Header["Micro-Stream"] - - // get the socket - s, exists := t.getSocket(id) - if !exists { - // no op - continue - } - - // is the socket closed? - select { - case <-s.closed: - // closed - delete(t.sockets, id) - continue - default: - // process - } - - // is the socket new? - select { - // if its new it will block here - case <-s.wait: - // its not new - default: - // its new - // set remote address of the socket - s.remote = msg.Header["Remote"] - close(s.wait) - } - - tmsg := &transport.Message{ - Header: msg.Header, - Body: msg.Body, - } - - // TODO: don't block on queuing - // append to recv backlog - s.recv <- &message{id: id, data: tmsg} - } -} - -// Close the tunnel -func (t *tun) Close() error { - t.mtx.Lock() - defer t.mtx.Unlock() - - if !t.connected { - return nil - } - - select { - case <-t.closed: - return nil - default: - // close all the sockets - for _, s := range t.sockets { - s.Close() - } - // close the connection - close(t.closed) - t.connected = false - } - - return nil -} - -// Connect the tunnel -func (t *tun) Connect() error { - t.mtx.Lock() - defer t.mtx.Unlock() - - // already connected - if t.connected { - return nil - } - - // set as connected - t.connected = true - // create new close channel - t.closed = make(chan bool) - - // process messages to be sent - go t.process() - // process incoming messages - go t.listen() - - return nil -} - -// Dial an address -func (t *tun) Dial(addr string) (Conn, error) { - c := t.newSocket(addr) - // set remote - c.remote = addr - // set local - c.local = t.net.Addr() - return c, nil -} - -func (t *tun) Accept(addr string) (Conn, error) { - c := t.newSocket(addr) - // set remote - c.remote = t.net.Addr() - // set local - c.local = addr - - select { - case <-c.closed: - return nil, errors.New("error creating socket") - // wait for the first message - case <-c.wait: - } - - // return socket - return c, nil -} diff --git a/network/tunnel/socket.go b/network/tunnel/socket.go deleted file mode 100644 index dac5837d..00000000 --- a/network/tunnel/socket.go +++ /dev/null @@ -1,82 +0,0 @@ -package tunnel - -import ( - "errors" - - "github.com/micro/go-micro/network/transport" -) - -// socket is our pseudo socket for transport.Socket -type socket struct { - // socket id based on Micro-Stream - id string - // closed - closed chan bool - // remote addr - remote string - // local addr - local string - // send chan - send chan *message - // recv chan - recv chan *message - // wait until we have a connection - wait chan bool -} - -// message is sent over the send channel -type message struct { - // socket id - id string - // transport data - data *transport.Message -} - -func (s *socket) Remote() string { - return s.remote -} - -func (s *socket) Local() string { - return s.local -} - -func (s *socket) Id() string { - return s.id -} - -func (s *socket) Send(m *transport.Message) error { - select { - case <-s.closed: - return errors.New("socket is closed") - default: - // no op - } - // append to backlog - s.send <- &message{id: s.id, data: m} - return nil -} - -func (s *socket) Recv(m *transport.Message) error { - select { - case <-s.closed: - return errors.New("socket is closed") - default: - // no op - } - // recv from backlog - msg := <-s.recv - // set message - *m = *msg.data - // return nil - return nil -} - -func (s *socket) Close() error { - select { - case <-s.closed: - // no op - default: - close(s.closed) - } - return nil -} diff --git a/network/tunnel/socket_test.go b/network/tunnel/socket_test.go deleted file mode 100644 index 086bf60f..00000000 --- a/network/tunnel/socket_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package tunnel - -import ( - "testing" - - "github.com/micro/go-micro/network/transport" -) - -func TestTunnelSocket(t *testing.T) { - s := &socket{ - id: "1", - closed: make(chan bool), - remote: "remote", - local: "local", - send: make(chan *message, 1), - recv: make(chan *message, 1), - wait: make(chan bool), - } - - // check addresses local and remote - if s.Local() != s.local { - t.Fatalf("Expected s.Local %s got %s", s.local, s.Local()) - } - if s.Remote() != s.remote { - t.Fatalf("Expected s.Remote %s got %s", s.remote, s.Remote()) - } - - // send a message - s.Send(&transport.Message{Header: map[string]string{}}) - - // get sent message - msg := <-s.send - - if msg.id != s.id { - t.Fatalf("Expected sent message id %s got %s", s.id, msg.id) - } - - // recv a message - msg.data.Header["Foo"] = "bar" - s.recv <- msg - - m := new(transport.Message) - s.Recv(m) - - // check header - if m.Header["Foo"] != "bar" { - t.Fatalf("Did not receive correct message %+v", m) - } - - // close the connection - s.Close() - - // check connection - err := s.Send(m) - if err == nil { - t.Fatal("Expected closed connection") - } - err = s.Recv(m) - if err == nil { - t.Fatal("Expected closed connection") - } -} diff --git a/network/tunnel/tunnel.go b/network/tunnel/tunnel.go deleted file mode 100644 index d25d228d..00000000 --- a/network/tunnel/tunnel.go +++ /dev/null @@ -1,64 +0,0 @@ -// Package tunnel provides a network tunnel -package tunnel - -import ( - "github.com/micro/go-micro/config/options" - "github.com/micro/go-micro/network/transport" -) - -// Tunnel creates a network tunnel -type Tunnel interface { - // Connect connects the tunnel - Connect() error - // Close closes the tunnel - Close() error - // Dial an endpoint - Dial(addr string) (Conn, error) - // Accept connections - Accept(addr string) (Conn, error) -} - -// Conn return a transport socket with a unique id. -// This means Conn can be used as a transport.Socket -type Conn interface { - // Unique id of the connection - Id() string - // Underlying socket - transport.Socket -} - -// A network interface to use for sending/receiving. -// When Tunnel.Connect is called it starts processing -// messages over the interface. -type Interface interface { - // Address of the interface - Addr() string - // Receive new messages - Recv() (*Message, error) - // Send messages - Send(*Message) error -} - -// Messages received over the interface -type Message struct { - Header map[string]string - Body []byte -} - -// NewTunnel creates a new tunnel -func NewTunnel(opts ...options.Option) Tunnel { - options := options.NewOptions(opts...) - - i, ok := options.Values().Get("tunnel.net") - if !ok { - // wtf - return nil - } - - return newTunnel(i.(Interface)) -} - -// WithInterface passes in the interface -func WithInterface(net Interface) options.Option { - return options.WithValue("tunnel.net", net) -} From b642d5e1c0dae67755f845ba67a79fcbc6a5e153 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 9 Jul 2019 16:53:30 +0100 Subject: [PATCH 136/287] remove proto dir --- network/proto/network.micro.go | 21 --- network/proto/network.pb.go | 234 --------------------------------- network/proto/network.proto | 34 ----- 3 files changed, 289 deletions(-) delete mode 100644 network/proto/network.micro.go delete mode 100644 network/proto/network.pb.go delete mode 100644 network/proto/network.proto diff --git a/network/proto/network.micro.go b/network/proto/network.micro.go deleted file mode 100644 index 96883952..00000000 --- a/network/proto/network.micro.go +++ /dev/null @@ -1,21 +0,0 @@ -// Code generated by protoc-gen-micro. DO NOT EDIT. -// source: micro/go-micro/network/proto/network.proto - -package go_micro_network - -import ( - fmt "fmt" - proto "github.com/golang/protobuf/proto" - math "math" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package diff --git a/network/proto/network.pb.go b/network/proto/network.pb.go deleted file mode 100644 index 06f52273..00000000 --- a/network/proto/network.pb.go +++ /dev/null @@ -1,234 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: micro/go-micro/network/proto/network.proto - -package go_micro_network - -import ( - fmt "fmt" - proto "github.com/golang/protobuf/proto" - math "math" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package - -// A connect message is for connecting to the network -type Connect struct { - // the unique muid (mac) address of the node - Muid string `protobuf:"bytes,1,opt,name=muid,proto3" json:"muid,omitempty"` - // Lease specifies an existing lease to indicate - // we don't need a new address, we just want to - // establish a link. - Lease *Lease `protobuf:"bytes,2,opt,name=lease,proto3" json:"lease,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Connect) Reset() { *m = Connect{} } -func (m *Connect) String() string { return proto.CompactTextString(m) } -func (*Connect) ProtoMessage() {} -func (*Connect) Descriptor() ([]byte, []int) { - return fileDescriptor_4daa91d05ddc28b6, []int{0} -} - -func (m *Connect) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Connect.Unmarshal(m, b) -} -func (m *Connect) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Connect.Marshal(b, m, deterministic) -} -func (m *Connect) XXX_Merge(src proto.Message) { - xxx_messageInfo_Connect.Merge(m, src) -} -func (m *Connect) XXX_Size() int { - return xxx_messageInfo_Connect.Size(m) -} -func (m *Connect) XXX_DiscardUnknown() { - xxx_messageInfo_Connect.DiscardUnknown(m) -} - -var xxx_messageInfo_Connect proto.InternalMessageInfo - -func (m *Connect) GetMuid() string { - if m != nil { - return m.Muid - } - return "" -} - -func (m *Connect) GetLease() *Lease { - if m != nil { - return m.Lease - } - return nil -} - -// A lease is returned to anyone attempting to connect with a valid muid. -type Lease struct { - // unique lease id - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - // timestamp of lease - Timestamp int64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` - // author is the muid of the author - Author string `protobuf:"bytes,3,opt,name=author,proto3" json:"author,omitempty"` - // the node - Node *Node `protobuf:"bytes,4,opt,name=node,proto3" json:"node,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Lease) Reset() { *m = Lease{} } -func (m *Lease) String() string { return proto.CompactTextString(m) } -func (*Lease) ProtoMessage() {} -func (*Lease) Descriptor() ([]byte, []int) { - return fileDescriptor_4daa91d05ddc28b6, []int{1} -} - -func (m *Lease) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Lease.Unmarshal(m, b) -} -func (m *Lease) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Lease.Marshal(b, m, deterministic) -} -func (m *Lease) XXX_Merge(src proto.Message) { - xxx_messageInfo_Lease.Merge(m, src) -} -func (m *Lease) XXX_Size() int { - return xxx_messageInfo_Lease.Size(m) -} -func (m *Lease) XXX_DiscardUnknown() { - xxx_messageInfo_Lease.DiscardUnknown(m) -} - -var xxx_messageInfo_Lease proto.InternalMessageInfo - -func (m *Lease) GetId() string { - if m != nil { - return m.Id - } - return "" -} - -func (m *Lease) GetTimestamp() int64 { - if m != nil { - return m.Timestamp - } - return 0 -} - -func (m *Lease) GetAuthor() string { - if m != nil { - return m.Author - } - return "" -} - -func (m *Lease) GetNode() *Node { - if m != nil { - return m.Node - } - return nil -} - -// A node is the network node -type Node struct { - Muid string `protobuf:"bytes,1,opt,name=muid,proto3" json:"muid,omitempty"` - Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` - Address string `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"` - Network string `protobuf:"bytes,4,opt,name=network,proto3" json:"network,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Node) Reset() { *m = Node{} } -func (m *Node) String() string { return proto.CompactTextString(m) } -func (*Node) ProtoMessage() {} -func (*Node) Descriptor() ([]byte, []int) { - return fileDescriptor_4daa91d05ddc28b6, []int{2} -} - -func (m *Node) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Node.Unmarshal(m, b) -} -func (m *Node) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Node.Marshal(b, m, deterministic) -} -func (m *Node) XXX_Merge(src proto.Message) { - xxx_messageInfo_Node.Merge(m, src) -} -func (m *Node) XXX_Size() int { - return xxx_messageInfo_Node.Size(m) -} -func (m *Node) XXX_DiscardUnknown() { - xxx_messageInfo_Node.DiscardUnknown(m) -} - -var xxx_messageInfo_Node proto.InternalMessageInfo - -func (m *Node) GetMuid() string { - if m != nil { - return m.Muid - } - return "" -} - -func (m *Node) GetId() string { - if m != nil { - return m.Id - } - return "" -} - -func (m *Node) GetAddress() string { - if m != nil { - return m.Address - } - return "" -} - -func (m *Node) GetNetwork() string { - if m != nil { - return m.Network - } - return "" -} - -func init() { - proto.RegisterType((*Connect)(nil), "go.micro.network.Connect") - proto.RegisterType((*Lease)(nil), "go.micro.network.Lease") - proto.RegisterType((*Node)(nil), "go.micro.network.Node") -} - -func init() { - proto.RegisterFile("micro/go-micro/network/proto/network.proto", fileDescriptor_4daa91d05ddc28b6) -} - -var fileDescriptor_4daa91d05ddc28b6 = []byte{ - // 229 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x90, 0xc1, 0x6a, 0xc3, 0x30, - 0x0c, 0x86, 0x49, 0x9a, 0xb6, 0x44, 0x83, 0x31, 0x74, 0xe8, 0x7c, 0xd8, 0xa1, 0xe4, 0x54, 0x0a, - 0x75, 0x61, 0x7b, 0x84, 0x5d, 0xcb, 0x0e, 0x7e, 0x80, 0x41, 0x56, 0x8b, 0x2e, 0x6c, 0xb6, 0x8a, - 0xed, 0x32, 0xf6, 0xf6, 0x23, 0x8a, 0x93, 0xc1, 0xd6, 0x9b, 0x3e, 0xe9, 0xf7, 0xff, 0xcb, 0x82, - 0xad, 0xeb, 0x8e, 0x81, 0xf7, 0x27, 0xde, 0x0d, 0x85, 0xa7, 0xf4, 0xc5, 0xe1, 0x63, 0x7f, 0x0e, - 0x9c, 0x26, 0xd2, 0x42, 0x78, 0x77, 0x62, 0x2d, 0x2a, 0x9d, 0xfb, 0xcd, 0x01, 0x96, 0xcf, 0xec, - 0x3d, 0x1d, 0x13, 0x22, 0x54, 0xee, 0xd2, 0x59, 0x55, 0xac, 0x8b, 0x4d, 0x6d, 0xa4, 0xc6, 0x1d, - 0xcc, 0x3f, 0xa9, 0x8d, 0xa4, 0xca, 0x75, 0xb1, 0xb9, 0x79, 0xbc, 0xd7, 0x7f, 0x0d, 0xf4, 0xa1, - 0x1f, 0x9b, 0x41, 0xd5, 0x7c, 0xc3, 0x5c, 0x18, 0x6f, 0xa1, 0x9c, 0x9c, 0xca, 0xce, 0xe2, 0x03, - 0xd4, 0xa9, 0x73, 0x14, 0x53, 0xeb, 0xce, 0xe2, 0x35, 0x33, 0xbf, 0x0d, 0x5c, 0xc1, 0xa2, 0xbd, - 0xa4, 0x77, 0x0e, 0x6a, 0x26, 0x2f, 0x32, 0xe1, 0x16, 0x2a, 0xcf, 0x96, 0x54, 0x25, 0xe1, 0xab, - 0xff, 0xe1, 0x2f, 0x6c, 0xc9, 0x88, 0xa6, 0x79, 0x85, 0xaa, 0xa7, 0xab, 0xbf, 0x18, 0xb6, 0x29, - 0xa7, 0x6d, 0x14, 0x2c, 0x5b, 0x6b, 0x03, 0xc5, 0x98, 0x03, 0x47, 0xec, 0x27, 0xd9, 0x5b, 0x42, - 0x6b, 0x33, 0xe2, 0xdb, 0x42, 0x2e, 0xf8, 0xf4, 0x13, 0x00, 0x00, 0xff, 0xff, 0xba, 0xcc, 0x46, - 0x1e, 0x6f, 0x01, 0x00, 0x00, -} diff --git a/network/proto/network.proto b/network/proto/network.proto deleted file mode 100644 index a1800e37..00000000 --- a/network/proto/network.proto +++ /dev/null @@ -1,34 +0,0 @@ -syntax = "proto3"; - -package go.micro.network; - -// A connect message is for connecting to the network -message Connect { - // the unique muid (mac) address of the node - string muid = 1; - - // Lease specifies an existing lease to indicate - // we don't need a new address, we just want to - // establish a link. - Lease lease = 2; -} - -// A lease is returned to anyone attempting to connect with a valid muid. -message Lease { - // unique lease id - string id = 1; - // timestamp of lease - int64 timestamp = 2; - // author is the muid of the author - string author = 3; - // the node - Node node = 4; -} - -// A node is the network node -message Node { - string muid = 1; - string id = 2; - string address = 3; - string network = 4; -} From 97282a5377938e2e44b50c338ade770a449f39ae Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 9 Jul 2019 16:54:44 +0100 Subject: [PATCH 137/287] remove resolver --- network/resolver/dns/dns.go | 30 -------------- network/resolver/http/http.go | 59 --------------------------- network/resolver/registry/registry.go | 37 ----------------- network/resolver/resolver.go | 15 ------- 4 files changed, 141 deletions(-) delete mode 100644 network/resolver/dns/dns.go delete mode 100644 network/resolver/http/http.go delete mode 100644 network/resolver/registry/registry.go delete mode 100644 network/resolver/resolver.go diff --git a/network/resolver/dns/dns.go b/network/resolver/dns/dns.go deleted file mode 100644 index c905df0e..00000000 --- a/network/resolver/dns/dns.go +++ /dev/null @@ -1,30 +0,0 @@ -// Package dns resolves ids to dns srv records -package dns - -import ( - "fmt" - "net" - - "github.com/micro/go-micro/network/resolver" -) - -type Resolver struct{} - -// Resolve assumes ID is a domain name e.g micro.mu -func (r *Resolver) Resolve(id string) ([]*resolver.Record, error) { - _, addrs, err := net.LookupSRV("network", "udp", id) - if err != nil { - return nil, err - } - var records []*resolver.Record - for _, addr := range addrs { - address := addr.Target - if addr.Port > 0 { - address = fmt.Sprintf("%s:%d", addr.Target, addr.Port) - } - records = append(records, &resolver.Record{ - Address: address, - }) - } - return records, nil -} diff --git a/network/resolver/http/http.go b/network/resolver/http/http.go deleted file mode 100644 index 80ff4d61..00000000 --- a/network/resolver/http/http.go +++ /dev/null @@ -1,59 +0,0 @@ -// Package http resolves ids to network addresses using a http request -package http - -import ( - "encoding/json" - "io/ioutil" - "net/http" - "net/url" - - "github.com/micro/go-micro/network/resolver" -) - -type Resolver struct { - // If not set, defaults to http - Proto string - - // Path sets the path to lookup. Defaults to /network - Path string -} - -// Resolve assumes ID is a domain which can be converted to a http://id/network request -func (r *Resolver) Resolve(id string) ([]*resolver.Record, error) { - proto := "http" - path := "/network" - - if len(r.Proto) > 0 { - proto = r.Proto - } - - if len(r.Path) > 0 { - path = r.Path - } - - uri := &url.URL{ - Scheme: proto, - Path: path, - Host: id, - } - - rsp, err := http.Get(uri.String()) - if err != nil { - return nil, err - } - defer rsp.Body.Close() - - b, err := ioutil.ReadAll(rsp.Body) - if err != nil { - return nil, err - } - - // encoding format is assumed to be json - var records []*resolver.Record - - if err := json.Unmarshal(b, &records); err != nil { - return nil, err - } - - return records, nil -} diff --git a/network/resolver/registry/registry.go b/network/resolver/registry/registry.go deleted file mode 100644 index c7ef796a..00000000 --- a/network/resolver/registry/registry.go +++ /dev/null @@ -1,37 +0,0 @@ -// Package registry resolves ids using the go-micro registry -package registry - -import ( - "github.com/micro/go-micro/network/resolver" - "github.com/micro/go-micro/registry" -) - -type Resolver struct { - // Registry is the registry to use otherwise we use the defaul - Registry registry.Registry -} - -// Resolve assumes ID is a domain name e.g micro.mu -func (r *Resolver) Resolve(id string) ([]*resolver.Record, error) { - reg := r.Registry - if reg == nil { - reg = registry.DefaultRegistry - } - - services, err := reg.GetService(id) - if err != nil { - return nil, err - } - - var records []*resolver.Record - - for _, service := range services { - for _, node := range service.Nodes { - records = append(records, &resolver.Record{ - Address: node.Address, - }) - } - } - - return records, nil -} diff --git a/network/resolver/resolver.go b/network/resolver/resolver.go deleted file mode 100644 index 6c54eb95..00000000 --- a/network/resolver/resolver.go +++ /dev/null @@ -1,15 +0,0 @@ -// Package resolver resolves network ids to addresses -package resolver - -// Resolver is network resolver. It's used to find network nodes -// via id to connect to. This is done based on Network.Id(). -// Before we can be part of any network, we have to connect to it. -type Resolver interface { - // Resolve returns a list of addresses for an id - Resolve(id string) ([]*Record, error) -} - -// A resolved record -type Record struct { - Address string `json:"address"` -} From 0bf54c122f2c0de242ff61cc4350a170b0657135 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 9 Jul 2019 18:41:26 +0100 Subject: [PATCH 138/287] move transport back --- client/grpc/grpc.go | 2 +- client/options.go | 2 +- client/options_test.go | 2 +- client/rpc_client.go | 2 +- client/rpc_codec.go | 2 +- client/rpc_pool.go | 2 +- client/rpc_pool_test.go | 4 ++-- client/rpc_response.go | 2 +- config/cmd/cmd.go | 8 ++++---- config/cmd/options.go | 2 +- network/default.go | 2 +- network/link.go | 2 +- network/network.go | 2 +- options.go | 2 +- server/grpc/options.go | 2 +- server/options.go | 2 +- server/rpc_codec.go | 2 +- server/rpc_codec_test.go | 2 +- server/rpc_request.go | 2 +- server/rpc_response.go | 2 +- server/rpc_server.go | 2 +- {network/transport => transport}/grpc/grpc.go | 4 ++-- {network/transport => transport}/grpc/grpc_test.go | 2 +- {network/transport => transport}/grpc/handler.go | 4 ++-- .../transport => transport}/grpc/proto/transport.micro.go | 2 +- .../transport => transport}/grpc/proto/transport.pb.go | 6 +++--- .../transport => transport}/grpc/proto/transport.proto | 0 {network/transport => transport}/grpc/socket.go | 4 ++-- {network/transport => transport}/http/http.go | 2 +- {network/transport => transport}/http/http_test.go | 2 +- {network/transport => transport}/http/options.go | 2 +- {network/transport => transport}/http_proxy.go | 0 {network/transport => transport}/http_transport.go | 0 {network/transport => transport}/http_transport_test.go | 0 {network/transport => transport}/memory/memory.go | 2 +- {network/transport => transport}/memory/memory_test.go | 2 +- {network/transport => transport}/options.go | 0 {network/transport => transport}/quic/quic.go | 2 +- {network/transport => transport}/transport.go | 0 39 files changed, 42 insertions(+), 42 deletions(-) rename {network/transport => transport}/grpc/grpc.go (97%) rename {network/transport => transport}/grpc/grpc_test.go (97%) rename {network/transport => transport}/grpc/handler.go (85%) rename {network/transport => transport}/grpc/proto/transport.micro.go (98%) rename {network/transport => transport}/grpc/proto/transport.pb.go (96%) rename {network/transport => transport}/grpc/proto/transport.proto (100%) rename {network/transport => transport}/grpc/socket.go (93%) rename {network/transport => transport}/http/http.go (85%) rename {network/transport => transport}/http/http_test.go (97%) rename {network/transport => transport}/http/options.go (91%) rename {network/transport => transport}/http_proxy.go (100%) rename {network/transport => transport}/http_transport.go (100%) rename {network/transport => transport}/http_transport_test.go (100%) rename {network/transport => transport}/memory/memory.go (98%) rename {network/transport => transport}/memory/memory_test.go (97%) rename {network/transport => transport}/options.go (100%) rename {network/transport => transport}/quic/quic.go (98%) rename {network/transport => transport}/transport.go (100%) diff --git a/client/grpc/grpc.go b/client/grpc/grpc.go index e79b5406..48215270 100644 --- a/client/grpc/grpc.go +++ b/client/grpc/grpc.go @@ -16,7 +16,7 @@ import ( "github.com/micro/go-micro/codec" "github.com/micro/go-micro/errors" "github.com/micro/go-micro/metadata" - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" "github.com/micro/go-micro/registry" "google.golang.org/grpc" diff --git a/client/options.go b/client/options.go index 3032d23b..9f0c3f80 100644 --- a/client/options.go +++ b/client/options.go @@ -7,7 +7,7 @@ import ( "github.com/micro/go-micro/broker" "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/codec" - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" "github.com/micro/go-micro/registry" ) diff --git a/client/options_test.go b/client/options_test.go index f7c892ca..9252994c 100644 --- a/client/options_test.go +++ b/client/options_test.go @@ -4,7 +4,7 @@ import ( "testing" "time" - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" ) func TestCallOptions(t *testing.T) { diff --git a/client/rpc_client.go b/client/rpc_client.go index 8f729252..2b974289 100644 --- a/client/rpc_client.go +++ b/client/rpc_client.go @@ -15,7 +15,7 @@ import ( "github.com/micro/go-micro/codec" "github.com/micro/go-micro/errors" "github.com/micro/go-micro/metadata" - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" "github.com/micro/go-micro/registry" ) diff --git a/client/rpc_codec.go b/client/rpc_codec.go index 91aae303..f3697b4b 100644 --- a/client/rpc_codec.go +++ b/client/rpc_codec.go @@ -12,7 +12,7 @@ import ( "github.com/micro/go-micro/codec/proto" "github.com/micro/go-micro/codec/protorpc" "github.com/micro/go-micro/errors" - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" "github.com/micro/go-micro/registry" ) diff --git a/client/rpc_pool.go b/client/rpc_pool.go index 9cff2587..9fdd7736 100644 --- a/client/rpc_pool.go +++ b/client/rpc_pool.go @@ -4,7 +4,7 @@ import ( "sync" "time" - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" ) type pool struct { diff --git a/client/rpc_pool_test.go b/client/rpc_pool_test.go index 2f7bcb5e..6c5875f1 100644 --- a/client/rpc_pool_test.go +++ b/client/rpc_pool_test.go @@ -4,8 +4,8 @@ import ( "testing" "time" - "github.com/micro/go-micro/network/transport" - "github.com/micro/go-micro/network/transport/memory" + "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/transport/memory" ) func testPool(t *testing.T, size int, ttl time.Duration) { diff --git a/client/rpc_response.go b/client/rpc_response.go index d2fa61f2..08aaa84d 100644 --- a/client/rpc_response.go +++ b/client/rpc_response.go @@ -2,7 +2,7 @@ package client import ( "github.com/micro/go-micro/codec" - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" ) type rpcResponse struct { diff --git a/config/cmd/cmd.go b/config/cmd/cmd.go index f2537de7..8d7c3c03 100644 --- a/config/cmd/cmd.go +++ b/config/cmd/cmd.go @@ -38,10 +38,10 @@ import ( "github.com/micro/go-micro/client/selector/static" // transports - "github.com/micro/go-micro/network/transport" - tgrpc "github.com/micro/go-micro/network/transport/grpc" - thttp "github.com/micro/go-micro/network/transport/http" - tmem "github.com/micro/go-micro/network/transport/memory" + "github.com/micro/go-micro/transport" + tgrpc "github.com/micro/go-micro/transport/grpc" + thttp "github.com/micro/go-micro/transport/http" + tmem "github.com/micro/go-micro/transport/memory" ) type Cmd interface { diff --git a/config/cmd/options.go b/config/cmd/options.go index be703f56..b4917c27 100644 --- a/config/cmd/options.go +++ b/config/cmd/options.go @@ -6,7 +6,7 @@ import ( "github.com/micro/go-micro/broker" "github.com/micro/go-micro/client" "github.com/micro/go-micro/client/selector" - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/server" ) diff --git a/network/default.go b/network/default.go index 494ecbd2..e282adeb 100644 --- a/network/default.go +++ b/network/default.go @@ -7,7 +7,7 @@ import ( "github.com/google/uuid" "github.com/micro/go-micro/config/options" - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" "github.com/micro/go-micro/util/addr" ) diff --git a/network/link.go b/network/link.go index e805e55c..319692d3 100644 --- a/network/link.go +++ b/network/link.go @@ -6,7 +6,7 @@ import ( "sync" "github.com/google/uuid" - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" ) type link struct { diff --git a/network/network.go b/network/network.go index 164c8a98..b27347df 100644 --- a/network/network.go +++ b/network/network.go @@ -3,7 +3,7 @@ package network import ( "github.com/micro/go-micro/config/options" - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" ) // Network defines a network interface. The network is a single diff --git a/options.go b/options.go index 355e1cfc..1b8a5724 100644 --- a/options.go +++ b/options.go @@ -9,7 +9,7 @@ import ( "github.com/micro/go-micro/client" "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/config/cmd" - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/server" ) diff --git a/server/grpc/options.go b/server/grpc/options.go index e1c2efc9..3c9d125f 100644 --- a/server/grpc/options.go +++ b/server/grpc/options.go @@ -6,7 +6,7 @@ import ( "github.com/micro/go-micro/broker" "github.com/micro/go-micro/codec" - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/server" "github.com/micro/go-micro/server/debug" diff --git a/server/options.go b/server/options.go index 200a7a18..018958a2 100644 --- a/server/options.go +++ b/server/options.go @@ -7,7 +7,7 @@ import ( "github.com/micro/go-micro/broker" "github.com/micro/go-micro/codec" - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/server/debug" ) diff --git a/server/rpc_codec.go b/server/rpc_codec.go index a23b0a3a..797fa79c 100644 --- a/server/rpc_codec.go +++ b/server/rpc_codec.go @@ -10,7 +10,7 @@ import ( "github.com/micro/go-micro/codec/jsonrpc" "github.com/micro/go-micro/codec/proto" "github.com/micro/go-micro/codec/protorpc" - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" "github.com/pkg/errors" ) diff --git a/server/rpc_codec_test.go b/server/rpc_codec_test.go index 3fb03cf4..1088af01 100644 --- a/server/rpc_codec_test.go +++ b/server/rpc_codec_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/micro/go-micro/codec" - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" ) // testCodec is a dummy codec that only knows how to encode nil bodies diff --git a/server/rpc_request.go b/server/rpc_request.go index c69c8605..40995b14 100644 --- a/server/rpc_request.go +++ b/server/rpc_request.go @@ -2,7 +2,7 @@ package server import ( "github.com/micro/go-micro/codec" - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" ) type rpcRequest struct { diff --git a/server/rpc_response.go b/server/rpc_response.go index 55b5b126..d89fa0b6 100644 --- a/server/rpc_response.go +++ b/server/rpc_response.go @@ -4,7 +4,7 @@ import ( "net/http" "github.com/micro/go-micro/codec" - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" ) type rpcResponse struct { diff --git a/server/rpc_server.go b/server/rpc_server.go index 2cabb635..284d499d 100644 --- a/server/rpc_server.go +++ b/server/rpc_server.go @@ -13,7 +13,7 @@ import ( "github.com/micro/go-micro/broker" "github.com/micro/go-micro/codec" "github.com/micro/go-micro/metadata" - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/util/addr" log "github.com/micro/go-micro/util/log" diff --git a/network/transport/grpc/grpc.go b/transport/grpc/grpc.go similarity index 97% rename from network/transport/grpc/grpc.go rename to transport/grpc/grpc.go index 6b8dc8c8..a60ec70e 100644 --- a/network/transport/grpc/grpc.go +++ b/transport/grpc/grpc.go @@ -6,7 +6,7 @@ import ( "crypto/tls" "net" - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" maddr "github.com/micro/go-micro/util/addr" mnet "github.com/micro/go-micro/util/net" mls "github.com/micro/go-micro/util/tls" @@ -14,7 +14,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials" - pb "github.com/micro/go-micro/network/transport/grpc/proto" + pb "github.com/micro/go-micro/transport/grpc/proto" ) type grpcTransport struct { diff --git a/network/transport/grpc/grpc_test.go b/transport/grpc/grpc_test.go similarity index 97% rename from network/transport/grpc/grpc_test.go rename to transport/grpc/grpc_test.go index 85abf12d..d4e82346 100644 --- a/network/transport/grpc/grpc_test.go +++ b/transport/grpc/grpc_test.go @@ -4,7 +4,7 @@ import ( "strings" "testing" - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" ) func expectedPort(t *testing.T, expected string, lsn transport.Listener) { diff --git a/network/transport/grpc/handler.go b/transport/grpc/handler.go similarity index 85% rename from network/transport/grpc/handler.go rename to transport/grpc/handler.go index 6dc1b512..3220f7dd 100644 --- a/network/transport/grpc/handler.go +++ b/transport/grpc/handler.go @@ -3,8 +3,8 @@ package grpc import ( "runtime/debug" - "github.com/micro/go-micro/network/transport" - pb "github.com/micro/go-micro/network/transport/grpc/proto" + "github.com/micro/go-micro/transport" + pb "github.com/micro/go-micro/transport/grpc/proto" "github.com/micro/go-micro/util/log" "google.golang.org/grpc/peer" ) diff --git a/network/transport/grpc/proto/transport.micro.go b/transport/grpc/proto/transport.micro.go similarity index 98% rename from network/transport/grpc/proto/transport.micro.go rename to transport/grpc/proto/transport.micro.go index 1b8d840e..81cf981c 100644 --- a/network/transport/grpc/proto/transport.micro.go +++ b/transport/grpc/proto/transport.micro.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-micro. DO NOT EDIT. -// source: go-micro/network/transport/grpc/proto/transport.proto +// source: go-micro/transport/grpc/proto/transport.proto package go_micro_grpc_transport diff --git a/network/transport/grpc/proto/transport.pb.go b/transport/grpc/proto/transport.pb.go similarity index 96% rename from network/transport/grpc/proto/transport.pb.go rename to transport/grpc/proto/transport.pb.go index c8fb8933..a9702987 100644 --- a/network/transport/grpc/proto/transport.pb.go +++ b/transport/grpc/proto/transport.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-go. DO NOT EDIT. -// source: go-micro/network/transport/grpc/proto/transport.proto +// source: go-micro/transport/grpc/proto/transport.proto package go_micro_grpc_transport @@ -75,7 +75,7 @@ func init() { } func init() { - proto.RegisterFile("go-micro/network/transport/grpc/proto/transport.proto", fileDescriptor_29b90b9ccd5e0da5) + proto.RegisterFile("go-micro/transport/grpc/proto/transport.proto", fileDescriptor_29b90b9ccd5e0da5) } var fileDescriptor_29b90b9ccd5e0da5 = []byte{ @@ -197,5 +197,5 @@ var _Transport_serviceDesc = grpc.ServiceDesc{ ClientStreams: true, }, }, - Metadata: "go-micro/network/transport/grpc/proto/transport.proto", + Metadata: "go-micro/transport/grpc/proto/transport.proto", } diff --git a/network/transport/grpc/proto/transport.proto b/transport/grpc/proto/transport.proto similarity index 100% rename from network/transport/grpc/proto/transport.proto rename to transport/grpc/proto/transport.proto diff --git a/network/transport/grpc/socket.go b/transport/grpc/socket.go similarity index 93% rename from network/transport/grpc/socket.go rename to transport/grpc/socket.go index 1d072cbe..2567559d 100644 --- a/network/transport/grpc/socket.go +++ b/transport/grpc/socket.go @@ -1,8 +1,8 @@ package grpc import ( - "github.com/micro/go-micro/network/transport" - pb "github.com/micro/go-micro/network/transport/grpc/proto" + "github.com/micro/go-micro/transport" + pb "github.com/micro/go-micro/transport/grpc/proto" "google.golang.org/grpc" ) diff --git a/network/transport/http/http.go b/transport/http/http.go similarity index 85% rename from network/transport/http/http.go rename to transport/http/http.go index a3a6bbfc..672db54c 100644 --- a/network/transport/http/http.go +++ b/transport/http/http.go @@ -2,7 +2,7 @@ package http import ( - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" ) // NewTransport returns a new http transport using net/http and supporting http2 diff --git a/network/transport/http/http_test.go b/transport/http/http_test.go similarity index 97% rename from network/transport/http/http_test.go rename to transport/http/http_test.go index 57445031..faaf5215 100644 --- a/network/transport/http/http_test.go +++ b/transport/http/http_test.go @@ -4,7 +4,7 @@ import ( "sync" "testing" - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" ) func call(b *testing.B, c int) { diff --git a/network/transport/http/options.go b/transport/http/options.go similarity index 91% rename from network/transport/http/options.go rename to transport/http/options.go index 3d70f94b..2a6e56c5 100644 --- a/network/transport/http/options.go +++ b/transport/http/options.go @@ -4,7 +4,7 @@ import ( "context" "net/http" - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" ) // Handle registers the handler for the given pattern. diff --git a/network/transport/http_proxy.go b/transport/http_proxy.go similarity index 100% rename from network/transport/http_proxy.go rename to transport/http_proxy.go diff --git a/network/transport/http_transport.go b/transport/http_transport.go similarity index 100% rename from network/transport/http_transport.go rename to transport/http_transport.go diff --git a/network/transport/http_transport_test.go b/transport/http_transport_test.go similarity index 100% rename from network/transport/http_transport_test.go rename to transport/http_transport_test.go diff --git a/network/transport/memory/memory.go b/transport/memory/memory.go similarity index 98% rename from network/transport/memory/memory.go rename to transport/memory/memory.go index 25782d50..ed00ce69 100644 --- a/network/transport/memory/memory.go +++ b/transport/memory/memory.go @@ -9,7 +9,7 @@ import ( "sync" "time" - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" ) type memorySocket struct { diff --git a/network/transport/memory/memory_test.go b/transport/memory/memory_test.go similarity index 97% rename from network/transport/memory/memory_test.go rename to transport/memory/memory_test.go index 0ff5b31d..72952e09 100644 --- a/network/transport/memory/memory_test.go +++ b/transport/memory/memory_test.go @@ -3,7 +3,7 @@ package memory import ( "testing" - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" ) func TestMemoryTransport(t *testing.T) { diff --git a/network/transport/options.go b/transport/options.go similarity index 100% rename from network/transport/options.go rename to transport/options.go diff --git a/network/transport/quic/quic.go b/transport/quic/quic.go similarity index 98% rename from network/transport/quic/quic.go rename to transport/quic/quic.go index 548b1bc2..2622ec84 100644 --- a/network/transport/quic/quic.go +++ b/transport/quic/quic.go @@ -6,7 +6,7 @@ import ( "encoding/gob" "github.com/lucas-clemente/quic-go" - "github.com/micro/go-micro/network/transport" + "github.com/micro/go-micro/transport" utls "github.com/micro/go-micro/util/tls" ) diff --git a/network/transport/transport.go b/transport/transport.go similarity index 100% rename from network/transport/transport.go rename to transport/transport.go From eda380284c4ae75ebbc5b14a292db28296c53cf4 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 9 Jul 2019 18:45:14 +0100 Subject: [PATCH 139/287] remove network --- network/default.go | 164 -------------------------------------- network/default_test.go | 86 -------------------- network/link.go | 172 ---------------------------------------- network/network.go | 88 -------------------- 4 files changed, 510 deletions(-) delete mode 100644 network/default.go delete mode 100644 network/default_test.go delete mode 100644 network/link.go delete mode 100644 network/network.go diff --git a/network/default.go b/network/default.go deleted file mode 100644 index e282adeb..00000000 --- a/network/default.go +++ /dev/null @@ -1,164 +0,0 @@ -package network - -import ( - "fmt" - "io" - "sync" - - "github.com/google/uuid" - "github.com/micro/go-micro/config/options" - "github.com/micro/go-micro/transport" - "github.com/micro/go-micro/util/addr" -) - -// default network implementation -type network struct { - options.Options - - // name of the network - name string - - // network address used where one is specified - address string - - // transport - transport transport.Transport -} - -type listener struct { - // start accepting once - once sync.Once - // close channel to close the connection - closed chan bool - // the listener - listener transport.Listener - // the connection queue - conns chan Conn -} - -func (n *network) Create() (*Node, error) { - ip, err := addr.Extract(n.address) - if err != nil { - return nil, err - } - return &Node{ - Id: fmt.Sprintf("%s-%s", n.name, uuid.New().String()), - Address: ip, - Network: n.Name(), - Metadata: map[string]string{ - "network": n.String(), - "transport": n.transport.String(), - }, - }, nil -} - -func (n *network) Name() string { - return n.name -} - -func (n *network) String() string { - return "local" -} - -func (n *network) Connect(node *Node) (Conn, error) { - c, err := n.transport.Dial(node.Address) - if err != nil { - return nil, err - } - return newLink(c.(transport.Socket)), nil -} - -func (n *network) Listen(node *Node) (Listener, error) { - l, err := n.transport.Listen(node.Address) - if err != nil { - return nil, err - } - return newListener(l), nil -} - -func (l *listener) process() { - if err := l.listener.Accept(l.accept); err != nil { - // close the listener - l.Close() - } -} - -func (l *listener) accept(sock transport.Socket) { - // create a new link and pass it through - link := newLink(sock) - - // send it - l.conns <- link - - // wait for it to be closed - select { - case <-l.closed: - return - case <-link.closed: - return - } -} - -func (l *listener) Address() string { - return l.listener.Addr() -} - -func (l *listener) Close() error { - select { - case <-l.closed: - return nil - default: - close(l.closed) - } - return nil -} - -func (l *listener) Accept() (Conn, error) { - l.once.Do(func() { - // TODO: catch the error - go l.process() - }) - select { - case c := <-l.conns: - return c, nil - case <-l.closed: - return nil, io.EOF - } -} - -func newListener(l transport.Listener) *listener { - return &listener{ - closed: make(chan bool), - conns: make(chan Conn), - listener: l, - } -} - -func newNetwork(opts ...options.Option) *network { - options := options.NewOptions(opts...) - - net := &network{ - name: DefaultName, - transport: transport.DefaultTransport, - } - - // get network name - name, ok := options.Values().Get("network.name") - if ok { - net.name = name.(string) - } - - // get network name - address, ok := options.Values().Get("network.address") - if ok { - net.address = address.(string) - } - - // get network transport - t, ok := options.Values().Get("network.transport") - if ok { - net.transport = t.(transport.Transport) - } - - return net -} diff --git a/network/default_test.go b/network/default_test.go deleted file mode 100644 index da10fdc8..00000000 --- a/network/default_test.go +++ /dev/null @@ -1,86 +0,0 @@ -package network - -import ( - "io" - "testing" -) - -func TestNetwork(t *testing.T) { - // create a new network - n := newNetwork() - - // create a new node - node, err := n.Create() - if err != nil { - t.Fatal(err) - } - - // set ourselves a random port - node.Address = node.Address + ":0" - - l, err := n.Listen(node) - if err != nil { - t.Fatal(err) - } - - wait := make(chan error) - - go func() { - var gerr error - - for { - c, err := l.Accept() - if err != nil { - gerr = err - break - } - m := new(Message) - if err := c.Recv(m); err != nil { - gerr = err - break - } - if err := c.Send(m); err != nil { - gerr = err - break - } - } - - wait <- gerr - }() - - node.Address = l.Address() - - // connect to the node - conn, err := n.Connect(node) - if err != nil { - t.Fatal(err) - } - - // send a message - if err := conn.Send(&Message{ - Header: map[string]string{"Foo": "bar"}, - Body: []byte(`hello world`), - }); err != nil { - t.Fatal(err) - } - - m := new(Message) - // send a message - if err := conn.Recv(m); err != nil { - t.Fatal(err) - } - - if m.Header["Foo"] != "bar" { - t.Fatalf("Received unexpected message %+v", m) - } - - // close the listener - l.Close() - - // get listener error - err = <-wait - - if err != io.EOF { - t.Fatal(err) - } -} diff --git a/network/link.go b/network/link.go deleted file mode 100644 index 319692d3..00000000 --- a/network/link.go +++ /dev/null @@ -1,172 +0,0 @@ -package network - -import ( - "errors" - "io" - "sync" - - "github.com/google/uuid" - "github.com/micro/go-micro/transport" -) - -type link struct { - closed chan bool - - sync.RWMutex - - // the link id - id string - - // the send queue to the socket - sendQueue chan *Message - // the recv queue to the socket - recvQueue chan *Message - - // the socket for this link - socket transport.Socket - - // determines the cost of the link - // based on queue length and roundtrip - length int - weight int -} - -var ( - ErrLinkClosed = errors.New("link closed") -) - -func newLink(sock transport.Socket) *link { - l := &link{ - id: uuid.New().String(), - socket: sock, - closed: make(chan bool), - sendQueue: make(chan *Message, 128), - recvQueue: make(chan *Message, 128), - } - go l.process() - return l -} - -// link methods - -// process processes messages on the send queue. -// these are messages to be sent to the remote side. -func (l *link) process() { - go func() { - for { - m := new(Message) - if err := l.recv(m); err != nil { - return - } - - select { - case l.recvQueue <- m: - case <-l.closed: - return - } - } - }() - - for { - select { - case m := <-l.sendQueue: - if err := l.send(m); err != nil { - return - } - case <-l.closed: - return - } - } -} - -// send a message over the link -func (l *link) send(m *Message) error { - tm := new(transport.Message) - tm.Header = m.Header - tm.Body = m.Body - // send via the transport socket - return l.socket.Send(tm) -} - -// recv a message on the link -func (l *link) recv(m *Message) error { - if m.Header == nil { - m.Header = make(map[string]string) - } - - tm := new(transport.Message) - - // receive the transport message - if err := l.socket.Recv(tm); err != nil { - return err - } - - // set the message - m.Header = tm.Header - m.Body = tm.Body - - return nil -} - -// Close the link -func (l *link) Close() error { - select { - case <-l.closed: - return nil - default: - close(l.closed) - return l.socket.Close() - } -} - -// returns the node id -func (l *link) Id() string { - l.RLock() - defer l.RUnlock() - return l.id -} - -func (l *link) Remote() string { - l.RLock() - defer l.RUnlock() - return l.socket.Remote() -} - -func (l *link) Local() string { - l.RLock() - defer l.RUnlock() - return l.socket.Local() -} - -func (l *link) Length() int { - l.RLock() - defer l.RUnlock() - return l.length -} - -func (l *link) Weight() int { - return len(l.sendQueue) + len(l.recvQueue) -} - -// Accept accepts a message on the socket -func (l *link) Recv(m *Message) error { - select { - case <-l.closed: - return io.EOF - case rm := <-l.recvQueue: - *m = *rm - return nil - } - // never reach - return nil -} - -// Send sends a message on the socket immediately -func (l *link) Send(m *Message) error { - select { - case <-l.closed: - return io.EOF - case l.sendQueue <- m: - } - return nil -} diff --git a/network/network.go b/network/network.go deleted file mode 100644 index b27347df..00000000 --- a/network/network.go +++ /dev/null @@ -1,88 +0,0 @@ -// Package network is a package for defining a network overlay -package network - -import ( - "github.com/micro/go-micro/config/options" - "github.com/micro/go-micro/transport" -) - -// Network defines a network interface. The network is a single -// shared network between all nodes connected to it. The network -// is responsible for routing messages to the correct services. -type Network interface { - options.Options - // Name of the network - Name() string - // Create returns a new network node id/address - Create() (*Node, error) - // Connect to a node on the network - Connect(*Node) (Conn, error) - // Listen for connections for this node - Listen(*Node) (Listener, error) -} - -// Node is a network node represented with id/address and -// metadata which includes the network name, transport, etc -type Node struct { - Id string - Address string - Network string - Metadata map[string]string -} - -// A network node listener which can be used to receive messages -type Listener interface { - Address() string - Close() error - Accept() (Conn, error) -} - -// A connection from another node on the network -type Conn interface { - // Unique id of the connection - Id() string - // Close the connection - Close() error - // Send a message - Send(*Message) error - // Receive a message - Recv(*Message) error - // The remote node - Remote() string - // The local node - Local() string -} - -// The message type sent over the network -type Message struct { - Header map[string]string - Body []byte -} - -var ( - // The default network name is local - DefaultName = "go.micro" - - // just the standard network element - DefaultNetwork = NewNetwork() -) - -// NewNetwork returns a new network interface -func NewNetwork(opts ...options.Option) Network { - return newNetwork(opts...) -} - -// Name sets the network name -func Name(n string) options.Option { - return options.WithValue("network.name", n) -} - -// Address sets the network address -func Address(a string) options.Option { - return options.WithValue("network.address", a) -} - -// Transport sets the network transport -func Transport(t transport.Transport) options.Option { - return options.WithValue("network.transport", t) -} From 0a1b65722166269c72b40de3ca125d090c78d327 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 07:45:27 +0100 Subject: [PATCH 140/287] visual cleanup of router code --- network/router/default.go | 31 +++------ network/router/options.go | 16 ++--- network/router/router.go | 114 ++++++++++++++++------------------ network/router/table/route.go | 6 -- network/router/table/table.go | 6 -- 5 files changed, 69 insertions(+), 104 deletions(-) diff --git a/network/router/default.go b/network/router/default.go index c37fd49d..b6438e94 100644 --- a/network/router/default.go +++ b/network/router/default.go @@ -31,6 +31,8 @@ const ( // router provides default router implementation type router struct { + // embed the table + table.Table opts Options status Status exit chan struct{} @@ -52,6 +54,7 @@ func newRouter(opts ...Option) Router { } return &router{ + Table: options.Table, opts: options, status: Status{Error: nil, Code: Stopped}, exit: make(chan struct{}), @@ -75,26 +78,6 @@ func (r *router) Options() Options { return r.opts } -// ID returns router ID -func (r *router) ID() string { - return r.opts.ID -} - -// Table returns routing table -func (r *router) Table() table.Table { - return r.opts.Table -} - -// Address returns router's bind address -func (r *router) Address() string { - return r.opts.Address -} - -// Network returns the address router advertises to the network -func (r *router) Network() string { - return r.opts.Network -} - // manageServiceRoutes manages routes for a given service. // It returns error of the routing table action fails. func (r *router) manageServiceRoutes(service *registry.Service, action string) error { @@ -224,7 +207,7 @@ func (r *router) advertEvents(advType AdvertType, events []*table.Event) { defer r.advertWg.Done() a := &Advert{ - ID: r.ID(), + Id: r.opts.Id, Type: advType, Timestamp: time.Now(), Events: events, @@ -490,8 +473,8 @@ func (r *router) Advertise() (<-chan *Advert, error) { return r.advertChan, nil } -// Update updates the routing table using the advertised values -func (r *router) Update(a *Advert) error { +// Process updates the routing table using the advertised values +func (r *router) Process(a *Advert) error { // NOTE: event sorting might not be necessary // copy update events intp new slices events := make([]*table.Event, len(a.Events)) @@ -546,6 +529,6 @@ func (r *router) Stop() error { } // String prints debugging information about router -func (r router) String() string { +func (r *router) String() string { return "router" } diff --git a/network/router/options.go b/network/router/options.go index 96d956f6..1405ed6e 100644 --- a/network/router/options.go +++ b/network/router/options.go @@ -15,8 +15,8 @@ var ( // Options are router options type Options struct { - // ID is router id - ID string + // Id is router id + Id string // Address is router address Address string // Gateway is micro network gateway @@ -29,10 +29,10 @@ type Options struct { Table table.Table } -// ID sets Router ID -func ID(id string) Option { +// Id sets Router Id +func Id(id string) Option { return func(o *Options) { - o.ID = id + o.Id = id } } @@ -57,8 +57,8 @@ func Network(n string) Option { } } -// RoutingTable sets the routing table -func RoutingTable(t table.Table) Option { +// Table sets the routing table +func Table(t table.Table) Option { return func(o *Options) { o.Table = t } @@ -74,7 +74,7 @@ func Registry(r registry.Registry) Option { // DefaultOptions returns router default options func DefaultOptions() Options { return Options{ - ID: uuid.New().String(), + Id: uuid.New().String(), Address: DefaultAddress, Network: DefaultNetwork, Registry: registry.DefaultRegistry, diff --git a/network/router/router.go b/network/router/router.go index 715bcc56..23722a6a 100644 --- a/network/router/router.go +++ b/network/router/router.go @@ -7,43 +7,6 @@ import ( "github.com/micro/go-micro/network/router/table" ) -var ( - // DefaultRouter is default network router - DefaultRouter = NewRouter() -) - -// Router is an interface for a routing control plane -type Router interface { - // Init initializes the router with options - Init(...Option) error - // Options returns the router options - Options() Options - // ID returns the ID of the router - ID() string - // Address returns the router adddress - Address() string - // Network returns the network address of the router - Network() string - // Table returns the routing table - Table() table.Table - // Advertise advertises routes to the network - Advertise() (<-chan *Advert, error) - // Update updates the routing table - Update(*Advert) error - // Status returns router status - Status() Status - // Stop stops the router - Stop() error - // String returns debug info - String() string -} - -// Option used by the router -type Option func(*Options) - -// AdvertType is route advertisement type -type AdvertType int - const ( // Announce is advertised when the router announces itself Announce AdvertType = iota @@ -51,6 +14,15 @@ const ( Update ) +const ( + // Running means the router is up and running + Running StatusCode = iota + // Stopped means the router has been stopped + Stopped + // Error means the router has encountered error + Error +) + // String returns string representation of update event func (at AdvertType) String() string { switch at { @@ -63,10 +35,50 @@ func (at AdvertType) String() string { } } +// String returns human readable status code +func (sc StatusCode) String() string { + switch sc { + case Running: + return "RUNNING" + case Stopped: + return "STOPPED" + case Error: + return "ERROR" + default: + return "UNKNOWN" + } +} + +// Router is an interface for a routing control plane +type Router interface { + // Init initializes the router with options + Init(...Option) error + // Options returns the router options + Options() Options + // Table returns the routing table + table.Table + // Advertise advertises routes to the network + Advertise() (<-chan *Advert, error) + // Process processes incoming adverts + Process(*Advert) error + // Status returns router status + Status() Status + // Stop stops the router + Stop() error + // String returns debug info + String() string +} + +// Option used by the router +type Option func(*Options) + +// AdvertType is route advertisement type +type AdvertType int + // Advert contains a list of events advertised by the router to the network type Advert struct { - // ID is the router ID - ID string + // Id is the router Id + Id string // Type is type of advert Type AdvertType // Timestamp marks the time when the update is sent @@ -89,29 +101,11 @@ type Status struct { Code StatusCode } -const ( - // Running means the router is up and running - Running StatusCode = iota - // Stopped means the router has been stopped - Stopped - // Error means the router has encountered error - Error +var ( + // DefaultRouter is default network router + DefaultRouter = NewRouter() ) -// String returns human readable status code -func (sc StatusCode) String() string { - switch sc { - case Running: - return "RUNNING" - case Stopped: - return "STOPPED" - case Error: - return "ERROR" - default: - return "UNKNOWN" - } -} - // NewRouter creates new Router and returns it func NewRouter(opts ...Option) Router { return newRouter(opts...) diff --git a/network/router/table/route.go b/network/router/table/route.go index 652abd28..50a52068 100644 --- a/network/router/table/route.go +++ b/network/router/table/route.go @@ -34,11 +34,5 @@ func (r *Route) Hash() uint64 { h := fnv.New64() h.Reset() h.Write([]byte(r.Service + r.Address + r.Gateway + r.Network + r.Link)) - return h.Sum64() } - -// String returns human readable route -func (r Route) String() string { - return "route" -} diff --git a/network/router/table/table.go b/network/router/table/table.go index 9d353a54..f08e05b6 100644 --- a/network/router/table/table.go +++ b/network/router/table/table.go @@ -13,10 +13,6 @@ var ( // Table defines routing table interface type Table interface { - // Init initializes the router with options - Init(...TableOption) error - // Options returns the router options - Options() TableOptions // Add adds new route to the routing table Add(Route) error // Delete deletes existing route from the routing table @@ -31,8 +27,6 @@ type Table interface { Watch(opts ...WatchOption) (Watcher, error) // Size returns the size of the routing table Size() int - // String prints the routing table - String() string } // TableOption used by the routing table From 64ec0633a3b2da74812a9ef8457b6f8e7e573725 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 07:47:17 +0100 Subject: [PATCH 141/287] Fix breaks and go fmt --- client/grpc/grpc.go | 2 +- client/options.go | 2 +- client/rpc_client.go | 2 +- client/rpc_codec.go | 2 +- client/selector/router/router.go | 2 +- config/cmd/options.go | 2 +- network/proxy/mucp/mucp.go | 2 +- options.go | 2 +- server/grpc/options.go | 2 +- server/options.go | 2 +- server/rpc_server.go | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/client/grpc/grpc.go b/client/grpc/grpc.go index 48215270..7f389012 100644 --- a/client/grpc/grpc.go +++ b/client/grpc/grpc.go @@ -16,8 +16,8 @@ import ( "github.com/micro/go-micro/codec" "github.com/micro/go-micro/errors" "github.com/micro/go-micro/metadata" - "github.com/micro/go-micro/transport" "github.com/micro/go-micro/registry" + "github.com/micro/go-micro/transport" "google.golang.org/grpc" "google.golang.org/grpc/credentials" diff --git a/client/options.go b/client/options.go index 9f0c3f80..9f363d74 100644 --- a/client/options.go +++ b/client/options.go @@ -7,8 +7,8 @@ import ( "github.com/micro/go-micro/broker" "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/codec" - "github.com/micro/go-micro/transport" "github.com/micro/go-micro/registry" + "github.com/micro/go-micro/transport" ) type Options struct { diff --git a/client/rpc_client.go b/client/rpc_client.go index 2b974289..ea63041e 100644 --- a/client/rpc_client.go +++ b/client/rpc_client.go @@ -15,8 +15,8 @@ import ( "github.com/micro/go-micro/codec" "github.com/micro/go-micro/errors" "github.com/micro/go-micro/metadata" - "github.com/micro/go-micro/transport" "github.com/micro/go-micro/registry" + "github.com/micro/go-micro/transport" ) type rpcClient struct { diff --git a/client/rpc_codec.go b/client/rpc_codec.go index f3697b4b..6ff84a64 100644 --- a/client/rpc_codec.go +++ b/client/rpc_codec.go @@ -12,8 +12,8 @@ import ( "github.com/micro/go-micro/codec/proto" "github.com/micro/go-micro/codec/protorpc" "github.com/micro/go-micro/errors" - "github.com/micro/go-micro/transport" "github.com/micro/go-micro/registry" + "github.com/micro/go-micro/transport" ) const ( diff --git a/client/selector/router/router.go b/client/selector/router/router.go index 14146fba..ada33595 100644 --- a/client/selector/router/router.go +++ b/client/selector/router/router.go @@ -44,7 +44,7 @@ type routerKey struct{} func (r *routerSelector) getRoutes(service string) ([]table.Route, error) { if !r.remote { // lookup router for routes for the service - return r.r.Table().Lookup(table.NewQuery( + return r.r.Lookup(table.NewQuery( table.QueryService(service), )) } diff --git a/config/cmd/options.go b/config/cmd/options.go index b4917c27..1f221f35 100644 --- a/config/cmd/options.go +++ b/config/cmd/options.go @@ -6,9 +6,9 @@ import ( "github.com/micro/go-micro/broker" "github.com/micro/go-micro/client" "github.com/micro/go-micro/client/selector" - "github.com/micro/go-micro/transport" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/server" + "github.com/micro/go-micro/transport" ) type Options struct { diff --git a/network/proxy/mucp/mucp.go b/network/proxy/mucp/mucp.go index 05880fc9..22f04bc9 100644 --- a/network/proxy/mucp/mucp.go +++ b/network/proxy/mucp/mucp.go @@ -106,7 +106,7 @@ func (p *Proxy) getRoute(service string) ([]string, error) { // in future we might set a default gateway if p.Router != nil { // lookup the router - routes, err := p.Router.Table().Lookup( + routes, err := p.Router.Lookup( table.NewQuery(table.QueryService(service)), ) if err != nil { diff --git a/options.go b/options.go index 1b8a5724..d566a353 100644 --- a/options.go +++ b/options.go @@ -9,9 +9,9 @@ import ( "github.com/micro/go-micro/client" "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/config/cmd" - "github.com/micro/go-micro/transport" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/server" + "github.com/micro/go-micro/transport" ) type Options struct { diff --git a/server/grpc/options.go b/server/grpc/options.go index 3c9d125f..65d82fcc 100644 --- a/server/grpc/options.go +++ b/server/grpc/options.go @@ -6,10 +6,10 @@ import ( "github.com/micro/go-micro/broker" "github.com/micro/go-micro/codec" - "github.com/micro/go-micro/transport" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/server" "github.com/micro/go-micro/server/debug" + "github.com/micro/go-micro/transport" "google.golang.org/grpc" "google.golang.org/grpc/encoding" ) diff --git a/server/options.go b/server/options.go index 018958a2..15de9b83 100644 --- a/server/options.go +++ b/server/options.go @@ -7,9 +7,9 @@ import ( "github.com/micro/go-micro/broker" "github.com/micro/go-micro/codec" - "github.com/micro/go-micro/transport" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/server/debug" + "github.com/micro/go-micro/transport" ) type Options struct { diff --git a/server/rpc_server.go b/server/rpc_server.go index 284d499d..8bb7b547 100644 --- a/server/rpc_server.go +++ b/server/rpc_server.go @@ -13,8 +13,8 @@ import ( "github.com/micro/go-micro/broker" "github.com/micro/go-micro/codec" "github.com/micro/go-micro/metadata" - "github.com/micro/go-micro/transport" "github.com/micro/go-micro/registry" + "github.com/micro/go-micro/transport" "github.com/micro/go-micro/util/addr" log "github.com/micro/go-micro/util/log" ) From a08b64c8ab905cc2b8b40a6f521208fb0442e601 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 07:50:33 +0100 Subject: [PATCH 142/287] remove the string methods --- network/router/router.go | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/network/router/router.go b/network/router/router.go index 23722a6a..9416b196 100644 --- a/network/router/router.go +++ b/network/router/router.go @@ -23,32 +23,6 @@ const ( Error ) -// String returns string representation of update event -func (at AdvertType) String() string { - switch at { - case Announce: - return "ANNOUNCE" - case Update: - return "UPDATE" - default: - return "UNKNOWN" - } -} - -// String returns human readable status code -func (sc StatusCode) String() string { - switch sc { - case Running: - return "RUNNING" - case Stopped: - return "STOPPED" - case Error: - return "ERROR" - default: - return "UNKNOWN" - } -} - // Router is an interface for a routing control plane type Router interface { // Init initializes the router with options From c36107e811f4c051e50c628ed6bb58253ddda78c Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 07:51:24 +0100 Subject: [PATCH 143/287] cleanup consts --- network/router/router.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/network/router/router.go b/network/router/router.go index 9416b196..4834edac 100644 --- a/network/router/router.go +++ b/network/router/router.go @@ -8,19 +8,19 @@ import ( ) const ( - // Announce is advertised when the router announces itself - Announce AdvertType = iota - // Update advertises route updates - Update -) - -const ( + // Status codes // Running means the router is up and running Running StatusCode = iota // Stopped means the router has been stopped Stopped // Error means the router has encountered error Error + + // Advert types + // Announce is advertised when the router announces itself + Announce AdvertType = iota + // Update advertises route updates + Update ) // Router is an interface for a routing control plane From 9955ed2034994321f25a67b11ad6b524493dbda9 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 07:56:18 +0100 Subject: [PATCH 144/287] move table --- network/router/router.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/network/router/router.go b/network/router/router.go index 4834edac..7beb5653 100644 --- a/network/router/router.go +++ b/network/router/router.go @@ -25,12 +25,12 @@ const ( // Router is an interface for a routing control plane type Router interface { + // Router provides a routing table + table.Table // Init initializes the router with options Init(...Option) error // Options returns the router options Options() Options - // Table returns the routing table - table.Table // Advertise advertises routes to the network Advertise() (<-chan *Advert, error) // Process processes incoming adverts From 5b565f9f10d941216ab7c172dd4a1a085d723437 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 07:56:52 +0100 Subject: [PATCH 145/287] update comment --- network/router/router.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network/router/router.go b/network/router/router.go index 7beb5653..39e8d94a 100644 --- a/network/router/router.go +++ b/network/router/router.go @@ -39,7 +39,7 @@ type Router interface { Status() Status // Stop stops the router Stop() error - // String returns debug info + // Returns the router implementation String() string } From b23d955536e8e36cf11de7286ffd7ce8888a3dc8 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 08:26:33 +0100 Subject: [PATCH 146/287] Use gateway if available --- client/selector/router/router.go | 5 ++++- network/proxy/mucp/mucp.go | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/client/selector/router/router.go b/client/selector/router/router.go index ada33595..7f391f5b 100644 --- a/client/selector/router/router.go +++ b/client/selector/router/router.go @@ -162,7 +162,10 @@ func (r *routerSelector) Select(service string, opts ...selector.SelectOption) ( route := routes[idx%len(routes)] // defaults to gateway and no port - address := route.Gateway + address := route.Address + if len(route.Gateway) > 0 { + address = route.Gateway + } // return as a node return ®istry.Node{ diff --git a/network/proxy/mucp/mucp.go b/network/proxy/mucp/mucp.go index 22f04bc9..101f5f2a 100644 --- a/network/proxy/mucp/mucp.go +++ b/network/proxy/mucp/mucp.go @@ -84,7 +84,11 @@ func (p *Proxy) getRoute(service string) ([]string, error) { toNodes := func(routes []table.Route) []string { var nodes []string for _, node := range routes { - nodes = append(nodes, node.Gateway) + address := node.Address + if len(node.Gateway) > 0 { + address = node.Gateway + } + nodes = append(nodes, address) } return nodes } From 55f8045a70f5ff63f7cb5c792222ae115e9de445 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 17:12:51 +0100 Subject: [PATCH 147/287] Add link: a layer ontop of a transport socket --- network/link/link.go | 273 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 273 insertions(+) create mode 100644 network/link/link.go diff --git a/network/link/link.go b/network/link/link.go new file mode 100644 index 00000000..4458226e --- /dev/null +++ b/network/link/link.go @@ -0,0 +1,273 @@ +package link + +import ( + "errors" + "io" + "sync" + + "github.com/micro/go-micro/config/options" + "github.com/micro/go-micro/transport" +) + +// Link is a layer ontop of a transport socket with the +// buffering send and recv queue's with the ability to +// measure the actual transport link and reconnect. +type Link interface { + // provides the transport.Socket interface + transport.Socket + // Connect connects the link. It must be called first. + Connect() error + // Id of the link likely a uuid if not specified + Id() string + // Status of the link + Status() string + // Depth of the buffers + Weight() int + // Rate of the link + Length() int +} + +type link struct { + sync.RWMutex + + // the link id + id string + + // the remote end to dial + addr string + + // channel used to close the link + closed chan bool + + // if its connected + connected bool + + // the transport to use + transport transport.Transport + + // the send queue to the socket + sendQueue chan *transport.Message + // the recv queue to the socket + recvQueue chan *transport.Message + + // the socket for this link + socket transport.Socket + + // determines the cost of the link + // based on queue length and roundtrip + length int + weight int +} + +var ( + ErrLinkClosed = errors.New("link closed") +) + +func newLink(options options.Options) *link { + // default values + id := "local" + addr := "127.0.0.1:10001" + tr := transport.DefaultTransport + + lid, ok := options.Values().Get("link.id") + if ok { + id = lid.(string) + } + + laddr, ok := options.Values().Get("link.address") + if ok { + addr = laddr.(string) + } + + ltr, ok := options.Values().Get("link.transport") + if ok { + tr = ltr.(transport.Transport) + } + + l := &link{ + // the remote end to dial + addr: addr, + // transport to dial link + transport: tr, + // unique id assigned to the link + id: id, + // the closed channel used to close the conn + closed: make(chan bool), + // then send queue + sendQueue: make(chan *transport.Message, 128), + // the receive queue + recvQueue: make(chan *transport.Message, 128), + } + + // return the link + return l +} + +// link methods + +// process processes messages on the send queue. +// these are messages to be sent to the remote side. +func (l *link) process() { + go func() { + for { + m := new(transport.Message) + if err := l.recv(m); err != nil { + return + } + + select { + case l.recvQueue <- m: + case <-l.closed: + return + } + } + }() + + for { + select { + case m := <-l.sendQueue: + if err := l.send(m); err != nil { + return + } + case <-l.closed: + return + } + } +} + +// send a message over the link +func (l *link) send(m *transport.Message) error { + // TODO: measure time taken and calculate length/rate + // send via the transport socket + return l.socket.Send(m) +} + +// recv a message on the link +func (l *link) recv(m *transport.Message) error { + if m.Header == nil { + m.Header = make(map[string]string) + } + // receive the transport message + return l.socket.Recv(m) +} + +func (l *link) Connect() error { + l.Lock() + if l.connected { + l.Unlock() + return nil + } + + // replace closed + l.closed = make(chan bool) + + // dial the endpoint + c, err := l.transport.Dial(l.addr) + if err != nil { + l.Unlock() + return nil + } + + // set the socket + l.socket = c + + // kick start the processing + go l.process() + + return nil +} + +// Close the link +func (l *link) Close() error { + select { + case <-l.closed: + return nil + default: + close(l.closed) + l.Lock() + l.connected = false + l.Unlock() + return l.socket.Close() + } +} + +// returns the node id +func (l *link) Id() string { + l.RLock() + defer l.RUnlock() + return l.id +} + +func (l *link) Remote() string { + l.RLock() + defer l.RUnlock() + return l.socket.Remote() +} + +func (l *link) Local() string { + l.RLock() + defer l.RUnlock() + return l.socket.Local() +} + +func (l *link) Length() int { + l.RLock() + defer l.RUnlock() + return l.length +} + +func (l *link) Weight() int { + return len(l.sendQueue) + len(l.recvQueue) +} + +// Accept accepts a message on the socket +func (l *link) Recv(m *transport.Message) error { + select { + case <-l.closed: + return io.EOF + case rm := <-l.recvQueue: + *m = *rm + return nil + } + // never reach + return nil +} + +// Send sends a message on the socket immediately +func (l *link) Send(m *transport.Message) error { + select { + case <-l.closed: + return io.EOF + case l.sendQueue <- m: + } + return nil +} + +func (l *link) Status() string { + select { + case <-l.closed: + return "closed" + default: + return "connected" + } +} + +// NewLink creates a new link on top of a socket +func NewLink(opts ...options.Option) Link { + return newLink(options.NewOptions(opts...)) +} + +// Sets the link id +func Id(id string) options.Option { + return options.WithValue("link.id", id) +} + +// The address to use for the link +func Address(a string) options.Option { + return options.WithValue("link.address", a) +} + +// The transport to use for the link +func Transport(t transport.Transport) options.Option { + return options.WithValue("link.transport", t) +} From 86dfa82dface801031dff17c81544d45ddab5cb5 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Wed, 10 Jul 2019 17:21:55 +0100 Subject: [PATCH 148/287] Added List and Watch rpc calls. --- network/router/proto/router.micro.go | 99 +++++++++++ network/router/proto/router.pb.go | 245 ++++++++++++++++++++++++--- network/router/proto/router.proto | 32 +++- 3 files changed, 356 insertions(+), 20 deletions(-) diff --git a/network/router/proto/router.micro.go b/network/router/proto/router.micro.go index 9c4fdb1e..bba03161 100644 --- a/network/router/proto/router.micro.go +++ b/network/router/proto/router.micro.go @@ -34,7 +34,9 @@ var _ server.Option // Client API for Router service type RouterService interface { + Watch(ctx context.Context, in *WatchRequest, opts ...client.CallOption) (Router_WatchService, error) Lookup(ctx context.Context, in *LookupRequest, opts ...client.CallOption) (*LookupResponse, error) + List(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*ListResponse, error) } type routerService struct { @@ -55,6 +57,50 @@ func NewRouterService(name string, c client.Client) RouterService { } } +func (c *routerService) Watch(ctx context.Context, in *WatchRequest, opts ...client.CallOption) (Router_WatchService, error) { + req := c.c.NewRequest(c.name, "Router.Watch", &WatchRequest{}) + stream, err := c.c.Stream(ctx, req, opts...) + if err != nil { + return nil, err + } + if err := stream.Send(in); err != nil { + return nil, err + } + return &routerServiceWatch{stream}, nil +} + +type Router_WatchService interface { + SendMsg(interface{}) error + RecvMsg(interface{}) error + Close() error + Recv() (*TableEvent, error) +} + +type routerServiceWatch struct { + stream client.Stream +} + +func (x *routerServiceWatch) Close() error { + return x.stream.Close() +} + +func (x *routerServiceWatch) SendMsg(m interface{}) error { + return x.stream.Send(m) +} + +func (x *routerServiceWatch) RecvMsg(m interface{}) error { + return x.stream.Recv(m) +} + +func (x *routerServiceWatch) Recv() (*TableEvent, error) { + m := new(TableEvent) + err := x.stream.Recv(m) + if err != nil { + return nil, err + } + return m, nil +} + func (c *routerService) Lookup(ctx context.Context, in *LookupRequest, opts ...client.CallOption) (*LookupResponse, error) { req := c.c.NewRequest(c.name, "Router.Lookup", in) out := new(LookupResponse) @@ -65,15 +111,29 @@ func (c *routerService) Lookup(ctx context.Context, in *LookupRequest, opts ...c return out, nil } +func (c *routerService) List(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*ListResponse, error) { + req := c.c.NewRequest(c.name, "Router.List", in) + out := new(ListResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // Server API for Router service type RouterHandler interface { + Watch(context.Context, *WatchRequest, Router_WatchStream) error Lookup(context.Context, *LookupRequest, *LookupResponse) error + List(context.Context, *ListRequest, *ListResponse) error } func RegisterRouterHandler(s server.Server, hdlr RouterHandler, opts ...server.HandlerOption) error { type router interface { + Watch(ctx context.Context, stream server.Stream) error Lookup(ctx context.Context, in *LookupRequest, out *LookupResponse) error + List(ctx context.Context, in *ListRequest, out *ListResponse) error } type Router struct { router @@ -86,6 +146,45 @@ type routerHandler struct { RouterHandler } +func (h *routerHandler) Watch(ctx context.Context, stream server.Stream) error { + m := new(WatchRequest) + if err := stream.Recv(m); err != nil { + return err + } + return h.RouterHandler.Watch(ctx, m, &routerWatchStream{stream}) +} + +type Router_WatchStream interface { + SendMsg(interface{}) error + RecvMsg(interface{}) error + Close() error + Send(*TableEvent) error +} + +type routerWatchStream struct { + stream server.Stream +} + +func (x *routerWatchStream) Close() error { + return x.stream.Close() +} + +func (x *routerWatchStream) SendMsg(m interface{}) error { + return x.stream.Send(m) +} + +func (x *routerWatchStream) RecvMsg(m interface{}) error { + return x.stream.Recv(m) +} + +func (x *routerWatchStream) Send(m *TableEvent) error { + return x.stream.Send(m) +} + func (h *routerHandler) Lookup(ctx context.Context, in *LookupRequest, out *LookupResponse) error { return h.RouterHandler.Lookup(ctx, in, out) } + +func (h *routerHandler) List(ctx context.Context, in *ListRequest, out *ListResponse) error { + return h.RouterHandler.List(ctx, in, out) +} diff --git a/network/router/proto/router.pb.go b/network/router/proto/router.pb.go index d7d7a520..2682a494 100644 --- a/network/router/proto/router.pb.go +++ b/network/router/proto/router.pb.go @@ -20,6 +20,35 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package +// EventType is TableEvent type +type EventType int32 + +const ( + EventType_Insert EventType = 0 + EventType_Delete EventType = 1 + EventType_Update EventType = 2 +) + +var EventType_name = map[int32]string{ + 0: "Insert", + 1: "Delete", + 2: "Update", +} + +var EventType_value = map[string]int32{ + "Insert": 0, + "Delete": 1, + "Update": 2, +} + +func (x EventType) String() string { + return proto.EnumName(EventType_name, int32(x)) +} + +func (EventType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_367072455c71aedc, []int{0} +} + // LookupRequest is made to Lookup type LookupRequest struct { Query *Query `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"` @@ -60,7 +89,7 @@ func (m *LookupRequest) GetQuery() *Query { return nil } -// LookupResponse is returns by Lookup +// LookupResponse is returned by Lookup type LookupResponse struct { Routes []*Route `protobuf:"bytes,1,rep,name=routes,proto3" json:"routes,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -100,6 +129,169 @@ func (m *LookupResponse) GetRoutes() []*Route { return nil } +// WatchRequest is made to Watch Router +type WatchRequest struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *WatchRequest) Reset() { *m = WatchRequest{} } +func (m *WatchRequest) String() string { return proto.CompactTextString(m) } +func (*WatchRequest) ProtoMessage() {} +func (*WatchRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_367072455c71aedc, []int{2} +} + +func (m *WatchRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_WatchRequest.Unmarshal(m, b) +} +func (m *WatchRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_WatchRequest.Marshal(b, m, deterministic) +} +func (m *WatchRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_WatchRequest.Merge(m, src) +} +func (m *WatchRequest) XXX_Size() int { + return xxx_messageInfo_WatchRequest.Size(m) +} +func (m *WatchRequest) XXX_DiscardUnknown() { + xxx_messageInfo_WatchRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_WatchRequest proto.InternalMessageInfo + +// TableEvent is streamed by WatchRequest +type TableEvent struct { + // time of table event + Type EventType `protobuf:"varint,1,opt,name=type,proto3,enum=EventType" json:"type,omitempty"` + // unix timestamp of event + Timestamp int64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + // service route + Route *Route `protobuf:"bytes,3,opt,name=route,proto3" json:"route,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TableEvent) Reset() { *m = TableEvent{} } +func (m *TableEvent) String() string { return proto.CompactTextString(m) } +func (*TableEvent) ProtoMessage() {} +func (*TableEvent) Descriptor() ([]byte, []int) { + return fileDescriptor_367072455c71aedc, []int{3} +} + +func (m *TableEvent) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TableEvent.Unmarshal(m, b) +} +func (m *TableEvent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TableEvent.Marshal(b, m, deterministic) +} +func (m *TableEvent) XXX_Merge(src proto.Message) { + xxx_messageInfo_TableEvent.Merge(m, src) +} +func (m *TableEvent) XXX_Size() int { + return xxx_messageInfo_TableEvent.Size(m) +} +func (m *TableEvent) XXX_DiscardUnknown() { + xxx_messageInfo_TableEvent.DiscardUnknown(m) +} + +var xxx_messageInfo_TableEvent proto.InternalMessageInfo + +func (m *TableEvent) GetType() EventType { + if m != nil { + return m.Type + } + return EventType_Insert +} + +func (m *TableEvent) GetTimestamp() int64 { + if m != nil { + return m.Timestamp + } + return 0 +} + +func (m *TableEvent) GetRoute() *Route { + if m != nil { + return m.Route + } + return nil +} + +// ListRequest is made to List routes +type ListRequest struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListRequest) Reset() { *m = ListRequest{} } +func (m *ListRequest) String() string { return proto.CompactTextString(m) } +func (*ListRequest) ProtoMessage() {} +func (*ListRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_367072455c71aedc, []int{4} +} + +func (m *ListRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ListRequest.Unmarshal(m, b) +} +func (m *ListRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ListRequest.Marshal(b, m, deterministic) +} +func (m *ListRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListRequest.Merge(m, src) +} +func (m *ListRequest) XXX_Size() int { + return xxx_messageInfo_ListRequest.Size(m) +} +func (m *ListRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ListRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ListRequest proto.InternalMessageInfo + +// ListResponse is returned by List +type ListResponse struct { + Routes []*Route `protobuf:"bytes,1,rep,name=routes,proto3" json:"routes,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListResponse) Reset() { *m = ListResponse{} } +func (m *ListResponse) String() string { return proto.CompactTextString(m) } +func (*ListResponse) ProtoMessage() {} +func (*ListResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_367072455c71aedc, []int{5} +} + +func (m *ListResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ListResponse.Unmarshal(m, b) +} +func (m *ListResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ListResponse.Marshal(b, m, deterministic) +} +func (m *ListResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListResponse.Merge(m, src) +} +func (m *ListResponse) XXX_Size() int { + return xxx_messageInfo_ListResponse.Size(m) +} +func (m *ListResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ListResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_ListResponse proto.InternalMessageInfo + +func (m *ListResponse) GetRoutes() []*Route { + if m != nil { + return m.Routes + } + return nil +} + // Query is passed in a LookupRequest type Query struct { // service to lookup @@ -113,7 +305,7 @@ func (m *Query) Reset() { *m = Query{} } func (m *Query) String() string { return proto.CompactTextString(m) } func (*Query) ProtoMessage() {} func (*Query) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{2} + return fileDescriptor_367072455c71aedc, []int{6} } func (m *Query) XXX_Unmarshal(b []byte) error { @@ -164,7 +356,7 @@ func (m *Route) Reset() { *m = Route{} } func (m *Route) String() string { return proto.CompactTextString(m) } func (*Route) ProtoMessage() {} func (*Route) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{3} + return fileDescriptor_367072455c71aedc, []int{7} } func (m *Route) XXX_Unmarshal(b []byte) error { @@ -228,8 +420,13 @@ func (m *Route) GetMetric() int64 { } func init() { + proto.RegisterEnum("EventType", EventType_name, EventType_value) proto.RegisterType((*LookupRequest)(nil), "LookupRequest") proto.RegisterType((*LookupResponse)(nil), "LookupResponse") + proto.RegisterType((*WatchRequest)(nil), "WatchRequest") + proto.RegisterType((*TableEvent)(nil), "TableEvent") + proto.RegisterType((*ListRequest)(nil), "ListRequest") + proto.RegisterType((*ListResponse)(nil), "ListResponse") proto.RegisterType((*Query)(nil), "Query") proto.RegisterType((*Route)(nil), "Route") } @@ -237,20 +434,30 @@ func init() { func init() { proto.RegisterFile("router.proto", fileDescriptor_367072455c71aedc) } var fileDescriptor_367072455c71aedc = []byte{ - // 238 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x90, 0xc1, 0x4a, 0xc4, 0x30, - 0x10, 0x86, 0x8d, 0xdd, 0x46, 0x1c, 0x75, 0x85, 0x1c, 0x24, 0x88, 0x48, 0xcd, 0x69, 0x41, 0x2c, - 0xb2, 0xe2, 0x5b, 0x78, 0x31, 0x6f, 0x50, 0x77, 0x07, 0x29, 0xd5, 0xa6, 0x3b, 0x49, 0x5c, 0xf6, - 0x59, 0x7c, 0x59, 0xc9, 0x24, 0x7b, 0xe8, 0xc1, 0x5b, 0xbf, 0xf9, 0x66, 0x7e, 0x9a, 0x1f, 0x2e, - 0xc9, 0xc5, 0x80, 0xd4, 0x4e, 0xe4, 0x82, 0x33, 0x4f, 0x70, 0xf5, 0xe6, 0xdc, 0x10, 0x27, 0x8b, - 0xbb, 0x88, 0x3e, 0xa8, 0x3b, 0xa8, 0x77, 0x11, 0xe9, 0xa0, 0x45, 0x23, 0x56, 0x17, 0x6b, 0xd9, - 0xbe, 0x27, 0xb2, 0x79, 0x68, 0x9e, 0x61, 0x79, 0x5c, 0xf7, 0x93, 0x1b, 0x3d, 0xaa, 0x7b, 0x90, - 0x1c, 0xe8, 0xb5, 0x68, 0x2a, 0x3e, 0xb0, 0x09, 0x6d, 0x99, 0x9a, 0x07, 0xa8, 0x39, 0x41, 0x69, - 0x38, 0xf3, 0x48, 0x3f, 0xfd, 0x06, 0x39, 0xfa, 0xdc, 0x1e, 0xd1, 0xfc, 0x0a, 0xa8, 0xf9, 0xe8, - 0xff, 0x9d, 0x64, 0xba, 0xed, 0x96, 0xd0, 0x7b, 0x7d, 0x9a, 0x4d, 0xc1, 0x64, 0x3e, 0xbb, 0x80, - 0xfb, 0xee, 0xa0, 0xab, 0x6c, 0x0a, 0x26, 0x33, 0x62, 0xd8, 0x3b, 0x1a, 0xf4, 0x22, 0x9b, 0x82, - 0x4a, 0xc1, 0xe2, 0xab, 0x1f, 0x07, 0x5d, 0xf3, 0x98, 0xbf, 0xd5, 0x0d, 0xc8, 0x6f, 0x0c, 0xd4, - 0x6f, 0xb4, 0x6c, 0xc4, 0xaa, 0xb2, 0x85, 0xd6, 0xaf, 0x20, 0xf9, 0xe7, 0x48, 0x3d, 0x82, 0xcc, - 0x8f, 0x57, 0xcb, 0x76, 0x56, 0xda, 0xed, 0x75, 0x3b, 0x6f, 0xc5, 0x9c, 0x7c, 0x48, 0xee, 0xf7, - 0xe5, 0x2f, 0x00, 0x00, 0xff, 0xff, 0xd3, 0x99, 0xfb, 0x2d, 0x6f, 0x01, 0x00, 0x00, + // 390 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0xc1, 0x8e, 0xd3, 0x30, + 0x10, 0x8d, 0xb7, 0x89, 0x51, 0xa6, 0x49, 0xa8, 0x7c, 0x40, 0x56, 0xb5, 0x5a, 0x15, 0x4b, 0x88, + 0x15, 0x08, 0xb3, 0x2a, 0xbf, 0x00, 0x07, 0xa4, 0xbd, 0x60, 0x2d, 0xe2, 0x9c, 0x6d, 0x47, 0x6c, + 0xd4, 0x36, 0xc9, 0xda, 0xce, 0xae, 0xf2, 0x01, 0x7c, 0x05, 0x3f, 0x8b, 0x3c, 0x49, 0x68, 0x7b, + 0x40, 0xe2, 0x36, 0xef, 0x8d, 0xed, 0x79, 0x9e, 0xf7, 0x20, 0xb3, 0x4d, 0xe7, 0xd1, 0xea, 0xd6, + 0x36, 0xbe, 0x51, 0x1f, 0x20, 0xbf, 0x6d, 0x9a, 0x5d, 0xd7, 0x1a, 0x7c, 0xec, 0xd0, 0x79, 0x71, + 0x09, 0xc9, 0x63, 0x87, 0xb6, 0x97, 0x6c, 0xc5, 0xae, 0xe7, 0x6b, 0xae, 0xbf, 0x05, 0x64, 0x06, + 0x52, 0xdd, 0x40, 0x31, 0x1d, 0x77, 0x6d, 0x53, 0x3b, 0x14, 0x57, 0xc0, 0xe9, 0x41, 0x27, 0xd9, + 0x6a, 0x46, 0x17, 0x4c, 0x80, 0x66, 0x64, 0x55, 0x01, 0xd9, 0x8f, 0xd2, 0x6f, 0x1e, 0xc6, 0xf7, + 0xd5, 0x03, 0xc0, 0x5d, 0x79, 0xbf, 0xc7, 0x2f, 0x4f, 0x58, 0x7b, 0x71, 0x05, 0xb1, 0xef, 0x5b, + 0xa4, 0x61, 0xc5, 0x1a, 0x34, 0xb1, 0x77, 0x7d, 0x8b, 0x86, 0x78, 0x71, 0x09, 0xa9, 0xaf, 0x0e, + 0xe8, 0x7c, 0x79, 0x68, 0xe5, 0xc5, 0x8a, 0x5d, 0xcf, 0xcc, 0x91, 0x08, 0x5a, 0x69, 0x8a, 0x9c, + 0x8d, 0x5a, 0x87, 0xd1, 0x03, 0xa9, 0x72, 0x98, 0xdf, 0x56, 0xce, 0x4f, 0x83, 0x35, 0x64, 0x03, + 0xfc, 0x4f, 0xe1, 0xaf, 0x21, 0xa1, 0xaf, 0x0b, 0x09, 0x2f, 0x1c, 0xda, 0xa7, 0x6a, 0x33, 0xc8, + 0x4c, 0xcd, 0x04, 0xd5, 0x6f, 0x06, 0x09, 0x5d, 0xfa, 0xf7, 0x99, 0xd0, 0x29, 0xb7, 0x5b, 0x8b, + 0xce, 0x91, 0xfe, 0xd4, 0x4c, 0x30, 0x74, 0x7e, 0x96, 0x1e, 0x9f, 0xcb, 0x9e, 0xf4, 0xa7, 0x66, + 0x82, 0xa1, 0x53, 0xa3, 0x7f, 0x6e, 0xec, 0x4e, 0xc6, 0x43, 0x67, 0x84, 0x42, 0x40, 0xbc, 0xaf, + 0xea, 0x9d, 0x4c, 0x88, 0xa6, 0x5a, 0xbc, 0x02, 0x7e, 0x40, 0x6f, 0xab, 0x8d, 0xe4, 0xb4, 0xa0, + 0x11, 0xbd, 0xfb, 0x08, 0xe9, 0xdf, 0x75, 0x0a, 0x00, 0xfe, 0xb5, 0x76, 0x68, 0xfd, 0x22, 0x0a, + 0xf5, 0x67, 0xdc, 0xa3, 0xc7, 0x05, 0x0b, 0xf5, 0xf7, 0x76, 0x5b, 0x7a, 0x5c, 0x5c, 0xac, 0x7f, + 0x31, 0xe0, 0xf4, 0x1d, 0x2b, 0xde, 0x42, 0x42, 0xae, 0x89, 0x5c, 0x9f, 0xba, 0xb7, 0x9c, 0xeb, + 0xa3, 0x79, 0x2a, 0xba, 0x61, 0xe2, 0x3d, 0xf0, 0x21, 0x10, 0xa2, 0xd0, 0x67, 0x41, 0x5a, 0xbe, + 0xd4, 0xe7, 0x49, 0x51, 0x91, 0x78, 0x03, 0x71, 0xb0, 0x40, 0x64, 0xfa, 0xc4, 0x98, 0x65, 0xae, + 0x4f, 0x7d, 0x51, 0xd1, 0x3d, 0xa7, 0x68, 0x7e, 0xfa, 0x13, 0x00, 0x00, 0xff, 0xff, 0x7e, 0xbb, + 0x6d, 0x5c, 0xaa, 0x02, 0x00, 0x00, } diff --git a/network/router/proto/router.proto b/network/router/proto/router.proto index 4d278d0f..3d3a3fce 100644 --- a/network/router/proto/router.proto +++ b/network/router/proto/router.proto @@ -2,7 +2,9 @@ syntax = "proto3"; // Router service is used by the proxy to lookup routes service Router { + rpc Watch(WatchRequest) returns (stream TableEvent) {}; rpc Lookup(LookupRequest) returns (LookupResponse) {}; + rpc List(ListRequest) returns (ListResponse) {}; } // LookupRequest is made to Lookup @@ -10,11 +12,39 @@ message LookupRequest { Query query = 1; } -// LookupResponse is returns by Lookup +// LookupResponse is returned by Lookup message LookupResponse { repeated Route routes = 1; } +// WatchRequest is made to Watch Router +message WatchRequest {} + +// EventType is TableEvent type +enum EventType { + Insert = 0; + Delete = 1; + Update = 2; +} + +// TableEvent is streamed by WatchRequest +message TableEvent { + // time of table event + EventType type = 1; + // unix timestamp of event + int64 timestamp = 2; + // service route + Route route = 3; +} + +// ListRequest is made to List routes +message ListRequest {} + +// ListResponse is returned by List +message ListResponse { + repeated Route routes = 1; +} + // Query is passed in a LookupRequest message Query { // service to lookup From 66c2519696832b5dcdb223b6d36df6502874bc80 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 17:36:04 +0100 Subject: [PATCH 149/287] Add Tunnel: an interface for stream duplexing over a link --- network/tunnel/default.go | 232 ++++++++++++++++++++++++++++++++++++++ network/tunnel/socket.go | 82 ++++++++++++++ network/tunnel/tunnel.go | 31 +++++ 3 files changed, 345 insertions(+) create mode 100644 network/tunnel/default.go create mode 100644 network/tunnel/socket.go create mode 100644 network/tunnel/tunnel.go diff --git a/network/tunnel/default.go b/network/tunnel/default.go new file mode 100644 index 00000000..c9f274f0 --- /dev/null +++ b/network/tunnel/default.go @@ -0,0 +1,232 @@ +package tunnel + +import ( + "crypto/sha256" + "errors" + "fmt" + "sync" + + "github.com/google/uuid" + "github.com/micro/go-micro/network/link" + "github.com/micro/go-micro/transport" +) + +// tun represents a network tunnel +type tun struct { + link link.Link + + sync.RWMutex + + // connect + connected bool + + // the send channel + send chan *message + // close channel + closed chan bool + + // sockets + sockets map[string]*socket +} + +// create new tunnel +func newTunnel(link link.Link) *tun { + return &tun{ + link: link, + send: make(chan *message, 128), + closed: make(chan bool), + sockets: make(map[string]*socket), + } +} + +func (t *tun) getSocket(id string) (*socket, bool) { + // get the socket + t.RLock() + s, ok := t.sockets[id] + t.RUnlock() + return s, ok +} + +func (t *tun) newSocket(id string) *socket { + // new id if it doesn't exist + if len(id) == 0 { + id = uuid.New().String() + } + + // hash the id + h := sha256.New() + h.Write([]byte(id)) + id = fmt.Sprintf("%x", h.Sum(nil)) + + // new socket + s := &socket{ + id: id, + closed: make(chan bool), + recv: make(chan *message, 128), + send: t.send, + } + + // save socket + t.Lock() + t.sockets[id] = s + t.Unlock() + + // return socket + return s +} + +// process outgoing messages +func (t *tun) process() { + // manage the send buffer + // all pseudo sockets throw everything down this + for { + select { + case msg := <-t.send: + nmsg := &transport.Message{ + Header: msg.data.Header, + Body: msg.data.Body, + } + + // set the stream id on the outgoing message + nmsg.Header["Micro-Tunnel"] = msg.id + + // send the message via the interface + if err := t.link.Send(nmsg); err != nil { + // no op + // TODO: do something + } + case <-t.closed: + return + } + } +} + +// process incoming messages +func (t *tun) listen() { + for { + // process anything via the net interface + msg := new(transport.Message) + err := t.link.Recv(msg) + if err != nil { + return + } + + // a stream id + id := msg.Header["Micro-Tunnel"] + + // get the socket + s, exists := t.getSocket(id) + if !exists { + // no op + continue + } + + // is the socket closed? + select { + case <-s.closed: + // closed + delete(t.sockets, id) + continue + default: + // process + } + + // is the socket new? + select { + // if its new it will block here + case <-s.wait: + // its not new + default: + // its new + // set remote address of the socket + s.remote = msg.Header["Remote"] + close(s.wait) + } + + tmsg := &transport.Message{ + Header: msg.Header, + Body: msg.Body, + } + + // TODO: don't block on queuing + // append to recv backlog + s.recv <- &message{id: id, data: tmsg} + } +} + +// Close the tunnel +func (t *tun) Close() error { + t.Lock() + defer t.Unlock() + + if !t.connected { + return nil + } + + select { + case <-t.closed: + return nil + default: + // close all the sockets + for _, s := range t.sockets { + s.Close() + } + // close the connection + close(t.closed) + t.connected = false + } + + return nil +} + +// Connect the tunnel +func (t *tun) Connect() error { + t.Lock() + defer t.Unlock() + + // already connected + if t.connected { + return nil + } + + // set as connected + t.connected = true + // create new close channel + t.closed = make(chan bool) + + // process messages to be sent + go t.process() + // process incoming messages + go t.listen() + + return nil +} + +// Dial an address +func (t *tun) Dial(addr string) (Conn, error) { + c := t.newSocket(addr) + // set remote + c.remote = addr + // set local + c.local = t.link.Local() + return c, nil +} + +func (t *tun) Accept(addr string) (Conn, error) { + // create a new socket by hashing the address + c := t.newSocket(addr) + // set remote. it will be replaced by the first message received + c.remote = t.link.Remote() + // set local + c.local = addr + + select { + case <-c.closed: + return nil, errors.New("error creating socket") + // wait for the first message + case <-c.wait: + } + + // return socket + return c, nil +} diff --git a/network/tunnel/socket.go b/network/tunnel/socket.go new file mode 100644 index 00000000..861e3f4c --- /dev/null +++ b/network/tunnel/socket.go @@ -0,0 +1,82 @@ +package tunnel + +import ( + "errors" + + "github.com/micro/go-micro/transport" +) + +// socket is our pseudo socket for transport.Socket +type socket struct { + // socket id based on Micro-Tunnel + id string + // closed + closed chan bool + // remote addr + remote string + // local addr + local string + // send chan + send chan *message + // recv chan + recv chan *message + // wait until we have a connection + wait chan bool +} + +// message is sent over the send channel +type message struct { + // socket id + id string + // transport data + data *transport.Message +} + +func (s *socket) Remote() string { + return s.remote +} + +func (s *socket) Local() string { + return s.local +} + +func (s *socket) Id() string { + return s.id +} + +func (s *socket) Send(m *transport.Message) error { + select { + case <-s.closed: + return errors.New("socket is closed") + default: + // no op + } + // append to backlog + s.send <- &message{id: s.id, data: m} + return nil +} + +func (s *socket) Recv(m *transport.Message) error { + select { + case <-s.closed: + return errors.New("socket is closed") + default: + // no op + } + // recv from backlog + msg := <-s.recv + // set message + *m = *msg.data + // return nil + return nil +} + +func (s *socket) Close() error { + select { + case <-s.closed: + // no op + default: + close(s.closed) + } + return nil +} diff --git a/network/tunnel/tunnel.go b/network/tunnel/tunnel.go new file mode 100644 index 00000000..837701e4 --- /dev/null +++ b/network/tunnel/tunnel.go @@ -0,0 +1,31 @@ +// Package tunnel provides a network tunnel +package tunnel + +import ( + "github.com/micro/go-micro/network/link" + "github.com/micro/go-micro/transport" +) + +// Tunnel creates a network tunnel +type Tunnel interface { + // Connect connects the tunnel + Connect() error + // Close closes the tunnel + Close() error + // Dial an endpoint + Dial(addr string) (Conn, error) + // Accept connections + Accept(addr string) (Conn, error) +} + +type Conn interface { + // Specifies the tunnel id + Id() string + // a transport socket + transport.Socket +} + +// NewTunnel creates a new tunnel on top of a link +func NewTunnel(l link.Link) Tunnel { + return newTunnel(l) +} From 4e3a230356b9164879db427ab34ab78682ad7aa1 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 17:40:14 +0100 Subject: [PATCH 150/287] top level package comment --- network/link/link.go | 1 + 1 file changed, 1 insertion(+) diff --git a/network/link/link.go b/network/link/link.go index 4458226e..e50c683f 100644 --- a/network/link/link.go +++ b/network/link/link.go @@ -1,3 +1,4 @@ +// Package link provides a measured transport.Socket link package link import ( From 717ba4b3c00534a115a2e229c514dd378cd9fbc8 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 17:41:17 +0100 Subject: [PATCH 151/287] Add tunnel comments --- network/tunnel/tunnel.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/network/tunnel/tunnel.go b/network/tunnel/tunnel.go index 837701e4..3189e81d 100644 --- a/network/tunnel/tunnel.go +++ b/network/tunnel/tunnel.go @@ -1,4 +1,4 @@ -// Package tunnel provides a network tunnel +// Package tunnel provides a network tunnel ontop of a link package tunnel import ( @@ -6,7 +6,9 @@ import ( "github.com/micro/go-micro/transport" ) -// Tunnel creates a network tunnel +// Tunnel creates a network tunnel on top of a link. +// It establishes multiple streams using the Micro-Tunnel header +// created as a hash of the address. type Tunnel interface { // Connect connects the tunnel Connect() error From 27cfc068282c841cc6d5bd69d94854a0227af36c Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 17:42:41 +0100 Subject: [PATCH 152/287] Cleanup and move around the link code --- network/link/default.go | 231 ++++++++++++++++++++++++++++++++++++++++ network/link/link.go | 223 -------------------------------------- 2 files changed, 231 insertions(+), 223 deletions(-) create mode 100644 network/link/default.go diff --git a/network/link/default.go b/network/link/default.go new file mode 100644 index 00000000..0e55f033 --- /dev/null +++ b/network/link/default.go @@ -0,0 +1,231 @@ +// Package link provides a measured transport.Socket link +package link + +import ( + "io" + "sync" + + "github.com/micro/go-micro/config/options" + "github.com/micro/go-micro/transport" +) + +type link struct { + sync.RWMutex + + // the link id + id string + + // the remote end to dial + addr string + + // channel used to close the link + closed chan bool + + // if its connected + connected bool + + // the transport to use + transport transport.Transport + + // the send queue to the socket + sendQueue chan *transport.Message + // the recv queue to the socket + recvQueue chan *transport.Message + + // the socket for this link + socket transport.Socket + + // determines the cost of the link + // based on queue length and roundtrip + length int + weight int +} + +func newLink(options options.Options) *link { + // default values + id := "local" + addr := "127.0.0.1:10001" + tr := transport.DefaultTransport + + lid, ok := options.Values().Get("link.id") + if ok { + id = lid.(string) + } + + laddr, ok := options.Values().Get("link.address") + if ok { + addr = laddr.(string) + } + + ltr, ok := options.Values().Get("link.transport") + if ok { + tr = ltr.(transport.Transport) + } + + l := &link{ + // the remote end to dial + addr: addr, + // transport to dial link + transport: tr, + // unique id assigned to the link + id: id, + // the closed channel used to close the conn + closed: make(chan bool), + // then send queue + sendQueue: make(chan *transport.Message, 128), + // the receive queue + recvQueue: make(chan *transport.Message, 128), + } + + // return the link + return l +} + +// link methods + +// process processes messages on the send queue. +// these are messages to be sent to the remote side. +func (l *link) process() { + go func() { + for { + m := new(transport.Message) + if err := l.recv(m); err != nil { + return + } + + select { + case l.recvQueue <- m: + case <-l.closed: + return + } + } + }() + + for { + select { + case m := <-l.sendQueue: + if err := l.send(m); err != nil { + return + } + case <-l.closed: + return + } + } +} + +// send a message over the link +func (l *link) send(m *transport.Message) error { + // TODO: measure time taken and calculate length/rate + // send via the transport socket + return l.socket.Send(m) +} + +// recv a message on the link +func (l *link) recv(m *transport.Message) error { + if m.Header == nil { + m.Header = make(map[string]string) + } + // receive the transport message + return l.socket.Recv(m) +} + +func (l *link) Connect() error { + l.Lock() + if l.connected { + l.Unlock() + return nil + } + + // replace closed + l.closed = make(chan bool) + + // dial the endpoint + c, err := l.transport.Dial(l.addr) + if err != nil { + l.Unlock() + return nil + } + + // set the socket + l.socket = c + + // kick start the processing + go l.process() + + return nil +} + +// Close the link +func (l *link) Close() error { + select { + case <-l.closed: + return nil + default: + close(l.closed) + l.Lock() + l.connected = false + l.Unlock() + return l.socket.Close() + } +} + +// returns the node id +func (l *link) Id() string { + l.RLock() + defer l.RUnlock() + return l.id +} + +func (l *link) Remote() string { + l.RLock() + defer l.RUnlock() + return l.socket.Remote() +} + +func (l *link) Local() string { + l.RLock() + defer l.RUnlock() + return l.socket.Local() +} + +func (l *link) Length() int { + l.RLock() + defer l.RUnlock() + return l.length +} + +func (l *link) Weight() int { + return len(l.sendQueue) + len(l.recvQueue) +} + +// Accept accepts a message on the socket +func (l *link) Recv(m *transport.Message) error { + select { + case <-l.closed: + return io.EOF + case rm := <-l.recvQueue: + *m = *rm + return nil + } + // never reach + return nil +} + +// Send sends a message on the socket immediately +func (l *link) Send(m *transport.Message) error { + select { + case <-l.closed: + return io.EOF + case l.sendQueue <- m: + } + return nil +} + +func (l *link) Status() string { + select { + case <-l.closed: + return "closed" + default: + return "connected" + } +} diff --git a/network/link/link.go b/network/link/link.go index e50c683f..7f3c7496 100644 --- a/network/link/link.go +++ b/network/link/link.go @@ -3,8 +3,6 @@ package link import ( "errors" - "io" - "sync" "github.com/micro/go-micro/config/options" "github.com/micro/go-micro/transport" @@ -28,231 +26,10 @@ type Link interface { Length() int } -type link struct { - sync.RWMutex - - // the link id - id string - - // the remote end to dial - addr string - - // channel used to close the link - closed chan bool - - // if its connected - connected bool - - // the transport to use - transport transport.Transport - - // the send queue to the socket - sendQueue chan *transport.Message - // the recv queue to the socket - recvQueue chan *transport.Message - - // the socket for this link - socket transport.Socket - - // determines the cost of the link - // based on queue length and roundtrip - length int - weight int -} - var ( ErrLinkClosed = errors.New("link closed") ) -func newLink(options options.Options) *link { - // default values - id := "local" - addr := "127.0.0.1:10001" - tr := transport.DefaultTransport - - lid, ok := options.Values().Get("link.id") - if ok { - id = lid.(string) - } - - laddr, ok := options.Values().Get("link.address") - if ok { - addr = laddr.(string) - } - - ltr, ok := options.Values().Get("link.transport") - if ok { - tr = ltr.(transport.Transport) - } - - l := &link{ - // the remote end to dial - addr: addr, - // transport to dial link - transport: tr, - // unique id assigned to the link - id: id, - // the closed channel used to close the conn - closed: make(chan bool), - // then send queue - sendQueue: make(chan *transport.Message, 128), - // the receive queue - recvQueue: make(chan *transport.Message, 128), - } - - // return the link - return l -} - -// link methods - -// process processes messages on the send queue. -// these are messages to be sent to the remote side. -func (l *link) process() { - go func() { - for { - m := new(transport.Message) - if err := l.recv(m); err != nil { - return - } - - select { - case l.recvQueue <- m: - case <-l.closed: - return - } - } - }() - - for { - select { - case m := <-l.sendQueue: - if err := l.send(m); err != nil { - return - } - case <-l.closed: - return - } - } -} - -// send a message over the link -func (l *link) send(m *transport.Message) error { - // TODO: measure time taken and calculate length/rate - // send via the transport socket - return l.socket.Send(m) -} - -// recv a message on the link -func (l *link) recv(m *transport.Message) error { - if m.Header == nil { - m.Header = make(map[string]string) - } - // receive the transport message - return l.socket.Recv(m) -} - -func (l *link) Connect() error { - l.Lock() - if l.connected { - l.Unlock() - return nil - } - - // replace closed - l.closed = make(chan bool) - - // dial the endpoint - c, err := l.transport.Dial(l.addr) - if err != nil { - l.Unlock() - return nil - } - - // set the socket - l.socket = c - - // kick start the processing - go l.process() - - return nil -} - -// Close the link -func (l *link) Close() error { - select { - case <-l.closed: - return nil - default: - close(l.closed) - l.Lock() - l.connected = false - l.Unlock() - return l.socket.Close() - } -} - -// returns the node id -func (l *link) Id() string { - l.RLock() - defer l.RUnlock() - return l.id -} - -func (l *link) Remote() string { - l.RLock() - defer l.RUnlock() - return l.socket.Remote() -} - -func (l *link) Local() string { - l.RLock() - defer l.RUnlock() - return l.socket.Local() -} - -func (l *link) Length() int { - l.RLock() - defer l.RUnlock() - return l.length -} - -func (l *link) Weight() int { - return len(l.sendQueue) + len(l.recvQueue) -} - -// Accept accepts a message on the socket -func (l *link) Recv(m *transport.Message) error { - select { - case <-l.closed: - return io.EOF - case rm := <-l.recvQueue: - *m = *rm - return nil - } - // never reach - return nil -} - -// Send sends a message on the socket immediately -func (l *link) Send(m *transport.Message) error { - select { - case <-l.closed: - return io.EOF - case l.sendQueue <- m: - } - return nil -} - -func (l *link) Status() string { - select { - case <-l.closed: - return "closed" - default: - return "connected" - } -} - // NewLink creates a new link on top of a socket func NewLink(opts ...options.Option) Link { return newLink(options.NewOptions(opts...)) From c71576a5382a361913fa33dc8b88a5abdffd92bb Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 17:43:36 +0100 Subject: [PATCH 153/287] Update link Id comment --- network/link/link.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network/link/link.go b/network/link/link.go index 7f3c7496..ddf4be3c 100644 --- a/network/link/link.go +++ b/network/link/link.go @@ -16,7 +16,7 @@ type Link interface { transport.Socket // Connect connects the link. It must be called first. Connect() error - // Id of the link likely a uuid if not specified + // Id of the link is "local" if not specified Id() string // Status of the link Status() string From 8f5aed707ecd26f25faa8da6a73ead4a6fd84ebe Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Wed, 10 Jul 2019 17:46:22 +0100 Subject: [PATCH 154/287] Table.Add is now Table.Create. Insesrt event is now Create event. --- network/router/default.go | 8 ++++---- network/router/table/default.go | 13 +++++++------ network/router/table/default_test.go | 16 ++++++++-------- network/router/table/table.go | 4 ++-- network/router/table/watcher.go | 26 +++----------------------- 5 files changed, 24 insertions(+), 43 deletions(-) diff --git a/network/router/default.go b/network/router/default.go index b6438e94..eab80522 100644 --- a/network/router/default.go +++ b/network/router/default.go @@ -95,7 +95,7 @@ func (r *router) manageServiceRoutes(service *registry.Service, action string) e } switch action { case "insert", "create": - if err := r.opts.Table.Add(route); err != nil && err != table.ErrDuplicateRoute { + if err := r.opts.Table.Create(route); err != nil && err != table.ErrDuplicateRoute { return fmt.Errorf("failed adding route for service %s: %s", service.Name, err) } case "delete": @@ -227,7 +227,7 @@ func isFlapping(curr, prev *table.Event) bool { return true } - if curr.Type == table.Insert && prev.Type == table.Delete || curr.Type == table.Delete && prev.Type == table.Insert { + if curr.Type == table.Create && prev.Type == table.Delete || curr.Type == table.Delete && prev.Type == table.Create { return true } @@ -389,7 +389,7 @@ func (r *router) Advertise() (<-chan *Advert, error) { events := make([]*table.Event, len(routes)) for i, route := range routes { event := &table.Event{ - Type: table.Insert, + Type: table.Create, Timestamp: time.Now(), Route: route, } @@ -406,7 +406,7 @@ func (r *router) Advertise() (<-chan *Advert, error) { Network: "*", Metric: table.DefaultLocalMetric, } - if err := r.opts.Table.Add(route); err != nil { + if err := r.opts.Table.Create(route); err != nil { return nil, fmt.Errorf("failed adding default gateway route: %s", err) } } diff --git a/network/router/table/default.go b/network/router/table/default.go index 76de3f97..91a84af6 100644 --- a/network/router/table/default.go +++ b/network/router/table/default.go @@ -2,6 +2,7 @@ package table import ( "sync" + "time" "github.com/google/uuid" ) @@ -51,8 +52,8 @@ func (t *table) Options() TableOptions { return t.opts } -// Add adds a route to the routing table -func (t *table) Add(r Route) error { +// Create creates new route in the routing table +func (t *table) Create(r Route) error { service := r.Service sum := r.Hash() @@ -63,14 +64,14 @@ func (t *table) Add(r Route) error { if _, ok := t.m[service]; !ok { t.m[service] = make(map[uint64]Route) t.m[service][sum] = r - go t.sendEvent(&Event{Type: Insert, Route: r}) + go t.sendEvent(&Event{Type: Create, Timestamp: time.Now(), Route: r}) return nil } // add new route to the table for the route destination if _, ok := t.m[service][sum]; !ok { t.m[service][sum] = r - go t.sendEvent(&Event{Type: Insert, Route: r}) + go t.sendEvent(&Event{Type: Create, Timestamp: time.Now(), Route: r}) return nil } @@ -90,7 +91,7 @@ func (t *table) Delete(r Route) error { } delete(t.m[service], sum) - go t.sendEvent(&Event{Type: Delete, Route: r}) + go t.sendEvent(&Event{Type: Delete, Timestamp: time.Now(), Route: r}) return nil } @@ -111,7 +112,7 @@ func (t *table) Update(r Route) error { // if the route has been found update it if _, ok := t.m[service][sum]; ok { t.m[service][sum] = r - go t.sendEvent(&Event{Type: Update, Route: r}) + go t.sendEvent(&Event{Type: Update, Timestamp: time.Now(), Route: r}) return nil } diff --git a/network/router/table/default_test.go b/network/router/table/default_test.go index 3f7acdb6..d7d0fc72 100644 --- a/network/router/table/default_test.go +++ b/network/router/table/default_test.go @@ -16,11 +16,11 @@ func testSetup() (Table, Route) { return table, route } -func TestAdd(t *testing.T) { +func TestCreate(t *testing.T) { table, route := testSetup() testTableSize := table.Size() - if err := table.Add(route); err != nil { + if err := table.Create(route); err != nil { t.Errorf("error adding route: %s", err) } testTableSize += 1 @@ -28,7 +28,7 @@ func TestAdd(t *testing.T) { // adds new route for the original destination route.Gateway = "dest.gw2" - if err := table.Add(route); err != nil { + if err := table.Create(route); err != nil { t.Errorf("error adding route: %s", err) } testTableSize += 1 @@ -38,7 +38,7 @@ func TestAdd(t *testing.T) { } // adding the same route under Insert policy must error - if err := table.Add(route); err != ErrDuplicateRoute { + if err := table.Create(route); err != ErrDuplicateRoute { t.Errorf("error adding route. Expected error: %s, found: %s", ErrDuplicateRoute, err) } } @@ -47,7 +47,7 @@ func TestDelete(t *testing.T) { table, route := testSetup() testTableSize := table.Size() - if err := table.Add(route); err != nil { + if err := table.Create(route); err != nil { t.Errorf("error adding route: %s", err) } testTableSize += 1 @@ -77,7 +77,7 @@ func TestUpdate(t *testing.T) { table, route := testSetup() testTableSize := table.Size() - if err := table.Add(route); err != nil { + if err := table.Create(route); err != nil { t.Errorf("error adding route: %s", err) } testTableSize += 1 @@ -113,7 +113,7 @@ func TestList(t *testing.T) { for i := 0; i < len(svc); i++ { route.Service = svc[i] - if err := table.Add(route); err != nil { + if err := table.Create(route); err != nil { t.Errorf("error adding route: %s", err) } } @@ -143,7 +143,7 @@ func TestLookup(t *testing.T) { route.Service = svc[i] route.Network = net[i] route.Gateway = gw[i] - if err := table.Add(route); err != nil { + if err := table.Create(route); err != nil { t.Errorf("error adding route: %s", err) } } diff --git a/network/router/table/table.go b/network/router/table/table.go index f08e05b6..c549617c 100644 --- a/network/router/table/table.go +++ b/network/router/table/table.go @@ -13,8 +13,8 @@ var ( // Table defines routing table interface type Table interface { - // Add adds new route to the routing table - Add(Route) error + // Create new route in the routing table + Create(Route) error // Delete deletes existing route from the routing table Delete(Route) error // Update updates route in the routing table diff --git a/network/router/table/watcher.go b/network/router/table/watcher.go index c089ddfc..0f8fab7f 100644 --- a/network/router/table/watcher.go +++ b/network/router/table/watcher.go @@ -2,7 +2,6 @@ package table import ( "errors" - "fmt" "time" ) @@ -15,28 +14,14 @@ var ( type EventType int const ( - // Insert is emitted when a new route has been inserted - Insert EventType = iota + // Create is emitted when a new route has been created + Create EventType = iota // Delete is emitted when an existing route has been deleted Delete // Update is emitted when an existing route has been updated Update ) -// String returns string representation of the event -func (et EventType) String() string { - switch et { - case Insert: - return "INSERT" - case Delete: - return "DELETE" - case Update: - return "UPDATE" - default: - return "UNKNOWN" - } -} - // Event is returned by a call to Next on the watcher. type Event struct { // Type defines type of event @@ -47,11 +32,6 @@ type Event struct { Route Route } -// String prints human readable Event -func (e Event) String() string { - return fmt.Sprintf("[EVENT] time: %s type: %s", e.Timestamp, e.Type) -} - // WatchOption is used to define what routes to watch in the table type WatchOption func(*WatchOptions) @@ -88,7 +68,7 @@ type tableWatcher struct { // Next returns the next noticed action taken on table // TODO: this needs to be thought through properly; -// right now we only allow to watch destination +// right now we only allow to watch service func (w *tableWatcher) Next() (*Event, error) { for { select { From f3d9177233eb31ecabed1aa657b9706d3132449b Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 18:24:03 +0100 Subject: [PATCH 155/287] Add sessions to tunnel --- network/tunnel/default.go | 52 +++++++++++++++++----- network/tunnel/listener.go | 89 ++++++++++++++++++++++++++++++++++++++ network/tunnel/socket.go | 8 +++- network/tunnel/tunnel.go | 8 +++- 4 files changed, 142 insertions(+), 15 deletions(-) create mode 100644 network/tunnel/listener.go diff --git a/network/tunnel/default.go b/network/tunnel/default.go index c9f274f0..e8d32bdd 100644 --- a/network/tunnel/default.go +++ b/network/tunnel/default.go @@ -60,10 +60,11 @@ func (t *tun) newSocket(id string) *socket { // new socket s := &socket{ - id: id, - closed: make(chan bool), - recv: make(chan *message, 128), - send: t.send, + id: id, + session: t.newSession(), + closed: make(chan bool), + recv: make(chan *message, 128), + send: t.send, } // save socket @@ -75,6 +76,11 @@ func (t *tun) newSocket(id string) *socket { return s } +// TODO: use tunnel id as part of the session +func (t *tun) newSession() string { + return uuid.New().String() +} + // process outgoing messages func (t *tun) process() { // manage the send buffer @@ -87,8 +93,11 @@ func (t *tun) process() { Body: msg.data.Body, } - // set the stream id on the outgoing message - nmsg.Header["Micro-Tunnel"] = msg.id + // set the tunnel id on the outgoing message + nmsg.Header["Micro-Tunnel-Id"] = msg.id + + // set the session id + nmsg.Header["Micro-Tunnel-Session"] = msg.session // send the message via the interface if err := t.link.Send(nmsg); err != nil { @@ -111,8 +120,11 @@ func (t *tun) listen() { return } - // a stream id - id := msg.Header["Micro-Tunnel"] + // the tunnel id + id := msg.Header["Micro-Tunnel-Id"] + + // the session id + session := msg.Header["Micro-Tunnel-Session"] // get the socket s, exists := t.getSocket(id) @@ -150,7 +162,7 @@ func (t *tun) listen() { // TODO: don't block on queuing // append to recv backlog - s.recv <- &message{id: id, data: tmsg} + s.recv <- &message{id: id, session: session, data: tmsg} } } @@ -209,10 +221,12 @@ func (t *tun) Dial(addr string) (Conn, error) { c.remote = addr // set local c.local = t.link.Local() + return c, nil } -func (t *tun) Accept(addr string) (Conn, error) { +// Accept a connection on the address +func (t *tun) Listen(addr string) (Listener, error) { // create a new socket by hashing the address c := t.newSocket(addr) // set remote. it will be replaced by the first message received @@ -227,6 +241,20 @@ func (t *tun) Accept(addr string) (Conn, error) { case <-c.wait: } - // return socket - return c, nil + tl := &tunListener{ + addr: addr, + // the accept channel + accept: make(chan *socket, 128), + // the channel to close + closed: make(chan bool), + // the connection + conn: c, + // the listener socket + socket: c, + } + + go tl.process() + + // return the listener + return tl, nil } diff --git a/network/tunnel/listener.go b/network/tunnel/listener.go new file mode 100644 index 00000000..6a8d1ba3 --- /dev/null +++ b/network/tunnel/listener.go @@ -0,0 +1,89 @@ +package tunnel + +import ( + "io" +) + +type tunListener struct { + // address of the listener + addr string + // the accept channel + accept chan *socket + // the channel to close + closed chan bool + // the connection + conn Conn + // the listener socket + socket *socket +} + +func (t *tunListener) process() { + // our connection map for session + conns := make(map[string]*socket) + + for { + select { + case <-t.closed: + return + // receive a new message + case m := <-t.socket.recv: + // get a socket + sock, ok := conns[m.session] + if !ok { + // create a new socket session + sock = &socket{ + // our tunnel id + id: m.id, + // the session id + session: m.session, + // close chan + closed: make(chan bool), + // recv called by the acceptor + recv: make(chan *message, 128), + // use the internal send buffer + send: t.socket.send, + } + + // save the socket + conns[m.session] = sock + } + + // send this to the accept chan + select { + case <-t.closed: + return + case t.accept <- sock: + } + } + } +} + +func (t *tunListener) Addr() string { + return t.addr +} + +func (t *tunListener) Close() error { + select { + case <-t.closed: + return nil + default: + close(t.closed) + } + return nil +} + +// Everytime accept is called we essentially block till we get a new connection +func (t *tunListener) Accept() (Conn, error) { + select { + // if the socket is closed return + case <-t.closed: + return nil, io.EOF + // wait for a new connection + case c, ok := <-t.accept: + if !ok { + return nil, io.EOF + } + return c, nil + } + return nil, nil +} diff --git a/network/tunnel/socket.go b/network/tunnel/socket.go index 861e3f4c..96d16567 100644 --- a/network/tunnel/socket.go +++ b/network/tunnel/socket.go @@ -10,6 +10,8 @@ import ( type socket struct { // socket id based on Micro-Tunnel id string + // the session id based on Micro.Tunnel-Session + session string // closed closed chan bool // remote addr @@ -26,8 +28,10 @@ type socket struct { // message is sent over the send channel type message struct { - // socket id + // tunnel id id string + // the session id + session string // transport data data *transport.Message } @@ -52,7 +56,7 @@ func (s *socket) Send(m *transport.Message) error { // no op } // append to backlog - s.send <- &message{id: s.id, data: m} + s.send <- &message{id: s.id, session: s.session, data: m} return nil } diff --git a/network/tunnel/tunnel.go b/network/tunnel/tunnel.go index 3189e81d..60ad0f25 100644 --- a/network/tunnel/tunnel.go +++ b/network/tunnel/tunnel.go @@ -17,7 +17,13 @@ type Tunnel interface { // Dial an endpoint Dial(addr string) (Conn, error) // Accept connections - Accept(addr string) (Conn, error) + Listen(addr string) (Listener, error) +} + +type Listener interface { + Addr() string + Close() error + Accept() (Conn, error) } type Conn interface { From 89231f701b0aaf3bbc1f4d59482939391f104c94 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 18:26:11 +0100 Subject: [PATCH 156/287] Add comments and session --- network/tunnel/socket.go | 4 ++++ network/tunnel/tunnel.go | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/network/tunnel/socket.go b/network/tunnel/socket.go index 96d16567..b1c55797 100644 --- a/network/tunnel/socket.go +++ b/network/tunnel/socket.go @@ -48,6 +48,10 @@ func (s *socket) Id() string { return s.id } +func (s *socket) Session() string { + return s.session +} + func (s *socket) Send(m *transport.Message) error { select { case <-s.closed: diff --git a/network/tunnel/tunnel.go b/network/tunnel/tunnel.go index 60ad0f25..92b279b7 100644 --- a/network/tunnel/tunnel.go +++ b/network/tunnel/tunnel.go @@ -20,15 +20,19 @@ type Tunnel interface { Listen(addr string) (Listener, error) } +// The listener provides similar constructs to the transport.Listener type Listener interface { Addr() string Close() error Accept() (Conn, error) } +// Conn is a connection dialed or accepted which includes the tunnel id and session type Conn interface { // Specifies the tunnel id Id() string + // The session + Session() string // a transport socket transport.Socket } From 0f16eb2858de7495a58f46b50a6087c1f1ba0b2e Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 18:35:10 +0100 Subject: [PATCH 157/287] add further comments to tunnel --- network/tunnel/default.go | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/network/tunnel/default.go b/network/tunnel/default.go index e8d32bdd..1067924e 100644 --- a/network/tunnel/default.go +++ b/network/tunnel/default.go @@ -13,19 +13,21 @@ import ( // tun represents a network tunnel type tun struct { + // the link on top of which we build a tunnel link link.Link sync.RWMutex - // connect + // to indicate if we're connected or not connected bool - // the send channel + // the send channel for all messages send chan *message + // close channel closed chan bool - // sockets + // a map of sockets based on Micro-Tunnel-Id sockets map[string]*socket } @@ -39,6 +41,7 @@ func newTunnel(link link.Link) *tun { } } +// getSocket returns a socket from the internal socket map func (t *tun) getSocket(id string) (*socket, bool) { // get the socket t.RLock() @@ -47,6 +50,7 @@ func (t *tun) getSocket(id string) (*socket, bool) { return s, ok } +// newSocket creates a new socket and saves it func (t *tun) newSocket(id string) *socket { // new id if it doesn't exist if len(id) == 0 { @@ -81,7 +85,7 @@ func (t *tun) newSession() string { return uuid.New().String() } -// process outgoing messages +// process outgoing messages sent by all local sockets func (t *tun) process() { // manage the send buffer // all pseudo sockets throw everything down this @@ -129,7 +133,8 @@ func (t *tun) listen() { // get the socket s, exists := t.getSocket(id) if !exists { - // no op + // drop it, we don't care about + // messages we don't know about continue } @@ -145,24 +150,35 @@ func (t *tun) listen() { // is the socket new? select { - // if its new it will block here + // if its new the socket is actually blocked waiting + // for a connection. so we check if its waiting. case <-s.wait: - // its not new + // if its waiting e.g its new then we close it default: - // its new // set remote address of the socket s.remote = msg.Header["Remote"] close(s.wait) } + // construct a new transport message tmsg := &transport.Message{ Header: msg.Header, Body: msg.Body, } - // TODO: don't block on queuing + // construct the internal message + imsg := &message{ + id: id, + session: session, + data: tmsg, + } + // append to recv backlog - s.recv <- &message{id: id, session: session, data: tmsg} + // we don't block if we can't pass it on + select { + case s.recv <- imsg: + default: + } } } From 163b917ec7c15d8457dc59615c360a6bbd704da3 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Wed, 10 Jul 2019 18:37:46 +0100 Subject: [PATCH 158/287] proto.EventType Insert is now Create to mirror table.Event --- network/router/proto/router.pb.go | 58 +++++++++++++++---------------- network/router/proto/router.proto | 2 +- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/network/router/proto/router.pb.go b/network/router/proto/router.pb.go index 2682a494..a3416785 100644 --- a/network/router/proto/router.pb.go +++ b/network/router/proto/router.pb.go @@ -24,19 +24,19 @@ const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package type EventType int32 const ( - EventType_Insert EventType = 0 + EventType_Create EventType = 0 EventType_Delete EventType = 1 EventType_Update EventType = 2 ) var EventType_name = map[int32]string{ - 0: "Insert", + 0: "Create", 1: "Delete", 2: "Update", } var EventType_value = map[string]int32{ - "Insert": 0, + "Create": 0, "Delete": 1, "Update": 2, } @@ -203,7 +203,7 @@ func (m *TableEvent) GetType() EventType { if m != nil { return m.Type } - return EventType_Insert + return EventType_Create } func (m *TableEvent) GetTimestamp() int64 { @@ -434,30 +434,30 @@ func init() { func init() { proto.RegisterFile("router.proto", fileDescriptor_367072455c71aedc) } var fileDescriptor_367072455c71aedc = []byte{ - // 390 bytes of a gzipped FileDescriptorProto + // 388 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0xc1, 0x8e, 0xd3, 0x30, - 0x10, 0x8d, 0xb7, 0x89, 0x51, 0xa6, 0x49, 0xa8, 0x7c, 0x40, 0x56, 0xb5, 0x5a, 0x15, 0x4b, 0x88, - 0x15, 0x08, 0xb3, 0x2a, 0xbf, 0x00, 0x07, 0xa4, 0xbd, 0x60, 0x2d, 0xe2, 0x9c, 0x6d, 0x47, 0x6c, - 0xd4, 0x36, 0xc9, 0xda, 0xce, 0xae, 0xf2, 0x01, 0x7c, 0x05, 0x3f, 0x8b, 0x3c, 0x49, 0x68, 0x7b, - 0x40, 0xe2, 0x36, 0xef, 0x8d, 0xed, 0x79, 0x9e, 0xf7, 0x20, 0xb3, 0x4d, 0xe7, 0xd1, 0xea, 0xd6, - 0x36, 0xbe, 0x51, 0x1f, 0x20, 0xbf, 0x6d, 0x9a, 0x5d, 0xd7, 0x1a, 0x7c, 0xec, 0xd0, 0x79, 0x71, - 0x09, 0xc9, 0x63, 0x87, 0xb6, 0x97, 0x6c, 0xc5, 0xae, 0xe7, 0x6b, 0xae, 0xbf, 0x05, 0x64, 0x06, - 0x52, 0xdd, 0x40, 0x31, 0x1d, 0x77, 0x6d, 0x53, 0x3b, 0x14, 0x57, 0xc0, 0xe9, 0x41, 0x27, 0xd9, - 0x6a, 0x46, 0x17, 0x4c, 0x80, 0x66, 0x64, 0x55, 0x01, 0xd9, 0x8f, 0xd2, 0x6f, 0x1e, 0xc6, 0xf7, - 0xd5, 0x03, 0xc0, 0x5d, 0x79, 0xbf, 0xc7, 0x2f, 0x4f, 0x58, 0x7b, 0x71, 0x05, 0xb1, 0xef, 0x5b, - 0xa4, 0x61, 0xc5, 0x1a, 0x34, 0xb1, 0x77, 0x7d, 0x8b, 0x86, 0x78, 0x71, 0x09, 0xa9, 0xaf, 0x0e, - 0xe8, 0x7c, 0x79, 0x68, 0xe5, 0xc5, 0x8a, 0x5d, 0xcf, 0xcc, 0x91, 0x08, 0x5a, 0x69, 0x8a, 0x9c, - 0x8d, 0x5a, 0x87, 0xd1, 0x03, 0xa9, 0x72, 0x98, 0xdf, 0x56, 0xce, 0x4f, 0x83, 0x35, 0x64, 0x03, - 0xfc, 0x4f, 0xe1, 0xaf, 0x21, 0xa1, 0xaf, 0x0b, 0x09, 0x2f, 0x1c, 0xda, 0xa7, 0x6a, 0x33, 0xc8, - 0x4c, 0xcd, 0x04, 0xd5, 0x6f, 0x06, 0x09, 0x5d, 0xfa, 0xf7, 0x99, 0xd0, 0x29, 0xb7, 0x5b, 0x8b, - 0xce, 0x91, 0xfe, 0xd4, 0x4c, 0x30, 0x74, 0x7e, 0x96, 0x1e, 0x9f, 0xcb, 0x9e, 0xf4, 0xa7, 0x66, - 0x82, 0xa1, 0x53, 0xa3, 0x7f, 0x6e, 0xec, 0x4e, 0xc6, 0x43, 0x67, 0x84, 0x42, 0x40, 0xbc, 0xaf, - 0xea, 0x9d, 0x4c, 0x88, 0xa6, 0x5a, 0xbc, 0x02, 0x7e, 0x40, 0x6f, 0xab, 0x8d, 0xe4, 0xb4, 0xa0, - 0x11, 0xbd, 0xfb, 0x08, 0xe9, 0xdf, 0x75, 0x0a, 0x00, 0xfe, 0xb5, 0x76, 0x68, 0xfd, 0x22, 0x0a, - 0xf5, 0x67, 0xdc, 0xa3, 0xc7, 0x05, 0x0b, 0xf5, 0xf7, 0x76, 0x5b, 0x7a, 0x5c, 0x5c, 0xac, 0x7f, - 0x31, 0xe0, 0xf4, 0x1d, 0x2b, 0xde, 0x42, 0x42, 0xae, 0x89, 0x5c, 0x9f, 0xba, 0xb7, 0x9c, 0xeb, - 0xa3, 0x79, 0x2a, 0xba, 0x61, 0xe2, 0x3d, 0xf0, 0x21, 0x10, 0xa2, 0xd0, 0x67, 0x41, 0x5a, 0xbe, - 0xd4, 0xe7, 0x49, 0x51, 0x91, 0x78, 0x03, 0x71, 0xb0, 0x40, 0x64, 0xfa, 0xc4, 0x98, 0x65, 0xae, - 0x4f, 0x7d, 0x51, 0xd1, 0x3d, 0xa7, 0x68, 0x7e, 0xfa, 0x13, 0x00, 0x00, 0xff, 0xff, 0x7e, 0xbb, - 0x6d, 0x5c, 0xaa, 0x02, 0x00, 0x00, + 0x10, 0x8d, 0xb7, 0x89, 0x51, 0xa6, 0x49, 0x58, 0xf9, 0x80, 0xac, 0x6a, 0xb5, 0x2a, 0x96, 0x10, + 0x2b, 0x10, 0x66, 0x55, 0x3e, 0x01, 0xb8, 0xed, 0x05, 0x6b, 0x11, 0xe7, 0x6c, 0x3b, 0x62, 0xa3, + 0xb6, 0x49, 0xd6, 0x76, 0xb6, 0xca, 0x07, 0xf0, 0x15, 0xfc, 0x2c, 0xf2, 0x24, 0xa1, 0xed, 0x01, + 0x89, 0xdb, 0xbc, 0x37, 0xb6, 0xe7, 0x79, 0xde, 0x83, 0xcc, 0x36, 0x9d, 0x47, 0xab, 0x5b, 0xdb, + 0xf8, 0x46, 0x7d, 0x80, 0xfc, 0xae, 0x69, 0xb6, 0x5d, 0x6b, 0xf0, 0xa9, 0x43, 0xe7, 0xc5, 0x15, + 0x24, 0x4f, 0x1d, 0xda, 0x5e, 0xb2, 0x25, 0xbb, 0x99, 0xaf, 0xb8, 0xfe, 0x16, 0x90, 0x19, 0x48, + 0x75, 0x0b, 0xc5, 0x74, 0xdc, 0xb5, 0x4d, 0xed, 0x50, 0x5c, 0x03, 0xa7, 0x07, 0x9d, 0x64, 0xcb, + 0x19, 0x5d, 0x30, 0x01, 0x9a, 0x91, 0x55, 0x05, 0x64, 0x3f, 0x4a, 0xbf, 0x7e, 0x1c, 0xdf, 0x57, + 0x8f, 0x00, 0xf7, 0xe5, 0xc3, 0x0e, 0xbf, 0x3e, 0x63, 0xed, 0xc5, 0x35, 0xc4, 0xbe, 0x6f, 0x91, + 0x86, 0x15, 0x2b, 0xd0, 0xc4, 0xde, 0xf7, 0x2d, 0x1a, 0xe2, 0xc5, 0x15, 0xa4, 0xbe, 0xda, 0xa3, + 0xf3, 0xe5, 0xbe, 0x95, 0x17, 0x4b, 0x76, 0x33, 0x33, 0x47, 0x22, 0x68, 0xa5, 0x29, 0x72, 0x36, + 0x6a, 0x1d, 0x46, 0x0f, 0xa4, 0xca, 0x61, 0x7e, 0x57, 0x39, 0x3f, 0x0d, 0xd6, 0x90, 0x0d, 0xf0, + 0x3f, 0x85, 0xbf, 0x86, 0x84, 0xbe, 0x2e, 0x24, 0xbc, 0x70, 0x68, 0x9f, 0xab, 0xf5, 0x20, 0x33, + 0x35, 0x13, 0x54, 0xbf, 0x19, 0x24, 0x74, 0xe9, 0xdf, 0x67, 0x42, 0xa7, 0xdc, 0x6c, 0x2c, 0x3a, + 0x47, 0xfa, 0x53, 0x33, 0xc1, 0xd0, 0xf9, 0x59, 0x7a, 0x3c, 0x94, 0x3d, 0xe9, 0x4f, 0xcd, 0x04, + 0x43, 0xa7, 0x46, 0x7f, 0x68, 0xec, 0x56, 0xc6, 0x43, 0x67, 0x84, 0x42, 0x40, 0xbc, 0xab, 0xea, + 0xad, 0x4c, 0x88, 0xa6, 0x5a, 0xbc, 0x02, 0xbe, 0x47, 0x6f, 0xab, 0xb5, 0xe4, 0xb4, 0xa0, 0x11, + 0xbd, 0xfb, 0x08, 0xe9, 0xdf, 0x75, 0x0a, 0x00, 0xfe, 0xd9, 0x62, 0xe9, 0xf1, 0x32, 0x0a, 0xf5, + 0x17, 0xdc, 0xa1, 0xc7, 0x4b, 0x16, 0xea, 0xef, 0xed, 0x26, 0xf0, 0x17, 0xab, 0x5f, 0x0c, 0x38, + 0x7d, 0xc7, 0x8a, 0xb7, 0x90, 0x90, 0x6b, 0x22, 0xd7, 0xa7, 0xee, 0x2d, 0xe6, 0xfa, 0x68, 0x9e, + 0x8a, 0x6e, 0x99, 0x78, 0x0f, 0x7c, 0x08, 0x84, 0x28, 0xf4, 0x59, 0x90, 0x16, 0x2f, 0xf5, 0x79, + 0x52, 0x54, 0x24, 0xde, 0x40, 0x1c, 0x2c, 0x10, 0x99, 0x3e, 0x31, 0x66, 0x91, 0xeb, 0x53, 0x5f, + 0x54, 0xf4, 0xc0, 0x29, 0x9a, 0x9f, 0xfe, 0x04, 0x00, 0x00, 0xff, 0xff, 0x67, 0x70, 0xf8, 0xfa, + 0xaa, 0x02, 0x00, 0x00, } diff --git a/network/router/proto/router.proto b/network/router/proto/router.proto index 3d3a3fce..434e0dc5 100644 --- a/network/router/proto/router.proto +++ b/network/router/proto/router.proto @@ -22,7 +22,7 @@ message WatchRequest {} // EventType is TableEvent type enum EventType { - Insert = 0; + Create = 0; Delete = 1; Update = 2; } From 0a39fe39c378964240ef3a08fb25a477f5244258 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 19:01:24 +0100 Subject: [PATCH 159/287] Update tunnel to use id+session for the key --- network/tunnel/default.go | 65 +++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/network/tunnel/default.go b/network/tunnel/default.go index 1067924e..c0d63e78 100644 --- a/network/tunnel/default.go +++ b/network/tunnel/default.go @@ -31,7 +31,7 @@ type tun struct { sockets map[string]*socket } -// create new tunnel +// create new tunnel on top of a link func newTunnel(link link.Link) *tun { return &tun{ link: link, @@ -41,22 +41,18 @@ func newTunnel(link link.Link) *tun { } } -// getSocket returns a socket from the internal socket map -func (t *tun) getSocket(id string) (*socket, bool) { +// getSocket returns a socket from the internal socket map. +// It does this based on the Micro-Tunnel-Id and Micro-Tunnel-Session +func (t *tun) getSocket(id, session string) (*socket, bool) { // get the socket t.RLock() - s, ok := t.sockets[id] + s, ok := t.sockets[id+session] t.RUnlock() return s, ok } // newSocket creates a new socket and saves it -func (t *tun) newSocket(id string) *socket { - // new id if it doesn't exist - if len(id) == 0 { - id = uuid.New().String() - } - +func (t *tun) newSocket(id, session string) (*socket, bool) { // hash the id h := sha256.New() h.Write([]byte(id)) @@ -65,7 +61,7 @@ func (t *tun) newSocket(id string) *socket { // new socket s := &socket{ id: id, - session: t.newSession(), + session: session, closed: make(chan bool), recv: make(chan *message, 128), send: t.send, @@ -73,11 +69,17 @@ func (t *tun) newSocket(id string) *socket { // save socket t.Lock() - t.sockets[id] = s + _, ok := t.sockets[id+session] + if ok { + // socket already exists + t.Unlock() + return nil, false + } + t.sockets[id+session] = s t.Unlock() // return socket - return s + return s, true } // TODO: use tunnel id as part of the session @@ -130,10 +132,19 @@ func (t *tun) listen() { // the session id session := msg.Header["Micro-Tunnel-Session"] - // get the socket - s, exists := t.getSocket(id) + // try get it based on just the tunnel id + // the assumption here is that a listener + // has no session but its set a listener session + if len(session) == 0 { + session = "listener" + } + + // get the socket based on the tunnel id and session + // this could be something we dialed in which case + // we have a session for it otherwise its a listener + s, exists := t.getSocket(id, session) if !exists { - // drop it, we don't care about + // drop it, we don't care about // messages we don't know about continue } @@ -168,9 +179,9 @@ func (t *tun) listen() { // construct the internal message imsg := &message{ - id: id, + id: id, session: session, - data: tmsg, + data: tmsg, } // append to recv backlog @@ -232,7 +243,10 @@ func (t *tun) Connect() error { // Dial an address func (t *tun) Dial(addr string) (Conn, error) { - c := t.newSocket(addr) + c, ok := t.newSocket(addr, t.newSession()) + if !ok { + return nil, errors.New("error dialing " + addr) + } // set remote c.remote = addr // set local @@ -244,19 +258,16 @@ func (t *tun) Dial(addr string) (Conn, error) { // Accept a connection on the address func (t *tun) Listen(addr string) (Listener, error) { // create a new socket by hashing the address - c := t.newSocket(addr) + c, ok := t.newSocket(addr, "listener") + if !ok { + return nil, errors.New("already listening on " + addr) + } + // set remote. it will be replaced by the first message received c.remote = t.link.Remote() // set local c.local = addr - select { - case <-c.closed: - return nil, errors.New("error creating socket") - // wait for the first message - case <-c.wait: - } - tl := &tunListener{ addr: addr, // the accept channel From 1f218f7b488d60d48a7c93472b1f098c78305498 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 19:07:18 +0100 Subject: [PATCH 160/287] Allow the socket to be specified --- network/link/default.go | 9 +++++++++ network/link/link.go | 15 ++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/network/link/default.go b/network/link/default.go index 0e55f033..52193da1 100644 --- a/network/link/default.go +++ b/network/link/default.go @@ -43,6 +43,7 @@ type link struct { func newLink(options options.Options) *link { // default values + var sock transport.Socket id := "local" addr := "127.0.0.1:10001" tr := transport.DefaultTransport @@ -62,11 +63,19 @@ func newLink(options options.Options) *link { tr = ltr.(transport.Transport) } + lsock, ok := options.Values().Get("link.socket") + if ok { + sock = lsock.(transport.Socket) + } + l := &link{ // the remote end to dial addr: addr, // transport to dial link transport: tr, + // the socket to use + // this is nil if not specified + socket: sock, // unique id assigned to the link id: id, // the closed channel used to close the conn diff --git a/network/link/link.go b/network/link/link.go index ddf4be3c..8be328cc 100644 --- a/network/link/link.go +++ b/network/link/link.go @@ -14,7 +14,8 @@ import ( type Link interface { // provides the transport.Socket interface transport.Socket - // Connect connects the link. It must be called first. + // Connect connects the link. It must be called first + // if there's an expectation to create a new socket. Connect() error // Id of the link is "local" if not specified Id() string @@ -40,12 +41,20 @@ func Id(id string) options.Option { return options.WithValue("link.id", id) } -// The address to use for the link +// The address to use for the link. Connect must be +// called for this to be used. func Address(a string) options.Option { return options.WithValue("link.address", a) } -// The transport to use for the link +// The transport to use for the link where we +// want to dial the connection first. func Transport(t transport.Transport) options.Option { return options.WithValue("link.transport", t) } + +// Socket sets the socket where it was accepted +// from a remote end. +func Socket(s transport.Socket) options.Option { + return options.WithValue("link.socket", s) +} From 8c157c1d5fab16edc9bbb403b9d89bafcc609b68 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 19:09:22 +0100 Subject: [PATCH 161/287] update link comments --- network/link/link.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/network/link/link.go b/network/link/link.go index 8be328cc..3acfd772 100644 --- a/network/link/link.go +++ b/network/link/link.go @@ -1,4 +1,4 @@ -// Package link provides a measured transport.Socket link +// Package link provides a measured link on top of a transport.Socket package link import ( @@ -8,9 +8,10 @@ import ( "github.com/micro/go-micro/transport" ) -// Link is a layer ontop of a transport socket with the +// Link is a layer on top of a transport socket with the // buffering send and recv queue's with the ability to -// measure the actual transport link and reconnect. +// measure the actual transport link and reconnect if +// an address is specified. type Link interface { // provides the transport.Socket interface transport.Socket @@ -36,13 +37,13 @@ func NewLink(opts ...options.Option) Link { return newLink(options.NewOptions(opts...)) } -// Sets the link id +// Sets the link id which otherwise defaults to "local" func Id(id string) options.Option { return options.WithValue("link.id", id) } // The address to use for the link. Connect must be -// called for this to be used. +// called for this to be used, its otherwise unused. func Address(a string) options.Option { return options.WithValue("link.address", a) } @@ -53,8 +54,7 @@ func Transport(t transport.Transport) options.Option { return options.WithValue("link.transport", t) } -// Socket sets the socket where it was accepted -// from a remote end. +// Socket sets the socket to use instead of dialing. func Socket(s transport.Socket) options.Option { return options.WithValue("link.socket", s) } From 4cca2b43a31298dfb4a296f979f587609e28f531 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 19:11:32 +0100 Subject: [PATCH 162/287] Add further link comments --- network/link/default.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/network/link/default.go b/network/link/default.go index 52193da1..369f97b7 100644 --- a/network/link/default.go +++ b/network/link/default.go @@ -92,8 +92,7 @@ func newLink(options options.Options) *link { // link methods -// process processes messages on the send queue. -// these are messages to be sent to the remote side. +// process processes messages on the send and receive queues. func (l *link) process() { go func() { for { @@ -138,6 +137,7 @@ func (l *link) recv(m *transport.Message) error { return l.socket.Recv(m) } +// Connect attempts to connect to an address and sets the socket func (l *link) Connect() error { l.Lock() if l.connected { @@ -185,24 +185,28 @@ func (l *link) Id() string { return l.id } +// the remote ip of the link func (l *link) Remote() string { l.RLock() defer l.RUnlock() return l.socket.Remote() } +// the local ip of the link func (l *link) Local() string { l.RLock() defer l.RUnlock() return l.socket.Local() } +// length/rate of the link func (l *link) Length() int { l.RLock() defer l.RUnlock() return l.length } +// weight checks the size of the queues func (l *link) Weight() int { return len(l.sendQueue) + len(l.recvQueue) } From ffae0f0fabfd2341f8d54b559eaa8b3da6feb4ec Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 19:13:50 +0100 Subject: [PATCH 163/287] Add a comment for tunnel processor --- network/tunnel/default.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/network/tunnel/default.go b/network/tunnel/default.go index c0d63e78..38605002 100644 --- a/network/tunnel/default.go +++ b/network/tunnel/default.go @@ -280,6 +280,10 @@ func (t *tun) Listen(addr string) (Listener, error) { socket: c, } + // this kicks off the internal message processor + // for the listener so it can create pseudo sockets + // per session if they do not exist or pass messages + // to the existign sessions go tl.process() // return the listener From 217f540601cd99badc3c46636d3720b5d22fdd2c Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 19:17:36 +0100 Subject: [PATCH 164/287] The listener has no session id --- network/tunnel/default.go | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/network/tunnel/default.go b/network/tunnel/default.go index 38605002..7087b0a4 100644 --- a/network/tunnel/default.go +++ b/network/tunnel/default.go @@ -132,11 +132,12 @@ func (t *tun) listen() { // the session id session := msg.Header["Micro-Tunnel-Session"] - // try get it based on just the tunnel id - // the assumption here is that a listener - // has no session but its set a listener session + // if the session id is blank there's nothing we can do + // TODO: check this is the case, is there any reason + // why we'd have a blank session? Is the tunnel + // used for some other purpose? if len(session) == 0 { - session = "listener" + continue } // get the socket based on the tunnel id and session @@ -144,9 +145,17 @@ func (t *tun) listen() { // we have a session for it otherwise its a listener s, exists := t.getSocket(id, session) if !exists { - // drop it, we don't care about - // messages we don't know about - continue + // try get it based on just the tunnel id + // the assumption here is that a listener + // has no session but its set a listener session + s, exists = t.getSocket(id, "listener") + if !exists { + conti + + // drop it, we don't care about + // messages we don't know about + continue + } } // is the socket closed? From 7c29be288b95d5eccf81ddc6a8a673ed6475c77d Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 19:33:34 +0100 Subject: [PATCH 165/287] Update a tunnel top level comment --- network/tunnel/tunnel.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/network/tunnel/tunnel.go b/network/tunnel/tunnel.go index 92b279b7..021aeeae 100644 --- a/network/tunnel/tunnel.go +++ b/network/tunnel/tunnel.go @@ -7,8 +7,9 @@ import ( ) // Tunnel creates a network tunnel on top of a link. -// It establishes multiple streams using the Micro-Tunnel header -// created as a hash of the address. +// It establishes multiple streams using the Micro-Tunnel-Id header +// and Micro-Tunnel-Session header. The tunnel id is a hash of +// the address being requested. type Tunnel interface { // Connect connects the tunnel Connect() error From c5dd737568dd2167dfd244c8c7a066198f8d1c3c Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 19:58:30 +0100 Subject: [PATCH 166/287] Add back in broker address --- broker/broker.go | 1 + server/rpc_server.go | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/broker/broker.go b/broker/broker.go index b7b9dcb0..2871e818 100644 --- a/broker/broker.go +++ b/broker/broker.go @@ -5,6 +5,7 @@ package broker type Broker interface { Init(...Option) error Options() Options + Address() string Connect() error Disconnect() error Publish(topic string, m *Message, opts ...PublishOption) error diff --git a/server/rpc_server.go b/server/rpc_server.go index 8bb7b547..696151e3 100644 --- a/server/rpc_server.go +++ b/server/rpc_server.go @@ -498,10 +498,9 @@ func (s *rpcServer) Start() error { return err } - baddr := strings.Join(config.Broker.Options().Addrs, ",") bname := config.Broker.String() - log.Logf("Broker [%s] Connected to %s", bname, baddr) + log.Logf("Broker [%s] Connected to %s", bname, config.Broker.Address()) // use RegisterCheck func before register if err = s.opts.RegisterCheck(s.opts.Context); err != nil { From e17ecf66b18df50cac6db21fcf11cdf8ae31e0b6 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 20:03:55 +0100 Subject: [PATCH 167/287] Fix breaking code --- network/tunnel/default.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/network/tunnel/default.go b/network/tunnel/default.go index 7087b0a4..50bc1130 100644 --- a/network/tunnel/default.go +++ b/network/tunnel/default.go @@ -150,8 +150,6 @@ func (t *tun) listen() { // has no session but its set a listener session s, exists = t.getSocket(id, "listener") if !exists { - conti - // drop it, we don't care about // messages we don't know about continue From 998a23c9634b3eeeb6cef1d658d98da94f3cd23c Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 20:04:01 +0100 Subject: [PATCH 168/287] Functional code for link --- network/link/default.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/network/link/default.go b/network/link/default.go index 369f97b7..f0d01ecd 100644 --- a/network/link/default.go +++ b/network/link/default.go @@ -44,8 +44,8 @@ type link struct { func newLink(options options.Options) *link { // default values var sock transport.Socket + var addr string id := "local" - addr := "127.0.0.1:10001" tr := transport.DefaultTransport lid, ok := options.Values().Get("link.id") @@ -144,14 +144,20 @@ func (l *link) Connect() error { l.Unlock() return nil } + defer l.Unlock() // replace closed l.closed = make(chan bool) + // assume existing socket + if len(l.addr) == 0 { + go l.process() + return nil + } + // dial the endpoint c, err := l.transport.Dial(l.addr) if err != nil { - l.Unlock() return nil } From 1f744b31a4bea4258c13811296e1257638efe937 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 10 Jul 2019 21:03:53 +0100 Subject: [PATCH 169/287] Return the dead node when deleting the service --- registry/consul/watcher.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/registry/consul/watcher.go b/registry/consul/watcher.go index 7d843482..03140355 100644 --- a/registry/consul/watcher.go +++ b/registry/consul/watcher.go @@ -224,9 +224,14 @@ func (cw *consulWatcher) handle(idx uint64, data interface{}) { cw.RUnlock() // remove unknown services from registry + // save the things we want to delete + deleted := make(map[string][]*registry.Service) + for service, _ := range rservices { if _, ok := services[service]; !ok { cw.Lock() + // save this before deleting + deleted[service] = cw.services[service] delete(cw.services, service) cw.Unlock() } @@ -237,6 +242,11 @@ func (cw *consulWatcher) handle(idx uint64, data interface{}) { if _, ok := services[service]; !ok { w.Stop() delete(cw.watchers, service) + for _, oldService := range deleted[service] { + // send a delete for the service nodes that we're removing + cw.next <- ®istry.Result{Action: "delete", Service: oldService} + } + // sent the empty list as the last resort to indicate to delete the entire service cw.next <- ®istry.Result{Action: "delete", Service: ®istry.Service{Name: service}} } } From a0ee7d2092accfa4502e60cdc277941bec0a6e51 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Wed, 10 Jul 2019 21:28:32 +0100 Subject: [PATCH 170/287] Added update action to manageServiceRoutes. Table is embedded; skip opts --- network/router/default.go | 27 +++++++++++++++++---------- network/router/table/default.go | 13 ++++++------- network/router/table/default_test.go | 7 ++++--- 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/network/router/default.go b/network/router/default.go index eab80522..6250608a 100644 --- a/network/router/default.go +++ b/network/router/default.go @@ -83,6 +83,7 @@ func (r *router) Options() Options { func (r *router) manageServiceRoutes(service *registry.Service, action string) error { // action is the routing table action action = strings.ToLower(action) + // take route action on each service node for _, node := range service.Nodes { route := table.Route{ @@ -93,19 +94,25 @@ func (r *router) manageServiceRoutes(service *registry.Service, action string) e Link: table.DefaultLink, Metric: table.DefaultLocalMetric, } + switch action { - case "insert", "create": - if err := r.opts.Table.Create(route); err != nil && err != table.ErrDuplicateRoute { + case "create": + if err := r.Create(route); err != nil && err != table.ErrDuplicateRoute { return fmt.Errorf("failed adding route for service %s: %s", service.Name, err) } + case "update": + if err := r.Update(route); err != nil && err != table.ErrDuplicateRoute { + return fmt.Errorf("failed updating route for service %s: %s", service.Name, err) + } case "delete": - if err := r.opts.Table.Delete(route); err != nil && err != table.ErrRouteNotFound { - return fmt.Errorf("failed deleting route for service %v: %s", service.Name, err) + if err := r.Delete(route); err != nil && err != table.ErrRouteNotFound { + return fmt.Errorf("failed deleting route for service %s: %s", service.Name, err) } default: - return fmt.Errorf("failed to manage route for service %v. Unknown action: %s", service.Name, action) + return fmt.Errorf("failed to manage route for service %s. Unknown action: %s", service.Name, action) } } + return nil } @@ -376,12 +383,12 @@ func (r *router) Advertise() (<-chan *Advert, error) { if r.status.Code != Running { // add all local service routes into the routing table - if err := r.manageRegistryRoutes(r.opts.Registry, "insert"); err != nil { + if err := r.manageRegistryRoutes(r.opts.Registry, "create"); err != nil { return nil, fmt.Errorf("failed adding routes: %s", err) } // list routing table routes to announce - routes, err := r.opts.Table.List() + routes, err := r.List() if err != nil { return nil, fmt.Errorf("failed listing routes: %s", err) } @@ -406,7 +413,7 @@ func (r *router) Advertise() (<-chan *Advert, error) { Network: "*", Metric: table.DefaultLocalMetric, } - if err := r.opts.Table.Create(route); err != nil { + if err := r.Create(route); err != nil { return nil, fmt.Errorf("failed adding default gateway route: %s", err) } } @@ -420,7 +427,7 @@ func (r *router) Advertise() (<-chan *Advert, error) { } // routing table watcher - tableWatcher, err := r.opts.Table.Watch() + tableWatcher, err := r.Watch() if err != nil { return nil, fmt.Errorf("failed creating routing table watcher: %v", err) } @@ -487,7 +494,7 @@ func (r *router) Process(a *Advert) error { for _, event := range events { // create a copy of the route route := event.Route - if err := r.opts.Table.Update(route); err != nil { + if err := r.Update(route); err != nil { return fmt.Errorf("failed updating routing table: %v", err) } } diff --git a/network/router/table/default.go b/network/router/table/default.go index 91a84af6..09aba529 100644 --- a/network/router/table/default.go +++ b/network/router/table/default.go @@ -106,17 +106,16 @@ func (t *table) Update(r Route) error { // check if the route destination has any routes in the table if _, ok := t.m[service]; !ok { - return ErrRouteNotFound - } - - // if the route has been found update it - if _, ok := t.m[service][sum]; ok { + t.m[service] = make(map[uint64]Route) t.m[service][sum] = r - go t.sendEvent(&Event{Type: Update, Timestamp: time.Now(), Route: r}) + go t.sendEvent(&Event{Type: Create, Timestamp: time.Now(), Route: r}) return nil } - return ErrRouteNotFound + t.m[service][sum] = r + go t.sendEvent(&Event{Type: Update, Timestamp: time.Now(), Route: r}) + + return nil } // List returns a list of all routes in the table diff --git a/network/router/table/default_test.go b/network/router/table/default_test.go index d7d0fc72..b4238336 100644 --- a/network/router/table/default_test.go +++ b/network/router/table/default_test.go @@ -94,12 +94,13 @@ func TestUpdate(t *testing.T) { t.Errorf("invalid number of routes. Expected: %d, found: %d", testTableSize, table.Size()) } - // this should error as the destination does not exist + // this should add a new route route.Service = "rand.dest" - if err := table.Update(route); err != ErrRouteNotFound { - t.Errorf("error updating route. Expected error: %s, found: %s", ErrRouteNotFound, err) + if err := table.Update(route); err != nil { + t.Errorf("error updating route: %s", err) } + testTableSize += 1 if table.Size() != testTableSize { t.Errorf("invalid number of routes. Expected: %d, found: %d", testTableSize, table.Size()) From 29fa8de98ed62d90b85f29a1883a684d0ea26dfc Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Thu, 11 Jul 2019 01:21:03 +0300 Subject: [PATCH 171/287] memory transport: fix race cond on channel close Signed-off-by: Vasiliy Tolstov --- transport/memory/memory.go | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/transport/memory/memory.go b/transport/memory/memory.go index ed00ce69..274e98c9 100644 --- a/transport/memory/memory.go +++ b/transport/memory/memory.go @@ -12,6 +12,10 @@ import ( "github.com/micro/go-micro/transport" ) +var ( + r = rand.New(rand.NewSource(time.Now().UnixNano())) +) + type memorySocket struct { recv chan *transport.Message send chan *transport.Message @@ -22,6 +26,7 @@ type memorySocket struct { local string remote string + sync.RWMutex } type memoryClient struct { @@ -34,16 +39,18 @@ type memoryListener struct { exit chan bool conn chan *memorySocket opts transport.ListenOptions + sync.RWMutex } type memoryTransport struct { opts transport.Options - - sync.Mutex + sync.RWMutex listeners map[string]*memoryListener } func (ms *memorySocket) Recv(m *transport.Message) error { + ms.RLock() + defer ms.RUnlock() select { case <-ms.exit: return errors.New("connection closed") @@ -64,6 +71,8 @@ func (ms *memorySocket) Remote() string { } func (ms *memorySocket) Send(m *transport.Message) error { + ms.RLock() + defer ms.RUnlock() select { case <-ms.exit: return errors.New("connection closed") @@ -75,6 +84,8 @@ func (ms *memorySocket) Send(m *transport.Message) error { } func (ms *memorySocket) Close() error { + ms.RLock() + defer ms.RUnlock() select { case <-ms.exit: return nil @@ -89,6 +100,8 @@ func (m *memoryListener) Addr() string { } func (m *memoryListener) Close() error { + m.Lock() + defer m.Unlock() select { case <-m.exit: return nil @@ -117,8 +130,8 @@ func (m *memoryListener) Accept(fn func(transport.Socket)) error { } func (m *memoryTransport) Dial(addr string, opts ...transport.DialOption) (transport.Client, error) { - m.Lock() - defer m.Unlock() + m.RLock() + defer m.RUnlock() listener, ok := m.listeners[addr] if !ok { @@ -165,7 +178,6 @@ func (m *memoryTransport) Listen(addr string, opts ...transport.ListenOption) (t // if zero port then randomly assign one if len(parts) > 1 && parts[len(parts)-1] == "0" { - r := rand.New(rand.NewSource(time.Now().UnixNano())) i := r.Intn(10000) // set addr with port addr = fmt.Sprintf("%s:%d", parts[:len(parts)-1], 10000+i) From ae5376cc0ebb7833662ab02f548992549b17835a Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 11 Jul 2019 00:14:36 +0100 Subject: [PATCH 172/287] functioning tunnel/link code --- network/link/default.go | 40 +++++++++++++++++++++++++++++++++++++- network/tunnel/default.go | 39 ++++++++++++++++++++++++++++++++++++- network/tunnel/listener.go | 2 ++ 3 files changed, 79 insertions(+), 2 deletions(-) diff --git a/network/link/default.go b/network/link/default.go index f0d01ecd..f6742b83 100644 --- a/network/link/default.go +++ b/network/link/default.go @@ -4,6 +4,7 @@ package link import ( "io" "sync" + "time" "github.com/micro/go-micro/config/options" "github.com/micro/go-micro/transport" @@ -109,12 +110,49 @@ func (l *link) process() { } }() + // messages sent + i := 0 + length := 0 + for { select { case m := <-l.sendQueue: + t := time.Now() + + // send the message if err := l.send(m); err != nil { return } + + // get header size, body size and time taken + hl := len(m.Header) + bl := len(m.Body) + d := time.Since(t) + + // don't calculate on empty messages + if hl == 0 && bl == 0 { + continue + } + + // increment sent + i++ + + // time take to send some bits and bytes + td := float64(hl+bl) / float64(d.Nanoseconds()) + // increase the scale + td += 1 + + // judge the length + length = int(td) / (length + int(td)) + + // every 10 messages update length + if (i % 10) == 1 { + // cost average the length + // save it + l.Lock() + l.length = length + l.Unlock() + } case <-l.closed: return } @@ -158,7 +196,7 @@ func (l *link) Connect() error { // dial the endpoint c, err := l.transport.Dial(l.addr) if err != nil { - return nil + return err } // set the socket diff --git a/network/tunnel/default.go b/network/tunnel/default.go index 50bc1130..89e04dd3 100644 --- a/network/tunnel/default.go +++ b/network/tunnel/default.go @@ -65,6 +65,7 @@ func (t *tun) newSocket(id, session string) (*socket, bool) { closed: make(chan bool), recv: make(chan *message, 128), send: t.send, + wait: make(chan bool), } // save socket @@ -126,6 +127,16 @@ func (t *tun) listen() { return } + // first check Micro-Tunnel + switch msg.Header["Micro-Tunnel"] { + case "connect": + // assuming new connection + // TODO: do something with this + case "close": + // assuming connection closed + // TODO: do something with this + } + // the tunnel id id := msg.Header["Micro-Tunnel-Id"] @@ -136,7 +147,7 @@ func (t *tun) listen() { // TODO: check this is the case, is there any reason // why we'd have a blank session? Is the tunnel // used for some other purpose? - if len(session) == 0 { + if len(id) == 0 || len(session) == 0 { continue } @@ -200,6 +211,22 @@ func (t *tun) listen() { } } +func (t *tun) connect() error { + return t.link.Send(&transport.Message{ + Header: map[string]string{ + "Micro-Tunnel": "connect", + }, + }) +} + +func (t *tun) close() error { + return t.link.Send(&transport.Message{ + Header: map[string]string{ + "Micro-Tunnel": "close", + }, + }) +} + // Close the tunnel func (t *tun) Close() error { t.Lock() @@ -220,6 +247,11 @@ func (t *tun) Close() error { // close the connection close(t.closed) t.connected = false + + // send a close message + // we don't close the link + // just the tunnel + return t.close() } return nil @@ -235,6 +267,11 @@ func (t *tun) Connect() error { return nil } + // send the connect message + if err := t.connect(); err != nil { + return err + } + // set as connected t.connected = true // create new close channel diff --git a/network/tunnel/listener.go b/network/tunnel/listener.go index 6a8d1ba3..dac315ce 100644 --- a/network/tunnel/listener.go +++ b/network/tunnel/listener.go @@ -42,6 +42,8 @@ func (t *tunListener) process() { recv: make(chan *message, 128), // use the internal send buffer send: t.socket.send, + // wait + wait: make(chan bool), } // save the socket From 9b1cb4ef0e2f13bcab46840594aee261d3518b79 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 11 Jul 2019 00:55:50 +0100 Subject: [PATCH 173/287] functioning tunnel with test --- network/tunnel/default.go | 2 + network/tunnel/listener.go | 16 ++++- network/tunnel/tunnel_test.go | 111 ++++++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 network/tunnel/tunnel_test.go diff --git a/network/tunnel/default.go b/network/tunnel/default.go index 89e04dd3..a810783e 100644 --- a/network/tunnel/default.go +++ b/network/tunnel/default.go @@ -132,9 +132,11 @@ func (t *tun) listen() { case "connect": // assuming new connection // TODO: do something with this + continue case "close": // assuming connection closed // TODO: do something with this + continue } // the tunnel id diff --git a/network/tunnel/listener.go b/network/tunnel/listener.go index dac315ce..6c803eb9 100644 --- a/network/tunnel/listener.go +++ b/network/tunnel/listener.go @@ -46,15 +46,25 @@ func (t *tunListener) process() { wait: make(chan bool), } + // first message + sock.recv <- m + // save the socket conns[m.session] = sock + + // send to accept chan + select { + case <-t.closed: + return + case t.accept <- sock: + } } // send this to the accept chan select { - case <-t.closed: - return - case t.accept <- sock: + case <-sock.closed: + delete(conns, m.session) + case sock.recv <- m: } } } diff --git a/network/tunnel/tunnel_test.go b/network/tunnel/tunnel_test.go new file mode 100644 index 00000000..d8b84739 --- /dev/null +++ b/network/tunnel/tunnel_test.go @@ -0,0 +1,111 @@ +package tunnel + +import ( + "testing" + + "github.com/micro/go-micro/network/link" + "github.com/micro/go-micro/transport" +) + +func testAccept(t *testing.T, l transport.Listener, wait chan bool) error { + // accept new connections on the transport + // establish a link and tunnel + return l.Accept(func(s transport.Socket) { + // convert the socket into a link + li := link.NewLink( + link.Socket(s), + ) + + // connect the link e.g start internal buffers + if err := li.Connect(); err != nil { + t.Fatal(err) + } + + // create a new tunnel + tun := NewTunnel(li) + + // connect the tunnel + if err := tun.Connect(); err != nil { + t.Fatal(err) + } + + // listen on some virtual address + tl, err := tun.Listen("test-tunnel") + if err != nil { + t.Fatal(err) + return + } + + // accept a connection + c, err := tl.Accept() + if err != nil { + t.Fatal(err) + } + + // get a message + for { + m := new(transport.Message) + if err := c.Recv(m); err != nil { + t.Fatal(err) + } + close(wait) + return + } + }) +} + +func testSend(t *testing.T, addr string) { + // create a new link + l := link.NewLink( + link.Address(addr), + ) + + // connect the link, this includes dialing + if err := l.Connect(); err != nil { + t.Fatal(err) + } + + // create a tunnel on the link + tun := NewTunnel(l) + + // connect the tunnel with the remote side + if err := tun.Connect(); err != nil { + t.Fatal(err) + } + + // dial a new session + c, err := tun.Dial("test-tunnel") + if err != nil { + t.Fatal(err) + } + + m := transport.Message{ + Header: map[string]string{ + "test": "header", + }, + } + if err := c.Send(&m); err != nil { + t.Fatal(err) + } +} + +func TestTunnel(t *testing.T) { + // create a new listener + tr := transport.NewTransport() + l, err := tr.Listen(":0") + if err != nil { + t.Fatal(err) + } + defer l.Close() + + wait := make(chan bool) + + // start accepting connections + go testAccept(t, l, wait) + + // send a message + testSend(t, l.Addr()) + + // wait until message is received + <-wait +} From 3abe3aa28b9b66ec701bb0358e2df44d1490040f Mon Sep 17 00:00:00 2001 From: magodo Date: Thu, 11 Jul 2019 12:51:55 +0800 Subject: [PATCH 174/287] store.Read() returns honor `Record.Expiry` --- data/store/memory/memory.go | 9 ++++++++ data/store/memory/memory_test.go | 37 ++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 data/store/memory/memory_test.go diff --git a/data/store/memory/memory.go b/data/store/memory/memory.go index 0e06eefa..16f68136 100644 --- a/data/store/memory/memory.go +++ b/data/store/memory/memory.go @@ -36,6 +36,11 @@ func (m *memoryStore) Dump() ([]*store.Record, error) { if d > time.Duration(0) && t > d { continue } + + // update expiry + v.r.Expiry -= t + v.c = time.Now() + values = append(values, v.r) } @@ -60,6 +65,10 @@ func (m *memoryStore) Read(key string) (*store.Record, error) { return nil, store.ErrNotFound } + // update expiry + v.r.Expiry -= t + v.c = time.Now() + return v.r, nil } diff --git a/data/store/memory/memory_test.go b/data/store/memory/memory_test.go new file mode 100644 index 00000000..44483869 --- /dev/null +++ b/data/store/memory/memory_test.go @@ -0,0 +1,37 @@ +package memory + +import ( + "testing" + "time" + + "github.com/micro/go-micro/data/store" +) + +func TestReadRecordExpire(t *testing.T) { + s := NewStore() + + var ( + key = "foo" + expire = 100 * time.Millisecond + ) + rec := &store.Record{ + Key: key, + Value: nil, + Expiry: expire, + } + s.Write(rec) + + rrec, err := s.Read(key) + if err != nil { + t.Fatal(err) + } + if rrec.Expiry >= expire { + t.Fatal("expiry of read record is not changed") + } + + time.Sleep(expire) + + if _, err := s.Read(key); err != store.ErrNotFound { + t.Fatal("expire elapsed, but key still accessable") + } +} From c8d57032bcdaf201ac09480bba2be5dc04bfd3c7 Mon Sep 17 00:00:00 2001 From: magodo Date: Thu, 11 Jul 2019 12:58:20 +0800 Subject: [PATCH 175/287] update expiry only if it is non-zero --- data/store/memory/memory.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/data/store/memory/memory.go b/data/store/memory/memory.go index 16f68136..75aafce0 100644 --- a/data/store/memory/memory.go +++ b/data/store/memory/memory.go @@ -38,8 +38,10 @@ func (m *memoryStore) Dump() ([]*store.Record, error) { } // update expiry - v.r.Expiry -= t - v.c = time.Now() + if d > time.Duration(0) { + v.r.Expiry -= t + v.c = time.Now() + } values = append(values, v.r) } @@ -66,8 +68,10 @@ func (m *memoryStore) Read(key string) (*store.Record, error) { } // update expiry - v.r.Expiry -= t - v.c = time.Now() + if d > time.Duration(0) { + v.r.Expiry -= t + v.c = time.Now() + } return v.r, nil } From bdeae91063d1a6c2639a01829fd81d548cbcef4f Mon Sep 17 00:00:00 2001 From: magodo Date: Thu, 11 Jul 2019 14:13:58 +0800 Subject: [PATCH 176/287] condense code --- data/store/memory/memory.go | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/data/store/memory/memory.go b/data/store/memory/memory.go index 75aafce0..bb7892e8 100644 --- a/data/store/memory/memory.go +++ b/data/store/memory/memory.go @@ -32,13 +32,12 @@ func (m *memoryStore) Dump() ([]*store.Record, error) { d := v.r.Expiry t := time.Since(v.c) - // expired - if d > time.Duration(0) && t > d { - continue - } - - // update expiry if d > time.Duration(0) { + // expired + if t > d { + continue + } + // update expiry v.r.Expiry -= t v.c = time.Now() } @@ -63,12 +62,11 @@ func (m *memoryStore) Read(key string) (*store.Record, error) { t := time.Since(v.c) // expired - if d > time.Duration(0) && t > d { - return nil, store.ErrNotFound - } - - // update expiry if d > time.Duration(0) { + if t > d { + return nil, store.ErrNotFound + } + // update expiry v.r.Expiry -= t v.c = time.Now() } From dab0e9e9bc6ff1f48971a34a2c34326f3fafc967 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 11 Jul 2019 09:38:20 +0100 Subject: [PATCH 177/287] Set next protos in quic --- transport/quic/quic.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/transport/quic/quic.go b/transport/quic/quic.go index 2622ec84..c461b870 100644 --- a/transport/quic/quic.go +++ b/transport/quic/quic.go @@ -109,6 +109,7 @@ func (q *quicTransport) Dial(addr string, opts ...transport.DialOption) (transpo if config == nil { config = &tls.Config{ InsecureSkipVerify: true, + NextProtos: []string{"http/1.1"}, } } s, err := quic.DialAddr(addr, config, nil) @@ -150,6 +151,7 @@ func (q *quicTransport) Listen(addr string, opts ...transport.ListenOption) (tra } config = &tls.Config{ Certificates: []tls.Certificate{cfg}, + NextProtos: []string{"http/1.1"}, } } From 65815862265ba45d4c4a9f932198b63c98d33f57 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 11 Jul 2019 10:34:01 +0100 Subject: [PATCH 178/287] Make tunnel test use quic --- network/tunnel/tunnel_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/network/tunnel/tunnel_test.go b/network/tunnel/tunnel_test.go index d8b84739..6e171375 100644 --- a/network/tunnel/tunnel_test.go +++ b/network/tunnel/tunnel_test.go @@ -5,8 +5,10 @@ import ( "github.com/micro/go-micro/network/link" "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/transport/quic" ) +// testAccept will accept connections on the transport, create a new link and tunnel on top func testAccept(t *testing.T, l transport.Listener, wait chan bool) error { // accept new connections on the transport // establish a link and tunnel @@ -54,10 +56,12 @@ func testAccept(t *testing.T, l transport.Listener, wait chan bool) error { }) } +// testSend will create a new link to an address and then a tunnel on top func testSend(t *testing.T, addr string) { // create a new link l := link.NewLink( link.Address(addr), + link.Transport(quic.NewTransport()), ) // connect the link, this includes dialing @@ -91,7 +95,7 @@ func testSend(t *testing.T, addr string) { func TestTunnel(t *testing.T) { // create a new listener - tr := transport.NewTransport() + tr := quic.NewTransport() l, err := tr.Listen(":0") if err != nil { t.Fatal(err) From 7631463b941d09fa15d83cb187cb3ac8855245d6 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 11 Jul 2019 10:47:02 +0100 Subject: [PATCH 179/287] fix compilation errors --- transport/quic/quic.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/transport/quic/quic.go b/transport/quic/quic.go index c461b870..8a1e3f61 100644 --- a/transport/quic/quic.go +++ b/transport/quic/quic.go @@ -2,6 +2,7 @@ package quic import ( + "context" "crypto/tls" "encoding/gob" @@ -67,12 +68,12 @@ func (q *quicListener) Close() error { func (q *quicListener) Accept(fn func(transport.Socket)) error { for { - s, err := q.l.Accept() + s, err := q.l.Accept(context.TODO()) if err != nil { return err } - stream, err := s.AcceptStream() + stream, err := s.AcceptStream(context.TODO()) if err != nil { continue } @@ -117,7 +118,7 @@ func (q *quicTransport) Dial(addr string, opts ...transport.DialOption) (transpo return nil, err } - st, err := s.OpenStreamSync() + st, err := s.OpenStreamSync(context.TODO()) if err != nil { return nil, err } From 35a1de91a982a9be8cda52ba5126684a77fb9c3a Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Thu, 11 Jul 2019 12:36:39 +0100 Subject: [PATCH 180/287] Advertise full table every minute. --- network/router/default.go | 139 ++++++++++++++++++++++---------- network/router/router.go | 3 +- network/router/table/watcher.go | 16 ++++ 3 files changed, 115 insertions(+), 43 deletions(-) diff --git a/network/router/default.go b/network/router/default.go index 6250608a..5b13b2ae 100644 --- a/network/router/default.go +++ b/network/router/default.go @@ -13,14 +13,16 @@ import ( ) const ( - // AdvertiseTick is time interval in which we advertise route updates - AdvertiseTick = 5 * time.Second + // AdvertiseEventsTick is time interval in which the router advertises route updates + AdvertiseEventsTick = 5 * time.Second + // AdvertiseTableTick is time interval in which router advertises all routes found in routing table + AdvertiseTableTick = 1 * time.Minute // AdvertSuppress is advert suppression threshold AdvertSuppress = 2000 // AdvertRecover is advert recovery threshold AdvertRecover = 750 // DefaultAdvertTTL is default advertisement TTL - DefaultAdvertTTL = time.Minute + DefaultAdvertTTL = 1 * time.Minute // PenaltyDecay is the penalty decay PenaltyDecay = 1.15 // Delete penalises route addition and deletion @@ -78,6 +80,28 @@ func (r *router) Options() Options { return r.opts } +// manageRoute applies route action on the routing table +func (r *router) manageRoute(route table.Route, action string) error { + switch action { + case "create": + if err := r.Create(route); err != nil && err != table.ErrDuplicateRoute { + return fmt.Errorf("failed adding route for service %s: %s", route.Service, err) + } + case "update": + if err := r.Update(route); err != nil && err != table.ErrDuplicateRoute { + return fmt.Errorf("failed updating route for service %s: %s", route.Service, err) + } + case "delete": + if err := r.Delete(route); err != nil && err != table.ErrRouteNotFound { + return fmt.Errorf("failed deleting route for service %s: %s", route.Service, err) + } + default: + return fmt.Errorf("failed to manage route for service %s. Unknown action: %s", route.Service, action) + } + + return nil +} + // manageServiceRoutes manages routes for a given service. // It returns error of the routing table action fails. func (r *router) manageServiceRoutes(service *registry.Service, action string) error { @@ -95,21 +119,8 @@ func (r *router) manageServiceRoutes(service *registry.Service, action string) e Metric: table.DefaultLocalMetric, } - switch action { - case "create": - if err := r.Create(route); err != nil && err != table.ErrDuplicateRoute { - return fmt.Errorf("failed adding route for service %s: %s", service.Name, err) - } - case "update": - if err := r.Update(route); err != nil && err != table.ErrDuplicateRoute { - return fmt.Errorf("failed updating route for service %s: %s", service.Name, err) - } - case "delete": - if err := r.Delete(route); err != nil && err != table.ErrRouteNotFound { - return fmt.Errorf("failed deleting route for service %s: %s", service.Name, err) - } - default: - return fmt.Errorf("failed to manage route for service %s. Unknown action: %s", service.Name, action) + if err := r.manageRoute(route, action); err != nil { + return err } } @@ -132,8 +143,8 @@ func (r *router) manageRegistryRoutes(reg registry.Registry, action string) erro continue } // manage the routes for all returned services - for _, s := range srvs { - if err := r.manageServiceRoutes(s, action); err != nil { + for _, srv := range srvs { + if err := r.manageServiceRoutes(srv, action); err != nil { return err } } @@ -210,12 +221,14 @@ func (r *router) watchTable(w table.Watcher) error { return watchErr } -func (r *router) advertEvents(advType AdvertType, events []*table.Event) { +// advertiseEvents advertises events to event subscribers +func (r *router) advertiseEvents(advType AdvertType, events []*table.Event) { defer r.advertWg.Done() a := &Advert{ Id: r.opts.Id, Type: advType, + TTL: DefaultAdvertTTL, Timestamp: time.Now(), Events: events, } @@ -225,7 +238,45 @@ func (r *router) advertEvents(advType AdvertType, events []*table.Event) { case <-r.exit: return } +} +// advertiseTable advertises the whole routing table to the network +func (r *router) advertiseTable() error { + // create table advertisement ticker + ticker := time.NewTicker(AdvertiseTableTick) + + for { + select { + case <-ticker.C: + // list routing table routes to announce + routes, err := r.List() + if err != nil { + return fmt.Errorf("failed listing routes: %s", err) + } + // collect all the added routes before we attempt to add default gateway + events := make([]*table.Event, len(routes)) + for i, route := range routes { + event := &table.Event{ + Type: table.Update, + Timestamp: time.Now(), + Route: route, + } + events[i] = event + } + + // advertise all routes as Update events to subscribers + if len(events) > 0 { + go func() { + r.advertWg.Add(1) + r.advertiseEvents(Update, events) + }() + } + case <-r.exit: + return nil + } + } + + return nil } // isFlapping detects if the event is flapping based on the current and previous event status. @@ -241,8 +292,8 @@ func isFlapping(curr, prev *table.Event) bool { return false } -// updateEvent is a table event enriched with advertisement data -type updateEvent struct { +// advertEvent is a table event enriched with advertisement data +type advertEvent struct { *table.Event // timestamp marks the time the event has been received timestamp time.Time @@ -258,15 +309,16 @@ type updateEvent struct { // It suppresses unhealthy flapping events and advertises healthy events upstream. func (r *router) processEvents() error { // ticker to periodically scan event for advertising - ticker := time.NewTicker(AdvertiseTick) + ticker := time.NewTicker(AdvertiseEventsTick) // eventMap is a map of advert events - eventMap := make(map[uint64]*updateEvent) + eventMap := make(map[uint64]*advertEvent) for { select { case <-ticker.C: var events []*table.Event // collect all events which are not flapping + // TODO: decay the events and update suppression for key, event := range eventMap { if !event.isFlapping && !event.isSuppressed { e := new(table.Event) @@ -277,9 +329,10 @@ func (r *router) processEvents() error { } } + // advertise all Update events to subscribers if len(events) > 0 { r.advertWg.Add(1) - go r.advertEvents(Update, events) + go r.advertiseEvents(Update, events) } case e := <-r.eventChan: // event timestamp @@ -301,7 +354,7 @@ func (r *router) processEvents() error { hash := e.Route.Hash() event, ok := eventMap[hash] if !ok { - event = &updateEvent{ + event = &advertEvent{ Event: e, penalty: penalty, timestamp: time.Now(), @@ -334,7 +387,7 @@ func (r *router) processEvents() error { } } - // we probably never reach this place + // we probably never reach this code path return nil } @@ -438,7 +491,7 @@ func (r *router) Advertise() (<-chan *Advert, error) { } // error channel collecting goroutine errors - errChan := make(chan error, 3) + errChan := make(chan error, 4) r.wg.Add(1) go func() { @@ -457,24 +510,27 @@ func (r *router) Advertise() (<-chan *Advert, error) { r.wg.Add(1) go func() { defer r.wg.Done() - // listen to routing table events and process them + // watch routing table events and process them errChan <- r.processEvents() }() + r.advertWg.Add(1) + go func() { + defer r.advertWg.Done() + // advertise the whole routing table + errChan <- r.advertiseTable() + }() + + // advertise your presence + r.advertWg.Add(1) + go r.advertiseEvents(Announce, events) + // watch for errors and cleanup r.wg.Add(1) go r.watchErrors(errChan) - // advertise your presence - r.advertWg.Add(1) - go r.advertEvents(Announce, events) - // mark router as running and set its Error to nil - status := Status{ - Code: Running, - Error: nil, - } - r.status = status + r.status = Status{Code: Running, Error: nil} } return r.advertChan, nil @@ -494,8 +550,9 @@ func (r *router) Process(a *Advert) error { for _, event := range events { // create a copy of the route route := event.Route - if err := r.Update(route); err != nil { - return fmt.Errorf("failed updating routing table: %v", err) + action := event.Type + if err := r.manageRoute(route, fmt.Sprintf("%s", action)); err != nil { + return fmt.Errorf("failed applying action %s to routing table: %s", action, err) } } diff --git a/network/router/router.go b/network/router/router.go index 39e8d94a..724f38be 100644 --- a/network/router/router.go +++ b/network/router/router.go @@ -58,8 +58,7 @@ type Advert struct { // Timestamp marks the time when the update is sent Timestamp time.Time // TTL is Advert TTL - // TODO: not used - TTL time.Time + TTL time.Duration // Events is a list of routing table events to advertise Events []*table.Event } diff --git a/network/router/table/watcher.go b/network/router/table/watcher.go index 0f8fab7f..503993ff 100644 --- a/network/router/table/watcher.go +++ b/network/router/table/watcher.go @@ -22,6 +22,22 @@ const ( Update ) +// String implements fmt.Stringer +// NOTE: we need this as this makes converting the numeric codes +// into miro style string actions very simple +func (et EventType) String() string { + switch et { + case Create: + return "create" + case Delete: + return "delete" + case Update: + return "update" + default: + return "unknown" + } +} + // Event is returned by a call to Next on the watcher. type Event struct { // Type defines type of event From 360e193a01bc4e0a65b1d7c7bd16164521615489 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 11 Jul 2019 12:47:50 +0100 Subject: [PATCH 181/287] update go mod --- go.mod | 40 +++++++++++++++++++--------------------- go.sum | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 21 deletions(-) diff --git a/go.mod b/go.mod index 1b5454b1..8a7e1b6b 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/micro/go-micro go 1.12 require ( - cloud.google.com/go v0.40.0 // indirect + cloud.google.com/go v0.41.0 // indirect github.com/BurntSushi/toml v0.3.1 github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 // indirect github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 // indirect @@ -17,16 +17,14 @@ require ( github.com/fsouza/go-dockerclient v1.4.1 github.com/ghodss/yaml v1.0.0 github.com/gliderlabs/ssh v0.2.2 // indirect + github.com/go-kit/kit v0.9.0 // indirect github.com/go-log/log v0.1.0 github.com/go-playground/locales v0.12.1 // indirect github.com/go-playground/universal-translator v0.16.0 // indirect - github.com/golang/mock v1.3.1 // indirect - github.com/golang/protobuf v1.3.1 - github.com/google/btree v1.0.0 // indirect - github.com/google/pprof v0.0.0-20190515194954-54271f7e092f // indirect + github.com/golang/protobuf v1.3.2 github.com/google/uuid v1.1.1 - github.com/googleapis/gax-go/v2 v2.0.5 // indirect - github.com/gorilla/handlers v1.4.0 + github.com/gorilla/handlers v1.4.1 + github.com/gorilla/mux v1.7.3 // indirect github.com/gorilla/websocket v1.4.0 github.com/hashicorp/consul/api v1.1.0 github.com/hashicorp/go-immutable-radix v1.1.0 // indirect @@ -42,17 +40,18 @@ require ( github.com/imdario/mergo v0.3.7 github.com/joncalhoun/qson v0.0.0-20170526102502-8a9cab3a62b1 github.com/json-iterator/go v1.1.6 + github.com/kevinburke/ssh_config v0.0.0-20190630040420-2e50c441276c // indirect github.com/kisielk/errcheck v1.2.0 // indirect github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect - github.com/kr/pty v1.1.5 // indirect + github.com/kr/pty v1.1.8 // indirect github.com/leodido/go-urn v1.1.0 // indirect github.com/lucas-clemente/quic-go v0.11.2 - github.com/marten-seemann/qtls v0.2.4 // indirect + github.com/marten-seemann/qtls v0.3.1 // indirect github.com/mattn/go-colorable v0.1.2 // indirect github.com/mattn/go-runewidth v0.0.4 // indirect github.com/micro/cli v0.2.0 github.com/micro/mdns v0.1.0 - github.com/miekg/dns v1.1.14 // indirect + github.com/miekg/dns v1.1.15 // indirect github.com/mitchellh/gox v1.0.1 // indirect github.com/mitchellh/hashstructure v1.0.0 github.com/nats-io/nats.go v1.8.1 @@ -63,23 +62,22 @@ require ( github.com/pkg/errors v0.8.1 github.com/posener/complete v1.2.1 // indirect github.com/prometheus/common v0.6.0 // indirect + github.com/prometheus/procfs v0.0.3 // indirect github.com/sirupsen/logrus v1.4.2 // indirect github.com/stretchr/objx v0.2.0 // indirect github.com/technoweenie/multipartstreamer v1.0.1 // indirect - go.opencensus.io v0.22.0 // indirect - golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443 - golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522 // indirect - golang.org/x/image v0.0.0-20190618124811-92942e4437e2 // indirect + golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 + golang.org/x/exp v0.0.0-20190627132806-fd42eb6b336f // indirect + golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9 // indirect golang.org/x/mobile v0.0.0-20190607214518-6fa95d984e88 // indirect golang.org/x/mod v0.1.0 // indirect - golang.org/x/net v0.0.0-20190620200207-3b0461eec859 - golang.org/x/sys v0.0.0-20190621062556-bf70e4678053 // indirect - golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect - golang.org/x/tools v0.0.0-20190620191750-1fa568393b23 // indirect - google.golang.org/appengine v1.6.1 // indirect - google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601 // indirect - google.golang.org/grpc v1.21.1 + golang.org/x/net v0.0.0-20190628185345-da137c7871d7 + golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 // indirect + golang.org/x/tools v0.0.0-20190710184609-286818132824 // indirect + google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532 // indirect + google.golang.org/grpc v1.22.0 gopkg.in/go-playground/validator.v9 v9.29.0 + gopkg.in/src-d/go-billy.v4 v4.3.1 // indirect gopkg.in/src-d/go-git.v4 v4.12.0 gopkg.in/telegram-bot-api.v4 v4.6.4 honnef.co/go/tools v0.0.0-20190614002413-cb51c254f01b // indirect diff --git a/go.sum b/go.sum index b576c0b1..605b53f5 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,7 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.40.0/go.mod h1:Tk58MuI9rbLMKlAjeO/bDnteAx7tX2gJIXw4T5Jwlro= +cloud.google.com/go v0.41.0/go.mod h1:OauMR7DV8fzvZIl2qg6rkaIhD/vmgk4iwEw/h6ercmg= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -39,6 +40,7 @@ github.com/containerd/continuity v0.0.0-20181203112020-004b46473808 h1:4BX8f882b github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc h1:TP+534wVlf61smEIq1nwLLAjQVEK2EADoW3CX9AuT+8= github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/docker/docker v0.7.3-0.20190309235953-33c3200e0d16 h1:dmUn0SuGx7unKFwxyeQ/oLUHhEfZosEDrpmYM+6MTuc= @@ -65,6 +67,7 @@ github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aev github.com/gliderlabs/ssh v0.1.3/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-log/log v0.1.0 h1:wudGTNsiGzrD5ZjgIkVZ517ugi2XRe9Q/xRCzwEO4/U= github.com/go-log/log v0.1.0/go.mod h1:4mBwpdRMFLiuXZDCwU2lKQFsoSCo72j3HqBK9d81N2M= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -85,6 +88,8 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= 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 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= @@ -101,7 +106,10 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gorilla/handlers v1.4.0 h1:XulKRWSQK5uChr4pEgSE4Tc/OcmnU9GJuSwdog/tZsA= github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/handlers v1.4.1 h1:BHvcRGJe/TrL+OqFxoKQGddTgeibiOjaBssV5a/N9sw= +github.com/gorilla/handlers v1.4.1/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/hashicorp/consul/api v1.1.0 h1:BNQPM9ytxj6jbjjdRPioQ94T6YXriSopn0i8COv6SRA= @@ -170,6 +178,8 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e h1:RgQk53JHp/Cjunrr1WlsXSZpqXn+uREuHvUVcK82CV8= github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kevinburke/ssh_config v0.0.0-20190630040420-2e50c441276c h1:VAx3LRNjVNvjtgO7KFRuT/3aye/0zJvwn01rHSfoolo= +github.com/kevinburke/ssh_config v0.0.0-20190630040420-2e50c441276c/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= @@ -179,6 +189,7 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= @@ -188,6 +199,8 @@ github.com/marten-seemann/qtls v0.2.3 h1:0yWJ43C62LsZt08vuQJDK1uC1czUc3FJeCLPoNA github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= github.com/marten-seemann/qtls v0.2.4 h1:mCJ6i1jAqcsm9XODrSGvXECodoAb1STta+TkxJCwCnE= github.com/marten-seemann/qtls v0.2.4/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= +github.com/marten-seemann/qtls v0.3.1 h1:ySYIvhFjFY2JsNHY6VACvomMEDy3EvdPA6yciUFAiHw= +github.com/marten-seemann/qtls v0.3.1/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= @@ -204,6 +217,8 @@ github.com/miekg/dns v1.1.3 h1:1g0r1IvskvgL8rR+AcHzUA+oFmGcQlaIm4IqakufeMM= github.com/miekg/dns v1.1.3/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.14 h1:wkQWn9wIp4mZbwW8XV6Km6owkvRPbOiV004ZM2CkGvA= github.com/miekg/dns v1.1.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.15 h1:CSSIDtllwGLMoA6zjdKnaE6Tx6eVUxQ29LUgGetiDCI= +github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -266,6 +281,7 @@ github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= @@ -308,11 +324,15 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmV golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443 h1:IcSOAf4PyMp3U3XbIEj1/xJ2BjNN2jWv7JoyOsMxXUU= golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190627132806-fd42eb6b336f/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190618124811-92942e4437e2/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -342,6 +362,8 @@ golang.org/x/net v0.0.0-20190607181551-461777fb6f67/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 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-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8j4DQRpdYMnGn/bJUEU= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -372,6 +394,9 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190621062556-bf70e4678053 h1:T0MJjz97TtCXa3ZNW2Oenb3KQWB91K965zMEbIJ4ThA= golang.org/x/sys v0.0.0-20190621062556-bf70e4678053/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= +golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= 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= @@ -389,11 +414,15 @@ golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190530171427-2b03ca6e44eb/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190620191750-1fa568393b23/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624190245-7f2218787638/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190710184609-286818132824/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -408,10 +437,15 @@ google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601 h1:9VBRTdmgQxbs6HE0sUnMrSWNePppAJU07NYvX5dIB04= google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190626174449-989357319d63/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532 h1:5pOB7se0B2+IssELuQUs6uoBgYJenkU2AQlvopc2sRw= +google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1 h1:j6XxA85m/6txkUCHvzlV5f+HBNl/1r5cZ2A/3IEFOO8= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.0 h1:J0UbZOIrCAl+fpTOf8YLs4dJo8L/owV4LYVtAXQoPkw= +google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 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= @@ -423,6 +457,8 @@ gopkg.in/src-d/go-billy.v4 v4.2.1 h1:omN5CrMrMcQ+4I8bJ0wEhOBPanIRWzFC953IiXKdYzo gopkg.in/src-d/go-billy.v4 v4.2.1/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk= gopkg.in/src-d/go-billy.v4 v4.3.0 h1:KtlZ4c1OWbIs4jCv5ZXrTqG8EQocr0g/d4DjNg70aek= gopkg.in/src-d/go-billy.v4 v4.3.0/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk= +gopkg.in/src-d/go-billy.v4 v4.3.1 h1:OkK1DmefDy1Z6Veu82wdNj/cLpYORhdX4qdaYCPwc7s= +gopkg.in/src-d/go-billy.v4 v4.3.1/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk= gopkg.in/src-d/go-git-fixtures.v3 v3.1.1/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= gopkg.in/src-d/go-git.v4 v4.11.0 h1:cJwWgJ0DXifrNrXM6RGN1Y2yR60Rr1zQ9Q5DX5S9qgU= @@ -441,5 +477,6 @@ gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190614002413-cb51c254f01b/go.mod h1:JlmFZigtG9vBVR3QGIQ9g/Usz4BzH+Xm6Z8iHQWRYUw= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= From 9c851f297ba507297823d492085d72ef1f699e17 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Thu, 11 Jul 2019 21:14:34 +0100 Subject: [PATCH 182/287] Added proto.Advert type to protobuf definitions --- network/router/proto/router.micro.go | 10 +- network/router/proto/router.pb.go | 219 ++++++++++++++++++++------- network/router/proto/router.proto | 30 +++- 3 files changed, 194 insertions(+), 65 deletions(-) diff --git a/network/router/proto/router.micro.go b/network/router/proto/router.micro.go index bba03161..23b8087c 100644 --- a/network/router/proto/router.micro.go +++ b/network/router/proto/router.micro.go @@ -73,7 +73,7 @@ type Router_WatchService interface { SendMsg(interface{}) error RecvMsg(interface{}) error Close() error - Recv() (*TableEvent, error) + Recv() (*Event, error) } type routerServiceWatch struct { @@ -92,8 +92,8 @@ func (x *routerServiceWatch) RecvMsg(m interface{}) error { return x.stream.Recv(m) } -func (x *routerServiceWatch) Recv() (*TableEvent, error) { - m := new(TableEvent) +func (x *routerServiceWatch) Recv() (*Event, error) { + m := new(Event) err := x.stream.Recv(m) if err != nil { return nil, err @@ -158,7 +158,7 @@ type Router_WatchStream interface { SendMsg(interface{}) error RecvMsg(interface{}) error Close() error - Send(*TableEvent) error + Send(*Event) error } type routerWatchStream struct { @@ -177,7 +177,7 @@ func (x *routerWatchStream) RecvMsg(m interface{}) error { return x.stream.Recv(m) } -func (x *routerWatchStream) Send(m *TableEvent) error { +func (x *routerWatchStream) Send(m *Event) error { return x.stream.Send(m) } diff --git a/network/router/proto/router.pb.go b/network/router/proto/router.pb.go index a3416785..bad0d1ec 100644 --- a/network/router/proto/router.pb.go +++ b/network/router/proto/router.pb.go @@ -20,7 +20,33 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package -// EventType is TableEvent type +// AdvertType defines the type of advert +type AdvertType int32 + +const ( + AdvertType_AdvertAnnounce AdvertType = 0 + AdvertType_AdvertUpdate AdvertType = 1 +) + +var AdvertType_name = map[int32]string{ + 0: "AdvertAnnounce", + 1: "AdvertUpdate", +} + +var AdvertType_value = map[string]int32{ + "AdvertAnnounce": 0, + "AdvertUpdate": 1, +} + +func (x AdvertType) String() string { + return proto.EnumName(AdvertType_name, int32(x)) +} + +func (AdvertType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_367072455c71aedc, []int{0} +} + +// EventType defines the type of event type EventType int32 const ( @@ -46,7 +72,7 @@ func (x EventType) String() string { } func (EventType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{0} + return fileDescriptor_367072455c71aedc, []int{1} } // LookupRequest is made to Lookup @@ -161,9 +187,86 @@ func (m *WatchRequest) XXX_DiscardUnknown() { var xxx_messageInfo_WatchRequest proto.InternalMessageInfo -// TableEvent is streamed by WatchRequest -type TableEvent struct { - // time of table event +// Advert is router advertsement streamed by Watch +type Advert struct { + // id of the advertising router + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // type of advertisement + Type AdvertType `protobuf:"varint,2,opt,name=type,proto3,enum=AdvertType" json:"type,omitempty"` + // unix timestamp of the advertisement + Timestamp int64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + // TTL of the Advert + Ttl int64 `protobuf:"varint,4,opt,name=ttl,proto3" json:"ttl,omitempty"` + // events is a list of advertised events + Events []*Event `protobuf:"bytes,5,rep,name=events,proto3" json:"events,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Advert) Reset() { *m = Advert{} } +func (m *Advert) String() string { return proto.CompactTextString(m) } +func (*Advert) ProtoMessage() {} +func (*Advert) Descriptor() ([]byte, []int) { + return fileDescriptor_367072455c71aedc, []int{3} +} + +func (m *Advert) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Advert.Unmarshal(m, b) +} +func (m *Advert) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Advert.Marshal(b, m, deterministic) +} +func (m *Advert) XXX_Merge(src proto.Message) { + xxx_messageInfo_Advert.Merge(m, src) +} +func (m *Advert) XXX_Size() int { + return xxx_messageInfo_Advert.Size(m) +} +func (m *Advert) XXX_DiscardUnknown() { + xxx_messageInfo_Advert.DiscardUnknown(m) +} + +var xxx_messageInfo_Advert proto.InternalMessageInfo + +func (m *Advert) GetId() string { + if m != nil { + return m.Id + } + return "" +} + +func (m *Advert) GetType() AdvertType { + if m != nil { + return m.Type + } + return AdvertType_AdvertAnnounce +} + +func (m *Advert) GetTimestamp() int64 { + if m != nil { + return m.Timestamp + } + return 0 +} + +func (m *Advert) GetTtl() int64 { + if m != nil { + return m.Ttl + } + return 0 +} + +func (m *Advert) GetEvents() []*Event { + if m != nil { + return m.Events + } + return nil +} + +// Event is routing table event +type Event struct { + // type of event Type EventType `protobuf:"varint,1,opt,name=type,proto3,enum=EventType" json:"type,omitempty"` // unix timestamp of event Timestamp int64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` @@ -174,46 +277,46 @@ type TableEvent struct { XXX_sizecache int32 `json:"-"` } -func (m *TableEvent) Reset() { *m = TableEvent{} } -func (m *TableEvent) String() string { return proto.CompactTextString(m) } -func (*TableEvent) ProtoMessage() {} -func (*TableEvent) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{3} +func (m *Event) Reset() { *m = Event{} } +func (m *Event) String() string { return proto.CompactTextString(m) } +func (*Event) ProtoMessage() {} +func (*Event) Descriptor() ([]byte, []int) { + return fileDescriptor_367072455c71aedc, []int{4} } -func (m *TableEvent) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_TableEvent.Unmarshal(m, b) +func (m *Event) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Event.Unmarshal(m, b) } -func (m *TableEvent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_TableEvent.Marshal(b, m, deterministic) +func (m *Event) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Event.Marshal(b, m, deterministic) } -func (m *TableEvent) XXX_Merge(src proto.Message) { - xxx_messageInfo_TableEvent.Merge(m, src) +func (m *Event) XXX_Merge(src proto.Message) { + xxx_messageInfo_Event.Merge(m, src) } -func (m *TableEvent) XXX_Size() int { - return xxx_messageInfo_TableEvent.Size(m) +func (m *Event) XXX_Size() int { + return xxx_messageInfo_Event.Size(m) } -func (m *TableEvent) XXX_DiscardUnknown() { - xxx_messageInfo_TableEvent.DiscardUnknown(m) +func (m *Event) XXX_DiscardUnknown() { + xxx_messageInfo_Event.DiscardUnknown(m) } -var xxx_messageInfo_TableEvent proto.InternalMessageInfo +var xxx_messageInfo_Event proto.InternalMessageInfo -func (m *TableEvent) GetType() EventType { +func (m *Event) GetType() EventType { if m != nil { return m.Type } return EventType_Create } -func (m *TableEvent) GetTimestamp() int64 { +func (m *Event) GetTimestamp() int64 { if m != nil { return m.Timestamp } return 0 } -func (m *TableEvent) GetRoute() *Route { +func (m *Event) GetRoute() *Route { if m != nil { return m.Route } @@ -231,7 +334,7 @@ func (m *ListRequest) Reset() { *m = ListRequest{} } func (m *ListRequest) String() string { return proto.CompactTextString(m) } func (*ListRequest) ProtoMessage() {} func (*ListRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{4} + return fileDescriptor_367072455c71aedc, []int{5} } func (m *ListRequest) XXX_Unmarshal(b []byte) error { @@ -264,7 +367,7 @@ func (m *ListResponse) Reset() { *m = ListResponse{} } func (m *ListResponse) String() string { return proto.CompactTextString(m) } func (*ListResponse) ProtoMessage() {} func (*ListResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{5} + return fileDescriptor_367072455c71aedc, []int{6} } func (m *ListResponse) XXX_Unmarshal(b []byte) error { @@ -305,7 +408,7 @@ func (m *Query) Reset() { *m = Query{} } func (m *Query) String() string { return proto.CompactTextString(m) } func (*Query) ProtoMessage() {} func (*Query) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{6} + return fileDescriptor_367072455c71aedc, []int{7} } func (m *Query) XXX_Unmarshal(b []byte) error { @@ -356,7 +459,7 @@ func (m *Route) Reset() { *m = Route{} } func (m *Route) String() string { return proto.CompactTextString(m) } func (*Route) ProtoMessage() {} func (*Route) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{7} + return fileDescriptor_367072455c71aedc, []int{8} } func (m *Route) XXX_Unmarshal(b []byte) error { @@ -420,11 +523,13 @@ func (m *Route) GetMetric() int64 { } func init() { + proto.RegisterEnum("AdvertType", AdvertType_name, AdvertType_value) proto.RegisterEnum("EventType", EventType_name, EventType_value) proto.RegisterType((*LookupRequest)(nil), "LookupRequest") proto.RegisterType((*LookupResponse)(nil), "LookupResponse") proto.RegisterType((*WatchRequest)(nil), "WatchRequest") - proto.RegisterType((*TableEvent)(nil), "TableEvent") + proto.RegisterType((*Advert)(nil), "Advert") + proto.RegisterType((*Event)(nil), "Event") proto.RegisterType((*ListRequest)(nil), "ListRequest") proto.RegisterType((*ListResponse)(nil), "ListResponse") proto.RegisterType((*Query)(nil), "Query") @@ -434,30 +539,34 @@ func init() { func init() { proto.RegisterFile("router.proto", fileDescriptor_367072455c71aedc) } var fileDescriptor_367072455c71aedc = []byte{ - // 388 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0xc1, 0x8e, 0xd3, 0x30, - 0x10, 0x8d, 0xb7, 0x89, 0x51, 0xa6, 0x49, 0x58, 0xf9, 0x80, 0xac, 0x6a, 0xb5, 0x2a, 0x96, 0x10, - 0x2b, 0x10, 0x66, 0x55, 0x3e, 0x01, 0xb8, 0xed, 0x05, 0x6b, 0x11, 0xe7, 0x6c, 0x3b, 0x62, 0xa3, - 0xb6, 0x49, 0xd6, 0x76, 0xb6, 0xca, 0x07, 0xf0, 0x15, 0xfc, 0x2c, 0xf2, 0x24, 0xa1, 0xed, 0x01, - 0x89, 0xdb, 0xbc, 0x37, 0xb6, 0xe7, 0x79, 0xde, 0x83, 0xcc, 0x36, 0x9d, 0x47, 0xab, 0x5b, 0xdb, - 0xf8, 0x46, 0x7d, 0x80, 0xfc, 0xae, 0x69, 0xb6, 0x5d, 0x6b, 0xf0, 0xa9, 0x43, 0xe7, 0xc5, 0x15, - 0x24, 0x4f, 0x1d, 0xda, 0x5e, 0xb2, 0x25, 0xbb, 0x99, 0xaf, 0xb8, 0xfe, 0x16, 0x90, 0x19, 0x48, - 0x75, 0x0b, 0xc5, 0x74, 0xdc, 0xb5, 0x4d, 0xed, 0x50, 0x5c, 0x03, 0xa7, 0x07, 0x9d, 0x64, 0xcb, - 0x19, 0x5d, 0x30, 0x01, 0x9a, 0x91, 0x55, 0x05, 0x64, 0x3f, 0x4a, 0xbf, 0x7e, 0x1c, 0xdf, 0x57, - 0x8f, 0x00, 0xf7, 0xe5, 0xc3, 0x0e, 0xbf, 0x3e, 0x63, 0xed, 0xc5, 0x35, 0xc4, 0xbe, 0x6f, 0x91, - 0x86, 0x15, 0x2b, 0xd0, 0xc4, 0xde, 0xf7, 0x2d, 0x1a, 0xe2, 0xc5, 0x15, 0xa4, 0xbe, 0xda, 0xa3, - 0xf3, 0xe5, 0xbe, 0x95, 0x17, 0x4b, 0x76, 0x33, 0x33, 0x47, 0x22, 0x68, 0xa5, 0x29, 0x72, 0x36, - 0x6a, 0x1d, 0x46, 0x0f, 0xa4, 0xca, 0x61, 0x7e, 0x57, 0x39, 0x3f, 0x0d, 0xd6, 0x90, 0x0d, 0xf0, - 0x3f, 0x85, 0xbf, 0x86, 0x84, 0xbe, 0x2e, 0x24, 0xbc, 0x70, 0x68, 0x9f, 0xab, 0xf5, 0x20, 0x33, - 0x35, 0x13, 0x54, 0xbf, 0x19, 0x24, 0x74, 0xe9, 0xdf, 0x67, 0x42, 0xa7, 0xdc, 0x6c, 0x2c, 0x3a, - 0x47, 0xfa, 0x53, 0x33, 0xc1, 0xd0, 0xf9, 0x59, 0x7a, 0x3c, 0x94, 0x3d, 0xe9, 0x4f, 0xcd, 0x04, - 0x43, 0xa7, 0x46, 0x7f, 0x68, 0xec, 0x56, 0xc6, 0x43, 0x67, 0x84, 0x42, 0x40, 0xbc, 0xab, 0xea, - 0xad, 0x4c, 0x88, 0xa6, 0x5a, 0xbc, 0x02, 0xbe, 0x47, 0x6f, 0xab, 0xb5, 0xe4, 0xb4, 0xa0, 0x11, - 0xbd, 0xfb, 0x08, 0xe9, 0xdf, 0x75, 0x0a, 0x00, 0xfe, 0xd9, 0x62, 0xe9, 0xf1, 0x32, 0x0a, 0xf5, - 0x17, 0xdc, 0xa1, 0xc7, 0x4b, 0x16, 0xea, 0xef, 0xed, 0x26, 0xf0, 0x17, 0xab, 0x5f, 0x0c, 0x38, - 0x7d, 0xc7, 0x8a, 0xb7, 0x90, 0x90, 0x6b, 0x22, 0xd7, 0xa7, 0xee, 0x2d, 0xe6, 0xfa, 0x68, 0x9e, - 0x8a, 0x6e, 0x99, 0x78, 0x0f, 0x7c, 0x08, 0x84, 0x28, 0xf4, 0x59, 0x90, 0x16, 0x2f, 0xf5, 0x79, - 0x52, 0x54, 0x24, 0xde, 0x40, 0x1c, 0x2c, 0x10, 0x99, 0x3e, 0x31, 0x66, 0x91, 0xeb, 0x53, 0x5f, - 0x54, 0xf4, 0xc0, 0x29, 0x9a, 0x9f, 0xfe, 0x04, 0x00, 0x00, 0xff, 0xff, 0x67, 0x70, 0xf8, 0xfa, - 0xaa, 0x02, 0x00, 0x00, + // 461 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0x41, 0x8f, 0xd3, 0x4c, + 0x0c, 0xcd, 0xa4, 0x4d, 0x3e, 0xc5, 0x4d, 0xf3, 0x55, 0x3e, 0xa0, 0xa8, 0xaa, 0x96, 0x32, 0x12, + 0x52, 0xb5, 0x88, 0xb0, 0x2a, 0xbf, 0x60, 0x05, 0xdc, 0xf6, 0xc2, 0x08, 0xc4, 0x39, 0x24, 0x16, + 0x44, 0x6d, 0x93, 0xec, 0xcc, 0xa4, 0xab, 0xde, 0xb8, 0xf2, 0x1b, 0xf8, 0xb3, 0x68, 0x9c, 0x84, + 0x76, 0x91, 0x56, 0xe2, 0xe6, 0xf7, 0x6c, 0xc7, 0x9e, 0xf7, 0x1c, 0x88, 0x75, 0xd3, 0x59, 0xd2, + 0x59, 0xab, 0x1b, 0xdb, 0xc8, 0xd7, 0x30, 0xbf, 0x6b, 0x9a, 0x5d, 0xd7, 0x2a, 0xba, 0xef, 0xc8, + 0x58, 0x5c, 0x41, 0x70, 0xdf, 0x91, 0x3e, 0xa5, 0x62, 0x2d, 0x36, 0xb3, 0x6d, 0x98, 0x7d, 0x74, + 0x48, 0xf5, 0xa4, 0xbc, 0x81, 0x64, 0x2c, 0x37, 0x6d, 0x53, 0x1b, 0xc2, 0x2b, 0x08, 0xf9, 0x83, + 0x26, 0x15, 0xeb, 0x09, 0x37, 0x28, 0x07, 0xd5, 0xc0, 0xca, 0x04, 0xe2, 0x2f, 0xb9, 0x2d, 0xbe, + 0x0f, 0xdf, 0x97, 0x3f, 0x05, 0x84, 0xb7, 0xe5, 0x91, 0xb4, 0xc5, 0x04, 0xfc, 0xaa, 0xe4, 0x39, + 0x91, 0xf2, 0xab, 0x12, 0x9f, 0xc3, 0xd4, 0x9e, 0x5a, 0x4a, 0xfd, 0xb5, 0xd8, 0x24, 0xdb, 0x59, + 0xd6, 0x97, 0x7d, 0x3a, 0xb5, 0xa4, 0x38, 0x81, 0x2b, 0x88, 0x6c, 0x75, 0x20, 0x63, 0xf3, 0x43, + 0x9b, 0x4e, 0xd6, 0x62, 0x33, 0x51, 0x67, 0x02, 0x17, 0x30, 0xb1, 0x76, 0x9f, 0x4e, 0x99, 0x77, + 0xa1, 0xdb, 0x8d, 0x8e, 0x54, 0x5b, 0x93, 0x06, 0xc3, 0x6e, 0x1f, 0x1c, 0x54, 0x03, 0x2b, 0x0b, + 0x08, 0x98, 0xc0, 0xab, 0x61, 0xb2, 0xe0, 0xc9, 0xd0, 0x97, 0x3d, 0x35, 0xd8, 0xff, 0x7b, 0xf0, + 0x0a, 0x02, 0x7e, 0x2c, 0xaf, 0x74, 0x56, 0xa0, 0x27, 0xe5, 0x1c, 0x66, 0x77, 0x95, 0xb1, 0xe3, + 0xfb, 0x33, 0x88, 0x7b, 0xf8, 0x8f, 0xfa, 0xbd, 0x80, 0x80, 0x1d, 0xc0, 0x14, 0xfe, 0x33, 0xa4, + 0x8f, 0x55, 0x41, 0x83, 0x64, 0x23, 0x94, 0xbf, 0x04, 0x04, 0xdc, 0xf4, 0x74, 0x8d, 0xcb, 0xe4, + 0x65, 0xa9, 0xc9, 0x18, 0xde, 0x3f, 0x52, 0x23, 0x74, 0x99, 0x6f, 0xb9, 0xa5, 0x87, 0xfc, 0xc4, + 0xfb, 0x47, 0x6a, 0x84, 0x2e, 0x53, 0x93, 0x7d, 0x68, 0xf4, 0x8e, 0x45, 0x8d, 0xd4, 0x08, 0x11, + 0x61, 0xba, 0xaf, 0xea, 0x5d, 0x1a, 0x30, 0xcd, 0x31, 0x3e, 0x83, 0xf0, 0x40, 0x56, 0x57, 0x45, + 0x1a, 0xb2, 0x40, 0x03, 0xba, 0xde, 0x02, 0x9c, 0x8d, 0x44, 0x84, 0xa4, 0x47, 0xb7, 0x75, 0xdd, + 0x74, 0x75, 0x41, 0x0b, 0x0f, 0x17, 0x10, 0xf7, 0xdc, 0xe7, 0xb6, 0xcc, 0x2d, 0x2d, 0xc4, 0xf5, + 0x1b, 0x88, 0xfe, 0x58, 0x80, 0x00, 0xe1, 0x3b, 0x4d, 0x2e, 0xe1, 0xb9, 0xf8, 0x3d, 0xed, 0xc9, + 0x15, 0xb9, 0x78, 0x68, 0xf0, 0xb7, 0x3f, 0x04, 0x84, 0x2c, 0x81, 0x46, 0x09, 0x01, 0x1f, 0x1c, + 0xce, 0xb3, 0xcb, 0xc3, 0x5b, 0x0e, 0xe6, 0x4b, 0xef, 0x46, 0xe0, 0x2b, 0x08, 0xfb, 0x33, 0xc6, + 0x24, 0x7b, 0x74, 0xfe, 0xcb, 0xff, 0xb3, 0xc7, 0xf7, 0x2d, 0x3d, 0x7c, 0x09, 0x53, 0xe7, 0x18, + 0xc6, 0xd9, 0x85, 0x8f, 0xcb, 0x79, 0x76, 0x69, 0xa3, 0xf4, 0xbe, 0x86, 0xfc, 0x43, 0xbd, 0xfd, + 0x1d, 0x00, 0x00, 0xff, 0xff, 0x5e, 0x52, 0x2f, 0xa0, 0x60, 0x03, 0x00, 0x00, } diff --git a/network/router/proto/router.proto b/network/router/proto/router.proto index 434e0dc5..55eacf71 100644 --- a/network/router/proto/router.proto +++ b/network/router/proto/router.proto @@ -2,7 +2,7 @@ syntax = "proto3"; // Router service is used by the proxy to lookup routes service Router { - rpc Watch(WatchRequest) returns (stream TableEvent) {}; + rpc Watch(WatchRequest) returns (stream Event) {}; rpc Lookup(LookupRequest) returns (LookupResponse) {}; rpc List(ListRequest) returns (ListResponse) {}; } @@ -20,16 +20,36 @@ message LookupResponse { // WatchRequest is made to Watch Router message WatchRequest {} -// EventType is TableEvent type +// AdvertType defines the type of advert +enum AdvertType { + AdvertAnnounce = 0; + AdvertUpdate = 1; +} + +// Advert is router advertsement streamed by Watch +message Advert { + // id of the advertising router + string id = 1; + // type of advertisement + AdvertType type = 2; + // unix timestamp of the advertisement + int64 timestamp = 3; + // TTL of the Advert + int64 ttl = 4; + // events is a list of advertised events + repeated Event events = 5; +} + +// EventType defines the type of event enum EventType { Create = 0; Delete = 1; Update = 2; } -// TableEvent is streamed by WatchRequest -message TableEvent { - // time of table event +// Event is routing table event +message Event { + // type of event EventType type = 1; // unix timestamp of event int64 timestamp = 2; From 6b984136f7ba9aa5fcf61beac38b36a4ecbd9e78 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 11 Jul 2019 21:40:52 +0100 Subject: [PATCH 183/287] update go mod --- go.mod | 8 ++++---- go.sum | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 8a7e1b6b..1872558f 100644 --- a/go.mod +++ b/go.mod @@ -45,8 +45,7 @@ require ( github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect github.com/kr/pty v1.1.8 // indirect github.com/leodido/go-urn v1.1.0 // indirect - github.com/lucas-clemente/quic-go v0.11.2 - github.com/marten-seemann/qtls v0.3.1 // indirect + github.com/lucas-clemente/quic-go v0.7.1-0.20190710050138-1441923ab031 github.com/mattn/go-colorable v0.1.2 // indirect github.com/mattn/go-runewidth v0.0.4 // indirect github.com/micro/cli v0.2.0 @@ -55,6 +54,7 @@ require ( github.com/mitchellh/gox v1.0.1 // indirect github.com/mitchellh/hashstructure v1.0.0 github.com/nats-io/nats.go v1.8.1 + github.com/nats-io/nkeys v0.1.0 // indirect github.com/nlopes/slack v0.5.0 github.com/olekukonko/tablewriter v0.0.1 github.com/onsi/ginkgo v1.8.0 // indirect @@ -69,11 +69,11 @@ require ( golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 golang.org/x/exp v0.0.0-20190627132806-fd42eb6b336f // indirect golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9 // indirect - golang.org/x/mobile v0.0.0-20190607214518-6fa95d984e88 // indirect + golang.org/x/mobile v0.0.0-20190711165009-e47acb2ca7f9 // indirect golang.org/x/mod v0.1.0 // indirect golang.org/x/net v0.0.0-20190628185345-da137c7871d7 golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 // indirect - golang.org/x/tools v0.0.0-20190710184609-286818132824 // indirect + golang.org/x/tools v0.0.0-20190711191110-9a621aea19f8 // indirect google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532 // indirect google.golang.org/grpc v1.22.0 gopkg.in/go-playground/validator.v9 v9.29.0 diff --git a/go.sum b/go.sum index 605b53f5..8f5526ee 100644 --- a/go.sum +++ b/go.sum @@ -193,8 +193,11 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= +github.com/lucas-clemente/quic-go v0.7.1-0.20190710050138-1441923ab031 h1:wjcGvgllMOQw8wNYFH6acq/KlTAdjKMSo1EUYybHXto= +github.com/lucas-clemente/quic-go v0.7.1-0.20190710050138-1441923ab031/go.mod h1:lb5aAxL68VvhZ00e7yYuQVK/9FLggtYy4qo7oI5qzqA= github.com/lucas-clemente/quic-go v0.11.2 h1:Mop0ac3zALaBR3wGs6j8OYe/tcFvFsxTUFMkE/7yUOI= github.com/lucas-clemente/quic-go v0.11.2/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw= +github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI= github.com/marten-seemann/qtls v0.2.3 h1:0yWJ43C62LsZt08vuQJDK1uC1czUc3FJeCLPoNAI4vA= github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= github.com/marten-seemann/qtls v0.2.4 h1:mCJ6i1jAqcsm9XODrSGvXECodoAb1STta+TkxJCwCnE= @@ -243,6 +246,8 @@ github.com/nats-io/nats.go v1.8.1 h1:6lF/f1/NN6kzUDBz6pyvQDEXO39jqXcWRLu/tKjtOUQ github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= github.com/nats-io/nkeys v0.0.2 h1:+qM7QpgXnvDDixitZtQUBDY9w/s9mu1ghS+JIbsrx6M= github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= +github.com/nats-io/nkeys v0.1.0 h1:qMd4+pRHgdr1nAClu+2h/2a5F2TmKcCzjCDazVgRoX4= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nlopes/slack v0.5.0 h1:NbIae8Kd0NpqaEI3iUrsuS0KbcEDhzhc939jLW5fNm0= @@ -340,6 +345,7 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190607214518-6fa95d984e88/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mobile v0.0.0-20190711165009-e47acb2ca7f9/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -351,6 +357,7 @@ golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/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-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -420,6 +427,7 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190620191750-1fa568393b23/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624190245-7f2218787638/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190710184609-286818132824/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190711191110-9a621aea19f8/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= From 70d811c47a39fe2f13c0eb758756e2c0f450d53d Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 11 Jul 2019 21:46:27 +0100 Subject: [PATCH 184/287] don't use quic in the test --- network/tunnel/tunnel_test.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/network/tunnel/tunnel_test.go b/network/tunnel/tunnel_test.go index 6e171375..99146c3f 100644 --- a/network/tunnel/tunnel_test.go +++ b/network/tunnel/tunnel_test.go @@ -5,7 +5,6 @@ import ( "github.com/micro/go-micro/network/link" "github.com/micro/go-micro/transport" - "github.com/micro/go-micro/transport/quic" ) // testAccept will accept connections on the transport, create a new link and tunnel on top @@ -61,7 +60,6 @@ func testSend(t *testing.T, addr string) { // create a new link l := link.NewLink( link.Address(addr), - link.Transport(quic.NewTransport()), ) // connect the link, this includes dialing @@ -95,7 +93,7 @@ func testSend(t *testing.T, addr string) { func TestTunnel(t *testing.T) { // create a new listener - tr := quic.NewTransport() + tr := transport.NewTransport() l, err := tr.Listen(":0") if err != nil { t.Fatal(err) From a72e1185da90086935a9cc86703eddb06257aa61 Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Fri, 12 Jul 2019 12:11:08 +0300 Subject: [PATCH 185/287] memory transport: use write mutex lock when close Signed-off-by: Vasiliy Tolstov --- transport/memory/memory.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/transport/memory/memory.go b/transport/memory/memory.go index 274e98c9..b1f4f071 100644 --- a/transport/memory/memory.go +++ b/transport/memory/memory.go @@ -84,8 +84,8 @@ func (ms *memorySocket) Send(m *transport.Message) error { } func (ms *memorySocket) Close() error { - ms.RLock() - defer ms.RUnlock() + ms.Lock() + defer ms.Unlock() select { case <-ms.exit: return nil From 008749b2b0484e778c6dc7cb47a5fc927a2f0e87 Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Fri, 12 Jul 2019 23:47:37 +0300 Subject: [PATCH 186/287] broker memory: fix issue with publish/subscribe mutex locking have errors, so when two service (one pub, other sub) try to use this broker it waits for mutex release and nothing works Signed-off-by: Vasiliy Tolstov --- broker/memory/memory.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/broker/memory/memory.go b/broker/memory/memory.go index fb077faa..5ace9581 100644 --- a/broker/memory/memory.go +++ b/broker/memory/memory.go @@ -72,14 +72,14 @@ func (m *memoryBroker) Init(opts ...broker.Option) error { } func (m *memoryBroker) Publish(topic string, message *broker.Message, opts ...broker.PublishOption) error { - m.Lock() - defer m.Unlock() - + m.RLock() if !m.connected { + m.RUnlock() return errors.New("not connected") } subs, ok := m.Subscribers[topic] + m.RUnlock() if !ok { return nil } @@ -99,12 +99,12 @@ func (m *memoryBroker) Publish(topic string, message *broker.Message, opts ...br } func (m *memoryBroker) Subscribe(topic string, handler broker.Handler, opts ...broker.SubscribeOption) (broker.Subscriber, error) { - m.Lock() - defer m.Unlock() - + m.RLock() if !m.connected { + m.RUnlock() return nil, errors.New("not connected") } + m.RUnlock() var options broker.SubscribeOptions for _, o := range opts { @@ -119,7 +119,9 @@ func (m *memoryBroker) Subscribe(topic string, handler broker.Handler, opts ...b opts: options, } + m.Lock() m.Subscribers[topic] = append(m.Subscribers[topic], sub) + m.Unlock() go func() { <-sub.exit From 81d2259fac2158a56388c2a21863dc4c06c82cdf Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Sat, 13 Jul 2019 23:47:57 +0300 Subject: [PATCH 187/287] transport memory: fix races * fix race with rand.Intn for non default source * increase random interval to avoid issues when many services running on the host Signed-off-by: Vasiliy Tolstov --- transport/memory/memory.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/transport/memory/memory.go b/transport/memory/memory.go index b1f4f071..0d637f05 100644 --- a/transport/memory/memory.go +++ b/transport/memory/memory.go @@ -12,10 +12,6 @@ import ( "github.com/micro/go-micro/transport" ) -var ( - r = rand.New(rand.NewSource(time.Now().UnixNano())) -) - type memorySocket struct { recv chan *transport.Message send chan *transport.Message @@ -178,7 +174,7 @@ func (m *memoryTransport) Listen(addr string, opts ...transport.ListenOption) (t // if zero port then randomly assign one if len(parts) > 1 && parts[len(parts)-1] == "0" { - i := r.Intn(10000) + i := rand.Intn(20000) // set addr with port addr = fmt.Sprintf("%s:%d", parts[:len(parts)-1], 10000+i) } @@ -215,6 +211,7 @@ func (m *memoryTransport) String() string { } func NewTransport(opts ...transport.Option) transport.Transport { + rand.Seed(time.Now().UnixNano()) var options transport.Options for _, o := range opts { o(&options) From aa79c41fc5fb78c004cbe3e9e5b449ff9ae6318e Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Sun, 14 Jul 2019 18:34:32 -0700 Subject: [PATCH 188/287] update tunnel comment --- network/tunnel/tunnel.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/network/tunnel/tunnel.go b/network/tunnel/tunnel.go index 021aeeae..6d879521 100644 --- a/network/tunnel/tunnel.go +++ b/network/tunnel/tunnel.go @@ -1,4 +1,4 @@ -// Package tunnel provides a network tunnel ontop of a link +// Package tunnel provides gre network tunnelling package tunnel import ( @@ -6,7 +6,7 @@ import ( "github.com/micro/go-micro/transport" ) -// Tunnel creates a network tunnel on top of a link. +// Tunnel creates a gre network tunnel on top of a link. // It establishes multiple streams using the Micro-Tunnel-Id header // and Micro-Tunnel-Session header. The tunnel id is a hash of // the address being requested. From 609934ce99eec9dcece2f89b812b57d4398ca5f9 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Mon, 15 Jul 2019 11:13:58 +0100 Subject: [PATCH 189/287] Preallocate slices; avoide append() reallocations when copying data --- registry/util.go | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/registry/util.go b/registry/util.go index 5eb51a62..414c6ff3 100644 --- a/registry/util.go +++ b/registry/util.go @@ -51,33 +51,32 @@ func delNodes(old, del []*Node) []*Node { // Copy makes a copy of services func Copy(current []*Service) []*Service { - var services []*Service - - for _, service := range current { + services := make([]*Service, len(current)) + for i, service := range current { // copy service s := new(Service) *s = *service // copy nodes - var nodes []*Node - for _, node := range service.Nodes { + nodes := make([]*Node, len(service.Nodes)) + for j, node := range service.Nodes { n := new(Node) *n = *node - nodes = append(nodes, n) + nodes[j] = n } s.Nodes = nodes // copy endpoints - var eps []*Endpoint - for _, ep := range service.Endpoints { + eps := make([]*Endpoint, len(service.Endpoints)) + for j, ep := range service.Endpoints { e := new(Endpoint) *e = *ep - eps = append(eps, e) + eps[j] = e } s.Endpoints = eps // append service - services = append(services, s) + services[i] = s } return services From c108188d65672d1784e07fb90d3320d754596653 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Mon, 15 Jul 2019 14:47:33 +0100 Subject: [PATCH 190/287] Preallocate nodes slice in addNodes before populating it --- registry/util.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/registry/util.go b/registry/util.go index 414c6ff3..5cd04eb9 100644 --- a/registry/util.go +++ b/registry/util.go @@ -1,12 +1,11 @@ package registry func addNodes(old, neu []*Node) []*Node { - var nodes []*Node - + nodes := make([]*Node, len(neu)) // add all new nodes - for _, n := range neu { + for i, n := range neu { node := *n - nodes = append(nodes, &node) + nodes[i] = &node } // look at old nodes From 92495d22dbba7715bb818cd9cd40f393f2b34f21 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Tue, 16 Jul 2019 19:00:25 +0100 Subject: [PATCH 191/287] Fixes advert dampening behaviour. This commit adds the following changes: * advert now stores a list of route events as opposed to just last one * attempt to dedup route events before appending them to advert * have max suppress threshold for long time suppressed adverts * decaying events on every advert tick Originally we werent decaying penalties on every advert tick. That was incorrect behaviour. Furthermore some events would end up being accumulated potentially causing memory leaks. We were also overriding the last received router event which was causing incorrect sequence of events to be applied when received by a receiver: Create, Delete would be "squashed" into Delete only which would be nonsensical since the Create event would never be delivered hence we would be deleting nonexistent routes. Not Decaying the events on every tick or not having the max suppression threshold could lead to DoS by growing the router memory infinitely. --- network/router/default.go | 155 +++++++++++++++++++++----------------- 1 file changed, 85 insertions(+), 70 deletions(-) diff --git a/network/router/default.go b/network/router/default.go index 5b13b2ae..58050fdb 100644 --- a/network/router/default.go +++ b/network/router/default.go @@ -18,17 +18,24 @@ const ( // AdvertiseTableTick is time interval in which router advertises all routes found in routing table AdvertiseTableTick = 1 * time.Minute // AdvertSuppress is advert suppression threshold - AdvertSuppress = 2000 + AdvertSuppress = 2000.0 // AdvertRecover is advert recovery threshold - AdvertRecover = 750 + AdvertRecover = 750.0 // DefaultAdvertTTL is default advertisement TTL DefaultAdvertTTL = 1 * time.Minute - // PenaltyDecay is the penalty decay - PenaltyDecay = 1.15 - // Delete penalises route addition and deletion - Delete = 1000 + // DeletePenalty penalises route deletion + DeletePenalty = 1000.0 // UpdatePenalty penalises route updates - UpdatePenalty = 500 + UpdatePenalty = 500.0 + // PenaltyHalfLife is the time the advert penalty decays to half its value + PenaltyHalfLife = 2.0 + // MaxSuppressTime defines time after which the suppressed advert is deleted + MaxSuppressTime = 5 * time.Minute +) + +var ( + // PenaltyDecay is a coefficient which controls the speed the advert penalty decays + PenaltyDecay = math.Log(2) / PenaltyHalfLife ) // router provides default router implementation @@ -153,9 +160,9 @@ func (r *router) manageRegistryRoutes(reg registry.Registry, action string) erro return nil } -// watchServices watches services in given registry and updates the routing table accordingly. -// It returns error if the service registry watcher stops or if the routing table can't be updated. -func (r *router) watchServices(w registry.Watcher) error { +// watchRegistry watches sregistry and updates the routing table. +// It returns error if either the registry watcher fails with error or if the routing table update fails. +func (r *router) watchRegistry(w registry.Watcher) error { // wait in the background for the router to stop // when the router stops, stop the watcher and exit r.wg.Add(1) @@ -279,30 +286,17 @@ func (r *router) advertiseTable() error { return nil } -// isFlapping detects if the event is flapping based on the current and previous event status. -func isFlapping(curr, prev *table.Event) bool { - if curr.Type == table.Update && prev.Type == table.Update { - return true - } - - if curr.Type == table.Create && prev.Type == table.Delete || curr.Type == table.Delete && prev.Type == table.Create { - return true - } - - return false -} - -// advertEvent is a table event enriched with advertisement data -type advertEvent struct { - *table.Event - // timestamp marks the time the event has been received - timestamp time.Time - // penalty is current event penalty +// routeAdvert contains a list of route events to be advertised +type routeAdvert struct { + events []*table.Event + // lastUpdate records the time of the last advert update + lastUpdate time.Time + // penalty is current advert penalty penalty float64 - // isSuppressed flags if the event should be considered for flap detection + // isSuppressed flags the advert suppression isSuppressed bool - // isFlapping marks the event as flapping event - isFlapping bool + // suppressTime records the time interval the advert has been suppressed for + suppressTime time.Time } // processEvents processes routing table events. @@ -310,22 +304,44 @@ type advertEvent struct { func (r *router) processEvents() error { // ticker to periodically scan event for advertising ticker := time.NewTicker(AdvertiseEventsTick) - // eventMap is a map of advert events - eventMap := make(map[uint64]*advertEvent) + // advertMap is a map of advert events + advertMap := make(map[uint64]*routeAdvert) for { select { case <-ticker.C: var events []*table.Event // collect all events which are not flapping - // TODO: decay the events and update suppression - for key, event := range eventMap { - if !event.isFlapping && !event.isSuppressed { - e := new(table.Event) - *e = *event.Event - events = append(events, e) - // this deletes the advertised event from the map - delete(eventMap, key) + for key, advert := range advertMap { + // decay the event penalty + delta := time.Since(advert.lastUpdate).Seconds() + advert.penalty = advert.penalty * math.Exp(-delta*PenaltyDecay) + + // suppress/recover the event based on its penalty level + switch { + case advert.penalty > AdvertSuppress && !advert.isSuppressed: + advert.isSuppressed = true + advert.suppressTime = time.Now() + case advert.penalty < AdvertRecover && advert.isSuppressed: + advert.isSuppressed = false + } + + // max suppression time threshold has been reached, delete the advert + if advert.isSuppressed { + if time.Since(advert.suppressTime) > MaxSuppressTime { + delete(advertMap, key) + continue + } + } + + if !advert.isSuppressed { + for _, event := range advert.events { + e := new(table.Event) + *e = *event + events = append(events, e) + // delete the advert from the advertMap + delete(advertMap, key) + } } } @@ -335,8 +351,6 @@ func (r *router) processEvents() error { go r.advertiseEvents(Update, events) } case e := <-r.eventChan: - // event timestamp - now := time.Now() // if event is nil, continue if e == nil { continue @@ -348,36 +362,36 @@ func (r *router) processEvents() error { case table.Update: penalty = UpdatePenalty case table.Delete: - penalty = Delete + penalty = DeletePenalty } - // we use route hash as eventMap key + + // check if we have already registered the route + // we use the route hash as advertMap key hash := e.Route.Hash() - event, ok := eventMap[hash] + advert, ok := advertMap[hash] if !ok { - event = &advertEvent{ - Event: e, - penalty: penalty, - timestamp: time.Now(), + events := []*table.Event{e} + advert = &routeAdvert{ + events: events, + penalty: penalty, + lastUpdate: time.Now(), } - eventMap[hash] = event + advertMap[hash] = advert continue } - // update penalty for existing event: decay existing and add new penalty - delta := time.Since(event.timestamp).Seconds() - event.penalty = event.penalty*math.Exp(-delta) + penalty - event.timestamp = now - // suppress or recover the event based on its current penalty - if !event.isSuppressed && event.penalty > AdvertSuppress { - event.isSuppressed = true - } else if event.penalty < AdvertRecover { - event.isSuppressed = false - } - // if not suppressed decide if if its flapping - if !event.isSuppressed { - // detect if its flapping by comparing current and previous event - event.isFlapping = isFlapping(e, event.Event) + // attempt to squash last two events if possible + lastEvent := advert.events[len(advert.events)-1] + if lastEvent.Type == e.Type { + advert.events[len(advert.events)-1] = e + } else { + advert.events = append(advert.events, e) } + + // update event penalty and recorded timestamp + advert.lastUpdate = time.Now() + advert.penalty += penalty + case <-r.exit: // first wait for the advertiser to finish r.advertWg.Wait() @@ -484,8 +498,9 @@ func (r *router) Advertise() (<-chan *Advert, error) { if err != nil { return nil, fmt.Errorf("failed creating routing table watcher: %v", err) } - // service registry watcher - svcWatcher, err := r.opts.Registry.Watch() + + // registry watcher + regWatcher, err := r.opts.Registry.Watch() if err != nil { return nil, fmt.Errorf("failed creating service registry watcher: %v", err) } @@ -497,7 +512,7 @@ func (r *router) Advertise() (<-chan *Advert, error) { go func() { defer r.wg.Done() // watch local registry and register routes in routine table - errChan <- r.watchServices(svcWatcher) + errChan <- r.watchRegistry(regWatcher) }() r.wg.Add(1) @@ -594,5 +609,5 @@ func (r *router) Stop() error { // String prints debugging information about router func (r *router) String() string { - return "router" + return "default router" } From a3bddf583920d873a3a46acba164071221dbfcc7 Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Wed, 17 Jul 2019 00:19:59 +0300 Subject: [PATCH 192/287] changes to minimize allocations and provide useful info Signed-off-by: Vasiliy Tolstov --- client/rpc_client.go | 8 ++++---- server/rpc_server.go | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/client/rpc_client.go b/client/rpc_client.go index ea63041e..39d044d9 100644 --- a/client/rpc_client.go +++ b/client/rpc_client.go @@ -280,16 +280,16 @@ func (r *rpcClient) next(request Request, opts CallOptions) (selector.Next, erro // return remote address if len(opts.Address) > 0 { - var nodes []*registry.Node + nodes := make([]*registry.Node, len(opts.Address)) - for _, address := range opts.Address { - nodes = append(nodes, ®istry.Node{ + for i, address := range opts.Address { + nodes[i] = ®istry.Node{ Address: address, // Set the protocol Metadata: map[string]string{ "protocol": "mucp", }, - }) + } } // crude return method diff --git a/server/rpc_server.go b/server/rpc_server.go index 696151e3..533def1e 100644 --- a/server/rpc_server.go +++ b/server/rpc_server.go @@ -405,6 +405,7 @@ func (s *rpcServer) Register() error { if err != nil { return err } + log.Logf("Subscribing %s to topic: %s", node.Id, sub.Topic()) s.subscribers[sb] = []broker.Subscriber{sub} } @@ -465,7 +466,7 @@ func (s *rpcServer) Deregister() error { for sb, subs := range s.subscribers { for _, sub := range subs { - log.Logf("Unsubscribing from topic: %s", sub.Topic()) + log.Logf("Unsubscribing %s from topic: %s", node.Id, sub.Topic()) sub.Unsubscribe() } s.subscribers[sb] = nil From 280314667382b9c3395db9af3e2901c7369d84e1 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Wed, 17 Jul 2019 00:06:11 +0100 Subject: [PATCH 193/287] Renaming rampage Addressing the comments in #591, router.String() now returns "default" Furthermore, a tonne of other renaming has been included in this commit as a result of running go vet ./... inside the router package. --- network/router/default.go | 10 ++-------- network/router/table/default.go | 20 ++++++++++---------- network/router/table/default_test.go | 12 ++++++------ network/router/table/table.go | 6 +++--- 4 files changed, 21 insertions(+), 27 deletions(-) diff --git a/network/router/default.go b/network/router/default.go index 58050fdb..8af78ef3 100644 --- a/network/router/default.go +++ b/network/router/default.go @@ -160,7 +160,7 @@ func (r *router) manageRegistryRoutes(reg registry.Registry, action string) erro return nil } -// watchRegistry watches sregistry and updates the routing table. +// watchRegistry watches registry and updates routing table based on the received events. // It returns error if either the registry watcher fails with error or if the routing table update fails. func (r *router) watchRegistry(w registry.Watcher) error { // wait in the background for the router to stop @@ -282,8 +282,6 @@ func (r *router) advertiseTable() error { return nil } } - - return nil } // routeAdvert contains a list of route events to be advertised @@ -400,10 +398,6 @@ func (r *router) processEvents() error { return nil } } - - // we probably never reach this code path - - return nil } // watchErrors watches router errors and takes appropriate actions @@ -609,5 +603,5 @@ func (r *router) Stop() error { // String prints debugging information about router func (r *router) String() string { - return "default router" + return "default" } diff --git a/network/router/table/default.go b/network/router/table/default.go index 09aba529..bce75935 100644 --- a/network/router/table/default.go +++ b/network/router/table/default.go @@ -7,14 +7,14 @@ import ( "github.com/google/uuid" ) -// TableOptions specify routing table options +// Options specify routing table options // TODO: table options TBD in the future -type TableOptions struct{} +type Options struct{} // table is an in memory routing table type table struct { // opts are table options - opts TableOptions + opts Options // m stores routing table map m map[string]map[uint64]Route // w is a list of table watchers @@ -23,9 +23,9 @@ type table struct { } // newTable creates a new routing table and returns it -func newTable(opts ...TableOption) Table { +func newTable(opts ...Option) Table { // default options - var options TableOptions + var options Options // apply requested options for _, o := range opts { @@ -40,7 +40,7 @@ func newTable(opts ...TableOption) Table { } // Init initializes routing table with options -func (t *table) Init(opts ...TableOption) error { +func (t *table) Init(opts ...Option) error { for _, o := range opts { o(&t.opts) } @@ -48,7 +48,7 @@ func (t *table) Init(opts ...TableOption) error { } // Options returns routing table options -func (t *table) Options() TableOptions { +func (t *table) Options() Options { return t.opts } @@ -219,7 +219,7 @@ func (t *table) Size() int { defer t.RUnlock() size := 0 - for dest, _ := range t.m { + for dest := range t.m { size += len(t.m[dest]) } @@ -227,6 +227,6 @@ func (t *table) Size() int { } // String returns debug information -func (t table) String() string { - return "table" +func (t *table) String() string { + return "default" } diff --git a/network/router/table/default_test.go b/network/router/table/default_test.go index b4238336..275da8c2 100644 --- a/network/router/table/default_test.go +++ b/network/router/table/default_test.go @@ -23,7 +23,7 @@ func TestCreate(t *testing.T) { if err := table.Create(route); err != nil { t.Errorf("error adding route: %s", err) } - testTableSize += 1 + testTableSize++ // adds new route for the original destination route.Gateway = "dest.gw2" @@ -31,7 +31,7 @@ func TestCreate(t *testing.T) { if err := table.Create(route); err != nil { t.Errorf("error adding route: %s", err) } - testTableSize += 1 + testTableSize++ if table.Size() != testTableSize { t.Errorf("invalid number of routes. Expected: %d, found: %d", testTableSize, table.Size()) @@ -50,7 +50,7 @@ func TestDelete(t *testing.T) { if err := table.Create(route); err != nil { t.Errorf("error adding route: %s", err) } - testTableSize += 1 + testTableSize++ // should fail to delete non-existant route prevSvc := route.Service @@ -66,7 +66,7 @@ func TestDelete(t *testing.T) { if err := table.Delete(route); err != nil { t.Errorf("error deleting route: %s", err) } - testTableSize -= 1 + testTableSize-- if table.Size() != testTableSize { t.Errorf("invalid number of routes. Expected: %d, found: %d", testTableSize, table.Size()) @@ -80,7 +80,7 @@ func TestUpdate(t *testing.T) { if err := table.Create(route); err != nil { t.Errorf("error adding route: %s", err) } - testTableSize += 1 + testTableSize++ // change the metric of the original route route.Metric = 200 @@ -100,7 +100,7 @@ func TestUpdate(t *testing.T) { if err := table.Update(route); err != nil { t.Errorf("error updating route: %s", err) } - testTableSize += 1 + testTableSize++ if table.Size() != testTableSize { t.Errorf("invalid number of routes. Expected: %d, found: %d", testTableSize, table.Size()) diff --git a/network/router/table/table.go b/network/router/table/table.go index c549617c..2836e3d6 100644 --- a/network/router/table/table.go +++ b/network/router/table/table.go @@ -29,10 +29,10 @@ type Table interface { Size() int } -// TableOption used by the routing table -type TableOption func(*TableOptions) +// Option used by the routing table +type Option func(*Options) // NewTable creates new routing table and returns it -func NewTable(opts ...TableOption) Table { +func NewTable(opts ...Option) Table { return newTable(opts...) } From e688ab0a452f1d19560ece5015bc46488abe3080 Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Wed, 17 Jul 2019 10:38:50 +0300 Subject: [PATCH 194/287] fix ipv6 addr parsing and using Signed-off-by: Vasiliy Tolstov --- broker/http_broker.go | 19 +++++++++----- client/grpc/grpc_test.go | 9 +------ server/grpc/grpc.go | 44 +++++++++++++++++++------------ server/rpc_server.go | 45 ++++++++++++++++++++------------ transport/grpc/grpc_test.go | 8 +++--- transport/http_transport_test.go | 8 +++--- util/addr/addr.go | 13 +++++---- util/net/net.go | 26 ++++++++++-------- 8 files changed, 104 insertions(+), 68 deletions(-) diff --git a/broker/http_broker.go b/broker/http_broker.go index d28eeb2c..db4d78e7 100644 --- a/broker/http_broker.go +++ b/broker/http_broker.go @@ -13,8 +13,6 @@ import ( "net/http" "net/url" "runtime" - "strconv" - "strings" "sync" "time" @@ -614,18 +612,27 @@ func (h *httpBroker) Publish(topic string, msg *Message, opts ...PublishOption) } func (h *httpBroker) Subscribe(topic string, handler Handler, opts ...SubscribeOption) (Subscriber, error) { + var err error + var host, port string options := NewSubscribeOptions(opts...) // parse address for host, port - parts := strings.Split(h.Address(), ":") - host := strings.Join(parts[:len(parts)-1], ":") - port, _ := strconv.Atoi(parts[len(parts)-1]) + host, port, err = net.SplitHostPort(h.Address()) + if err != nil { + return nil, err + } addr, err := maddr.Extract(host) if err != nil { return nil, err } + // ipv6 addr + if addr == "::" { + // ipv6 addr + addr = fmt.Sprintf("[%s]", addr) + } + // create unique id id := h.id + "." + uuid.New().String() @@ -638,7 +645,7 @@ func (h *httpBroker) Subscribe(topic string, handler Handler, opts ...SubscribeO // register service node := ®istry.Node{ Id: id, - Address: fmt.Sprintf("%s:%d", addr, port), + Address: fmt.Sprintf("%s:%s", addr, port), Metadata: map[string]string{ "secure": fmt.Sprintf("%t", secure), }, diff --git a/client/grpc/grpc_test.go b/client/grpc/grpc_test.go index 3652ec6b..5696a267 100644 --- a/client/grpc/grpc_test.go +++ b/client/grpc/grpc_test.go @@ -2,10 +2,7 @@ package grpc import ( "context" - "fmt" "net" - "strconv" - "strings" "testing" "github.com/micro/go-micro/client" @@ -37,10 +34,6 @@ func TestGRPCClient(t *testing.T) { go s.Serve(l) defer s.Stop() - parts := strings.Split(l.Addr().String(), ":") - port, _ := strconv.Atoi(parts[len(parts)-1]) - addr := strings.Join(parts[:len(parts)-1], ":") - // create mock registry r := memory.NewRegistry() @@ -51,7 +44,7 @@ func TestGRPCClient(t *testing.T) { Nodes: []*registry.Node{ ®istry.Node{ Id: "test-1", - Address: fmt.Sprintf("%s:%d", addr, port), + Address: l.Addr().String(), }, }, }) diff --git a/server/grpc/grpc.go b/server/grpc/grpc.go index 8d2a2d8f..b3473efc 100644 --- a/server/grpc/grpc.go +++ b/server/grpc/grpc.go @@ -504,10 +504,11 @@ func (g *grpcServer) Subscribe(sb server.Subscriber) error { } func (g *grpcServer) Register() error { + var err error + var advt, host, port string + // parse address for host, port config := g.opts - var advt, host string - var port int // check the advertise address first // if it exists then use it, otherwise @@ -518,12 +519,17 @@ func (g *grpcServer) Register() error { advt = config.Address } - parts := strings.Split(advt, ":") - if len(parts) > 1 { - host = strings.Join(parts[:len(parts)-1], ":") - port, _ = strconv.Atoi(parts[len(parts)-1]) + if idx := strings.Count(advt, ":"); idx > 1 { + // ipv6 address in format [host]:port or ipv4 host:port + host, port, err = net.SplitHostPort(advt) + if err != nil { + return err + } + if host == "::" { + host = fmt.Sprintf("[%s]", host) + } } else { - host = parts[0] + host = advt } addr, err := addr.Extract(host) @@ -534,7 +540,7 @@ func (g *grpcServer) Register() error { // register service node := ®istry.Node{ Id: config.Name + "-" + config.Id, - Address: fmt.Sprintf("%s:%d", addr, port), + Address: fmt.Sprintf("%s:%s", addr, port), Metadata: config.Metadata, } @@ -629,9 +635,10 @@ func (g *grpcServer) Register() error { } func (g *grpcServer) Deregister() error { + var err error + var advt, host, port string + config := g.opts - var advt, host string - var port int // check the advertise address first // if it exists then use it, otherwise @@ -642,12 +649,17 @@ func (g *grpcServer) Deregister() error { advt = config.Address } - parts := strings.Split(advt, ":") - if len(parts) > 1 { - host = strings.Join(parts[:len(parts)-1], ":") - port, _ = strconv.Atoi(parts[len(parts)-1]) + if idx := strings.Count(advt, ":"); idx > 1 { + // ipv6 address in format [host]:port or ipv4 host:port + host, port, err = net.SplitHostPort(advt) + if err != nil { + return err + } + if host == "::" { + host = fmt.Sprintf("[%s]", host) + } } else { - host = parts[0] + host = advt } addr, err := addr.Extract(host) @@ -657,7 +669,7 @@ func (g *grpcServer) Deregister() error { node := ®istry.Node{ Id: config.Name + "-" + config.Id, - Address: fmt.Sprintf("%s:%d", addr, port), + Address: fmt.Sprintf("%s:%s", addr, port), } service := ®istry.Service{ diff --git a/server/rpc_server.go b/server/rpc_server.go index 533def1e..392f64b1 100644 --- a/server/rpc_server.go +++ b/server/rpc_server.go @@ -3,6 +3,7 @@ package server import ( "context" "fmt" + "net" "runtime/debug" "sort" "strconv" @@ -277,10 +278,11 @@ func (s *rpcServer) Subscribe(sb Subscriber) error { } func (s *rpcServer) Register() error { + var err error + var advt, host, port string + // parse address for host, port config := s.Options() - var advt, host string - var port int // check the advertise address first // if it exists then use it, otherwise @@ -291,12 +293,17 @@ func (s *rpcServer) Register() error { advt = config.Address } - parts := strings.Split(advt, ":") - if len(parts) > 1 { - host = strings.Join(parts[:len(parts)-1], ":") - port, _ = strconv.Atoi(parts[len(parts)-1]) + if idx := strings.Count(advt, ":"); idx > 1 { + // ipv6 address in format [host]:port or ipv4 host:port + host, port, err = net.SplitHostPort(advt) + if err != nil { + return err + } + if host == "::" { + host = fmt.Sprintf("[%s]", host) + } } else { - host = parts[0] + host = advt } addr, err := addr.Extract(host) @@ -313,7 +320,7 @@ func (s *rpcServer) Register() error { // register service node := ®istry.Node{ Id: config.Name + "-" + config.Id, - Address: fmt.Sprintf("%s:%d", addr, port), + Address: fmt.Sprintf("%s:%s", addr, port), Metadata: md, } @@ -413,9 +420,10 @@ func (s *rpcServer) Register() error { } func (s *rpcServer) Deregister() error { + var err error + var advt, host, port string + config := s.Options() - var advt, host string - var port int // check the advertise address first // if it exists then use it, otherwise @@ -426,12 +434,17 @@ func (s *rpcServer) Deregister() error { advt = config.Address } - parts := strings.Split(advt, ":") - if len(parts) > 1 { - host = strings.Join(parts[:len(parts)-1], ":") - port, _ = strconv.Atoi(parts[len(parts)-1]) + if idx := strings.Count(advt, ":"); idx > 1 { + // ipv6 address in format [host]:port or ipv4 host:port + host, port, err = net.SplitHostPort(advt) + if err != nil { + return err + } + if host == "::" { + host = fmt.Sprintf("[%s]", host) + } } else { - host = parts[0] + host = advt } addr, err := addr.Extract(host) @@ -441,7 +454,7 @@ func (s *rpcServer) Deregister() error { node := ®istry.Node{ Id: config.Name + "-" + config.Id, - Address: fmt.Sprintf("%s:%d", addr, port), + Address: fmt.Sprintf("%s:%s", addr, port), } service := ®istry.Service{ diff --git a/transport/grpc/grpc_test.go b/transport/grpc/grpc_test.go index d4e82346..b1e46ba5 100644 --- a/transport/grpc/grpc_test.go +++ b/transport/grpc/grpc_test.go @@ -1,15 +1,17 @@ package grpc import ( - "strings" + "net" "testing" "github.com/micro/go-micro/transport" ) func expectedPort(t *testing.T, expected string, lsn transport.Listener) { - parts := strings.Split(lsn.Addr(), ":") - port := parts[len(parts)-1] + _, port, err := net.SplitHostPort(lsn.Addr()) + if err != nil { + t.Errorf("Expected address to be `%s`, got error: %v", expected, err) + } if port != expected { lsn.Close() diff --git a/transport/http_transport_test.go b/transport/http_transport_test.go index fac80716..cbbc8658 100644 --- a/transport/http_transport_test.go +++ b/transport/http_transport_test.go @@ -2,14 +2,16 @@ package transport import ( "io" - "strings" + "net" "testing" "time" ) func expectedPort(t *testing.T, expected string, lsn Listener) { - parts := strings.Split(lsn.Addr(), ":") - port := parts[len(parts)-1] + _, port, err := net.SplitHostPort(lsn.Addr()) + if err != nil { + t.Errorf("Expected address to be `%s`, got error: %v", expected, err) + } if port != expected { lsn.Close() diff --git a/util/addr/addr.go b/util/addr/addr.go index ab3acca1..b2874533 100644 --- a/util/addr/addr.go +++ b/util/addr/addr.go @@ -30,7 +30,7 @@ func isPrivateIP(ipAddr string) bool { // Extract returns a real ip func Extract(addr string) (string, error) { // if addr specified then its returned - if len(addr) > 0 && (addr != "0.0.0.0" && addr != "[::]") { + if len(addr) > 0 && (addr != "0.0.0.0" && addr != "[::]" && addr != "::") { return addr, nil } @@ -113,10 +113,13 @@ func IPs() []string { continue } - ip = ip.To4() - if ip == nil { - continue - } + // dont skip ipv6 addrs + /* + ip = ip.To4() + if ip == nil { + continue + } + */ ipAddrs = append(ipAddrs, ip.String()) } diff --git a/util/net/net.go b/util/net/net.go index b092068f..f9726f6b 100644 --- a/util/net/net.go +++ b/util/net/net.go @@ -11,39 +11,43 @@ import ( // Listen takes addr:portmin-portmax and binds to the first available port // Example: Listen("localhost:5000-6000", fn) func Listen(addr string, fn func(string) (net.Listener, error)) (net.Listener, error) { - // host:port || host:min-max - parts := strings.Split(addr, ":") - // - if len(parts) < 2 { + if strings.Count(addr, ":") == 1 && strings.Count(addr, "-") == 0 { return fn(addr) } + // host:port || host:min-max + host, ports, err := net.SplitHostPort(addr) + if err != nil { + return nil, err + } + + if host == "::" { + host = fmt.Sprintf("[%s]", host) + } + // try to extract port range - ports := strings.Split(parts[len(parts)-1], "-") + prange := strings.Split(ports, "-") // single port - if len(ports) < 2 { + if len(prange) < 2 { return fn(addr) } // we have a port range // extract min port - min, err := strconv.Atoi(ports[0]) + min, err := strconv.Atoi(prange[0]) if err != nil { return nil, errors.New("unable to extract port range") } // extract max port - max, err := strconv.Atoi(ports[1]) + max, err := strconv.Atoi(prange[1]) if err != nil { return nil, errors.New("unable to extract port range") } - // set host - host := parts[:len(parts)-1] - // range the ports for port := min; port <= max; port++ { // try bind to host:port From 94b6455577b41c2de739d0f585133a51df9a8603 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Wed, 17 Jul 2019 13:02:47 +0100 Subject: [PATCH 195/287] Increment WaitGroup before launching advertiseEvents goroutine --- network/router/default.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/network/router/default.go b/network/router/default.go index 8af78ef3..0d153920 100644 --- a/network/router/default.go +++ b/network/router/default.go @@ -273,10 +273,8 @@ func (r *router) advertiseTable() error { // advertise all routes as Update events to subscribers if len(events) > 0 { - go func() { - r.advertWg.Add(1) - r.advertiseEvents(Update, events) - }() + r.advertWg.Add(1) + go r.advertiseEvents(Update, events) } case <-r.exit: return nil From 1217ca94b1dec8fc5da0f43ebdb1dda7b4b004a3 Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Thu, 18 Jul 2019 00:18:40 +0300 Subject: [PATCH 196/287] bunch of other ipv6 fixes Signed-off-by: Vasiliy Tolstov --- broker/http_broker.go | 8 +------- broker/memory/memory.go | 17 ++++++++++++++++- server/grpc/grpc.go | 15 +++++---------- server/rpc_server.go | 15 +++++---------- transport/memory/memory.go | 22 +++++++++++++++++----- transport/memory/memory_test.go | 4 ++-- util/net/net.go | 15 ++++++++++----- 7 files changed, 56 insertions(+), 40 deletions(-) diff --git a/broker/http_broker.go b/broker/http_broker.go index db4d78e7..5b362c14 100644 --- a/broker/http_broker.go +++ b/broker/http_broker.go @@ -627,12 +627,6 @@ func (h *httpBroker) Subscribe(topic string, handler Handler, opts ...SubscribeO return nil, err } - // ipv6 addr - if addr == "::" { - // ipv6 addr - addr = fmt.Sprintf("[%s]", addr) - } - // create unique id id := h.id + "." + uuid.New().String() @@ -645,7 +639,7 @@ func (h *httpBroker) Subscribe(topic string, handler Handler, opts ...SubscribeO // register service node := ®istry.Node{ Id: id, - Address: fmt.Sprintf("%s:%s", addr, port), + Address: mnet.HostPort(addr, port), Metadata: map[string]string{ "secure": fmt.Sprintf("%t", secure), }, diff --git a/broker/memory/memory.go b/broker/memory/memory.go index 5ace9581..effb22f3 100644 --- a/broker/memory/memory.go +++ b/broker/memory/memory.go @@ -3,15 +3,20 @@ package memory import ( "errors" + "math/rand" "sync" + "time" "github.com/google/uuid" "github.com/micro/go-micro/broker" + maddr "github.com/micro/go-micro/util/addr" + mnet "github.com/micro/go-micro/util/net" ) type memoryBroker struct { opts broker.Options + addr string sync.RWMutex connected bool Subscribers map[string][]*memorySubscriber @@ -35,7 +40,7 @@ func (m *memoryBroker) Options() broker.Options { } func (m *memoryBroker) Address() string { - return "" + return m.addr } func (m *memoryBroker) Connect() error { @@ -46,6 +51,15 @@ func (m *memoryBroker) Connect() error { return nil } + addr, err := maddr.Extract("::") + if err != nil { + return err + } + i := rand.Intn(20000) + // set addr with port + addr = mnet.HostPort(addr, 10000+i) + + m.addr = addr m.connected = true return nil @@ -171,6 +185,7 @@ func (m *memorySubscriber) Unsubscribe() error { func NewBroker(opts ...broker.Option) broker.Broker { var options broker.Options + rand.Seed(time.Now().UnixNano()) for _, o := range opts { o(&options) } diff --git a/server/grpc/grpc.go b/server/grpc/grpc.go index b3473efc..f92048f1 100644 --- a/server/grpc/grpc.go +++ b/server/grpc/grpc.go @@ -22,6 +22,7 @@ import ( "github.com/micro/go-micro/util/addr" mgrpc "github.com/micro/go-micro/util/grpc" "github.com/micro/go-micro/util/log" + mnet "github.com/micro/go-micro/util/net" "google.golang.org/grpc" "google.golang.org/grpc/codes" @@ -519,15 +520,12 @@ func (g *grpcServer) Register() error { advt = config.Address } - if idx := strings.Count(advt, ":"); idx > 1 { + if cnt := strings.Count(advt, ":"); cnt >= 1 { // ipv6 address in format [host]:port or ipv4 host:port host, port, err = net.SplitHostPort(advt) if err != nil { return err } - if host == "::" { - host = fmt.Sprintf("[%s]", host) - } } else { host = advt } @@ -540,7 +538,7 @@ func (g *grpcServer) Register() error { // register service node := ®istry.Node{ Id: config.Name + "-" + config.Id, - Address: fmt.Sprintf("%s:%s", addr, port), + Address: mnet.HostPort(addr, port), Metadata: config.Metadata, } @@ -649,15 +647,12 @@ func (g *grpcServer) Deregister() error { advt = config.Address } - if idx := strings.Count(advt, ":"); idx > 1 { + if cnt := strings.Count(advt, ":"); cnt >= 1 { // ipv6 address in format [host]:port or ipv4 host:port host, port, err = net.SplitHostPort(advt) if err != nil { return err } - if host == "::" { - host = fmt.Sprintf("[%s]", host) - } } else { host = advt } @@ -669,7 +664,7 @@ func (g *grpcServer) Deregister() error { node := ®istry.Node{ Id: config.Name + "-" + config.Id, - Address: fmt.Sprintf("%s:%s", addr, port), + Address: mnet.HostPort(addr, port), } service := ®istry.Service{ diff --git a/server/rpc_server.go b/server/rpc_server.go index 392f64b1..daa28faf 100644 --- a/server/rpc_server.go +++ b/server/rpc_server.go @@ -18,6 +18,7 @@ import ( "github.com/micro/go-micro/transport" "github.com/micro/go-micro/util/addr" log "github.com/micro/go-micro/util/log" + mnet "github.com/micro/go-micro/util/net" ) type rpcServer struct { @@ -293,15 +294,12 @@ func (s *rpcServer) Register() error { advt = config.Address } - if idx := strings.Count(advt, ":"); idx > 1 { + if cnt := strings.Count(advt, ":"); cnt >= 1 { // ipv6 address in format [host]:port or ipv4 host:port host, port, err = net.SplitHostPort(advt) if err != nil { return err } - if host == "::" { - host = fmt.Sprintf("[%s]", host) - } } else { host = advt } @@ -320,7 +318,7 @@ func (s *rpcServer) Register() error { // register service node := ®istry.Node{ Id: config.Name + "-" + config.Id, - Address: fmt.Sprintf("%s:%s", addr, port), + Address: mnet.HostPort(addr, port), Metadata: md, } @@ -434,15 +432,12 @@ func (s *rpcServer) Deregister() error { advt = config.Address } - if idx := strings.Count(advt, ":"); idx > 1 { + if cnt := strings.Count(advt, ":"); cnt >= 1 { // ipv6 address in format [host]:port or ipv4 host:port host, port, err = net.SplitHostPort(advt) if err != nil { return err } - if host == "::" { - host = fmt.Sprintf("[%s]", host) - } } else { host = advt } @@ -454,7 +449,7 @@ func (s *rpcServer) Deregister() error { node := ®istry.Node{ Id: config.Name + "-" + config.Id, - Address: fmt.Sprintf("%s:%s", addr, port), + Address: mnet.HostPort(addr, port), } service := ®istry.Service{ diff --git a/transport/memory/memory.go b/transport/memory/memory.go index 0d637f05..51f8d01a 100644 --- a/transport/memory/memory.go +++ b/transport/memory/memory.go @@ -5,11 +5,13 @@ import ( "errors" "fmt" "math/rand" - "strings" + "net" "sync" "time" "github.com/micro/go-micro/transport" + maddr "github.com/micro/go-micro/util/addr" + mnet "github.com/micro/go-micro/util/net" ) type memorySocket struct { @@ -170,15 +172,25 @@ func (m *memoryTransport) Listen(addr string, opts ...transport.ListenOption) (t o(&options) } - parts := strings.Split(addr, ":") + host, port, err := net.SplitHostPort(addr) + if err != nil { + return nil, err + } + + addr, err = maddr.Extract(host) + if err != nil { + return nil, err + } // if zero port then randomly assign one - if len(parts) > 1 && parts[len(parts)-1] == "0" { + if len(port) > 0 && port == "0" { i := rand.Intn(20000) - // set addr with port - addr = fmt.Sprintf("%s:%d", parts[:len(parts)-1], 10000+i) + port = fmt.Sprintf("%d", 10000+i) } + // set addr with port + addr = mnet.HostPort(addr, port) + if _, ok := m.listeners[addr]; ok { return nil, errors.New("already listening on " + addr) } diff --git a/transport/memory/memory_test.go b/transport/memory/memory_test.go index 72952e09..d779f53e 100644 --- a/transport/memory/memory_test.go +++ b/transport/memory/memory_test.go @@ -10,7 +10,7 @@ func TestMemoryTransport(t *testing.T) { tr := NewTransport() // bind / listen - l, err := tr.Listen("localhost:8080") + l, err := tr.Listen("127.0.0.1:8080") if err != nil { t.Fatalf("Unexpected error listening %v", err) } @@ -37,7 +37,7 @@ func TestMemoryTransport(t *testing.T) { }() // dial - c, err := tr.Dial("localhost:8080") + c, err := tr.Dial("127.0.0.1:8080") if err != nil { t.Fatalf("Unexpected error dialing %v", err) } diff --git a/util/net/net.go b/util/net/net.go index f9726f6b..7f0f4643 100644 --- a/util/net/net.go +++ b/util/net/net.go @@ -8,6 +8,15 @@ import ( "strings" ) +// HostPort format addr and port suitable for dial +func HostPort(addr string, port interface{}) string { + host := addr + if strings.Count(addr, ":") > 0 { + host = fmt.Sprintf("[%s]", addr) + } + return fmt.Sprintf("%s:%v", host, port) +} + // Listen takes addr:portmin-portmax and binds to the first available port // Example: Listen("localhost:5000-6000", fn) func Listen(addr string, fn func(string) (net.Listener, error)) (net.Listener, error) { @@ -22,10 +31,6 @@ func Listen(addr string, fn func(string) (net.Listener, error)) (net.Listener, e return nil, err } - if host == "::" { - host = fmt.Sprintf("[%s]", host) - } - // try to extract port range prange := strings.Split(ports, "-") @@ -51,7 +56,7 @@ func Listen(addr string, fn func(string) (net.Listener, error)) (net.Listener, e // range the ports for port := min; port <= max; port++ { // try bind to host:port - ln, err := fn(fmt.Sprintf("%s:%d", host, port)) + ln, err := fn(HostPort(host, port)) if err == nil { return ln, nil } From 502f6d3e9f8f337ba57cea3e6b7d87d45118a4f9 Mon Sep 17 00:00:00 2001 From: Bruce Wang Date: Mon, 22 Jul 2019 15:41:14 +0800 Subject: [PATCH 197/287] Update client.go fixed one typo --- client/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/client.go b/client/client.go index 80d7f49b..6d597342 100644 --- a/client/client.go +++ b/client/client.go @@ -10,7 +10,7 @@ import ( // Client is the interface used to make requests to services. // It supports Request/Response via Transport and Publishing via the Broker. -// It also supports bidiectional streaming of requests. +// It also supports bidirectional streaming of requests. type Client interface { Init(...Option) error Options() Options From 49dcc3d1bdfe11d98d4805649665127086d82bce Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 22 Jul 2019 09:57:34 -0700 Subject: [PATCH 198/287] Remove readme and examples from web repo --- web/README.md | 114 -------------------------- web/examples/README.md | 7 -- web/examples/helloworld/helloworld.go | 29 ------- 3 files changed, 150 deletions(-) delete mode 100644 web/README.md delete mode 100644 web/examples/README.md delete mode 100644 web/examples/helloworld/helloworld.go diff --git a/web/README.md b/web/README.md deleted file mode 100644 index 82084b96..00000000 --- a/web/README.md +++ /dev/null @@ -1,114 +0,0 @@ -# Go Web - -**Go Web** is a framework for micro service web development. - -## Overview - -Go Web provides a tiny HTTP web server library which leverages [go-micro](https://github.com/micro/go-micro) to create -micro web services as first class citizens in a microservice world. It wraps go-micro to give you service discovery, -heartbeating and the ability to create web apps as microservices. - -## Features - -- **Service Discovery** - Services are automatically registered in service discovery on startup. Go Web includes -a http.Client with pre-initialised roundtripper which makes use of service discovery so you can use service names. - -- **Heartbeating** - Go Web apps will periodically heartbeat with service discovery to provide liveness updates. -In the event a service fails it will be removed from the registry after a pre-defined expiry time. - -- **Custom Handlers** - Specify your own http router for handling requests. This allows you to maintain full -control over how you want to route to internal handlers. - -- **Static Serving** - Go Web automatically detects a local static `html` dir and serves files if no route handler -is specified. A quick solution for those who want to write JS web apps as microservices. - -## Getting Started - -- [Dependencies](#dependencies) -- [Usage](#usage) -- [Set Handler](#set-handler) -- [Call Service](#call-service) -- [Static Files](#static-files) - -## Dependencies - -Go Web makes use of Go Micro which means it needs service discovery - -See the [go-micro](https://github.com/micro/go-micro#service-discovery) for install instructions - -For a quick start use consul - -``` -# install -brew install consul - -# run -consul agent -dev -``` - -## Usage - -```go -service := web.NewService( - web.Name("example.com"), -) - -service.HandleFunc("/foo", fooHandler) - -if err := service.Init(); err != nil { - log.Fatal(err) -} - -if err := service.Run(); err != nil { - log.Fatal(err) -} -``` - -## Set Handler - -You might have a preference for a HTTP handler, so use something else. This loses the ability to register endpoints in discovery -but we'll fix that soon. - -```go -import "github.com/gorilla/mux" - -r := mux.NewRouter() -r.HandleFunc("/", indexHandler) -r.HandleFunc("/objects/{object}", objectHandler) - -service := web.NewService( - web.Handler(r) -) -``` - -## Call Service - -Go-web includes a http.Client with a custom http.RoundTripper that uses service discovery - -```go -c := service.Client() - -rsp, err := c.Get("http://example.com/foo") -``` - -This will lookup service discovery for the service `example.com` and route to one of the available nodes. - -## Static Files - -Go web was always meant as a way to register web apps where the majority of the code would be written in JS. To enable that by default, if no handler is registered on "/" and we find a local "html" directory then static files will be served. - -You will see a log output like so. - -``` -2019/05/12 14:55:47 Enabling static file serving from /tmp/foo/html -``` - -If you want to set this path manually use the StaticDir option. If a relative path is specified we will use os.Getwd() and prefix this. - -``` -service := web.NewService( - web.Name("example.com"), - web.StaticDir("/tmp/example.com/html"), -) - -``` diff --git a/web/examples/README.md b/web/examples/README.md deleted file mode 100644 index 5208291c..00000000 --- a/web/examples/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Examples - -Name | Description ---- | --- -[Message](https://github.com/micro/message-web) | A simple text based messaging web app -[Geo](https://github.com/micro/geo-web) | A geo location map demo - diff --git a/web/examples/helloworld/helloworld.go b/web/examples/helloworld/helloworld.go deleted file mode 100644 index 017b3b8b..00000000 --- a/web/examples/helloworld/helloworld.go +++ /dev/null @@ -1,29 +0,0 @@ -package main - -import ( - "fmt" - "log" - "net/http" - - "github.com/micro/go-micro/web" -) - -func helloWorldHandler(w http.ResponseWriter, r *http.Request) { - fmt.Fprint(w, `

Hello World

`) -} - -func main() { - service := web.NewService( - web.Name("helloworld"), - ) - - service.HandleFunc("/", helloWorldHandler) - - if err := service.Init(); err != nil { - log.Fatal(err) - } - - if err := service.Run(); err != nil { - log.Fatal(err) - } -} From 1e94d9fe5ae95b925800c6625a81d60ab528ad5a Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Wed, 24 Jul 2019 17:16:52 +0100 Subject: [PATCH 199/287] Router cleanup and refactoring for win and profit. This commit adds the following changes to router package: * it refactors Advertise() function which now does only what it claims to do: advertising * various router packages functions/methods have been renamed to make their functionality more obvious and more in line with what they actually do * function documentation changes related to the above bullet points --- network/router/default.go | 268 +++++++++++++++++++++----------------- network/router/options.go | 18 +-- network/router/router.go | 62 ++++----- 3 files changed, 193 insertions(+), 155 deletions(-) diff --git a/network/router/default.go b/network/router/default.go index 0d153920..ca336619 100644 --- a/network/router/default.go +++ b/network/router/default.go @@ -17,6 +17,8 @@ const ( AdvertiseEventsTick = 5 * time.Second // AdvertiseTableTick is time interval in which router advertises all routes found in routing table AdvertiseTableTick = 1 * time.Minute + // AdvertiseFlushTick is time the yet unconsumed advertisements are flush i.e. discarded + AdvertiseFlushTick = 15 * time.Second // AdvertSuppress is advert suppression threshold AdvertSuppress = 2000.0 // AdvertRecover is advert recovery threshold @@ -38,13 +40,14 @@ var ( PenaltyDecay = math.Log(2) / PenaltyHalfLife ) -// router provides default router implementation +// router implements default router type router struct { // embed the table table.Table opts Options status Status exit chan struct{} + errChan chan error eventChan chan *table.Event advertChan chan *Advert advertWg *sync.WaitGroup @@ -52,7 +55,7 @@ type router struct { sync.RWMutex } -// newRouter creates a new router and returns it +// newRouter creates new router and returns it func newRouter(opts ...Option) Router { // get default options options := DefaultOptions() @@ -62,16 +65,17 @@ func newRouter(opts ...Option) Router { o(&options) } - return &router{ - Table: options.Table, - opts: options, - status: Status{Error: nil, Code: Stopped}, - exit: make(chan struct{}), - eventChan: make(chan *table.Event), - advertChan: make(chan *Advert), - advertWg: &sync.WaitGroup{}, - wg: &sync.WaitGroup{}, + r := &router{ + Table: options.Table, + opts: options, + status: Status{Code: Stopped, Error: nil}, + advertWg: &sync.WaitGroup{}, + wg: &sync.WaitGroup{}, } + + go r.run() + + return r } // Init initializes router with given options @@ -87,7 +91,7 @@ func (r *router) Options() Options { return r.opts } -// manageRoute applies route action on the routing table +// manageRoute applies action on a given route func (r *router) manageRoute(route table.Route, action string) error { switch action { case "create": @@ -109,8 +113,8 @@ func (r *router) manageRoute(route table.Route, action string) error { return nil } -// manageServiceRoutes manages routes for a given service. -// It returns error of the routing table action fails. +// manageServiceRoutes applies action on all routes of given service. +// It returns error of the action fails with error. func (r *router) manageServiceRoutes(service *registry.Service, action string) error { // action is the routing table action action = strings.ToLower(action) @@ -134,7 +138,7 @@ func (r *router) manageServiceRoutes(service *registry.Service, action string) e return nil } -// manageRegistryRoutes manages routes for each service found in the registry. +// manageRegistryRoutes applies action on all routes of each service found in the registry. // It returns error if either the services failed to be listed or the routing table action fails. func (r *router) manageRegistryRoutes(reg registry.Registry, action string) error { services, err := reg.ListServices() @@ -228,8 +232,9 @@ func (r *router) watchTable(w table.Watcher) error { return watchErr } -// advertiseEvents advertises events to event subscribers -func (r *router) advertiseEvents(advType AdvertType, events []*table.Event) { +// publishAdvert publishes router advert to advert channel +// NOTE: this might cease to be a dedicated method in the future +func (r *router) publishAdvert(advType AdvertType, events []*table.Event) { defer r.advertWg.Done() a := &Advert{ @@ -274,7 +279,7 @@ func (r *router) advertiseTable() error { // advertise all routes as Update events to subscribers if len(events) > 0 { r.advertWg.Add(1) - go r.advertiseEvents(Update, events) + go r.publishAdvert(Update, events) } case <-r.exit: return nil @@ -295,14 +300,29 @@ type routeAdvert struct { suppressTime time.Time } -// processEvents processes routing table events. +// advertiseEvents advertises routing table events // It suppresses unhealthy flapping events and advertises healthy events upstream. -func (r *router) processEvents() error { +func (r *router) advertiseEvents() error { // ticker to periodically scan event for advertising ticker := time.NewTicker(AdvertiseEventsTick) // advertMap is a map of advert events advertMap := make(map[uint64]*routeAdvert) + // routing table watcher + tableWatcher, err := r.Watch() + if err != nil { + return fmt.Errorf("failed creating routing table watcher: %v", err) + } + + r.wg.Add(1) + go func() { + defer r.wg.Done() + select { + case r.errChan <- r.watchTable(tableWatcher): + case <-r.exit: + } + }() + for { select { case <-ticker.C: @@ -344,7 +364,7 @@ func (r *router) processEvents() error { // advertise all Update events to subscribers if len(events) > 0 { r.advertWg.Add(1) - go r.advertiseEvents(Update, events) + go r.publishAdvert(Update, events) } case e := <-r.eventChan: // if event is nil, continue @@ -399,30 +419,18 @@ func (r *router) processEvents() error { } // watchErrors watches router errors and takes appropriate actions -func (r *router) watchErrors(errChan <-chan error) { - defer r.wg.Done() - - var code StatusCode +func (r *router) watchErrors() { var err error select { case <-r.exit: - code = Stopped - case err = <-errChan: - code = Error + case err = <-r.errChan: } r.Lock() defer r.Unlock() - status := Status{ - Code: code, - Error: err, - } - r.status = status - - // stop the router if some error happened - if err != nil && code != Stopped { - // this will stop watchers which will close r.advertChan + if r.status.Code != Stopped { + // notify all goroutines to finish close(r.exit) // drain the advertise channel for range r.advertChan { @@ -432,20 +440,88 @@ func (r *router) watchErrors(errChan <-chan error) { } } + if err != nil { + r.status = Status{Code: Error, Error: err} + } } -// Advertise advertises the routes to the network. -// It returns error if any of the launched goroutines fail with error. +// Run runs the router. +// It returns error if the router is already running. +func (r *router) run() { + r.Lock() + defer r.Unlock() + + switch r.status.Code { + case Stopped, Error: + // add all local service routes into the routing table + if err := r.manageRegistryRoutes(r.opts.Registry, "create"); err != nil { + r.status = Status{Code: Error, Error: fmt.Errorf("failed adding registry routes: %s", err)} + return + } + + // add default gateway into routing table + if r.opts.Gateway != "" { + // note, the only non-default value is the gateway + route := table.Route{ + Service: "*", + Address: "*", + Gateway: r.opts.Gateway, + Network: "*", + Metric: table.DefaultLocalMetric, + } + if err := r.Create(route); err != nil { + r.status = Status{Code: Error, Error: fmt.Errorf("failed adding default gateway route: %s", err)} + return + } + } + + // create error and exit channels + r.errChan = make(chan error, 1) + r.exit = make(chan struct{}) + + // registry watcher + regWatcher, err := r.opts.Registry.Watch() + if err != nil { + r.status = Status{Code: Error, Error: fmt.Errorf("failed creating registry watcher: %v", err)} + return + } + + r.wg.Add(1) + go func() { + defer r.wg.Done() + select { + case r.errChan <- r.watchRegistry(regWatcher): + case <-r.exit: + } + }() + + // watch for errors and cleanup + r.wg.Add(1) + go func() { + defer r.wg.Done() + r.watchErrors() + }() + + // mark router as Running and set its Error to nil + r.status = Status{Code: Running, Error: nil} + + return + } + + return +} + +// Advertise stars advertising the routes to the network and returns the advertisements channel to consume from. +// If the router is already advertising it returns the channel to consume from. +// It returns error if either the router is not running or if the routing table fails to list the routes to advertise. func (r *router) Advertise() (<-chan *Advert, error) { r.Lock() defer r.Unlock() - if r.status.Code != Running { - // add all local service routes into the routing table - if err := r.manageRegistryRoutes(r.opts.Registry, "create"); err != nil { - return nil, fmt.Errorf("failed adding routes: %s", err) - } - + switch r.status.Code { + case Advertising: + return r.advertChan, nil + case Running: // list routing table routes to announce routes, err := r.List() if err != nil { @@ -462,85 +538,42 @@ func (r *router) Advertise() (<-chan *Advert, error) { events[i] = event } - // add default gateway into routing table - if r.opts.Gateway != "" { - // note, the only non-default value is the gateway - route := table.Route{ - Service: "*", - Address: "*", - Gateway: r.opts.Gateway, - Network: "*", - Metric: table.DefaultLocalMetric, + // create advertise and event channels + r.advertChan = make(chan *Advert) + r.eventChan = make(chan *table.Event) + + // advertise your presence + r.advertWg.Add(1) + go r.publishAdvert(Announce, events) + + r.wg.Add(1) + go func() { + defer r.wg.Done() + select { + case r.errChan <- r.advertiseEvents(): + case <-r.exit: } - if err := r.Create(route); err != nil { - return nil, fmt.Errorf("failed adding default gateway route: %s", err) - } - } - - // NOTE: we only need to recreate these if the router errored or was stopped - // TODO: These probably dont need to be struct members - if r.status.Code == Error || r.status.Code == Stopped { - r.exit = make(chan struct{}) - r.eventChan = make(chan *table.Event) - r.advertChan = make(chan *Advert) - } - - // routing table watcher - tableWatcher, err := r.Watch() - if err != nil { - return nil, fmt.Errorf("failed creating routing table watcher: %v", err) - } - - // registry watcher - regWatcher, err := r.opts.Registry.Watch() - if err != nil { - return nil, fmt.Errorf("failed creating service registry watcher: %v", err) - } - - // error channel collecting goroutine errors - errChan := make(chan error, 4) - - r.wg.Add(1) - go func() { - defer r.wg.Done() - // watch local registry and register routes in routine table - errChan <- r.watchRegistry(regWatcher) - }() - - r.wg.Add(1) - go func() { - defer r.wg.Done() - // watch local registry and register routes in routing table - errChan <- r.watchTable(tableWatcher) - }() - - r.wg.Add(1) - go func() { - defer r.wg.Done() - // watch routing table events and process them - errChan <- r.processEvents() }() r.advertWg.Add(1) go func() { defer r.advertWg.Done() // advertise the whole routing table - errChan <- r.advertiseTable() + select { + case r.errChan <- r.advertiseTable(): + case <-r.exit: + } }() - // advertise your presence - r.advertWg.Add(1) - go r.advertiseEvents(Announce, events) + // mark router as Running and set its Error to nil + r.status = Status{Code: Advertising, Error: nil} - // watch for errors and cleanup - r.wg.Add(1) - go r.watchErrors(errChan) - - // mark router as running and set its Error to nil - r.status = Status{Code: Running, Error: nil} + return r.advertChan, nil + case Stopped: + return nil, fmt.Errorf("not running") } - return r.advertChan, nil + return nil, fmt.Errorf("error: %s", r.status.Error) } // Process updates the routing table using the advertised values @@ -579,9 +612,9 @@ func (r *router) Status() Status { // Stop stops the router func (r *router) Stop() error { - r.RLock() - // only close the channel if the router is running - if r.status.Code == Running { + r.Lock() + // only close the channel if the router is running and/or advertising + if r.status.Code == Running || r.status.Code == Advertising { // notify all goroutines to finish close(r.exit) // drain the advertise channel @@ -590,8 +623,11 @@ func (r *router) Stop() error { // drain the event channel for range r.eventChan { } + + // mark the router as Stopped and set its Error to nil + r.status = Status{Code: Stopped, Error: nil} } - r.RUnlock() + r.Unlock() // wait for all goroutines to finish r.wg.Wait() diff --git a/network/router/options.go b/network/router/options.go index 1405ed6e..d64aca01 100644 --- a/network/router/options.go +++ b/network/router/options.go @@ -19,9 +19,9 @@ type Options struct { Id string // Address is router address Address string - // Gateway is micro network gateway + // Gateway is network gateway Gateway string - // Network is micro network + // Network is network address Network string // Registry is the local registry Registry registry.Registry @@ -57,13 +57,6 @@ func Network(n string) Option { } } -// Table sets the routing table -func Table(t table.Table) Option { - return func(o *Options) { - o.Table = t - } -} - // Registry sets the local registry func Registry(r registry.Registry) Option { return func(o *Options) { @@ -71,6 +64,13 @@ func Registry(r registry.Registry) Option { } } +// Table sets the routing table +func Table(t table.Table) Option { + return func(o *Options) { + o.Table = t + } +} + // DefaultOptions returns router default options func DefaultOptions() Options { return Options{ diff --git a/network/router/router.go b/network/router/router.go index 724f38be..8ce84fb1 100644 --- a/network/router/router.go +++ b/network/router/router.go @@ -7,20 +7,9 @@ import ( "github.com/micro/go-micro/network/router/table" ) -const ( - // Status codes - // Running means the router is up and running - Running StatusCode = iota - // Stopped means the router has been stopped - Stopped - // Error means the router has encountered error - Error - - // Advert types - // Announce is advertised when the router announces itself - Announce AdvertType = iota - // Update advertises route updates - Update +var ( + // DefaultRouter is default network router + DefaultRouter = NewRouter() ) // Router is an interface for a routing control plane @@ -46,9 +35,38 @@ type Router interface { // Option used by the router type Option func(*Options) +// StatusCode defines router status +type StatusCode int + +const ( + // Running means the router is up and running + Running StatusCode = iota + // Advertising means the router is advertising + Advertising + // Stopped means the router has been stopped + Stopped + // Error means the router has encountered error + Error +) + +// Status is router status +type Status struct { + // Error is router error + Error error + // Code defines router status + Code StatusCode +} + // AdvertType is route advertisement type type AdvertType int +const ( + // Announce is advertised when the router announces itself + Announce AdvertType = iota + // Update advertises route updates + Update +) + // Advert contains a list of events advertised by the router to the network type Advert struct { // Id is the router Id @@ -63,22 +81,6 @@ type Advert struct { Events []*table.Event } -// StatusCode defines router status -type StatusCode int - -// Status is router status -type Status struct { - // Error is router error - Error error - // Code defines router status - Code StatusCode -} - -var ( - // DefaultRouter is default network router - DefaultRouter = NewRouter() -) - // NewRouter creates new Router and returns it func NewRouter(opts ...Option) Router { return newRouter(opts...) From 13a8cfe7f3b7334ce1d7e4f9b7fc809126df86be Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Wed, 24 Jul 2019 17:22:27 +0100 Subject: [PATCH 200/287] Small function documentation update --- network/router/default.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/network/router/default.go b/network/router/default.go index ca336619..9340e8df 100644 --- a/network/router/default.go +++ b/network/router/default.go @@ -113,7 +113,7 @@ func (r *router) manageRoute(route table.Route, action string) error { return nil } -// manageServiceRoutes applies action on all routes of given service. +// manageServiceRoutes applies action to all routes of the service. // It returns error of the action fails with error. func (r *router) manageServiceRoutes(service *registry.Service, action string) error { // action is the routing table action @@ -138,7 +138,7 @@ func (r *router) manageServiceRoutes(service *registry.Service, action string) e return nil } -// manageRegistryRoutes applies action on all routes of each service found in the registry. +// manageRegistryRoutes applies action to all routes of each service found in the registry. // It returns error if either the services failed to be listed or the routing table action fails. func (r *router) manageRegistryRoutes(reg registry.Registry, action string) error { services, err := reg.ListServices() From b55adc0c30c6a21641be4eba1ca6af1ebc7b2e91 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Wed, 24 Jul 2019 18:13:51 +0100 Subject: [PATCH 201/287] mucp Proxy no longer uses RPC interface of router.Router directly --- network/proxy/mucp/mucp.go | 184 +++++++++---------------------------- 1 file changed, 44 insertions(+), 140 deletions(-) diff --git a/network/proxy/mucp/mucp.go b/network/proxy/mucp/mucp.go index 101f5f2a..96e3527f 100644 --- a/network/proxy/mucp/mucp.go +++ b/network/proxy/mucp/mucp.go @@ -4,12 +4,10 @@ package mucp import ( "context" "io" - "os" "strings" "sync" "github.com/micro/go-micro/client" - "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/codec" "github.com/micro/go-micro/codec/bytes" "github.com/micro/go-micro/config/options" @@ -17,7 +15,6 @@ import ( "github.com/micro/go-micro/network/router" "github.com/micro/go-micro/server" - pb "github.com/micro/go-micro/network/router/proto" "github.com/micro/go-micro/network/router/table" ) @@ -27,7 +24,7 @@ type Proxy struct { // embed options options.Options - // Endpoint specified the fixed service endpoint to call. + // Endpoint specifies the fixed service endpoint to call. Endpoint string // The client to use for outbound requests @@ -36,12 +33,9 @@ type Proxy struct { // The router for routes Router router.Router - // The router service client - RouterService pb.RouterService - // A fib of routes service:address sync.RWMutex - Routes map[string][]table.Route + Routes map[string]map[uint64]table.Route } // read client request and write to server @@ -79,155 +73,54 @@ func readLoop(r server.Request, s client.Stream) error { } } +// toNodes returns a list of node addresses from given routes +func toNodes(routes map[uint64]table.Route) []string { + var nodes []string + for _, node := range routes { + address := node.Address + if len(node.Gateway) > 0 { + address = node.Gateway + } + nodes = append(nodes, address) + } + return nodes +} + func (p *Proxy) getRoute(service string) ([]string, error) { - // converts routes to just addresses - toNodes := func(routes []table.Route) []string { - var nodes []string - for _, node := range routes { - address := node.Address - if len(node.Gateway) > 0 { - address = node.Gateway - } - nodes = append(nodes, address) - } - return nodes - } - // lookup the route cache first - p.RLock() + p.Lock() routes, ok := p.Routes[service] - // got it! if ok { - p.RUnlock() - return toNodes(routes), nil - } - p.RUnlock() - - // route cache miss, now lookup the router - // if it does not exist, don't error out - // the proxy will just hand off to the client - // and try the registry - // in future we might set a default gateway - if p.Router != nil { - // lookup the router - routes, err := p.Router.Lookup( - table.NewQuery(table.QueryService(service)), - ) - if err != nil { - return nil, err - } - - p.Lock() - if p.Routes == nil { - p.Routes = make(map[string][]table.Route) - } - p.Routes[service] = routes p.Unlock() - return toNodes(routes), nil } + p.Routes[service] = make(map[uint64]table.Route) + p.Unlock() - // we've tried getting cached routes - // we've tried using the router - addr := os.Getenv("MICRO_ROUTER_ADDRESS") - name := os.Getenv("MICRO_ROUTER") - - // no router is specified we're going to set the default - if len(name) == 0 && len(addr) == 0 { - p.Router = router.DefaultRouter - go p.Router.Advertise() - - // recursively execute getRoute - return p.getRoute(service) + // if the router is broken return error + if status := p.Router.Status(); status.Code == router.Error { + return nil, status.Error } - if len(name) == 0 { - name = "go.micro.router" + // lookup the routes in the router + results, err := p.Router.Lookup(table.NewQuery(table.QueryService(service))) + if err != nil { + return nil, err } - // lookup the remote router - - var addrs []string - - // set the remote address if specified - if len(addr) > 0 { - addrs = append(addrs, addr) - } else { - // we have a name so we need to check the registry - services, err := p.Client.Options().Registry.GetService(name) - if err != nil { - return nil, err - } - - for _, service := range services { - for _, node := range service.Nodes { - addrs = append(addrs, node.Address) - } - } - } - - // no router addresses available - if len(addrs) == 0 { - return nil, selector.ErrNoneAvailable - } - - var pbRoutes *pb.LookupResponse - var gerr error - - // set default client - if p.RouterService == nil { - p.RouterService = pb.NewRouterService(name, p.Client) - } - - // TODO: implement backoff and retries - for _, addr := range addrs { - // call the router - proutes, err := p.RouterService.Lookup(context.Background(), &pb.LookupRequest{ - Query: &pb.Query{ - Service: service, - }, - }, client.WithAddress(addr)) - if err != nil { - gerr = err - continue - } - // set routes - pbRoutes = proutes - break - } - - // errored out - if gerr != nil { - return nil, gerr - } - - // no routes - if pbRoutes == nil { - return nil, selector.ErrNoneAvailable - } - - // convert from pb to []*router.Route - for _, r := range pbRoutes.Routes { - routes = append(routes, table.Route{ - Service: r.Service, - Address: r.Address, - Gateway: r.Gateway, - Network: r.Network, - Link: r.Link, - Metric: int(r.Metric), - }) + // update the proxy cache + p.Lock() + for _, route := range results { + p.Routes[service][route.Hash()] = route } + routes = p.Routes[service] + p.Unlock() return toNodes(routes), nil } // ServeRequest honours the server.Router interface func (p *Proxy) ServeRequest(ctx context.Context, req server.Request, rsp server.Response) error { - // set default client - if p.Client == nil { - p.Client = client.DefaultClient - } - // service name service := req.Service() endpoint := req.Endpoint() @@ -342,13 +235,24 @@ func NewProxy(opts ...options.Option) proxy.Proxy { p.Client = c.(client.Client) } + // set the default client + if p.Client == nil { + p.Client = client.DefaultClient + } + // get router r, ok := p.Options.Values().Get("proxy.router") if ok { p.Router = r.(router.Router) - // TODO: should we advertise? - go p.Router.Advertise() } + // create default router and start it + if p.Router == nil { + p.Router = router.DefaultRouter + } + + // routes cache + p.Routes = make(map[string]map[uint64]table.Route) + return p } From 23f0231a098a71de58de5e5064b494feaec3947d Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Wed, 24 Jul 2019 19:03:13 +0100 Subject: [PATCH 202/287] Adds route watcher to mucp.Proxy --- network/proxy/mucp/mucp.go | 102 ++++++++++++++++++++++++++++++------- 1 file changed, 85 insertions(+), 17 deletions(-) diff --git a/network/proxy/mucp/mucp.go b/network/proxy/mucp/mucp.go index 96e3527f..d15118e3 100644 --- a/network/proxy/mucp/mucp.go +++ b/network/proxy/mucp/mucp.go @@ -3,6 +3,7 @@ package mucp import ( "context" + "fmt" "io" "strings" "sync" @@ -36,6 +37,9 @@ type Proxy struct { // A fib of routes service:address sync.RWMutex Routes map[string]map[uint64]table.Route + + // The channel to monitor watcher errors + errChan chan error } // read client request and write to server @@ -119,6 +123,55 @@ func (p *Proxy) getRoute(service string) ([]string, error) { return toNodes(routes), nil } +// manageRouteCache applies action on a given route to Proxy route cache +func (p *Proxy) manageRouteCache(route table.Route, action string) error { + switch action { + case "create", "update": + if _, ok := p.Routes[route.Service]; !ok { + p.Routes[route.Service] = make(map[uint64]table.Route) + } + p.Routes[route.Service][route.Hash()] = route + case "delete": + if _, ok := p.Routes[route.Service]; !ok { + return fmt.Errorf("route not found") + } + delete(p.Routes[route.Service], route.Hash()) + default: + return fmt.Errorf("unknown action: %s", action) + } + + return nil +} + +// watchRoutes watches service routes and updates proxy cache +func (p *Proxy) watchRoutes() { + // this is safe to do as the only way watchRoutes returns is + // when some error is written into error channel - we want to bail then + defer close(p.errChan) + + // route watcher + w, err := p.Router.Watch() + if err != nil { + p.errChan <- err + return + } + + for { + event, err := w.Next() + if err != nil { + p.errChan <- err + return + } + + p.Lock() + if err := p.manageRouteCache(event.Route, fmt.Sprintf("%s", event.Type)); err != nil { + // TODO: should we bail here? + continue + } + p.Unlock() + } +} + // ServeRequest honours the server.Router interface func (p *Proxy) ServeRequest(ctx context.Context, req server.Request, rsp server.Response) error { // service name @@ -181,28 +234,39 @@ func (p *Proxy) ServeRequest(ctx context.Context, req server.Request, rsp server // get raw response resp := stream.Response() + // route watcher error + var watchErr error + // create server response write loop for { - // read backend response body - body, err := resp.Read() - if err == io.EOF { - return nil - } else if err != nil { - return err - } + select { + case err := <-p.errChan: + if err != nil { + watchErr = err + } + return watchErr + default: + // read backend response body + body, err := resp.Read() + if err == io.EOF { + return nil + } else if err != nil { + return err + } - // read backend response header - hdr := resp.Header() + // read backend response header + hdr := resp.Header() - // write raw response header to client - rsp.WriteHeader(hdr) + // write raw response header to client + rsp.WriteHeader(hdr) - // write raw response body to client - err = rsp.Write(body) - if err == io.EOF { - return nil - } else if err != nil { - return err + // write raw response body to client + err = rsp.Write(body) + if err == io.EOF { + return nil + } else if err != nil { + return err + } } } @@ -254,5 +318,9 @@ func NewProxy(opts ...options.Option) proxy.Proxy { // routes cache p.Routes = make(map[string]map[uint64]table.Route) + // watch router service routes + p.errChan = make(chan error, 1) + go p.watchRoutes() + return p } From 809de7a052c7da8818accb4edbee39d9c8946a7f Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Wed, 24 Jul 2019 19:13:05 +0100 Subject: [PATCH 203/287] Mutex Unlock when we fail to store route in cache. --- network/proxy/mucp/mucp.go | 1 + 1 file changed, 1 insertion(+) diff --git a/network/proxy/mucp/mucp.go b/network/proxy/mucp/mucp.go index d15118e3..10e3669b 100644 --- a/network/proxy/mucp/mucp.go +++ b/network/proxy/mucp/mucp.go @@ -166,6 +166,7 @@ func (p *Proxy) watchRoutes() { p.Lock() if err := p.manageRouteCache(event.Route, fmt.Sprintf("%s", event.Type)); err != nil { // TODO: should we bail here? + p.Unlock() continue } p.Unlock() From 9ad5ae6644b3b4c1ed597e1231609fcb4535d953 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Wed, 24 Jul 2019 21:07:04 +0100 Subject: [PATCH 204/287] Adds new RPC methods to router service interface We have added Advertise() and Process() RPCs in this commit. --- network/router/proto/router.micro.go | 99 +++++++++++++++++++ network/router/proto/router.pb.go | 141 ++++++++++++++++++++------- network/router/proto/router.proto | 9 ++ 3 files changed, 213 insertions(+), 36 deletions(-) diff --git a/network/router/proto/router.micro.go b/network/router/proto/router.micro.go index 23b8087c..ea705d5f 100644 --- a/network/router/proto/router.micro.go +++ b/network/router/proto/router.micro.go @@ -37,6 +37,8 @@ type RouterService interface { Watch(ctx context.Context, in *WatchRequest, opts ...client.CallOption) (Router_WatchService, error) Lookup(ctx context.Context, in *LookupRequest, opts ...client.CallOption) (*LookupResponse, error) List(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*ListResponse, error) + Advertise(ctx context.Context, in *AdvertiseRequest, opts ...client.CallOption) (Router_AdvertiseService, error) + Process(ctx context.Context, in *Advert, opts ...client.CallOption) (*ProcessResponse, error) } type routerService struct { @@ -121,12 +123,68 @@ func (c *routerService) List(ctx context.Context, in *ListRequest, opts ...clien return out, nil } +func (c *routerService) Advertise(ctx context.Context, in *AdvertiseRequest, opts ...client.CallOption) (Router_AdvertiseService, error) { + req := c.c.NewRequest(c.name, "Router.Advertise", &AdvertiseRequest{}) + stream, err := c.c.Stream(ctx, req, opts...) + if err != nil { + return nil, err + } + if err := stream.Send(in); err != nil { + return nil, err + } + return &routerServiceAdvertise{stream}, nil +} + +type Router_AdvertiseService interface { + SendMsg(interface{}) error + RecvMsg(interface{}) error + Close() error + Recv() (*Advert, error) +} + +type routerServiceAdvertise struct { + stream client.Stream +} + +func (x *routerServiceAdvertise) Close() error { + return x.stream.Close() +} + +func (x *routerServiceAdvertise) SendMsg(m interface{}) error { + return x.stream.Send(m) +} + +func (x *routerServiceAdvertise) RecvMsg(m interface{}) error { + return x.stream.Recv(m) +} + +func (x *routerServiceAdvertise) Recv() (*Advert, error) { + m := new(Advert) + err := x.stream.Recv(m) + if err != nil { + return nil, err + } + return m, nil +} + +func (c *routerService) Process(ctx context.Context, in *Advert, opts ...client.CallOption) (*ProcessResponse, error) { + req := c.c.NewRequest(c.name, "Router.Process", in) + out := new(ProcessResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // Server API for Router service type RouterHandler interface { Watch(context.Context, *WatchRequest, Router_WatchStream) error Lookup(context.Context, *LookupRequest, *LookupResponse) error List(context.Context, *ListRequest, *ListResponse) error + Advertise(context.Context, *AdvertiseRequest, Router_AdvertiseStream) error + Process(context.Context, *Advert, *ProcessResponse) error } func RegisterRouterHandler(s server.Server, hdlr RouterHandler, opts ...server.HandlerOption) error { @@ -134,6 +192,8 @@ func RegisterRouterHandler(s server.Server, hdlr RouterHandler, opts ...server.H Watch(ctx context.Context, stream server.Stream) error Lookup(ctx context.Context, in *LookupRequest, out *LookupResponse) error List(ctx context.Context, in *ListRequest, out *ListResponse) error + Advertise(ctx context.Context, stream server.Stream) error + Process(ctx context.Context, in *Advert, out *ProcessResponse) error } type Router struct { router @@ -188,3 +248,42 @@ func (h *routerHandler) Lookup(ctx context.Context, in *LookupRequest, out *Look func (h *routerHandler) List(ctx context.Context, in *ListRequest, out *ListResponse) error { return h.RouterHandler.List(ctx, in, out) } + +func (h *routerHandler) Advertise(ctx context.Context, stream server.Stream) error { + m := new(AdvertiseRequest) + if err := stream.Recv(m); err != nil { + return err + } + return h.RouterHandler.Advertise(ctx, m, &routerAdvertiseStream{stream}) +} + +type Router_AdvertiseStream interface { + SendMsg(interface{}) error + RecvMsg(interface{}) error + Close() error + Send(*Advert) error +} + +type routerAdvertiseStream struct { + stream server.Stream +} + +func (x *routerAdvertiseStream) Close() error { + return x.stream.Close() +} + +func (x *routerAdvertiseStream) SendMsg(m interface{}) error { + return x.stream.Send(m) +} + +func (x *routerAdvertiseStream) RecvMsg(m interface{}) error { + return x.stream.Recv(m) +} + +func (x *routerAdvertiseStream) Send(m *Advert) error { + return x.stream.Send(m) +} + +func (h *routerHandler) Process(ctx context.Context, in *Advert, out *ProcessResponse) error { + return h.RouterHandler.Process(ctx, in, out) +} diff --git a/network/router/proto/router.pb.go b/network/router/proto/router.pb.go index bad0d1ec..1584f983 100644 --- a/network/router/proto/router.pb.go +++ b/network/router/proto/router.pb.go @@ -187,6 +187,38 @@ func (m *WatchRequest) XXX_DiscardUnknown() { var xxx_messageInfo_WatchRequest proto.InternalMessageInfo +// AdvertiseRequest request a stream of Adverts +type AdvertiseRequest struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AdvertiseRequest) Reset() { *m = AdvertiseRequest{} } +func (m *AdvertiseRequest) String() string { return proto.CompactTextString(m) } +func (*AdvertiseRequest) ProtoMessage() {} +func (*AdvertiseRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_367072455c71aedc, []int{3} +} + +func (m *AdvertiseRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AdvertiseRequest.Unmarshal(m, b) +} +func (m *AdvertiseRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AdvertiseRequest.Marshal(b, m, deterministic) +} +func (m *AdvertiseRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_AdvertiseRequest.Merge(m, src) +} +func (m *AdvertiseRequest) XXX_Size() int { + return xxx_messageInfo_AdvertiseRequest.Size(m) +} +func (m *AdvertiseRequest) XXX_DiscardUnknown() { + xxx_messageInfo_AdvertiseRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_AdvertiseRequest proto.InternalMessageInfo + // Advert is router advertsement streamed by Watch type Advert struct { // id of the advertising router @@ -208,7 +240,7 @@ func (m *Advert) Reset() { *m = Advert{} } func (m *Advert) String() string { return proto.CompactTextString(m) } func (*Advert) ProtoMessage() {} func (*Advert) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{3} + return fileDescriptor_367072455c71aedc, []int{4} } func (m *Advert) XXX_Unmarshal(b []byte) error { @@ -264,6 +296,38 @@ func (m *Advert) GetEvents() []*Event { return nil } +// ProcessResponse is returned by Process +type ProcessResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ProcessResponse) Reset() { *m = ProcessResponse{} } +func (m *ProcessResponse) String() string { return proto.CompactTextString(m) } +func (*ProcessResponse) ProtoMessage() {} +func (*ProcessResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_367072455c71aedc, []int{5} +} + +func (m *ProcessResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ProcessResponse.Unmarshal(m, b) +} +func (m *ProcessResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ProcessResponse.Marshal(b, m, deterministic) +} +func (m *ProcessResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ProcessResponse.Merge(m, src) +} +func (m *ProcessResponse) XXX_Size() int { + return xxx_messageInfo_ProcessResponse.Size(m) +} +func (m *ProcessResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ProcessResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_ProcessResponse proto.InternalMessageInfo + // Event is routing table event type Event struct { // type of event @@ -281,7 +345,7 @@ func (m *Event) Reset() { *m = Event{} } func (m *Event) String() string { return proto.CompactTextString(m) } func (*Event) ProtoMessage() {} func (*Event) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{4} + return fileDescriptor_367072455c71aedc, []int{6} } func (m *Event) XXX_Unmarshal(b []byte) error { @@ -334,7 +398,7 @@ func (m *ListRequest) Reset() { *m = ListRequest{} } func (m *ListRequest) String() string { return proto.CompactTextString(m) } func (*ListRequest) ProtoMessage() {} func (*ListRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{5} + return fileDescriptor_367072455c71aedc, []int{7} } func (m *ListRequest) XXX_Unmarshal(b []byte) error { @@ -367,7 +431,7 @@ func (m *ListResponse) Reset() { *m = ListResponse{} } func (m *ListResponse) String() string { return proto.CompactTextString(m) } func (*ListResponse) ProtoMessage() {} func (*ListResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{6} + return fileDescriptor_367072455c71aedc, []int{8} } func (m *ListResponse) XXX_Unmarshal(b []byte) error { @@ -408,7 +472,7 @@ func (m *Query) Reset() { *m = Query{} } func (m *Query) String() string { return proto.CompactTextString(m) } func (*Query) ProtoMessage() {} func (*Query) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{7} + return fileDescriptor_367072455c71aedc, []int{9} } func (m *Query) XXX_Unmarshal(b []byte) error { @@ -459,7 +523,7 @@ func (m *Route) Reset() { *m = Route{} } func (m *Route) String() string { return proto.CompactTextString(m) } func (*Route) ProtoMessage() {} func (*Route) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{8} + return fileDescriptor_367072455c71aedc, []int{10} } func (m *Route) XXX_Unmarshal(b []byte) error { @@ -528,7 +592,9 @@ func init() { proto.RegisterType((*LookupRequest)(nil), "LookupRequest") proto.RegisterType((*LookupResponse)(nil), "LookupResponse") proto.RegisterType((*WatchRequest)(nil), "WatchRequest") + proto.RegisterType((*AdvertiseRequest)(nil), "AdvertiseRequest") proto.RegisterType((*Advert)(nil), "Advert") + proto.RegisterType((*ProcessResponse)(nil), "ProcessResponse") proto.RegisterType((*Event)(nil), "Event") proto.RegisterType((*ListRequest)(nil), "ListRequest") proto.RegisterType((*ListResponse)(nil), "ListResponse") @@ -539,34 +605,37 @@ func init() { func init() { proto.RegisterFile("router.proto", fileDescriptor_367072455c71aedc) } var fileDescriptor_367072455c71aedc = []byte{ - // 461 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0x41, 0x8f, 0xd3, 0x4c, - 0x0c, 0xcd, 0xa4, 0x4d, 0x3e, 0xc5, 0x4d, 0xf3, 0x55, 0x3e, 0xa0, 0xa8, 0xaa, 0x96, 0x32, 0x12, - 0x52, 0xb5, 0x88, 0xb0, 0x2a, 0xbf, 0x60, 0x05, 0xdc, 0xf6, 0xc2, 0x08, 0xc4, 0x39, 0x24, 0x16, - 0x44, 0x6d, 0x93, 0xec, 0xcc, 0xa4, 0xab, 0xde, 0xb8, 0xf2, 0x1b, 0xf8, 0xb3, 0x68, 0x9c, 0x84, - 0x76, 0x91, 0x56, 0xe2, 0xe6, 0xf7, 0x6c, 0xc7, 0x9e, 0xf7, 0x1c, 0x88, 0x75, 0xd3, 0x59, 0xd2, - 0x59, 0xab, 0x1b, 0xdb, 0xc8, 0xd7, 0x30, 0xbf, 0x6b, 0x9a, 0x5d, 0xd7, 0x2a, 0xba, 0xef, 0xc8, - 0x58, 0x5c, 0x41, 0x70, 0xdf, 0x91, 0x3e, 0xa5, 0x62, 0x2d, 0x36, 0xb3, 0x6d, 0x98, 0x7d, 0x74, - 0x48, 0xf5, 0xa4, 0xbc, 0x81, 0x64, 0x2c, 0x37, 0x6d, 0x53, 0x1b, 0xc2, 0x2b, 0x08, 0xf9, 0x83, - 0x26, 0x15, 0xeb, 0x09, 0x37, 0x28, 0x07, 0xd5, 0xc0, 0xca, 0x04, 0xe2, 0x2f, 0xb9, 0x2d, 0xbe, - 0x0f, 0xdf, 0x97, 0x3f, 0x05, 0x84, 0xb7, 0xe5, 0x91, 0xb4, 0xc5, 0x04, 0xfc, 0xaa, 0xe4, 0x39, - 0x91, 0xf2, 0xab, 0x12, 0x9f, 0xc3, 0xd4, 0x9e, 0x5a, 0x4a, 0xfd, 0xb5, 0xd8, 0x24, 0xdb, 0x59, - 0xd6, 0x97, 0x7d, 0x3a, 0xb5, 0xa4, 0x38, 0x81, 0x2b, 0x88, 0x6c, 0x75, 0x20, 0x63, 0xf3, 0x43, - 0x9b, 0x4e, 0xd6, 0x62, 0x33, 0x51, 0x67, 0x02, 0x17, 0x30, 0xb1, 0x76, 0x9f, 0x4e, 0x99, 0x77, - 0xa1, 0xdb, 0x8d, 0x8e, 0x54, 0x5b, 0x93, 0x06, 0xc3, 0x6e, 0x1f, 0x1c, 0x54, 0x03, 0x2b, 0x0b, - 0x08, 0x98, 0xc0, 0xab, 0x61, 0xb2, 0xe0, 0xc9, 0xd0, 0x97, 0x3d, 0x35, 0xd8, 0xff, 0x7b, 0xf0, - 0x0a, 0x02, 0x7e, 0x2c, 0xaf, 0x74, 0x56, 0xa0, 0x27, 0xe5, 0x1c, 0x66, 0x77, 0x95, 0xb1, 0xe3, - 0xfb, 0x33, 0x88, 0x7b, 0xf8, 0x8f, 0xfa, 0xbd, 0x80, 0x80, 0x1d, 0xc0, 0x14, 0xfe, 0x33, 0xa4, - 0x8f, 0x55, 0x41, 0x83, 0x64, 0x23, 0x94, 0xbf, 0x04, 0x04, 0xdc, 0xf4, 0x74, 0x8d, 0xcb, 0xe4, - 0x65, 0xa9, 0xc9, 0x18, 0xde, 0x3f, 0x52, 0x23, 0x74, 0x99, 0x6f, 0xb9, 0xa5, 0x87, 0xfc, 0xc4, - 0xfb, 0x47, 0x6a, 0x84, 0x2e, 0x53, 0x93, 0x7d, 0x68, 0xf4, 0x8e, 0x45, 0x8d, 0xd4, 0x08, 0x11, - 0x61, 0xba, 0xaf, 0xea, 0x5d, 0x1a, 0x30, 0xcd, 0x31, 0x3e, 0x83, 0xf0, 0x40, 0x56, 0x57, 0x45, - 0x1a, 0xb2, 0x40, 0x03, 0xba, 0xde, 0x02, 0x9c, 0x8d, 0x44, 0x84, 0xa4, 0x47, 0xb7, 0x75, 0xdd, - 0x74, 0x75, 0x41, 0x0b, 0x0f, 0x17, 0x10, 0xf7, 0xdc, 0xe7, 0xb6, 0xcc, 0x2d, 0x2d, 0xc4, 0xf5, - 0x1b, 0x88, 0xfe, 0x58, 0x80, 0x00, 0xe1, 0x3b, 0x4d, 0x2e, 0xe1, 0xb9, 0xf8, 0x3d, 0xed, 0xc9, - 0x15, 0xb9, 0x78, 0x68, 0xf0, 0xb7, 0x3f, 0x04, 0x84, 0x2c, 0x81, 0x46, 0x09, 0x01, 0x1f, 0x1c, - 0xce, 0xb3, 0xcb, 0xc3, 0x5b, 0x0e, 0xe6, 0x4b, 0xef, 0x46, 0xe0, 0x2b, 0x08, 0xfb, 0x33, 0xc6, - 0x24, 0x7b, 0x74, 0xfe, 0xcb, 0xff, 0xb3, 0xc7, 0xf7, 0x2d, 0x3d, 0x7c, 0x09, 0x53, 0xe7, 0x18, - 0xc6, 0xd9, 0x85, 0x8f, 0xcb, 0x79, 0x76, 0x69, 0xa3, 0xf4, 0xbe, 0x86, 0xfc, 0x43, 0xbd, 0xfd, - 0x1d, 0x00, 0x00, 0xff, 0xff, 0x5e, 0x52, 0x2f, 0xa0, 0x60, 0x03, 0x00, 0x00, + // 508 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0x51, 0x6e, 0xd3, 0x40, + 0x10, 0xf5, 0x26, 0xb1, 0x2b, 0x4f, 0x13, 0xd7, 0x9d, 0x0f, 0x64, 0x45, 0x55, 0x09, 0x2b, 0x81, + 0xa2, 0x56, 0x2c, 0x55, 0x38, 0x41, 0x05, 0xfc, 0xf5, 0x03, 0x56, 0x20, 0xbe, 0x8d, 0x3d, 0x02, + 0x2b, 0x89, 0xed, 0xee, 0x6e, 0x52, 0xe5, 0x08, 0x9c, 0x81, 0x73, 0x71, 0x1f, 0xb4, 0xeb, 0x75, + 0x93, 0x46, 0xaa, 0xc4, 0xdf, 0xbc, 0x37, 0x33, 0xeb, 0xe7, 0x37, 0x33, 0x30, 0x56, 0xcd, 0xc6, + 0x90, 0x12, 0xad, 0x6a, 0x4c, 0xc3, 0xdf, 0xc2, 0xe4, 0xae, 0x69, 0x96, 0x9b, 0x56, 0xd2, 0xfd, + 0x86, 0xb4, 0xc1, 0x0b, 0x08, 0xef, 0x37, 0xa4, 0x76, 0x19, 0x9b, 0xb1, 0xf9, 0xe9, 0x22, 0x12, + 0x5f, 0x2c, 0x92, 0x1d, 0xc9, 0x6f, 0x20, 0xe9, 0xcb, 0x75, 0xdb, 0xd4, 0x9a, 0xf0, 0x12, 0x22, + 0xf7, 0xa0, 0xce, 0xd8, 0x6c, 0xe8, 0x1a, 0xa4, 0x85, 0xd2, 0xb3, 0x3c, 0x81, 0xf1, 0xf7, 0xdc, + 0x14, 0xbf, 0xfc, 0xfb, 0x1c, 0x21, 0xbd, 0x2d, 0xb7, 0xa4, 0x4c, 0xa5, 0xa9, 0xe7, 0x7e, 0x33, + 0x88, 0x3a, 0x12, 0x13, 0x18, 0x54, 0xa5, 0xfb, 0x76, 0x2c, 0x07, 0x55, 0x89, 0x2f, 0x61, 0x64, + 0x76, 0x2d, 0x65, 0x83, 0x19, 0x9b, 0x27, 0x8b, 0x53, 0xd1, 0x95, 0x7d, 0xdd, 0xb5, 0x24, 0x5d, + 0x02, 0x2f, 0x20, 0x36, 0xd5, 0x9a, 0xb4, 0xc9, 0xd7, 0x6d, 0x36, 0x9c, 0xb1, 0xf9, 0x50, 0xee, + 0x09, 0x4c, 0x61, 0x68, 0xcc, 0x2a, 0x1b, 0x39, 0xde, 0x86, 0x56, 0x2f, 0x6d, 0xa9, 0x36, 0x3a, + 0x0b, 0xbd, 0xde, 0x4f, 0x16, 0x4a, 0xcf, 0xf2, 0x73, 0x38, 0xfb, 0xac, 0x9a, 0x82, 0xb4, 0xee, + 0x7f, 0x91, 0x17, 0x10, 0xba, 0x1a, 0xbc, 0xf4, 0x62, 0x98, 0x13, 0x03, 0x5d, 0xe7, 0x73, 0x5a, + 0x06, 0xc7, 0x5a, 0x2e, 0x20, 0x74, 0x9e, 0x38, 0x95, 0x7b, 0xa3, 0x3a, 0x92, 0x4f, 0xe0, 0xf4, + 0xae, 0xd2, 0xa6, 0xb7, 0x44, 0xc0, 0xb8, 0x83, 0xff, 0x69, 0xf3, 0x2b, 0x08, 0xdd, 0xa0, 0x30, + 0x83, 0x13, 0x4d, 0x6a, 0x5b, 0x15, 0xe4, 0x5d, 0xec, 0x21, 0xff, 0xc3, 0x20, 0x74, 0x4d, 0xcf, + 0xd7, 0xd8, 0x4c, 0x5e, 0x96, 0x8a, 0xb4, 0x76, 0xfa, 0x63, 0xd9, 0x43, 0x9b, 0xf9, 0x99, 0x1b, + 0x7a, 0xc8, 0x77, 0x4e, 0x7f, 0x2c, 0x7b, 0x68, 0x33, 0x35, 0x99, 0x87, 0x46, 0x2d, 0x9d, 0xcf, + 0xb1, 0xec, 0x21, 0x22, 0x8c, 0x56, 0x55, 0xbd, 0xcc, 0x42, 0x47, 0xbb, 0x18, 0x5f, 0x40, 0xb4, + 0x26, 0xa3, 0xaa, 0x22, 0x8b, 0x9c, 0x41, 0x1e, 0x5d, 0x2d, 0x00, 0xf6, 0xb3, 0x45, 0x84, 0xa4, + 0x43, 0xb7, 0x75, 0xdd, 0x6c, 0xea, 0x82, 0xd2, 0x00, 0x53, 0x18, 0x77, 0xdc, 0xb7, 0xb6, 0xcc, + 0x0d, 0xa5, 0xec, 0xea, 0x1d, 0xc4, 0x8f, 0x23, 0x40, 0x80, 0xe8, 0x83, 0x22, 0x9b, 0x08, 0x6c, + 0xfc, 0x91, 0x56, 0x64, 0x8b, 0x6c, 0xec, 0x1b, 0x06, 0x8b, 0xbf, 0x0c, 0x22, 0x67, 0x81, 0x42, + 0x0e, 0xa1, 0xdb, 0x4b, 0x9c, 0x88, 0xc3, 0xfd, 0x9c, 0xfa, 0x7d, 0xe0, 0xc1, 0x0d, 0xc3, 0x6b, + 0x88, 0xba, 0x6d, 0xc7, 0x44, 0x3c, 0xb9, 0x92, 0xe9, 0x99, 0x78, 0x7a, 0x06, 0x3c, 0xc0, 0xd7, + 0x30, 0xb2, 0x13, 0xc3, 0xb1, 0x38, 0x98, 0xe3, 0x74, 0x22, 0x0e, 0xc7, 0xc8, 0x03, 0xbc, 0x86, + 0xf8, 0x71, 0xff, 0xf1, 0x5c, 0x1c, 0xdf, 0xc2, 0xf4, 0xc4, 0x53, 0x4e, 0xc0, 0x1b, 0x38, 0xf1, + 0xcb, 0x88, 0x3d, 0x3f, 0x4d, 0xc5, 0xf1, 0x7e, 0x06, 0x3f, 0x22, 0x77, 0xcc, 0xef, 0xff, 0x05, + 0x00, 0x00, 0xff, 0xff, 0x05, 0x67, 0xe4, 0x0e, 0xdc, 0x03, 0x00, 0x00, } diff --git a/network/router/proto/router.proto b/network/router/proto/router.proto index 55eacf71..cf775908 100644 --- a/network/router/proto/router.proto +++ b/network/router/proto/router.proto @@ -5,6 +5,8 @@ service Router { rpc Watch(WatchRequest) returns (stream Event) {}; rpc Lookup(LookupRequest) returns (LookupResponse) {}; rpc List(ListRequest) returns (ListResponse) {}; + rpc Advertise(AdvertiseRequest) returns (stream Advert) {}; + rpc Process(Advert) returns (ProcessResponse) {}; } // LookupRequest is made to Lookup @@ -20,6 +22,10 @@ message LookupResponse { // WatchRequest is made to Watch Router message WatchRequest {} + +// AdvertiseRequest request a stream of Adverts +message AdvertiseRequest {} + // AdvertType defines the type of advert enum AdvertType { AdvertAnnounce = 0; @@ -40,6 +46,9 @@ message Advert { repeated Event events = 5; } +// ProcessResponse is returned by Process +message ProcessResponse {} + // EventType defines the type of event enum EventType { Create = 0; From 7ca06f0c1d903d16df269f027495ddb9974ee5d8 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 26 Jul 2019 18:07:14 -0700 Subject: [PATCH 205/287] set router proto package name to go.micro.router --- network/router/proto/router.proto | 2 ++ 1 file changed, 2 insertions(+) diff --git a/network/router/proto/router.proto b/network/router/proto/router.proto index cf775908..eaa19b0e 100644 --- a/network/router/proto/router.proto +++ b/network/router/proto/router.proto @@ -1,5 +1,7 @@ syntax = "proto3"; +package go.micro.router; + // Router service is used by the proxy to lookup routes service Router { rpc Watch(WatchRequest) returns (stream Event) {}; From 4e27aac398431823eb634cd6d8c26d57e6952d9a Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 26 Jul 2019 18:07:36 -0700 Subject: [PATCH 206/287] regen router proto --- network/router/proto/router.micro.go | 6 +- network/router/proto/router.pb.go | 398 ++++++++++++++++++++++----- 2 files changed, 335 insertions(+), 69 deletions(-) diff --git a/network/router/proto/router.micro.go b/network/router/proto/router.micro.go index ea705d5f..5dc753e9 100644 --- a/network/router/proto/router.micro.go +++ b/network/router/proto/router.micro.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-micro. DO NOT EDIT. -// source: router.proto +// source: go-micro/network/router/proto/router.proto -package router +package go_micro_router import ( fmt "fmt" @@ -51,7 +51,7 @@ func NewRouterService(name string, c client.Client) RouterService { c = client.NewClient() } if len(name) == 0 { - name = "router" + name = "go.micro.router" } return &routerService{ c: c, diff --git a/network/router/proto/router.pb.go b/network/router/proto/router.pb.go index 1584f983..a15e1bd9 100644 --- a/network/router/proto/router.pb.go +++ b/network/router/proto/router.pb.go @@ -1,11 +1,13 @@ // Code generated by protoc-gen-go. DO NOT EDIT. -// source: router.proto +// source: go-micro/network/router/proto/router.proto -package router +package go_micro_router import ( + context "context" fmt "fmt" proto "github.com/golang/protobuf/proto" + grpc "google.golang.org/grpc" math "math" ) @@ -43,7 +45,7 @@ func (x AdvertType) String() string { } func (AdvertType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{0} + return fileDescriptor_fc08514fc6dadd29, []int{0} } // EventType defines the type of event @@ -72,7 +74,7 @@ func (x EventType) String() string { } func (EventType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{1} + return fileDescriptor_fc08514fc6dadd29, []int{1} } // LookupRequest is made to Lookup @@ -87,7 +89,7 @@ func (m *LookupRequest) Reset() { *m = LookupRequest{} } func (m *LookupRequest) String() string { return proto.CompactTextString(m) } func (*LookupRequest) ProtoMessage() {} func (*LookupRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{0} + return fileDescriptor_fc08514fc6dadd29, []int{0} } func (m *LookupRequest) XXX_Unmarshal(b []byte) error { @@ -127,7 +129,7 @@ func (m *LookupResponse) Reset() { *m = LookupResponse{} } func (m *LookupResponse) String() string { return proto.CompactTextString(m) } func (*LookupResponse) ProtoMessage() {} func (*LookupResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{1} + return fileDescriptor_fc08514fc6dadd29, []int{1} } func (m *LookupResponse) XXX_Unmarshal(b []byte) error { @@ -166,7 +168,7 @@ func (m *WatchRequest) Reset() { *m = WatchRequest{} } func (m *WatchRequest) String() string { return proto.CompactTextString(m) } func (*WatchRequest) ProtoMessage() {} func (*WatchRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{2} + return fileDescriptor_fc08514fc6dadd29, []int{2} } func (m *WatchRequest) XXX_Unmarshal(b []byte) error { @@ -198,7 +200,7 @@ func (m *AdvertiseRequest) Reset() { *m = AdvertiseRequest{} } func (m *AdvertiseRequest) String() string { return proto.CompactTextString(m) } func (*AdvertiseRequest) ProtoMessage() {} func (*AdvertiseRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{3} + return fileDescriptor_fc08514fc6dadd29, []int{3} } func (m *AdvertiseRequest) XXX_Unmarshal(b []byte) error { @@ -224,7 +226,7 @@ type Advert struct { // id of the advertising router Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // type of advertisement - Type AdvertType `protobuf:"varint,2,opt,name=type,proto3,enum=AdvertType" json:"type,omitempty"` + Type AdvertType `protobuf:"varint,2,opt,name=type,proto3,enum=go.micro.router.AdvertType" json:"type,omitempty"` // unix timestamp of the advertisement Timestamp int64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // TTL of the Advert @@ -240,7 +242,7 @@ func (m *Advert) Reset() { *m = Advert{} } func (m *Advert) String() string { return proto.CompactTextString(m) } func (*Advert) ProtoMessage() {} func (*Advert) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{4} + return fileDescriptor_fc08514fc6dadd29, []int{4} } func (m *Advert) XXX_Unmarshal(b []byte) error { @@ -307,7 +309,7 @@ func (m *ProcessResponse) Reset() { *m = ProcessResponse{} } func (m *ProcessResponse) String() string { return proto.CompactTextString(m) } func (*ProcessResponse) ProtoMessage() {} func (*ProcessResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{5} + return fileDescriptor_fc08514fc6dadd29, []int{5} } func (m *ProcessResponse) XXX_Unmarshal(b []byte) error { @@ -331,7 +333,7 @@ var xxx_messageInfo_ProcessResponse proto.InternalMessageInfo // Event is routing table event type Event struct { // type of event - Type EventType `protobuf:"varint,1,opt,name=type,proto3,enum=EventType" json:"type,omitempty"` + Type EventType `protobuf:"varint,1,opt,name=type,proto3,enum=go.micro.router.EventType" json:"type,omitempty"` // unix timestamp of event Timestamp int64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // service route @@ -345,7 +347,7 @@ func (m *Event) Reset() { *m = Event{} } func (m *Event) String() string { return proto.CompactTextString(m) } func (*Event) ProtoMessage() {} func (*Event) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{6} + return fileDescriptor_fc08514fc6dadd29, []int{6} } func (m *Event) XXX_Unmarshal(b []byte) error { @@ -398,7 +400,7 @@ func (m *ListRequest) Reset() { *m = ListRequest{} } func (m *ListRequest) String() string { return proto.CompactTextString(m) } func (*ListRequest) ProtoMessage() {} func (*ListRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{7} + return fileDescriptor_fc08514fc6dadd29, []int{7} } func (m *ListRequest) XXX_Unmarshal(b []byte) error { @@ -431,7 +433,7 @@ func (m *ListResponse) Reset() { *m = ListResponse{} } func (m *ListResponse) String() string { return proto.CompactTextString(m) } func (*ListResponse) ProtoMessage() {} func (*ListResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{8} + return fileDescriptor_fc08514fc6dadd29, []int{8} } func (m *ListResponse) XXX_Unmarshal(b []byte) error { @@ -472,7 +474,7 @@ func (m *Query) Reset() { *m = Query{} } func (m *Query) String() string { return proto.CompactTextString(m) } func (*Query) ProtoMessage() {} func (*Query) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{9} + return fileDescriptor_fc08514fc6dadd29, []int{9} } func (m *Query) XXX_Unmarshal(b []byte) error { @@ -523,7 +525,7 @@ func (m *Route) Reset() { *m = Route{} } func (m *Route) String() string { return proto.CompactTextString(m) } func (*Route) ProtoMessage() {} func (*Route) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{10} + return fileDescriptor_fc08514fc6dadd29, []int{10} } func (m *Route) XXX_Unmarshal(b []byte) error { @@ -587,55 +589,319 @@ func (m *Route) GetMetric() int64 { } func init() { - proto.RegisterEnum("AdvertType", AdvertType_name, AdvertType_value) - proto.RegisterEnum("EventType", EventType_name, EventType_value) - proto.RegisterType((*LookupRequest)(nil), "LookupRequest") - proto.RegisterType((*LookupResponse)(nil), "LookupResponse") - proto.RegisterType((*WatchRequest)(nil), "WatchRequest") - proto.RegisterType((*AdvertiseRequest)(nil), "AdvertiseRequest") - proto.RegisterType((*Advert)(nil), "Advert") - proto.RegisterType((*ProcessResponse)(nil), "ProcessResponse") - proto.RegisterType((*Event)(nil), "Event") - proto.RegisterType((*ListRequest)(nil), "ListRequest") - proto.RegisterType((*ListResponse)(nil), "ListResponse") - proto.RegisterType((*Query)(nil), "Query") - proto.RegisterType((*Route)(nil), "Route") + proto.RegisterEnum("go.micro.router.AdvertType", AdvertType_name, AdvertType_value) + proto.RegisterEnum("go.micro.router.EventType", EventType_name, EventType_value) + proto.RegisterType((*LookupRequest)(nil), "go.micro.router.LookupRequest") + proto.RegisterType((*LookupResponse)(nil), "go.micro.router.LookupResponse") + proto.RegisterType((*WatchRequest)(nil), "go.micro.router.WatchRequest") + proto.RegisterType((*AdvertiseRequest)(nil), "go.micro.router.AdvertiseRequest") + proto.RegisterType((*Advert)(nil), "go.micro.router.Advert") + proto.RegisterType((*ProcessResponse)(nil), "go.micro.router.ProcessResponse") + proto.RegisterType((*Event)(nil), "go.micro.router.Event") + proto.RegisterType((*ListRequest)(nil), "go.micro.router.ListRequest") + proto.RegisterType((*ListResponse)(nil), "go.micro.router.ListResponse") + proto.RegisterType((*Query)(nil), "go.micro.router.Query") + proto.RegisterType((*Route)(nil), "go.micro.router.Route") } -func init() { proto.RegisterFile("router.proto", fileDescriptor_367072455c71aedc) } - -var fileDescriptor_367072455c71aedc = []byte{ - // 508 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0x51, 0x6e, 0xd3, 0x40, - 0x10, 0xf5, 0x26, 0xb1, 0x2b, 0x4f, 0x13, 0xd7, 0x9d, 0x0f, 0x64, 0x45, 0x55, 0x09, 0x2b, 0x81, - 0xa2, 0x56, 0x2c, 0x55, 0x38, 0x41, 0x05, 0xfc, 0xf5, 0x03, 0x56, 0x20, 0xbe, 0x8d, 0x3d, 0x02, - 0x2b, 0x89, 0xed, 0xee, 0x6e, 0x52, 0xe5, 0x08, 0x9c, 0x81, 0x73, 0x71, 0x1f, 0xb4, 0xeb, 0x75, - 0x93, 0x46, 0xaa, 0xc4, 0xdf, 0xbc, 0x37, 0x33, 0xeb, 0xe7, 0x37, 0x33, 0x30, 0x56, 0xcd, 0xc6, - 0x90, 0x12, 0xad, 0x6a, 0x4c, 0xc3, 0xdf, 0xc2, 0xe4, 0xae, 0x69, 0x96, 0x9b, 0x56, 0xd2, 0xfd, - 0x86, 0xb4, 0xc1, 0x0b, 0x08, 0xef, 0x37, 0xa4, 0x76, 0x19, 0x9b, 0xb1, 0xf9, 0xe9, 0x22, 0x12, - 0x5f, 0x2c, 0x92, 0x1d, 0xc9, 0x6f, 0x20, 0xe9, 0xcb, 0x75, 0xdb, 0xd4, 0x9a, 0xf0, 0x12, 0x22, - 0xf7, 0xa0, 0xce, 0xd8, 0x6c, 0xe8, 0x1a, 0xa4, 0x85, 0xd2, 0xb3, 0x3c, 0x81, 0xf1, 0xf7, 0xdc, - 0x14, 0xbf, 0xfc, 0xfb, 0x1c, 0x21, 0xbd, 0x2d, 0xb7, 0xa4, 0x4c, 0xa5, 0xa9, 0xe7, 0x7e, 0x33, - 0x88, 0x3a, 0x12, 0x13, 0x18, 0x54, 0xa5, 0xfb, 0x76, 0x2c, 0x07, 0x55, 0x89, 0x2f, 0x61, 0x64, - 0x76, 0x2d, 0x65, 0x83, 0x19, 0x9b, 0x27, 0x8b, 0x53, 0xd1, 0x95, 0x7d, 0xdd, 0xb5, 0x24, 0x5d, - 0x02, 0x2f, 0x20, 0x36, 0xd5, 0x9a, 0xb4, 0xc9, 0xd7, 0x6d, 0x36, 0x9c, 0xb1, 0xf9, 0x50, 0xee, - 0x09, 0x4c, 0x61, 0x68, 0xcc, 0x2a, 0x1b, 0x39, 0xde, 0x86, 0x56, 0x2f, 0x6d, 0xa9, 0x36, 0x3a, - 0x0b, 0xbd, 0xde, 0x4f, 0x16, 0x4a, 0xcf, 0xf2, 0x73, 0x38, 0xfb, 0xac, 0x9a, 0x82, 0xb4, 0xee, - 0x7f, 0x91, 0x17, 0x10, 0xba, 0x1a, 0xbc, 0xf4, 0x62, 0x98, 0x13, 0x03, 0x5d, 0xe7, 0x73, 0x5a, - 0x06, 0xc7, 0x5a, 0x2e, 0x20, 0x74, 0x9e, 0x38, 0x95, 0x7b, 0xa3, 0x3a, 0x92, 0x4f, 0xe0, 0xf4, - 0xae, 0xd2, 0xa6, 0xb7, 0x44, 0xc0, 0xb8, 0x83, 0xff, 0x69, 0xf3, 0x2b, 0x08, 0xdd, 0xa0, 0x30, - 0x83, 0x13, 0x4d, 0x6a, 0x5b, 0x15, 0xe4, 0x5d, 0xec, 0x21, 0xff, 0xc3, 0x20, 0x74, 0x4d, 0xcf, - 0xd7, 0xd8, 0x4c, 0x5e, 0x96, 0x8a, 0xb4, 0x76, 0xfa, 0x63, 0xd9, 0x43, 0x9b, 0xf9, 0x99, 0x1b, - 0x7a, 0xc8, 0x77, 0x4e, 0x7f, 0x2c, 0x7b, 0x68, 0x33, 0x35, 0x99, 0x87, 0x46, 0x2d, 0x9d, 0xcf, - 0xb1, 0xec, 0x21, 0x22, 0x8c, 0x56, 0x55, 0xbd, 0xcc, 0x42, 0x47, 0xbb, 0x18, 0x5f, 0x40, 0xb4, - 0x26, 0xa3, 0xaa, 0x22, 0x8b, 0x9c, 0x41, 0x1e, 0x5d, 0x2d, 0x00, 0xf6, 0xb3, 0x45, 0x84, 0xa4, - 0x43, 0xb7, 0x75, 0xdd, 0x6c, 0xea, 0x82, 0xd2, 0x00, 0x53, 0x18, 0x77, 0xdc, 0xb7, 0xb6, 0xcc, - 0x0d, 0xa5, 0xec, 0xea, 0x1d, 0xc4, 0x8f, 0x23, 0x40, 0x80, 0xe8, 0x83, 0x22, 0x9b, 0x08, 0x6c, - 0xfc, 0x91, 0x56, 0x64, 0x8b, 0x6c, 0xec, 0x1b, 0x06, 0x8b, 0xbf, 0x0c, 0x22, 0x67, 0x81, 0x42, - 0x0e, 0xa1, 0xdb, 0x4b, 0x9c, 0x88, 0xc3, 0xfd, 0x9c, 0xfa, 0x7d, 0xe0, 0xc1, 0x0d, 0xc3, 0x6b, - 0x88, 0xba, 0x6d, 0xc7, 0x44, 0x3c, 0xb9, 0x92, 0xe9, 0x99, 0x78, 0x7a, 0x06, 0x3c, 0xc0, 0xd7, - 0x30, 0xb2, 0x13, 0xc3, 0xb1, 0x38, 0x98, 0xe3, 0x74, 0x22, 0x0e, 0xc7, 0xc8, 0x03, 0xbc, 0x86, - 0xf8, 0x71, 0xff, 0xf1, 0x5c, 0x1c, 0xdf, 0xc2, 0xf4, 0xc4, 0x53, 0x4e, 0xc0, 0x1b, 0x38, 0xf1, - 0xcb, 0x88, 0x3d, 0x3f, 0x4d, 0xc5, 0xf1, 0x7e, 0x06, 0x3f, 0x22, 0x77, 0xcc, 0xef, 0xff, 0x05, - 0x00, 0x00, 0xff, 0xff, 0x05, 0x67, 0xe4, 0x0e, 0xdc, 0x03, 0x00, 0x00, +func init() { + proto.RegisterFile("go-micro/network/router/proto/router.proto", fileDescriptor_fc08514fc6dadd29) +} + +var fileDescriptor_fc08514fc6dadd29 = []byte{ + // 553 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0xc1, 0x6e, 0xd3, 0x40, + 0x10, 0x8d, 0x9d, 0xd8, 0x95, 0xa7, 0x6d, 0x1a, 0xe6, 0x50, 0x2c, 0xd3, 0x42, 0xea, 0x53, 0x55, + 0x15, 0x07, 0x85, 0x33, 0x88, 0x02, 0xe5, 0xd2, 0x1e, 0xc0, 0x02, 0x71, 0x36, 0xf6, 0x28, 0x58, + 0x49, 0xbc, 0xee, 0xee, 0x26, 0x55, 0xce, 0x7c, 0x06, 0x5f, 0xc0, 0x07, 0x72, 0x47, 0x3b, 0xb6, + 0x13, 0x48, 0xea, 0x0b, 0xa7, 0xec, 0x9b, 0xf7, 0x66, 0x3d, 0x33, 0x3b, 0x2f, 0x70, 0x31, 0x11, + 0xcf, 0xe7, 0x79, 0x2a, 0xc5, 0xa8, 0x20, 0x7d, 0x2f, 0xe4, 0x74, 0x24, 0xc5, 0x42, 0x93, 0x1c, + 0x95, 0x52, 0x68, 0x51, 0x83, 0x88, 0x01, 0x1e, 0x4d, 0x44, 0xc4, 0xda, 0xa8, 0x0a, 0x87, 0xaf, + 0xe0, 0xf0, 0x56, 0x88, 0xe9, 0xa2, 0x8c, 0xe9, 0x6e, 0x41, 0x4a, 0xe3, 0x25, 0x38, 0x77, 0x0b, + 0x92, 0x2b, 0xdf, 0x1a, 0x5a, 0xe7, 0xfb, 0xe3, 0xe3, 0x68, 0x2b, 0x23, 0xfa, 0x64, 0xd8, 0xb8, + 0x12, 0x85, 0x6f, 0xa0, 0xdf, 0xa4, 0xab, 0x52, 0x14, 0x8a, 0x30, 0x02, 0x97, 0x85, 0xca, 0xb7, + 0x86, 0xdd, 0x07, 0x2f, 0x88, 0xcd, 0x4f, 0x5c, 0xab, 0xc2, 0x3e, 0x1c, 0x7c, 0x4d, 0x74, 0xfa, + 0xbd, 0xfe, 0x7e, 0x88, 0x30, 0xb8, 0xca, 0x96, 0x24, 0x75, 0xae, 0xa8, 0x89, 0xfd, 0xb2, 0xc0, + 0xad, 0x82, 0xd8, 0x07, 0x3b, 0xcf, 0xb8, 0x36, 0x2f, 0xb6, 0xf3, 0x0c, 0x47, 0xd0, 0xd3, 0xab, + 0x92, 0x7c, 0x7b, 0x68, 0x9d, 0xf7, 0xc7, 0x4f, 0x76, 0x3e, 0x56, 0xa5, 0x7d, 0x5e, 0x95, 0x14, + 0xb3, 0x10, 0x4f, 0xc0, 0xd3, 0xf9, 0x9c, 0x94, 0x4e, 0xe6, 0xa5, 0xdf, 0x1d, 0x5a, 0xe7, 0xdd, + 0x78, 0x13, 0xc0, 0x01, 0x74, 0xb5, 0x9e, 0xf9, 0x3d, 0x8e, 0x9b, 0xa3, 0xe9, 0x87, 0x96, 0x54, + 0x68, 0xe5, 0x3b, 0x2d, 0xfd, 0x5c, 0x1b, 0x3a, 0xae, 0x55, 0xe1, 0x23, 0x38, 0xfa, 0x28, 0x45, + 0x4a, 0x4a, 0x35, 0x23, 0x09, 0x7f, 0x58, 0xe0, 0xb0, 0x08, 0xa3, 0xba, 0x5a, 0x8b, 0xab, 0x0d, + 0x1e, 0xbe, 0xaa, 0xad, 0x58, 0x7b, 0xbb, 0xd8, 0x4b, 0x70, 0x38, 0x8f, 0xdb, 0x68, 0x9f, 0x74, + 0x25, 0x0a, 0x0f, 0x61, 0xff, 0x36, 0x57, 0xba, 0x99, 0xe9, 0x6b, 0x38, 0xa8, 0xe0, 0x7f, 0xbe, + 0xdb, 0x19, 0x38, 0xbc, 0x09, 0xe8, 0xc3, 0x9e, 0x22, 0xb9, 0xcc, 0x53, 0xaa, 0x9f, 0xa5, 0x81, + 0xe1, 0x4f, 0x0b, 0x1c, 0x4e, 0x6a, 0xd7, 0x18, 0x26, 0xc9, 0x32, 0x49, 0x4a, 0x71, 0x7f, 0x5e, + 0xdc, 0x40, 0xc3, 0x4c, 0x12, 0x4d, 0xf7, 0xc9, 0x8a, 0xfb, 0xf3, 0xe2, 0x06, 0x1a, 0xa6, 0xde, + 0x74, 0x7e, 0x28, 0x2f, 0x6e, 0x20, 0x22, 0xf4, 0x66, 0x79, 0x31, 0xf5, 0x1d, 0x0e, 0xf3, 0x19, + 0x8f, 0xc1, 0x9d, 0x93, 0x96, 0x79, 0xea, 0xbb, 0x3c, 0xc0, 0x1a, 0x5d, 0x8c, 0x01, 0x36, 0xcb, + 0x81, 0x08, 0xfd, 0x0a, 0x5d, 0x15, 0x85, 0x58, 0x14, 0x29, 0x0d, 0x3a, 0x38, 0x80, 0x83, 0x2a, + 0xf6, 0xa5, 0xcc, 0x12, 0x4d, 0x03, 0xeb, 0x62, 0x04, 0xde, 0xfa, 0x89, 0x10, 0xc0, 0x7d, 0x27, + 0xc9, 0x10, 0x1d, 0x73, 0x7e, 0x4f, 0x33, 0x32, 0x22, 0x73, 0xae, 0x13, 0xec, 0xf1, 0x6f, 0x1b, + 0x5c, 0x1e, 0x81, 0xc4, 0xb7, 0xe0, 0xf0, 0xa2, 0xe3, 0xe9, 0xce, 0x64, 0xff, 0x36, 0x40, 0xd0, + 0xb2, 0x60, 0x61, 0xe7, 0x85, 0x85, 0x37, 0xe0, 0x56, 0x76, 0xc3, 0xa7, 0x3b, 0xaa, 0x7f, 0x6c, + 0x1c, 0x3c, 0x6b, 0xe5, 0xeb, 0xa5, 0xec, 0xe0, 0x35, 0xf4, 0xcc, 0x06, 0xe0, 0xc9, 0xae, 0x74, + 0xb3, 0x27, 0xc1, 0x69, 0x0b, 0xbb, 0xbe, 0xe6, 0x06, 0xbc, 0xb5, 0x61, 0xf1, 0xac, 0xc5, 0x80, + 0x1b, 0x33, 0x07, 0x8f, 0x5b, 0x24, 0xdc, 0xe0, 0x07, 0xd8, 0xab, 0xdd, 0x83, 0x6d, 0xba, 0x60, + 0xb8, 0x43, 0x6c, 0x1b, 0xae, 0xf3, 0xcd, 0xe5, 0xbf, 0xbb, 0x97, 0x7f, 0x02, 0x00, 0x00, 0xff, + 0xff, 0x99, 0x8e, 0xb9, 0x97, 0x1c, 0x05, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// RouterClient is the client API for Router service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type RouterClient interface { + Watch(ctx context.Context, in *WatchRequest, opts ...grpc.CallOption) (Router_WatchClient, error) + Lookup(ctx context.Context, in *LookupRequest, opts ...grpc.CallOption) (*LookupResponse, error) + List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (*ListResponse, error) + Advertise(ctx context.Context, in *AdvertiseRequest, opts ...grpc.CallOption) (Router_AdvertiseClient, error) + Process(ctx context.Context, in *Advert, opts ...grpc.CallOption) (*ProcessResponse, error) +} + +type routerClient struct { + cc *grpc.ClientConn +} + +func NewRouterClient(cc *grpc.ClientConn) RouterClient { + return &routerClient{cc} +} + +func (c *routerClient) Watch(ctx context.Context, in *WatchRequest, opts ...grpc.CallOption) (Router_WatchClient, error) { + stream, err := c.cc.NewStream(ctx, &_Router_serviceDesc.Streams[0], "/go.micro.router.Router/Watch", opts...) + if err != nil { + return nil, err + } + x := &routerWatchClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type Router_WatchClient interface { + Recv() (*Event, error) + grpc.ClientStream +} + +type routerWatchClient struct { + grpc.ClientStream +} + +func (x *routerWatchClient) Recv() (*Event, error) { + m := new(Event) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *routerClient) Lookup(ctx context.Context, in *LookupRequest, opts ...grpc.CallOption) (*LookupResponse, error) { + out := new(LookupResponse) + err := c.cc.Invoke(ctx, "/go.micro.router.Router/Lookup", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *routerClient) List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (*ListResponse, error) { + out := new(ListResponse) + err := c.cc.Invoke(ctx, "/go.micro.router.Router/List", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *routerClient) Advertise(ctx context.Context, in *AdvertiseRequest, opts ...grpc.CallOption) (Router_AdvertiseClient, error) { + stream, err := c.cc.NewStream(ctx, &_Router_serviceDesc.Streams[1], "/go.micro.router.Router/Advertise", opts...) + if err != nil { + return nil, err + } + x := &routerAdvertiseClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type Router_AdvertiseClient interface { + Recv() (*Advert, error) + grpc.ClientStream +} + +type routerAdvertiseClient struct { + grpc.ClientStream +} + +func (x *routerAdvertiseClient) Recv() (*Advert, error) { + m := new(Advert) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *routerClient) Process(ctx context.Context, in *Advert, opts ...grpc.CallOption) (*ProcessResponse, error) { + out := new(ProcessResponse) + err := c.cc.Invoke(ctx, "/go.micro.router.Router/Process", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// RouterServer is the server API for Router service. +type RouterServer interface { + Watch(*WatchRequest, Router_WatchServer) error + Lookup(context.Context, *LookupRequest) (*LookupResponse, error) + List(context.Context, *ListRequest) (*ListResponse, error) + Advertise(*AdvertiseRequest, Router_AdvertiseServer) error + Process(context.Context, *Advert) (*ProcessResponse, error) +} + +func RegisterRouterServer(s *grpc.Server, srv RouterServer) { + s.RegisterService(&_Router_serviceDesc, srv) +} + +func _Router_Watch_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(WatchRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(RouterServer).Watch(m, &routerWatchServer{stream}) +} + +type Router_WatchServer interface { + Send(*Event) error + grpc.ServerStream +} + +type routerWatchServer struct { + grpc.ServerStream +} + +func (x *routerWatchServer) Send(m *Event) error { + return x.ServerStream.SendMsg(m) +} + +func _Router_Lookup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(LookupRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RouterServer).Lookup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/go.micro.router.Router/Lookup", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RouterServer).Lookup(ctx, req.(*LookupRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Router_List_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RouterServer).List(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/go.micro.router.Router/List", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RouterServer).List(ctx, req.(*ListRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Router_Advertise_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(AdvertiseRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(RouterServer).Advertise(m, &routerAdvertiseServer{stream}) +} + +type Router_AdvertiseServer interface { + Send(*Advert) error + grpc.ServerStream +} + +type routerAdvertiseServer struct { + grpc.ServerStream +} + +func (x *routerAdvertiseServer) Send(m *Advert) error { + return x.ServerStream.SendMsg(m) +} + +func _Router_Process_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Advert) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RouterServer).Process(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/go.micro.router.Router/Process", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RouterServer).Process(ctx, req.(*Advert)) + } + return interceptor(ctx, in, info, handler) +} + +var _Router_serviceDesc = grpc.ServiceDesc{ + ServiceName: "go.micro.router.Router", + HandlerType: (*RouterServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Lookup", + Handler: _Router_Lookup_Handler, + }, + { + MethodName: "List", + Handler: _Router_List_Handler, + }, + { + MethodName: "Process", + Handler: _Router_Process_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "Watch", + Handler: _Router_Watch_Handler, + ServerStreams: true, + }, + { + StreamName: "Advertise", + Handler: _Router_Advertise_Handler, + ServerStreams: true, + }, + }, + Metadata: "go-micro/network/router/proto/router.proto", } From 100cb9db6b844ec900919b19bfaf291d72e2aecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E4=B8=89?= <32760011+three-zhang@users.noreply.github.com> Date: Sat, 27 Jul 2019 11:11:16 +0800 Subject: [PATCH 207/287] fix bug https://github.com/micro/micro/issues/293 Send request failed using micro Content-Type application/grpc+json --- client/grpc/grpc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/grpc/grpc.go b/client/grpc/grpc.go index 7f389012..6f5c3789 100644 --- a/client/grpc/grpc.go +++ b/client/grpc/grpc.go @@ -127,7 +127,7 @@ func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.R ch := make(chan error, 1) go func() { - err := cc.Invoke(ctx, methodToGRPC(req.Service(), req.Endpoint()), req.Body(), rsp, grpc.ForceCodec(cf)) + err := cc.Invoke(ctx, methodToGRPC(req.Service(), req.Endpoint()), req.Body(), rsp, grpc.CallContentSubtype(cf.Name())) ch <- microError(err) }() From e22c4b4c07c8b3affbc959b5f504725a4e35ac4f Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Thu, 25 Jul 2019 23:19:05 +0100 Subject: [PATCH 208/287] table package is no more. Cleaned up unnecessary code, too. --- network/router/default.go | 61 ++++----- network/router/options.go | 9 +- network/router/{table => }/query.go | 36 +---- network/router/{table => }/route.go | 2 +- network/router/route_test.go | 24 ++++ network/router/router.go | 34 ++++- network/router/{table/default.go => table.go} | 128 +++++++----------- network/router/table/table.go | 38 ------ .../{table/default_test.go => table_test.go} | 42 +----- network/router/{table => }/watcher.go | 13 +- 10 files changed, 143 insertions(+), 244 deletions(-) rename network/router/{table => }/query.go (63%) rename network/router/{table => }/route.go (98%) create mode 100644 network/router/route_test.go rename network/router/{table/default.go => table.go} (54%) delete mode 100644 network/router/table/table.go rename network/router/{table/default_test.go => table_test.go} (78%) rename network/router/{table => }/watcher.go (88%) diff --git a/network/router/default.go b/network/router/default.go index 9340e8df..cf98da3c 100644 --- a/network/router/default.go +++ b/network/router/default.go @@ -8,7 +8,6 @@ import ( "sync" "time" - "github.com/micro/go-micro/network/router/table" "github.com/micro/go-micro/registry" ) @@ -43,12 +42,12 @@ var ( // router implements default router type router struct { // embed the table - table.Table + *Table opts Options status Status exit chan struct{} errChan chan error - eventChan chan *table.Event + eventChan chan *Event advertChan chan *Advert advertWg *sync.WaitGroup wg *sync.WaitGroup @@ -92,18 +91,18 @@ func (r *router) Options() Options { } // manageRoute applies action on a given route -func (r *router) manageRoute(route table.Route, action string) error { +func (r *router) manageRoute(route Route, action string) error { switch action { case "create": - if err := r.Create(route); err != nil && err != table.ErrDuplicateRoute { + if err := r.Create(route); err != nil && err != ErrDuplicateRoute { return fmt.Errorf("failed adding route for service %s: %s", route.Service, err) } case "update": - if err := r.Update(route); err != nil && err != table.ErrDuplicateRoute { + if err := r.Update(route); err != nil && err != ErrDuplicateRoute { return fmt.Errorf("failed updating route for service %s: %s", route.Service, err) } case "delete": - if err := r.Delete(route); err != nil && err != table.ErrRouteNotFound { + if err := r.Delete(route); err != nil && err != ErrRouteNotFound { return fmt.Errorf("failed deleting route for service %s: %s", route.Service, err) } default: @@ -121,13 +120,13 @@ func (r *router) manageServiceRoutes(service *registry.Service, action string) e // take route action on each service node for _, node := range service.Nodes { - route := table.Route{ + route := Route{ Service: service.Name, Address: node.Address, Gateway: "", Network: r.opts.Network, - Link: table.DefaultLink, - Metric: table.DefaultLocalMetric, + Link: DefaultLink, + Metric: DefaultLocalMetric, } if err := r.manageRoute(route, action); err != nil { @@ -197,7 +196,7 @@ func (r *router) watchRegistry(w registry.Watcher) error { // watchTable watches routing table entries and either adds or deletes locally registered service to/from network registry // It returns error if the locally registered services either fails to be added/deleted to/from network registry. -func (r *router) watchTable(w table.Watcher) error { +func (r *router) watchTable(w Watcher) error { // wait in the background for the router to stop // when the router stops, stop the watcher and exit r.wg.Add(1) @@ -212,7 +211,7 @@ func (r *router) watchTable(w table.Watcher) error { for { event, err := w.Next() if err != nil { - if err != table.ErrWatcherStopped { + if err != ErrWatcherStopped { watchErr = err } break @@ -234,7 +233,7 @@ func (r *router) watchTable(w table.Watcher) error { // publishAdvert publishes router advert to advert channel // NOTE: this might cease to be a dedicated method in the future -func (r *router) publishAdvert(advType AdvertType, events []*table.Event) { +func (r *router) publishAdvert(advType AdvertType, events []*Event) { defer r.advertWg.Done() a := &Advert{ @@ -266,10 +265,10 @@ func (r *router) advertiseTable() error { return fmt.Errorf("failed listing routes: %s", err) } // collect all the added routes before we attempt to add default gateway - events := make([]*table.Event, len(routes)) + events := make([]*Event, len(routes)) for i, route := range routes { - event := &table.Event{ - Type: table.Update, + event := &Event{ + Type: Update, Timestamp: time.Now(), Route: route, } @@ -279,7 +278,7 @@ func (r *router) advertiseTable() error { // advertise all routes as Update events to subscribers if len(events) > 0 { r.advertWg.Add(1) - go r.publishAdvert(Update, events) + go r.publishAdvert(RouteUpdate, events) } case <-r.exit: return nil @@ -289,7 +288,7 @@ func (r *router) advertiseTable() error { // routeAdvert contains a list of route events to be advertised type routeAdvert struct { - events []*table.Event + events []*Event // lastUpdate records the time of the last advert update lastUpdate time.Time // penalty is current advert penalty @@ -326,7 +325,7 @@ func (r *router) advertiseEvents() error { for { select { case <-ticker.C: - var events []*table.Event + var events []*Event // collect all events which are not flapping for key, advert := range advertMap { // decay the event penalty @@ -352,7 +351,7 @@ func (r *router) advertiseEvents() error { if !advert.isSuppressed { for _, event := range advert.events { - e := new(table.Event) + e := new(Event) *e = *event events = append(events, e) // delete the advert from the advertMap @@ -364,7 +363,7 @@ func (r *router) advertiseEvents() error { // advertise all Update events to subscribers if len(events) > 0 { r.advertWg.Add(1) - go r.publishAdvert(Update, events) + go r.publishAdvert(RouteUpdate, events) } case e := <-r.eventChan: // if event is nil, continue @@ -375,9 +374,9 @@ func (r *router) advertiseEvents() error { // determine the event penalty var penalty float64 switch e.Type { - case table.Update: + case Update: penalty = UpdatePenalty - case table.Delete: + case Delete: penalty = DeletePenalty } @@ -386,7 +385,7 @@ func (r *router) advertiseEvents() error { hash := e.Route.Hash() advert, ok := advertMap[hash] if !ok { - events := []*table.Event{e} + events := []*Event{e} advert = &routeAdvert{ events: events, penalty: penalty, @@ -462,12 +461,12 @@ func (r *router) run() { // add default gateway into routing table if r.opts.Gateway != "" { // note, the only non-default value is the gateway - route := table.Route{ + route := Route{ Service: "*", Address: "*", Gateway: r.opts.Gateway, Network: "*", - Metric: table.DefaultLocalMetric, + Metric: DefaultLocalMetric, } if err := r.Create(route); err != nil { r.status = Status{Code: Error, Error: fmt.Errorf("failed adding default gateway route: %s", err)} @@ -528,10 +527,10 @@ func (r *router) Advertise() (<-chan *Advert, error) { return nil, fmt.Errorf("failed listing routes: %s", err) } // collect all the added routes before we attempt to add default gateway - events := make([]*table.Event, len(routes)) + events := make([]*Event, len(routes)) for i, route := range routes { - event := &table.Event{ - Type: table.Create, + event := &Event{ + Type: Create, Timestamp: time.Now(), Route: route, } @@ -540,7 +539,7 @@ func (r *router) Advertise() (<-chan *Advert, error) { // create advertise and event channels r.advertChan = make(chan *Advert) - r.eventChan = make(chan *table.Event) + r.eventChan = make(chan *Event) // advertise your presence r.advertWg.Add(1) @@ -580,7 +579,7 @@ func (r *router) Advertise() (<-chan *Advert, error) { func (r *router) Process(a *Advert) error { // NOTE: event sorting might not be necessary // copy update events intp new slices - events := make([]*table.Event, len(a.Events)) + events := make([]*Event, len(a.Events)) copy(events, a.Events) // sort events by timestamp sort.Slice(events, func(i, j int) bool { diff --git a/network/router/options.go b/network/router/options.go index d64aca01..ac108b32 100644 --- a/network/router/options.go +++ b/network/router/options.go @@ -2,7 +2,6 @@ package router import ( "github.com/google/uuid" - "github.com/micro/go-micro/network/router/table" "github.com/micro/go-micro/registry" ) @@ -26,7 +25,7 @@ type Options struct { // Registry is the local registry Registry registry.Registry // Table is routing table - Table table.Table + Table *Table } // Id sets Router Id @@ -64,8 +63,8 @@ func Registry(r registry.Registry) Option { } } -// Table sets the routing table -func Table(t table.Table) Option { +// RoutingTable sets the routing table +func RoutingTable(t *Table) Option { return func(o *Options) { o.Table = t } @@ -78,6 +77,6 @@ func DefaultOptions() Options { Address: DefaultAddress, Network: DefaultNetwork, Registry: registry.DefaultRegistry, - Table: table.NewTable(), + Table: NewTable(), } } diff --git a/network/router/table/query.go b/network/router/query.go similarity index 63% rename from network/router/table/query.go rename to network/router/query.go index 7703e3b3..68fb3588 100644 --- a/network/router/table/query.go +++ b/network/router/query.go @@ -1,26 +1,4 @@ -package table - -// LookupPolicy defines query policy -type LookupPolicy int - -const ( - // DiscardIfNone discards query when no route is found - DiscardIfNone LookupPolicy = iota - // ClosestMatch returns closest match to supplied query - ClosestMatch -) - -// String returns human representation of LookupPolicy -func (lp LookupPolicy) String() string { - switch lp { - case DiscardIfNone: - return "DISCARD" - case ClosestMatch: - return "CLOSEST" - default: - return "UNKNOWN" - } -} +package router // QueryOption sets routing table query options type QueryOption func(*QueryOptions) @@ -33,8 +11,6 @@ type QueryOptions struct { Gateway string // Network is network address Network string - // Policy is query lookup policy - Policy LookupPolicy } // QueryService sets destination address @@ -58,14 +34,6 @@ func QueryNetwork(n string) QueryOption { } } -// QueryPolicy sets query policy -// NOTE: this might be renamed to filter or some such -func QueryPolicy(p LookupPolicy) QueryOption { - return func(o *QueryOptions) { - o.Policy = p - } -} - // Query is routing table query type Query interface { // Options returns query options @@ -80,12 +48,10 @@ type query struct { // NewQuery creates new query and returns it func NewQuery(opts ...QueryOption) Query { // default options - // NOTE: by default we use DefaultNetworkMetric qopts := QueryOptions{ Service: "*", Gateway: "*", Network: "*", - Policy: DiscardIfNone, } for _, o := range opts { diff --git a/network/router/table/route.go b/network/router/route.go similarity index 98% rename from network/router/table/route.go rename to network/router/route.go index 50a52068..fa9dbc72 100644 --- a/network/router/table/route.go +++ b/network/router/route.go @@ -1,4 +1,4 @@ -package table +package router import ( "hash/fnv" diff --git a/network/router/route_test.go b/network/router/route_test.go new file mode 100644 index 00000000..483b852c --- /dev/null +++ b/network/router/route_test.go @@ -0,0 +1,24 @@ +package router + +import "testing" + +func TestHash(t *testing.T) { + route1 := Route{ + Service: "dest.svc", + Gateway: "dest.gw", + Network: "dest.network", + Link: "det.link", + Metric: 10, + } + + // make a copy + route2 := route1 + + route1Hash := route1.Hash() + route2Hash := route2.Hash() + + // we should get the same hash + if route1Hash != route2Hash { + t.Errorf("identical routes result in different hashes") + } +} diff --git a/network/router/router.go b/network/router/router.go index 8ce84fb1..0a0e4788 100644 --- a/network/router/router.go +++ b/network/router/router.go @@ -3,8 +3,6 @@ package router import ( "time" - - "github.com/micro/go-micro/network/router/table" ) var ( @@ -14,8 +12,6 @@ var ( // Router is an interface for a routing control plane type Router interface { - // Router provides a routing table - table.Table // Init initializes the router with options Init(...Option) error // Options returns the router options @@ -24,6 +20,18 @@ type Router interface { Advertise() (<-chan *Advert, error) // Process processes incoming adverts Process(*Advert) error + // Create new route in the routing table + Create(Route) error + // Delete deletes existing route from the routing table + Delete(Route) error + // Update updates route in the routing table + Update(Route) error + // List returns the list of all routes in the table + List() ([]Route, error) + // Lookup looks up routes in the routing table and returns them + Lookup(Query) ([]Route, error) + // Watch returns a watcher which allows to track updates to the routing table + Watch(opts ...WatchOption) (Watcher, error) // Status returns router status Status() Status // Stop stops the router @@ -63,10 +71,22 @@ type AdvertType int const ( // Announce is advertised when the router announces itself Announce AdvertType = iota - // Update advertises route updates - Update + // RouteUpdate advertises route updates + RouteUpdate ) +// String returns human readable advertisement type +func (t AdvertType) String() string { + switch t { + case Announce: + return "announce" + case RouteUpdate: + return "update" + default: + return "unknown" + } +} + // Advert contains a list of events advertised by the router to the network type Advert struct { // Id is the router Id @@ -78,7 +98,7 @@ type Advert struct { // TTL is Advert TTL TTL time.Duration // Events is a list of routing table events to advertise - Events []*table.Event + Events []*Event } // NewRouter creates new Router and returns it diff --git a/network/router/table/default.go b/network/router/table.go similarity index 54% rename from network/router/table/default.go rename to network/router/table.go index bce75935..cb746cbb 100644 --- a/network/router/table/default.go +++ b/network/router/table.go @@ -1,59 +1,39 @@ -package table +package router import ( + "errors" "sync" "time" "github.com/google/uuid" ) -// Options specify routing table options -// TODO: table options TBD in the future -type Options struct{} +var ( + // ErrRouteNotFound is returned when no route was found in the routing table + ErrRouteNotFound = errors.New("route not found") + // ErrDuplicateRoute is returned when the route already exists + ErrDuplicateRoute = errors.New("duplicate route") +) -// table is an in memory routing table -type table struct { - // opts are table options - opts Options - // m stores routing table map - m map[string]map[uint64]Route - // w is a list of table watchers - w map[string]*tableWatcher +// Table is an in memory routing table +type Table struct { + // routes stores service routes + routes map[string]map[uint64]Route + // watchers stores table watchers + watchers map[string]*tableWatcher sync.RWMutex } -// newTable creates a new routing table and returns it -func newTable(opts ...Option) Table { - // default options - var options Options - - // apply requested options - for _, o := range opts { - o(&options) +// NewTable creates a new routing table and returns it +func NewTable(opts ...Option) *Table { + return &Table{ + routes: make(map[string]map[uint64]Route), + watchers: make(map[string]*tableWatcher), } - - return &table{ - opts: options, - m: make(map[string]map[uint64]Route), - w: make(map[string]*tableWatcher), - } -} - -// Init initializes routing table with options -func (t *table) Init(opts ...Option) error { - for _, o := range opts { - o(&t.opts) - } - return nil -} - -// Options returns routing table options -func (t *table) Options() Options { - return t.opts } // Create creates new route in the routing table -func (t *table) Create(r Route) error { +func (t *Table) Create(r Route) error { service := r.Service sum := r.Hash() @@ -61,16 +41,16 @@ func (t *table) Create(r Route) error { defer t.Unlock() // check if there are any routes in the table for the route destination - if _, ok := t.m[service]; !ok { - t.m[service] = make(map[uint64]Route) - t.m[service][sum] = r + if _, ok := t.routes[service]; !ok { + t.routes[service] = make(map[uint64]Route) + t.routes[service][sum] = r go t.sendEvent(&Event{Type: Create, Timestamp: time.Now(), Route: r}) return nil } // add new route to the table for the route destination - if _, ok := t.m[service][sum]; !ok { - t.m[service][sum] = r + if _, ok := t.routes[service][sum]; !ok { + t.routes[service][sum] = r go t.sendEvent(&Event{Type: Create, Timestamp: time.Now(), Route: r}) return nil } @@ -79,25 +59,25 @@ func (t *table) Create(r Route) error { } // Delete deletes the route from the routing table -func (t *table) Delete(r Route) error { +func (t *Table) Delete(r Route) error { service := r.Service sum := r.Hash() t.Lock() defer t.Unlock() - if _, ok := t.m[service]; !ok { + if _, ok := t.routes[service]; !ok { return ErrRouteNotFound } - delete(t.m[service], sum) + delete(t.routes[service], sum) go t.sendEvent(&Event{Type: Delete, Timestamp: time.Now(), Route: r}) return nil } // Update updates routing table with the new route -func (t *table) Update(r Route) error { +func (t *Table) Update(r Route) error { service := r.Service sum := r.Hash() @@ -105,26 +85,26 @@ func (t *table) Update(r Route) error { defer t.Unlock() // check if the route destination has any routes in the table - if _, ok := t.m[service]; !ok { - t.m[service] = make(map[uint64]Route) - t.m[service][sum] = r + if _, ok := t.routes[service]; !ok { + t.routes[service] = make(map[uint64]Route) + t.routes[service][sum] = r go t.sendEvent(&Event{Type: Create, Timestamp: time.Now(), Route: r}) return nil } - t.m[service][sum] = r + t.routes[service][sum] = r go t.sendEvent(&Event{Type: Update, Timestamp: time.Now(), Route: r}) return nil } // List returns a list of all routes in the table -func (t *table) List() ([]Route, error) { +func (t *Table) List() ([]Route, error) { t.RLock() defer t.RUnlock() var routes []Route - for _, rmap := range t.m { + for _, rmap := range t.routes { for _, route := range rmap { routes = append(routes, route) } @@ -155,21 +135,20 @@ func findRoutes(routes map[uint64]Route, network, router string) []Route { } // Lookup queries routing table and returns all routes that match the lookup query -func (t *table) Lookup(q Query) ([]Route, error) { +func (t *Table) Lookup(q Query) ([]Route, error) { t.RLock() defer t.RUnlock() if q.Options().Service != "*" { - // no routes found for the destination and query policy is not a DiscardIfNone - if _, ok := t.m[q.Options().Service]; !ok && q.Options().Policy != DiscardIfNone { + if _, ok := t.routes[q.Options().Service]; !ok { return nil, ErrRouteNotFound } - return findRoutes(t.m[q.Options().Service], q.Options().Network, q.Options().Gateway), nil + return findRoutes(t.routes[q.Options().Service], q.Options().Network, q.Options().Gateway), nil } var results []Route // search through all destinations - for _, routes := range t.m { + for _, routes := range t.routes { results = append(results, findRoutes(routes, q.Options().Network, q.Options().Gateway)...) } @@ -177,7 +156,7 @@ func (t *table) Lookup(q Query) ([]Route, error) { } // Watch returns routing table entry watcher -func (t *table) Watch(opts ...WatchOption) (Watcher, error) { +func (t *Table) Watch(opts ...WatchOption) (Watcher, error) { // by default watch everything wopts := WatchOptions{ Service: "*", @@ -187,25 +166,25 @@ func (t *table) Watch(opts ...WatchOption) (Watcher, error) { o(&wopts) } - watcher := &tableWatcher{ + w := &tableWatcher{ opts: wopts, resChan: make(chan *Event, 10), done: make(chan struct{}), } t.Lock() - t.w[uuid.New().String()] = watcher + t.watchers[uuid.New().String()] = w t.Unlock() - return watcher, nil + return w, nil } // sendEvent sends rules to all subscribe watchers -func (t *table) sendEvent(r *Event) { +func (t *Table) sendEvent(r *Event) { t.RLock() defer t.RUnlock() - for _, w := range t.w { + for _, w := range t.watchers { select { case w.resChan <- r: case <-w.done: @@ -213,20 +192,7 @@ func (t *table) sendEvent(r *Event) { } } -// Size returns the size of the routing table -func (t *table) Size() int { - t.RLock() - defer t.RUnlock() - - size := 0 - for dest := range t.m { - size += len(t.m[dest]) - } - - return size -} - // String returns debug information -func (t *table) String() string { - return "default" +func (t *Table) String() string { + return "table" } diff --git a/network/router/table/table.go b/network/router/table/table.go deleted file mode 100644 index 2836e3d6..00000000 --- a/network/router/table/table.go +++ /dev/null @@ -1,38 +0,0 @@ -package table - -import ( - "errors" -) - -var ( - // ErrRouteNotFound is returned when no route was found in the routing table - ErrRouteNotFound = errors.New("route not found") - // ErrDuplicateRoute is returned when the route already exists - ErrDuplicateRoute = errors.New("duplicate route") -) - -// Table defines routing table interface -type Table interface { - // Create new route in the routing table - Create(Route) error - // Delete deletes existing route from the routing table - Delete(Route) error - // Update updates route in the routing table - Update(Route) error - // List returns the list of all routes in the table - List() ([]Route, error) - // Lookup looks up routes in the routing table and returns them - Lookup(Query) ([]Route, error) - // Watch returns a watcher which allows to track updates to the routing table - Watch(opts ...WatchOption) (Watcher, error) - // Size returns the size of the routing table - Size() int -} - -// Option used by the routing table -type Option func(*Options) - -// NewTable creates new routing table and returns it -func NewTable(opts ...Option) Table { - return newTable(opts...) -} diff --git a/network/router/table/default_test.go b/network/router/table_test.go similarity index 78% rename from network/router/table/default_test.go rename to network/router/table_test.go index 275da8c2..eee734a2 100644 --- a/network/router/table/default_test.go +++ b/network/router/table_test.go @@ -1,8 +1,8 @@ -package table +package router import "testing" -func testSetup() (Table, Route) { +func testSetup() (*Table, Route) { table := NewTable() route := Route{ @@ -18,12 +18,10 @@ func testSetup() (Table, Route) { func TestCreate(t *testing.T) { table, route := testSetup() - testTableSize := table.Size() if err := table.Create(route); err != nil { t.Errorf("error adding route: %s", err) } - testTableSize++ // adds new route for the original destination route.Gateway = "dest.gw2" @@ -31,11 +29,6 @@ func TestCreate(t *testing.T) { if err := table.Create(route); err != nil { t.Errorf("error adding route: %s", err) } - testTableSize++ - - if table.Size() != testTableSize { - t.Errorf("invalid number of routes. Expected: %d, found: %d", testTableSize, table.Size()) - } // adding the same route under Insert policy must error if err := table.Create(route); err != ErrDuplicateRoute { @@ -45,12 +38,10 @@ func TestCreate(t *testing.T) { func TestDelete(t *testing.T) { table, route := testSetup() - testTableSize := table.Size() if err := table.Create(route); err != nil { t.Errorf("error adding route: %s", err) } - testTableSize++ // should fail to delete non-existant route prevSvc := route.Service @@ -66,21 +57,14 @@ func TestDelete(t *testing.T) { if err := table.Delete(route); err != nil { t.Errorf("error deleting route: %s", err) } - testTableSize-- - - if table.Size() != testTableSize { - t.Errorf("invalid number of routes. Expected: %d, found: %d", testTableSize, table.Size()) - } } func TestUpdate(t *testing.T) { table, route := testSetup() - testTableSize := table.Size() if err := table.Create(route); err != nil { t.Errorf("error adding route: %s", err) } - testTableSize++ // change the metric of the original route route.Metric = 200 @@ -89,22 +73,12 @@ func TestUpdate(t *testing.T) { t.Errorf("error updating route: %s", err) } - // the size of the table should not change as we're only updating the metric of an existing route - if table.Size() != testTableSize { - t.Errorf("invalid number of routes. Expected: %d, found: %d", testTableSize, table.Size()) - } - // this should add a new route route.Service = "rand.dest" if err := table.Update(route); err != nil { t.Errorf("error updating route: %s", err) } - testTableSize++ - - if table.Size() != testTableSize { - t.Errorf("invalid number of routes. Expected: %d, found: %d", testTableSize, table.Size()) - } } func TestList(t *testing.T) { @@ -127,10 +101,6 @@ func TestList(t *testing.T) { if len(routes) != len(svc) { t.Errorf("incorrect number of routes listed. Expected: %d, found: %d", len(svc), len(routes)) } - - if len(routes) != table.Size() { - t.Errorf("mismatch number of routes and table size. Expected: %d, found: %d", len(routes), table.Size()) - } } func TestLookup(t *testing.T) { @@ -157,10 +127,6 @@ func TestLookup(t *testing.T) { t.Errorf("error looking up routes: %s", err) } - if len(routes) != table.Size() { - t.Errorf("incorrect number of routes returned. Expected: %d, found: %d", table.Size(), len(routes)) - } - // query particular net query = NewQuery(QueryNetwork("net1")) @@ -218,8 +184,8 @@ func TestLookup(t *testing.T) { query = NewQuery(QueryService("foobar")) routes, err = table.Lookup(query) - if err != nil { - t.Errorf("error looking up routes: %s", err) + if err != ErrRouteNotFound { + t.Errorf("error looking up routes. Expected: %s, found: %s", ErrRouteNotFound, err) } if len(routes) != 0 { diff --git a/network/router/table/watcher.go b/network/router/watcher.go similarity index 88% rename from network/router/table/watcher.go rename to network/router/watcher.go index 503993ff..d1ff3ea7 100644 --- a/network/router/table/watcher.go +++ b/network/router/watcher.go @@ -1,4 +1,4 @@ -package table +package router import ( "errors" @@ -22,11 +22,9 @@ const ( Update ) -// String implements fmt.Stringer -// NOTE: we need this as this makes converting the numeric codes -// into miro style string actions very simple -func (et EventType) String() string { - switch et { +// String returns human readable event type +func (t EventType) String() string { + switch t { case Create: return "create" case Delete: @@ -83,8 +81,7 @@ type tableWatcher struct { } // Next returns the next noticed action taken on table -// TODO: this needs to be thought through properly; -// right now we only allow to watch service +// TODO: think this through properly; right now we only watch service func (w *tableWatcher) Next() (*Event, error) { for { select { From 2338780a61b2ff3f7eabd9ef77f74a0b826981f3 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Thu, 25 Jul 2019 23:24:46 +0100 Subject: [PATCH 209/287] Full router RPC coverage --- network/router/proto/router.micro.go | 121 ++++-- network/router/proto/router.pb.go | 610 ++++++++++----------------- network/router/proto/router.proto | 33 +- 3 files changed, 332 insertions(+), 432 deletions(-) diff --git a/network/router/proto/router.micro.go b/network/router/proto/router.micro.go index 5dc753e9..96386187 100644 --- a/network/router/proto/router.micro.go +++ b/network/router/proto/router.micro.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-micro. DO NOT EDIT. -// source: go-micro/network/router/proto/router.proto +// source: router.proto package go_micro_router @@ -34,11 +34,14 @@ var _ server.Option // Client API for Router service type RouterService interface { - Watch(ctx context.Context, in *WatchRequest, opts ...client.CallOption) (Router_WatchService, error) - Lookup(ctx context.Context, in *LookupRequest, opts ...client.CallOption) (*LookupResponse, error) List(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*ListResponse, error) + Lookup(ctx context.Context, in *LookupRequest, opts ...client.CallOption) (*LookupResponse, error) + Watch(ctx context.Context, in *WatchRequest, opts ...client.CallOption) (Router_WatchService, error) Advertise(ctx context.Context, in *AdvertiseRequest, opts ...client.CallOption) (Router_AdvertiseService, error) Process(ctx context.Context, in *Advert, opts ...client.CallOption) (*ProcessResponse, error) + Create(ctx context.Context, in *Route, opts ...client.CallOption) (*CreateResponse, error) + Delete(ctx context.Context, in *Route, opts ...client.CallOption) (*DeleteResponse, error) + Update(ctx context.Context, in *Route, opts ...client.CallOption) (*UpdateResponse, error) } type routerService struct { @@ -59,6 +62,26 @@ func NewRouterService(name string, c client.Client) RouterService { } } +func (c *routerService) List(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*ListResponse, error) { + req := c.c.NewRequest(c.name, "Router.List", in) + out := new(ListResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *routerService) Lookup(ctx context.Context, in *LookupRequest, opts ...client.CallOption) (*LookupResponse, error) { + req := c.c.NewRequest(c.name, "Router.Lookup", in) + out := new(LookupResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *routerService) Watch(ctx context.Context, in *WatchRequest, opts ...client.CallOption) (Router_WatchService, error) { req := c.c.NewRequest(c.name, "Router.Watch", &WatchRequest{}) stream, err := c.c.Stream(ctx, req, opts...) @@ -103,26 +126,6 @@ func (x *routerServiceWatch) Recv() (*Event, error) { return m, nil } -func (c *routerService) Lookup(ctx context.Context, in *LookupRequest, opts ...client.CallOption) (*LookupResponse, error) { - req := c.c.NewRequest(c.name, "Router.Lookup", in) - out := new(LookupResponse) - err := c.c.Call(ctx, req, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *routerService) List(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*ListResponse, error) { - req := c.c.NewRequest(c.name, "Router.List", in) - out := new(ListResponse) - err := c.c.Call(ctx, req, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *routerService) Advertise(ctx context.Context, in *AdvertiseRequest, opts ...client.CallOption) (Router_AdvertiseService, error) { req := c.c.NewRequest(c.name, "Router.Advertise", &AdvertiseRequest{}) stream, err := c.c.Stream(ctx, req, opts...) @@ -177,23 +180,59 @@ func (c *routerService) Process(ctx context.Context, in *Advert, opts ...client. return out, nil } +func (c *routerService) Create(ctx context.Context, in *Route, opts ...client.CallOption) (*CreateResponse, error) { + req := c.c.NewRequest(c.name, "Router.Create", in) + out := new(CreateResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *routerService) Delete(ctx context.Context, in *Route, opts ...client.CallOption) (*DeleteResponse, error) { + req := c.c.NewRequest(c.name, "Router.Delete", in) + out := new(DeleteResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *routerService) Update(ctx context.Context, in *Route, opts ...client.CallOption) (*UpdateResponse, error) { + req := c.c.NewRequest(c.name, "Router.Update", in) + out := new(UpdateResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // Server API for Router service type RouterHandler interface { - Watch(context.Context, *WatchRequest, Router_WatchStream) error - Lookup(context.Context, *LookupRequest, *LookupResponse) error List(context.Context, *ListRequest, *ListResponse) error + Lookup(context.Context, *LookupRequest, *LookupResponse) error + Watch(context.Context, *WatchRequest, Router_WatchStream) error Advertise(context.Context, *AdvertiseRequest, Router_AdvertiseStream) error Process(context.Context, *Advert, *ProcessResponse) error + Create(context.Context, *Route, *CreateResponse) error + Delete(context.Context, *Route, *DeleteResponse) error + Update(context.Context, *Route, *UpdateResponse) error } func RegisterRouterHandler(s server.Server, hdlr RouterHandler, opts ...server.HandlerOption) error { type router interface { - Watch(ctx context.Context, stream server.Stream) error - Lookup(ctx context.Context, in *LookupRequest, out *LookupResponse) error List(ctx context.Context, in *ListRequest, out *ListResponse) error + Lookup(ctx context.Context, in *LookupRequest, out *LookupResponse) error + Watch(ctx context.Context, stream server.Stream) error Advertise(ctx context.Context, stream server.Stream) error Process(ctx context.Context, in *Advert, out *ProcessResponse) error + Create(ctx context.Context, in *Route, out *CreateResponse) error + Delete(ctx context.Context, in *Route, out *DeleteResponse) error + Update(ctx context.Context, in *Route, out *UpdateResponse) error } type Router struct { router @@ -206,6 +245,14 @@ type routerHandler struct { RouterHandler } +func (h *routerHandler) List(ctx context.Context, in *ListRequest, out *ListResponse) error { + return h.RouterHandler.List(ctx, in, out) +} + +func (h *routerHandler) Lookup(ctx context.Context, in *LookupRequest, out *LookupResponse) error { + return h.RouterHandler.Lookup(ctx, in, out) +} + func (h *routerHandler) Watch(ctx context.Context, stream server.Stream) error { m := new(WatchRequest) if err := stream.Recv(m); err != nil { @@ -241,14 +288,6 @@ func (x *routerWatchStream) Send(m *Event) error { return x.stream.Send(m) } -func (h *routerHandler) Lookup(ctx context.Context, in *LookupRequest, out *LookupResponse) error { - return h.RouterHandler.Lookup(ctx, in, out) -} - -func (h *routerHandler) List(ctx context.Context, in *ListRequest, out *ListResponse) error { - return h.RouterHandler.List(ctx, in, out) -} - func (h *routerHandler) Advertise(ctx context.Context, stream server.Stream) error { m := new(AdvertiseRequest) if err := stream.Recv(m); err != nil { @@ -287,3 +326,15 @@ func (x *routerAdvertiseStream) Send(m *Advert) error { func (h *routerHandler) Process(ctx context.Context, in *Advert, out *ProcessResponse) error { return h.RouterHandler.Process(ctx, in, out) } + +func (h *routerHandler) Create(ctx context.Context, in *Route, out *CreateResponse) error { + return h.RouterHandler.Create(ctx, in, out) +} + +func (h *routerHandler) Delete(ctx context.Context, in *Route, out *DeleteResponse) error { + return h.RouterHandler.Delete(ctx, in, out) +} + +func (h *routerHandler) Update(ctx context.Context, in *Route, out *UpdateResponse) error { + return h.RouterHandler.Update(ctx, in, out) +} diff --git a/network/router/proto/router.pb.go b/network/router/proto/router.pb.go index a15e1bd9..ef9fc698 100644 --- a/network/router/proto/router.pb.go +++ b/network/router/proto/router.pb.go @@ -1,13 +1,11 @@ // Code generated by protoc-gen-go. DO NOT EDIT. -// source: go-micro/network/router/proto/router.proto +// source: router.proto package go_micro_router import ( - context "context" fmt "fmt" proto "github.com/golang/protobuf/proto" - grpc "google.golang.org/grpc" math "math" ) @@ -45,7 +43,7 @@ func (x AdvertType) String() string { } func (AdvertType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{0} + return fileDescriptor_367072455c71aedc, []int{0} } // EventType defines the type of event @@ -74,7 +72,79 @@ func (x EventType) String() string { } func (EventType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{1} + return fileDescriptor_367072455c71aedc, []int{1} +} + +// ListRequest is made to List routes +type ListRequest struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListRequest) Reset() { *m = ListRequest{} } +func (m *ListRequest) String() string { return proto.CompactTextString(m) } +func (*ListRequest) ProtoMessage() {} +func (*ListRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_367072455c71aedc, []int{0} +} + +func (m *ListRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ListRequest.Unmarshal(m, b) +} +func (m *ListRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ListRequest.Marshal(b, m, deterministic) +} +func (m *ListRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListRequest.Merge(m, src) +} +func (m *ListRequest) XXX_Size() int { + return xxx_messageInfo_ListRequest.Size(m) +} +func (m *ListRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ListRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ListRequest proto.InternalMessageInfo + +// ListResponse is returned by List +type ListResponse struct { + Routes []*Route `protobuf:"bytes,1,rep,name=routes,proto3" json:"routes,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListResponse) Reset() { *m = ListResponse{} } +func (m *ListResponse) String() string { return proto.CompactTextString(m) } +func (*ListResponse) ProtoMessage() {} +func (*ListResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_367072455c71aedc, []int{1} +} + +func (m *ListResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ListResponse.Unmarshal(m, b) +} +func (m *ListResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ListResponse.Marshal(b, m, deterministic) +} +func (m *ListResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListResponse.Merge(m, src) +} +func (m *ListResponse) XXX_Size() int { + return xxx_messageInfo_ListResponse.Size(m) +} +func (m *ListResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ListResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_ListResponse proto.InternalMessageInfo + +func (m *ListResponse) GetRoutes() []*Route { + if m != nil { + return m.Routes + } + return nil } // LookupRequest is made to Lookup @@ -89,7 +159,7 @@ func (m *LookupRequest) Reset() { *m = LookupRequest{} } func (m *LookupRequest) String() string { return proto.CompactTextString(m) } func (*LookupRequest) ProtoMessage() {} func (*LookupRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{0} + return fileDescriptor_367072455c71aedc, []int{2} } func (m *LookupRequest) XXX_Unmarshal(b []byte) error { @@ -129,7 +199,7 @@ func (m *LookupResponse) Reset() { *m = LookupResponse{} } func (m *LookupResponse) String() string { return proto.CompactTextString(m) } func (*LookupResponse) ProtoMessage() {} func (*LookupResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{1} + return fileDescriptor_367072455c71aedc, []int{3} } func (m *LookupResponse) XXX_Unmarshal(b []byte) error { @@ -168,7 +238,7 @@ func (m *WatchRequest) Reset() { *m = WatchRequest{} } func (m *WatchRequest) String() string { return proto.CompactTextString(m) } func (*WatchRequest) ProtoMessage() {} func (*WatchRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{2} + return fileDescriptor_367072455c71aedc, []int{4} } func (m *WatchRequest) XXX_Unmarshal(b []byte) error { @@ -200,7 +270,7 @@ func (m *AdvertiseRequest) Reset() { *m = AdvertiseRequest{} } func (m *AdvertiseRequest) String() string { return proto.CompactTextString(m) } func (*AdvertiseRequest) ProtoMessage() {} func (*AdvertiseRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{3} + return fileDescriptor_367072455c71aedc, []int{5} } func (m *AdvertiseRequest) XXX_Unmarshal(b []byte) error { @@ -242,7 +312,7 @@ func (m *Advert) Reset() { *m = Advert{} } func (m *Advert) String() string { return proto.CompactTextString(m) } func (*Advert) ProtoMessage() {} func (*Advert) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{4} + return fileDescriptor_367072455c71aedc, []int{6} } func (m *Advert) XXX_Unmarshal(b []byte) error { @@ -309,7 +379,7 @@ func (m *ProcessResponse) Reset() { *m = ProcessResponse{} } func (m *ProcessResponse) String() string { return proto.CompactTextString(m) } func (*ProcessResponse) ProtoMessage() {} func (*ProcessResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{5} + return fileDescriptor_367072455c71aedc, []int{7} } func (m *ProcessResponse) XXX_Unmarshal(b []byte) error { @@ -330,6 +400,102 @@ func (m *ProcessResponse) XXX_DiscardUnknown() { var xxx_messageInfo_ProcessResponse proto.InternalMessageInfo +// CreateResponse is returned by Create +type CreateResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateResponse) Reset() { *m = CreateResponse{} } +func (m *CreateResponse) String() string { return proto.CompactTextString(m) } +func (*CreateResponse) ProtoMessage() {} +func (*CreateResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_367072455c71aedc, []int{8} +} + +func (m *CreateResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CreateResponse.Unmarshal(m, b) +} +func (m *CreateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CreateResponse.Marshal(b, m, deterministic) +} +func (m *CreateResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateResponse.Merge(m, src) +} +func (m *CreateResponse) XXX_Size() int { + return xxx_messageInfo_CreateResponse.Size(m) +} +func (m *CreateResponse) XXX_DiscardUnknown() { + xxx_messageInfo_CreateResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateResponse proto.InternalMessageInfo + +// DeleteResponse is returned by Delete +type DeleteResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteResponse) Reset() { *m = DeleteResponse{} } +func (m *DeleteResponse) String() string { return proto.CompactTextString(m) } +func (*DeleteResponse) ProtoMessage() {} +func (*DeleteResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_367072455c71aedc, []int{9} +} + +func (m *DeleteResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteResponse.Unmarshal(m, b) +} +func (m *DeleteResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteResponse.Marshal(b, m, deterministic) +} +func (m *DeleteResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteResponse.Merge(m, src) +} +func (m *DeleteResponse) XXX_Size() int { + return xxx_messageInfo_DeleteResponse.Size(m) +} +func (m *DeleteResponse) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteResponse proto.InternalMessageInfo + +// UpdateResponse is returned by Update +type UpdateResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateResponse) Reset() { *m = UpdateResponse{} } +func (m *UpdateResponse) String() string { return proto.CompactTextString(m) } +func (*UpdateResponse) ProtoMessage() {} +func (*UpdateResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_367072455c71aedc, []int{10} +} + +func (m *UpdateResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UpdateResponse.Unmarshal(m, b) +} +func (m *UpdateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UpdateResponse.Marshal(b, m, deterministic) +} +func (m *UpdateResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateResponse.Merge(m, src) +} +func (m *UpdateResponse) XXX_Size() int { + return xxx_messageInfo_UpdateResponse.Size(m) +} +func (m *UpdateResponse) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_UpdateResponse proto.InternalMessageInfo + // Event is routing table event type Event struct { // type of event @@ -347,7 +513,7 @@ func (m *Event) Reset() { *m = Event{} } func (m *Event) String() string { return proto.CompactTextString(m) } func (*Event) ProtoMessage() {} func (*Event) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{6} + return fileDescriptor_367072455c71aedc, []int{11} } func (m *Event) XXX_Unmarshal(b []byte) error { @@ -389,78 +555,6 @@ func (m *Event) GetRoute() *Route { return nil } -// ListRequest is made to List routes -type ListRequest struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ListRequest) Reset() { *m = ListRequest{} } -func (m *ListRequest) String() string { return proto.CompactTextString(m) } -func (*ListRequest) ProtoMessage() {} -func (*ListRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{7} -} - -func (m *ListRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ListRequest.Unmarshal(m, b) -} -func (m *ListRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ListRequest.Marshal(b, m, deterministic) -} -func (m *ListRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ListRequest.Merge(m, src) -} -func (m *ListRequest) XXX_Size() int { - return xxx_messageInfo_ListRequest.Size(m) -} -func (m *ListRequest) XXX_DiscardUnknown() { - xxx_messageInfo_ListRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_ListRequest proto.InternalMessageInfo - -// ListResponse is returned by List -type ListResponse struct { - Routes []*Route `protobuf:"bytes,1,rep,name=routes,proto3" json:"routes,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ListResponse) Reset() { *m = ListResponse{} } -func (m *ListResponse) String() string { return proto.CompactTextString(m) } -func (*ListResponse) ProtoMessage() {} -func (*ListResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{8} -} - -func (m *ListResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ListResponse.Unmarshal(m, b) -} -func (m *ListResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ListResponse.Marshal(b, m, deterministic) -} -func (m *ListResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ListResponse.Merge(m, src) -} -func (m *ListResponse) XXX_Size() int { - return xxx_messageInfo_ListResponse.Size(m) -} -func (m *ListResponse) XXX_DiscardUnknown() { - xxx_messageInfo_ListResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_ListResponse proto.InternalMessageInfo - -func (m *ListResponse) GetRoutes() []*Route { - if m != nil { - return m.Routes - } - return nil -} - // Query is passed in a LookupRequest type Query struct { // service to lookup @@ -474,7 +568,7 @@ func (m *Query) Reset() { *m = Query{} } func (m *Query) String() string { return proto.CompactTextString(m) } func (*Query) ProtoMessage() {} func (*Query) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{9} + return fileDescriptor_367072455c71aedc, []int{12} } func (m *Query) XXX_Unmarshal(b []byte) error { @@ -525,7 +619,7 @@ func (m *Route) Reset() { *m = Route{} } func (m *Route) String() string { return proto.CompactTextString(m) } func (*Route) ProtoMessage() {} func (*Route) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{10} + return fileDescriptor_367072455c71aedc, []int{13} } func (m *Route) XXX_Unmarshal(b []byte) error { @@ -591,317 +685,61 @@ func (m *Route) GetMetric() int64 { func init() { proto.RegisterEnum("go.micro.router.AdvertType", AdvertType_name, AdvertType_value) proto.RegisterEnum("go.micro.router.EventType", EventType_name, EventType_value) + proto.RegisterType((*ListRequest)(nil), "go.micro.router.ListRequest") + proto.RegisterType((*ListResponse)(nil), "go.micro.router.ListResponse") proto.RegisterType((*LookupRequest)(nil), "go.micro.router.LookupRequest") proto.RegisterType((*LookupResponse)(nil), "go.micro.router.LookupResponse") proto.RegisterType((*WatchRequest)(nil), "go.micro.router.WatchRequest") proto.RegisterType((*AdvertiseRequest)(nil), "go.micro.router.AdvertiseRequest") proto.RegisterType((*Advert)(nil), "go.micro.router.Advert") proto.RegisterType((*ProcessResponse)(nil), "go.micro.router.ProcessResponse") + proto.RegisterType((*CreateResponse)(nil), "go.micro.router.CreateResponse") + proto.RegisterType((*DeleteResponse)(nil), "go.micro.router.DeleteResponse") + proto.RegisterType((*UpdateResponse)(nil), "go.micro.router.UpdateResponse") proto.RegisterType((*Event)(nil), "go.micro.router.Event") - proto.RegisterType((*ListRequest)(nil), "go.micro.router.ListRequest") - proto.RegisterType((*ListResponse)(nil), "go.micro.router.ListResponse") proto.RegisterType((*Query)(nil), "go.micro.router.Query") proto.RegisterType((*Route)(nil), "go.micro.router.Route") } -func init() { - proto.RegisterFile("go-micro/network/router/proto/router.proto", fileDescriptor_fc08514fc6dadd29) -} +func init() { proto.RegisterFile("router.proto", fileDescriptor_367072455c71aedc) } -var fileDescriptor_fc08514fc6dadd29 = []byte{ - // 553 bytes of a gzipped FileDescriptorProto +var fileDescriptor_367072455c71aedc = []byte{ + // 584 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0xc1, 0x6e, 0xd3, 0x40, - 0x10, 0x8d, 0x9d, 0xd8, 0x95, 0xa7, 0x6d, 0x1a, 0xe6, 0x50, 0x2c, 0xd3, 0x42, 0xea, 0x53, 0x55, - 0x15, 0x07, 0x85, 0x33, 0x88, 0x02, 0xe5, 0xd2, 0x1e, 0xc0, 0x02, 0x71, 0x36, 0xf6, 0x28, 0x58, - 0x49, 0xbc, 0xee, 0xee, 0x26, 0x55, 0xce, 0x7c, 0x06, 0x5f, 0xc0, 0x07, 0x72, 0x47, 0x3b, 0xb6, - 0x13, 0x48, 0xea, 0x0b, 0xa7, 0xec, 0x9b, 0xf7, 0x66, 0x3d, 0x33, 0x3b, 0x2f, 0x70, 0x31, 0x11, - 0xcf, 0xe7, 0x79, 0x2a, 0xc5, 0xa8, 0x20, 0x7d, 0x2f, 0xe4, 0x74, 0x24, 0xc5, 0x42, 0x93, 0x1c, - 0x95, 0x52, 0x68, 0x51, 0x83, 0x88, 0x01, 0x1e, 0x4d, 0x44, 0xc4, 0xda, 0xa8, 0x0a, 0x87, 0xaf, - 0xe0, 0xf0, 0x56, 0x88, 0xe9, 0xa2, 0x8c, 0xe9, 0x6e, 0x41, 0x4a, 0xe3, 0x25, 0x38, 0x77, 0x0b, - 0x92, 0x2b, 0xdf, 0x1a, 0x5a, 0xe7, 0xfb, 0xe3, 0xe3, 0x68, 0x2b, 0x23, 0xfa, 0x64, 0xd8, 0xb8, - 0x12, 0x85, 0x6f, 0xa0, 0xdf, 0xa4, 0xab, 0x52, 0x14, 0x8a, 0x30, 0x02, 0x97, 0x85, 0xca, 0xb7, - 0x86, 0xdd, 0x07, 0x2f, 0x88, 0xcd, 0x4f, 0x5c, 0xab, 0xc2, 0x3e, 0x1c, 0x7c, 0x4d, 0x74, 0xfa, - 0xbd, 0xfe, 0x7e, 0x88, 0x30, 0xb8, 0xca, 0x96, 0x24, 0x75, 0xae, 0xa8, 0x89, 0xfd, 0xb2, 0xc0, - 0xad, 0x82, 0xd8, 0x07, 0x3b, 0xcf, 0xb8, 0x36, 0x2f, 0xb6, 0xf3, 0x0c, 0x47, 0xd0, 0xd3, 0xab, - 0x92, 0x7c, 0x7b, 0x68, 0x9d, 0xf7, 0xc7, 0x4f, 0x76, 0x3e, 0x56, 0xa5, 0x7d, 0x5e, 0x95, 0x14, - 0xb3, 0x10, 0x4f, 0xc0, 0xd3, 0xf9, 0x9c, 0x94, 0x4e, 0xe6, 0xa5, 0xdf, 0x1d, 0x5a, 0xe7, 0xdd, - 0x78, 0x13, 0xc0, 0x01, 0x74, 0xb5, 0x9e, 0xf9, 0x3d, 0x8e, 0x9b, 0xa3, 0xe9, 0x87, 0x96, 0x54, - 0x68, 0xe5, 0x3b, 0x2d, 0xfd, 0x5c, 0x1b, 0x3a, 0xae, 0x55, 0xe1, 0x23, 0x38, 0xfa, 0x28, 0x45, - 0x4a, 0x4a, 0x35, 0x23, 0x09, 0x7f, 0x58, 0xe0, 0xb0, 0x08, 0xa3, 0xba, 0x5a, 0x8b, 0xab, 0x0d, - 0x1e, 0xbe, 0xaa, 0xad, 0x58, 0x7b, 0xbb, 0xd8, 0x4b, 0x70, 0x38, 0x8f, 0xdb, 0x68, 0x9f, 0x74, - 0x25, 0x0a, 0x0f, 0x61, 0xff, 0x36, 0x57, 0xba, 0x99, 0xe9, 0x6b, 0x38, 0xa8, 0xe0, 0x7f, 0xbe, - 0xdb, 0x19, 0x38, 0xbc, 0x09, 0xe8, 0xc3, 0x9e, 0x22, 0xb9, 0xcc, 0x53, 0xaa, 0x9f, 0xa5, 0x81, - 0xe1, 0x4f, 0x0b, 0x1c, 0x4e, 0x6a, 0xd7, 0x18, 0x26, 0xc9, 0x32, 0x49, 0x4a, 0x71, 0x7f, 0x5e, - 0xdc, 0x40, 0xc3, 0x4c, 0x12, 0x4d, 0xf7, 0xc9, 0x8a, 0xfb, 0xf3, 0xe2, 0x06, 0x1a, 0xa6, 0xde, - 0x74, 0x7e, 0x28, 0x2f, 0x6e, 0x20, 0x22, 0xf4, 0x66, 0x79, 0x31, 0xf5, 0x1d, 0x0e, 0xf3, 0x19, - 0x8f, 0xc1, 0x9d, 0x93, 0x96, 0x79, 0xea, 0xbb, 0x3c, 0xc0, 0x1a, 0x5d, 0x8c, 0x01, 0x36, 0xcb, - 0x81, 0x08, 0xfd, 0x0a, 0x5d, 0x15, 0x85, 0x58, 0x14, 0x29, 0x0d, 0x3a, 0x38, 0x80, 0x83, 0x2a, - 0xf6, 0xa5, 0xcc, 0x12, 0x4d, 0x03, 0xeb, 0x62, 0x04, 0xde, 0xfa, 0x89, 0x10, 0xc0, 0x7d, 0x27, - 0xc9, 0x10, 0x1d, 0x73, 0x7e, 0x4f, 0x33, 0x32, 0x22, 0x73, 0xae, 0x13, 0xec, 0xf1, 0x6f, 0x1b, - 0x5c, 0x1e, 0x81, 0xc4, 0xb7, 0xe0, 0xf0, 0xa2, 0xe3, 0xe9, 0xce, 0x64, 0xff, 0x36, 0x40, 0xd0, - 0xb2, 0x60, 0x61, 0xe7, 0x85, 0x85, 0x37, 0xe0, 0x56, 0x76, 0xc3, 0xa7, 0x3b, 0xaa, 0x7f, 0x6c, - 0x1c, 0x3c, 0x6b, 0xe5, 0xeb, 0xa5, 0xec, 0xe0, 0x35, 0xf4, 0xcc, 0x06, 0xe0, 0xc9, 0xae, 0x74, - 0xb3, 0x27, 0xc1, 0x69, 0x0b, 0xbb, 0xbe, 0xe6, 0x06, 0xbc, 0xb5, 0x61, 0xf1, 0xac, 0xc5, 0x80, - 0x1b, 0x33, 0x07, 0x8f, 0x5b, 0x24, 0xdc, 0xe0, 0x07, 0xd8, 0xab, 0xdd, 0x83, 0x6d, 0xba, 0x60, - 0xb8, 0x43, 0x6c, 0x1b, 0xae, 0xf3, 0xcd, 0xe5, 0xbf, 0xbb, 0x97, 0x7f, 0x02, 0x00, 0x00, 0xff, - 0xff, 0x99, 0x8e, 0xb9, 0x97, 0x1c, 0x05, 0x00, 0x00, -} - -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConn - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 - -// RouterClient is the client API for Router service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type RouterClient interface { - Watch(ctx context.Context, in *WatchRequest, opts ...grpc.CallOption) (Router_WatchClient, error) - Lookup(ctx context.Context, in *LookupRequest, opts ...grpc.CallOption) (*LookupResponse, error) - List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (*ListResponse, error) - Advertise(ctx context.Context, in *AdvertiseRequest, opts ...grpc.CallOption) (Router_AdvertiseClient, error) - Process(ctx context.Context, in *Advert, opts ...grpc.CallOption) (*ProcessResponse, error) -} - -type routerClient struct { - cc *grpc.ClientConn -} - -func NewRouterClient(cc *grpc.ClientConn) RouterClient { - return &routerClient{cc} -} - -func (c *routerClient) Watch(ctx context.Context, in *WatchRequest, opts ...grpc.CallOption) (Router_WatchClient, error) { - stream, err := c.cc.NewStream(ctx, &_Router_serviceDesc.Streams[0], "/go.micro.router.Router/Watch", opts...) - if err != nil { - return nil, err - } - x := &routerWatchClient{stream} - if err := x.ClientStream.SendMsg(in); err != nil { - return nil, err - } - if err := x.ClientStream.CloseSend(); err != nil { - return nil, err - } - return x, nil -} - -type Router_WatchClient interface { - Recv() (*Event, error) - grpc.ClientStream -} - -type routerWatchClient struct { - grpc.ClientStream -} - -func (x *routerWatchClient) Recv() (*Event, error) { - m := new(Event) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -func (c *routerClient) Lookup(ctx context.Context, in *LookupRequest, opts ...grpc.CallOption) (*LookupResponse, error) { - out := new(LookupResponse) - err := c.cc.Invoke(ctx, "/go.micro.router.Router/Lookup", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *routerClient) List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (*ListResponse, error) { - out := new(ListResponse) - err := c.cc.Invoke(ctx, "/go.micro.router.Router/List", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *routerClient) Advertise(ctx context.Context, in *AdvertiseRequest, opts ...grpc.CallOption) (Router_AdvertiseClient, error) { - stream, err := c.cc.NewStream(ctx, &_Router_serviceDesc.Streams[1], "/go.micro.router.Router/Advertise", opts...) - if err != nil { - return nil, err - } - x := &routerAdvertiseClient{stream} - if err := x.ClientStream.SendMsg(in); err != nil { - return nil, err - } - if err := x.ClientStream.CloseSend(); err != nil { - return nil, err - } - return x, nil -} - -type Router_AdvertiseClient interface { - Recv() (*Advert, error) - grpc.ClientStream -} - -type routerAdvertiseClient struct { - grpc.ClientStream -} - -func (x *routerAdvertiseClient) Recv() (*Advert, error) { - m := new(Advert) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -func (c *routerClient) Process(ctx context.Context, in *Advert, opts ...grpc.CallOption) (*ProcessResponse, error) { - out := new(ProcessResponse) - err := c.cc.Invoke(ctx, "/go.micro.router.Router/Process", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// RouterServer is the server API for Router service. -type RouterServer interface { - Watch(*WatchRequest, Router_WatchServer) error - Lookup(context.Context, *LookupRequest) (*LookupResponse, error) - List(context.Context, *ListRequest) (*ListResponse, error) - Advertise(*AdvertiseRequest, Router_AdvertiseServer) error - Process(context.Context, *Advert) (*ProcessResponse, error) -} - -func RegisterRouterServer(s *grpc.Server, srv RouterServer) { - s.RegisterService(&_Router_serviceDesc, srv) -} - -func _Router_Watch_Handler(srv interface{}, stream grpc.ServerStream) error { - m := new(WatchRequest) - if err := stream.RecvMsg(m); err != nil { - return err - } - return srv.(RouterServer).Watch(m, &routerWatchServer{stream}) -} - -type Router_WatchServer interface { - Send(*Event) error - grpc.ServerStream -} - -type routerWatchServer struct { - grpc.ServerStream -} - -func (x *routerWatchServer) Send(m *Event) error { - return x.ServerStream.SendMsg(m) -} - -func _Router_Lookup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(LookupRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(RouterServer).Lookup(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/go.micro.router.Router/Lookup", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(RouterServer).Lookup(ctx, req.(*LookupRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Router_List_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ListRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(RouterServer).List(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/go.micro.router.Router/List", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(RouterServer).List(ctx, req.(*ListRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _Router_Advertise_Handler(srv interface{}, stream grpc.ServerStream) error { - m := new(AdvertiseRequest) - if err := stream.RecvMsg(m); err != nil { - return err - } - return srv.(RouterServer).Advertise(m, &routerAdvertiseServer{stream}) -} - -type Router_AdvertiseServer interface { - Send(*Advert) error - grpc.ServerStream -} - -type routerAdvertiseServer struct { - grpc.ServerStream -} - -func (x *routerAdvertiseServer) Send(m *Advert) error { - return x.ServerStream.SendMsg(m) -} - -func _Router_Process_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(Advert) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(RouterServer).Process(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/go.micro.router.Router/Process", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(RouterServer).Process(ctx, req.(*Advert)) - } - return interceptor(ctx, in, info, handler) -} - -var _Router_serviceDesc = grpc.ServiceDesc{ - ServiceName: "go.micro.router.Router", - HandlerType: (*RouterServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Lookup", - Handler: _Router_Lookup_Handler, - }, - { - MethodName: "List", - Handler: _Router_List_Handler, - }, - { - MethodName: "Process", - Handler: _Router_Process_Handler, - }, - }, - Streams: []grpc.StreamDesc{ - { - StreamName: "Watch", - Handler: _Router_Watch_Handler, - ServerStreams: true, - }, - { - StreamName: "Advertise", - Handler: _Router_Advertise_Handler, - ServerStreams: true, - }, - }, - Metadata: "go-micro/network/router/proto/router.proto", + 0x10, 0xf5, 0x26, 0xb1, 0x2b, 0x4f, 0x53, 0xd7, 0xcc, 0xa1, 0x58, 0xa6, 0x40, 0xea, 0x53, 0x55, + 0x55, 0x2e, 0x0a, 0x67, 0x10, 0xa5, 0x94, 0x4b, 0x7b, 0x00, 0x0b, 0xc4, 0xd9, 0xd8, 0xa3, 0x62, + 0x25, 0xb1, 0xdd, 0xdd, 0x4d, 0xaa, 0x9c, 0xf9, 0x0c, 0xbe, 0x80, 0xff, 0xe0, 0xc3, 0x90, 0x77, + 0xed, 0x24, 0x38, 0xf1, 0xa1, 0x9c, 0xb2, 0x33, 0xf3, 0x66, 0xbc, 0x6f, 0xde, 0xbe, 0xc0, 0x90, + 0x17, 0x73, 0x49, 0x3c, 0x2c, 0x79, 0x21, 0x0b, 0x3c, 0xbc, 0x2b, 0xc2, 0x59, 0x96, 0xf0, 0x22, + 0xd4, 0xe9, 0xe0, 0x00, 0xf6, 0x6f, 0x33, 0x21, 0x23, 0xba, 0x9f, 0x93, 0x90, 0xc1, 0x5b, 0x18, + 0xea, 0x50, 0x94, 0x45, 0x2e, 0x08, 0x43, 0xb0, 0x14, 0x50, 0x78, 0x6c, 0xd4, 0x3f, 0xdd, 0x1f, + 0x1f, 0x85, 0xad, 0x01, 0x61, 0x54, 0xfd, 0x44, 0x35, 0x2a, 0x78, 0x03, 0x07, 0xb7, 0x45, 0x31, + 0x99, 0x97, 0xf5, 0x40, 0x3c, 0x07, 0xf3, 0x7e, 0x4e, 0x7c, 0xe9, 0xb1, 0x11, 0xdb, 0xd9, 0xff, + 0xb9, 0xaa, 0x46, 0x1a, 0x14, 0xbc, 0x03, 0xa7, 0x69, 0xff, 0xcf, 0x0b, 0x38, 0x30, 0xfc, 0x16, + 0xcb, 0xe4, 0x47, 0x43, 0x08, 0xc1, 0xbd, 0x4c, 0x17, 0xc4, 0x65, 0x26, 0xa8, 0xc9, 0xfd, 0x66, + 0x60, 0xe9, 0x24, 0x3a, 0xd0, 0xcb, 0x52, 0x75, 0x37, 0x3b, 0xea, 0x65, 0x29, 0x5e, 0xc0, 0x40, + 0x2e, 0x4b, 0xf2, 0x7a, 0x23, 0x76, 0xea, 0x8c, 0x9f, 0x6d, 0x7d, 0x4c, 0xb7, 0x7d, 0x59, 0x96, + 0x14, 0x29, 0x20, 0x1e, 0x83, 0x2d, 0xb3, 0x19, 0x09, 0x19, 0xcf, 0x4a, 0xaf, 0x3f, 0x62, 0xa7, + 0xfd, 0x68, 0x9d, 0x40, 0x17, 0xfa, 0x52, 0x4e, 0xbd, 0x81, 0xca, 0x57, 0xc7, 0x8a, 0x0f, 0x2d, + 0x28, 0x97, 0xc2, 0x33, 0x3b, 0xf8, 0x5c, 0x57, 0xe5, 0xa8, 0x46, 0x05, 0x4f, 0xe0, 0xf0, 0x13, + 0x2f, 0x12, 0x12, 0xa2, 0x59, 0x49, 0xe0, 0x82, 0x73, 0xc5, 0x29, 0x96, 0xb4, 0x99, 0xf9, 0x40, + 0x53, 0xfa, 0x37, 0xf3, 0xb5, 0x4c, 0x37, 0x31, 0x3f, 0x19, 0x98, 0x6a, 0x34, 0x86, 0x35, 0x47, + 0xa6, 0x38, 0xfa, 0xbb, 0x2f, 0xd0, 0x45, 0xb1, 0xd7, 0xa6, 0x78, 0x0e, 0xa6, 0xea, 0x53, 0xe4, + 0xbb, 0xf5, 0xd1, 0xa0, 0xe0, 0x04, 0x4c, 0x25, 0x38, 0x7a, 0xb0, 0x27, 0x88, 0x2f, 0xb2, 0x84, + 0xea, 0xed, 0x37, 0x61, 0xf0, 0x8b, 0x81, 0xa9, 0x7a, 0xba, 0x31, 0x55, 0x25, 0x4e, 0x53, 0x4e, + 0x42, 0xa8, 0x0b, 0xd9, 0x51, 0x13, 0x56, 0x95, 0xbb, 0x58, 0xd2, 0x43, 0xbc, 0x54, 0x17, 0xb2, + 0xa3, 0x26, 0xac, 0x2a, 0x39, 0xc9, 0x87, 0x82, 0x4f, 0x94, 0x1e, 0x76, 0xd4, 0x84, 0x88, 0x30, + 0x98, 0x66, 0xf9, 0xc4, 0x33, 0x55, 0x5a, 0x9d, 0xf1, 0x08, 0xac, 0x19, 0x49, 0x9e, 0x25, 0x9e, + 0xa5, 0x18, 0xd7, 0xd1, 0xd9, 0x18, 0x60, 0xfd, 0x06, 0x10, 0xc1, 0xd1, 0xd1, 0x65, 0x9e, 0x17, + 0xf3, 0x3c, 0x21, 0xd7, 0x40, 0x17, 0x86, 0x3a, 0xa7, 0x05, 0x70, 0xd9, 0xd9, 0x05, 0xd8, 0xab, + 0x9d, 0x22, 0x80, 0xa5, 0xd5, 0x73, 0x8d, 0xea, 0xac, 0x75, 0x73, 0x59, 0x75, 0xae, 0x1b, 0x7a, + 0xe3, 0x3f, 0x03, 0xb0, 0xd4, 0x0a, 0x38, 0x5e, 0xc3, 0xa0, 0x32, 0x24, 0x1e, 0x6f, 0xed, 0x75, + 0xc3, 0xb6, 0xfe, 0xf3, 0x8e, 0x6a, 0xad, 0xbd, 0x81, 0x37, 0x60, 0x69, 0x63, 0xe1, 0x8b, 0x6d, + 0xe8, 0xa6, 0x61, 0xfd, 0x97, 0x9d, 0xf5, 0xd5, 0xb0, 0xf7, 0x60, 0x2a, 0x8f, 0xe1, 0xf6, 0x67, + 0x37, 0xbd, 0xe7, 0x77, 0xbc, 0xed, 0xc0, 0x78, 0xc5, 0xf0, 0x06, 0xec, 0x95, 0x2f, 0xf1, 0xa4, + 0xc3, 0x67, 0x6b, 0xcf, 0xfa, 0x4f, 0x3b, 0x20, 0x6a, 0xd8, 0x47, 0xd8, 0xab, 0x4d, 0x82, 0x5d, + 0x38, 0x7f, 0xb4, 0x55, 0x68, 0xfb, 0xca, 0xc0, 0xab, 0x46, 0x1b, 0xec, 0x78, 0xc6, 0x3b, 0xb6, + 0xd3, 0xb2, 0xa2, 0x1a, 0xa2, 0x45, 0x7d, 0xc4, 0x90, 0x96, 0x7b, 0xd5, 0x10, 0xfd, 0x1a, 0x1e, + 0x31, 0xa4, 0x65, 0x78, 0xe3, 0xbb, 0xa5, 0xfe, 0xf3, 0x5f, 0xff, 0x0d, 0x00, 0x00, 0xff, 0xff, + 0xde, 0x0b, 0x1c, 0x4a, 0x03, 0x06, 0x00, 0x00, } diff --git a/network/router/proto/router.proto b/network/router/proto/router.proto index eaa19b0e..77bfb58b 100644 --- a/network/router/proto/router.proto +++ b/network/router/proto/router.proto @@ -4,11 +4,22 @@ package go.micro.router; // Router service is used by the proxy to lookup routes service Router { - rpc Watch(WatchRequest) returns (stream Event) {}; - rpc Lookup(LookupRequest) returns (LookupResponse) {}; rpc List(ListRequest) returns (ListResponse) {}; + rpc Lookup(LookupRequest) returns (LookupResponse) {}; + rpc Watch(WatchRequest) returns (stream Event) {}; rpc Advertise(AdvertiseRequest) returns (stream Advert) {}; rpc Process(Advert) returns (ProcessResponse) {}; + rpc Create(Route) returns (CreateResponse) {}; + rpc Delete(Route) returns (DeleteResponse) {}; + rpc Update(Route) returns (UpdateResponse) {}; +} + +// ListRequest is made to List routes +message ListRequest {} + +// ListResponse is returned by List +message ListResponse { + repeated Route routes = 1; } // LookupRequest is made to Lookup @@ -24,7 +35,6 @@ message LookupResponse { // WatchRequest is made to Watch Router message WatchRequest {} - // AdvertiseRequest request a stream of Adverts message AdvertiseRequest {} @@ -51,6 +61,15 @@ message Advert { // ProcessResponse is returned by Process message ProcessResponse {} +// CreateResponse is returned by Create +message CreateResponse {} + +// DeleteResponse is returned by Delete +message DeleteResponse {} + +// UpdateResponse is returned by Update +message UpdateResponse {} + // EventType defines the type of event enum EventType { Create = 0; @@ -68,14 +87,6 @@ message Event { Route route = 3; } -// ListRequest is made to List routes -message ListRequest {} - -// ListResponse is returned by List -message ListResponse { - repeated Route routes = 1; -} - // Query is passed in a LookupRequest message Query { // service to lookup From c3a8146d99e09db3bd527476ead5b12e3c8b87bf Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Thu, 25 Jul 2019 23:37:51 +0100 Subject: [PATCH 210/287] Added outline of router/service package. --- network/router/router.go | 2 + network/router/service/service.go | 113 ++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 network/router/service/service.go diff --git a/network/router/router.go b/network/router/router.go index 0a0e4788..cf2e1e9c 100644 --- a/network/router/router.go +++ b/network/router/router.go @@ -8,6 +8,8 @@ import ( var ( // DefaultRouter is default network router DefaultRouter = NewRouter() + // DefaultName is default router service name + DefaultName = "go.micro.router" ) // Router is an interface for a routing control plane diff --git a/network/router/service/service.go b/network/router/service/service.go new file mode 100644 index 00000000..ed2d0bf3 --- /dev/null +++ b/network/router/service/service.go @@ -0,0 +1,113 @@ +package service + +import ( + "sync" + + "github.com/micro/go-micro/client" + "github.com/micro/go-micro/network/router" + pb "github.com/micro/go-micro/network/router/proto" +) + +type svc struct { + router pb.RouterService + opts router.Options + status router.Status + sync.RWMutex +} + +// NewRouter creates new service router and returns it +func NewRouter(opts ...router.Option) router.Router { + // get default options + options := router.DefaultOptions() + + // apply requested options + for _, o := range opts { + o(&options) + } + + // NOTE: might need some client opts here + client := client.DefaultClient + + // NOTE: should we have Client/Service option in router.Options? + s := &svc{ + opts: options, + status: router.Status{Code: router.Stopped, Error: nil}, + router: pb.NewRouterService(router.DefaultName, client), + } + + return s +} + +// Init initializes router with given options +func (s *svc) Init(opts ...router.Option) error { + for _, o := range opts { + o(&s.opts) + } + return nil +} + +// Options returns router options +func (s *svc) Options() router.Options { + return s.opts +} + +// Advertise advertises routes to the network +func (s *svc) Advertise() (<-chan *router.Advert, error) { + return nil, nil +} + +// Process processes incoming adverts +func (s *svc) Process(a *router.Advert) error { + return nil +} + +// Create new route in the routing table +func (s *svc) Create(r router.Route) error { + return nil +} + +// Delete deletes existing route from the routing table +func (s *svc) Delete(r router.Route) error { + return nil +} + +// Update updates route in the routing table +func (s *svc) Update(r router.Route) error { + return nil +} + +// List returns the list of all routes in the table +func (s *svc) List() ([]router.Route, error) { + return nil, nil +} + +// Lookup looks up routes in the routing table and returns them +func (s *svc) Lookup(q router.Query) ([]router.Route, error) { + return nil, nil +} + +// Watch returns a watcher which allows to track updates to the routing table +func (s *svc) Watch(opts ...router.WatchOption) (router.Watcher, error) { + return nil, nil +} + +// Status returns router status +func (s *svc) Status() router.Status { + s.RLock() + defer s.RUnlock() + + // make a copy of the status + status := s.status + + return status +} + +// Stop stops the router +func (s *svc) Stop() error { + return nil +} + +// Returns the router implementation +func (s *svc) String() string { + return "service" +} From 22d0f1f08f38707ca87e06892a0d99daf9e8810a Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Thu, 25 Jul 2019 23:52:54 +0100 Subject: [PATCH 211/287] Changed documentation. --- network/router/router.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/network/router/router.go b/network/router/router.go index cf2e1e9c..f1041b63 100644 --- a/network/router/router.go +++ b/network/router/router.go @@ -24,15 +24,15 @@ type Router interface { Process(*Advert) error // Create new route in the routing table Create(Route) error - // Delete deletes existing route from the routing table + // Delete existing route from the routing table Delete(Route) error - // Update updates route in the routing table + // Update exiting route in the routing table Update(Route) error - // List returns the list of all routes in the table + // List lists all routes in the routing table List() ([]Route, error) - // Lookup looks up routes in the routing table and returns them + // Lookup queries routes in the routing table Lookup(Query) ([]Route, error) - // Watch returns a watcher which allows to track updates to the routing table + // Watch returns a watcher which tracks updates to the routing table Watch(opts ...WatchOption) (Watcher, error) // Status returns router status Status() Status From b6fb969ab9338dbeab1c79e54f5c70b1aeba953b Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Fri, 26 Jul 2019 12:43:17 +0100 Subject: [PATCH 212/287] Add List and Lookup implementation. Default error for not implement. --- network/router/proto/router.pb.go | 97 ++++++++++++++++++------------- network/router/proto/router.proto | 4 ++ network/router/service/service.go | 60 +++++++++++++++++-- 3 files changed, 116 insertions(+), 45 deletions(-) diff --git a/network/router/proto/router.pb.go b/network/router/proto/router.pb.go index ef9fc698..ae0b9a5c 100644 --- a/network/router/proto/router.pb.go +++ b/network/router/proto/router.pb.go @@ -5,8 +5,9 @@ package go_micro_router import ( fmt "fmt" - proto "github.com/golang/protobuf/proto" math "math" + + proto "github.com/golang/protobuf/proto" ) // Reference imports to suppress errors if they are not otherwise used. @@ -558,7 +559,11 @@ func (m *Event) GetRoute() *Route { // Query is passed in a LookupRequest type Query struct { // service to lookup - Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` + Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` + // gateway to lookup + Gateway string `protobuf:"bytes,2,opt,name=gateway,proto3" json:"gateway,omitempty"` + // network to lookup + Network string `protobuf:"bytes,3,opt,name=network,proto3" json:"network,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -596,6 +601,20 @@ func (m *Query) GetService() string { return "" } +func (m *Query) GetGateway() string { + if m != nil { + return m.Gateway + } + return "" +} + +func (m *Query) GetNetwork() string { + if m != nil { + return m.Network + } + return "" +} + // Route is a service route type Route struct { // service for the route @@ -704,42 +723,40 @@ func init() { func init() { proto.RegisterFile("router.proto", fileDescriptor_367072455c71aedc) } var fileDescriptor_367072455c71aedc = []byte{ - // 584 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0xc1, 0x6e, 0xd3, 0x40, - 0x10, 0xf5, 0x26, 0xb1, 0x2b, 0x4f, 0x53, 0xd7, 0xcc, 0xa1, 0x58, 0xa6, 0x40, 0xea, 0x53, 0x55, - 0x55, 0x2e, 0x0a, 0x67, 0x10, 0xa5, 0x94, 0x4b, 0x7b, 0x00, 0x0b, 0xc4, 0xd9, 0xd8, 0xa3, 0x62, - 0x25, 0xb1, 0xdd, 0xdd, 0x4d, 0xaa, 0x9c, 0xf9, 0x0c, 0xbe, 0x80, 0xff, 0xe0, 0xc3, 0x90, 0x77, - 0xed, 0x24, 0x38, 0xf1, 0xa1, 0x9c, 0xb2, 0x33, 0xf3, 0x66, 0xbc, 0x6f, 0xde, 0xbe, 0xc0, 0x90, - 0x17, 0x73, 0x49, 0x3c, 0x2c, 0x79, 0x21, 0x0b, 0x3c, 0xbc, 0x2b, 0xc2, 0x59, 0x96, 0xf0, 0x22, - 0xd4, 0xe9, 0xe0, 0x00, 0xf6, 0x6f, 0x33, 0x21, 0x23, 0xba, 0x9f, 0x93, 0x90, 0xc1, 0x5b, 0x18, - 0xea, 0x50, 0x94, 0x45, 0x2e, 0x08, 0x43, 0xb0, 0x14, 0x50, 0x78, 0x6c, 0xd4, 0x3f, 0xdd, 0x1f, - 0x1f, 0x85, 0xad, 0x01, 0x61, 0x54, 0xfd, 0x44, 0x35, 0x2a, 0x78, 0x03, 0x07, 0xb7, 0x45, 0x31, - 0x99, 0x97, 0xf5, 0x40, 0x3c, 0x07, 0xf3, 0x7e, 0x4e, 0x7c, 0xe9, 0xb1, 0x11, 0xdb, 0xd9, 0xff, - 0xb9, 0xaa, 0x46, 0x1a, 0x14, 0xbc, 0x03, 0xa7, 0x69, 0xff, 0xcf, 0x0b, 0x38, 0x30, 0xfc, 0x16, - 0xcb, 0xe4, 0x47, 0x43, 0x08, 0xc1, 0xbd, 0x4c, 0x17, 0xc4, 0x65, 0x26, 0xa8, 0xc9, 0xfd, 0x66, - 0x60, 0xe9, 0x24, 0x3a, 0xd0, 0xcb, 0x52, 0x75, 0x37, 0x3b, 0xea, 0x65, 0x29, 0x5e, 0xc0, 0x40, - 0x2e, 0x4b, 0xf2, 0x7a, 0x23, 0x76, 0xea, 0x8c, 0x9f, 0x6d, 0x7d, 0x4c, 0xb7, 0x7d, 0x59, 0x96, - 0x14, 0x29, 0x20, 0x1e, 0x83, 0x2d, 0xb3, 0x19, 0x09, 0x19, 0xcf, 0x4a, 0xaf, 0x3f, 0x62, 0xa7, - 0xfd, 0x68, 0x9d, 0x40, 0x17, 0xfa, 0x52, 0x4e, 0xbd, 0x81, 0xca, 0x57, 0xc7, 0x8a, 0x0f, 0x2d, - 0x28, 0x97, 0xc2, 0x33, 0x3b, 0xf8, 0x5c, 0x57, 0xe5, 0xa8, 0x46, 0x05, 0x4f, 0xe0, 0xf0, 0x13, - 0x2f, 0x12, 0x12, 0xa2, 0x59, 0x49, 0xe0, 0x82, 0x73, 0xc5, 0x29, 0x96, 0xb4, 0x99, 0xf9, 0x40, - 0x53, 0xfa, 0x37, 0xf3, 0xb5, 0x4c, 0x37, 0x31, 0x3f, 0x19, 0x98, 0x6a, 0x34, 0x86, 0x35, 0x47, - 0xa6, 0x38, 0xfa, 0xbb, 0x2f, 0xd0, 0x45, 0xb1, 0xd7, 0xa6, 0x78, 0x0e, 0xa6, 0xea, 0x53, 0xe4, - 0xbb, 0xf5, 0xd1, 0xa0, 0xe0, 0x04, 0x4c, 0x25, 0x38, 0x7a, 0xb0, 0x27, 0x88, 0x2f, 0xb2, 0x84, - 0xea, 0xed, 0x37, 0x61, 0xf0, 0x8b, 0x81, 0xa9, 0x7a, 0xba, 0x31, 0x55, 0x25, 0x4e, 0x53, 0x4e, - 0x42, 0xa8, 0x0b, 0xd9, 0x51, 0x13, 0x56, 0x95, 0xbb, 0x58, 0xd2, 0x43, 0xbc, 0x54, 0x17, 0xb2, - 0xa3, 0x26, 0xac, 0x2a, 0x39, 0xc9, 0x87, 0x82, 0x4f, 0x94, 0x1e, 0x76, 0xd4, 0x84, 0x88, 0x30, - 0x98, 0x66, 0xf9, 0xc4, 0x33, 0x55, 0x5a, 0x9d, 0xf1, 0x08, 0xac, 0x19, 0x49, 0x9e, 0x25, 0x9e, - 0xa5, 0x18, 0xd7, 0xd1, 0xd9, 0x18, 0x60, 0xfd, 0x06, 0x10, 0xc1, 0xd1, 0xd1, 0x65, 0x9e, 0x17, - 0xf3, 0x3c, 0x21, 0xd7, 0x40, 0x17, 0x86, 0x3a, 0xa7, 0x05, 0x70, 0xd9, 0xd9, 0x05, 0xd8, 0xab, - 0x9d, 0x22, 0x80, 0xa5, 0xd5, 0x73, 0x8d, 0xea, 0xac, 0x75, 0x73, 0x59, 0x75, 0xae, 0x1b, 0x7a, - 0xe3, 0x3f, 0x03, 0xb0, 0xd4, 0x0a, 0x38, 0x5e, 0xc3, 0xa0, 0x32, 0x24, 0x1e, 0x6f, 0xed, 0x75, - 0xc3, 0xb6, 0xfe, 0xf3, 0x8e, 0x6a, 0xad, 0xbd, 0x81, 0x37, 0x60, 0x69, 0x63, 0xe1, 0x8b, 0x6d, - 0xe8, 0xa6, 0x61, 0xfd, 0x97, 0x9d, 0xf5, 0xd5, 0xb0, 0xf7, 0x60, 0x2a, 0x8f, 0xe1, 0xf6, 0x67, - 0x37, 0xbd, 0xe7, 0x77, 0xbc, 0xed, 0xc0, 0x78, 0xc5, 0xf0, 0x06, 0xec, 0x95, 0x2f, 0xf1, 0xa4, - 0xc3, 0x67, 0x6b, 0xcf, 0xfa, 0x4f, 0x3b, 0x20, 0x6a, 0xd8, 0x47, 0xd8, 0xab, 0x4d, 0x82, 0x5d, - 0x38, 0x7f, 0xb4, 0x55, 0x68, 0xfb, 0xca, 0xc0, 0xab, 0x46, 0x1b, 0xec, 0x78, 0xc6, 0x3b, 0xb6, - 0xd3, 0xb2, 0xa2, 0x1a, 0xa2, 0x45, 0x7d, 0xc4, 0x90, 0x96, 0x7b, 0xd5, 0x10, 0xfd, 0x1a, 0x1e, - 0x31, 0xa4, 0x65, 0x78, 0xe3, 0xbb, 0xa5, 0xfe, 0xf3, 0x5f, 0xff, 0x0d, 0x00, 0x00, 0xff, 0xff, - 0xde, 0x0b, 0x1c, 0x4a, 0x03, 0x06, 0x00, 0x00, + // 555 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0xdd, 0x6e, 0x94, 0x40, + 0x14, 0x06, 0x76, 0xa1, 0xe1, 0x74, 0x97, 0xd2, 0x73, 0x61, 0x08, 0x69, 0xea, 0x66, 0x8c, 0xa6, + 0x69, 0xe3, 0xd8, 0xac, 0x4f, 0xd0, 0xa8, 0x77, 0xbd, 0x50, 0x62, 0xe3, 0x35, 0xc2, 0x89, 0x92, + 0xee, 0x02, 0x9d, 0x99, 0xdd, 0x66, 0x1f, 0xc1, 0x67, 0xf0, 0x75, 0x7c, 0x30, 0xc3, 0xcc, 0xd0, + 0x65, 0x49, 0x6a, 0xbc, 0x9b, 0xef, 0x9b, 0x8f, 0x73, 0xe6, 0xfc, 0x7c, 0xc0, 0x4c, 0x34, 0x1b, + 0x45, 0x82, 0xb7, 0xa2, 0x51, 0x0d, 0x9b, 0xc3, 0xf1, 0x6d, 0x25, 0x55, 0x46, 0x0f, 0x1b, 0x92, + 0x8a, 0x71, 0x98, 0x19, 0x28, 0xdb, 0xa6, 0x96, 0x84, 0xe7, 0x10, 0x68, 0xb9, 0x4c, 0xdc, 0xc5, + 0xe4, 0xe2, 0x78, 0x19, 0xf0, 0xac, 0x83, 0x99, 0x65, 0xd9, 0x5b, 0x98, 0xdf, 0x36, 0xcd, 0xfd, + 0xa6, 0xb5, 0x01, 0xf0, 0x0c, 0xfc, 0x87, 0x0d, 0x89, 0x5d, 0xe2, 0x2e, 0x5c, 0xad, 0xff, 0xd2, + 0xa1, 0xcc, 0x90, 0xec, 0x1a, 0xa2, 0x5e, 0xfe, 0x9f, 0x09, 0x22, 0x98, 0x7d, 0xcb, 0x55, 0xf1, + 0xb3, 0x7f, 0x20, 0x42, 0x7c, 0x53, 0x6e, 0x49, 0xa8, 0x4a, 0x52, 0xcf, 0xfd, 0x72, 0x21, 0x30, + 0x24, 0x46, 0xe0, 0x55, 0xa5, 0xce, 0x1d, 0x66, 0x5e, 0x55, 0xe2, 0x4b, 0x98, 0xaa, 0x5d, 0x4b, + 0x89, 0xb7, 0x70, 0x2f, 0xa2, 0xe5, 0x31, 0x37, 0xb2, 0xaf, 0xbb, 0x96, 0x32, 0x7d, 0x81, 0x67, + 0x10, 0xaa, 0x6a, 0x4d, 0x52, 0xe5, 0xeb, 0x36, 0x99, 0x2c, 0xdc, 0x8b, 0x49, 0xb6, 0x27, 0x30, + 0x86, 0x89, 0x52, 0xab, 0x64, 0xaa, 0xf9, 0xee, 0xd8, 0xbd, 0x97, 0xb6, 0x54, 0x2b, 0x99, 0xf8, + 0xf6, 0xbd, 0x9f, 0x3a, 0x98, 0x59, 0x96, 0x9d, 0xc2, 0xc9, 0x67, 0xd1, 0x14, 0x24, 0x65, 0x5f, + 0x22, 0x8b, 0x21, 0xfa, 0x20, 0x28, 0x57, 0x34, 0x64, 0x3e, 0xd2, 0x8a, 0x0e, 0x99, 0xbb, 0xb6, + 0x1c, 0x6a, 0x0a, 0xf0, 0x75, 0x64, 0x3c, 0xb7, 0x25, 0xb8, 0xba, 0x04, 0x30, 0xf9, 0x9e, 0xab, + 0xc0, 0x1b, 0x57, 0x70, 0x06, 0xbe, 0xee, 0xa4, 0xae, 0x6d, 0xdf, 0x5e, 0x43, 0xb2, 0x3b, 0xf0, + 0xf5, 0x7c, 0x30, 0x81, 0x23, 0x49, 0x62, 0x5b, 0x15, 0x64, 0x9b, 0xd7, 0xc3, 0xee, 0xe6, 0x47, + 0xae, 0xe8, 0x31, 0xdf, 0xe9, 0xe0, 0x61, 0xd6, 0xc3, 0xee, 0xa6, 0x26, 0xf5, 0xd8, 0x88, 0x7b, + 0x1d, 0x3c, 0xcc, 0x7a, 0xc8, 0x7e, 0xbb, 0xe0, 0xeb, 0x3c, 0xff, 0x8e, 0x9b, 0x97, 0xa5, 0x20, + 0x29, 0xfb, 0xb8, 0x16, 0x0e, 0x33, 0x4e, 0x9e, 0xcd, 0x38, 0x3d, 0xc8, 0x88, 0x08, 0xd3, 0x55, + 0x55, 0xdf, 0x27, 0xbe, 0xa6, 0xf5, 0x19, 0x5f, 0x40, 0xb0, 0x26, 0x25, 0xaa, 0x22, 0x09, 0x74, + 0x57, 0x2c, 0xba, 0x5c, 0x02, 0xec, 0xd7, 0x00, 0x11, 0x22, 0x83, 0x6e, 0xea, 0xba, 0xd9, 0xd4, + 0x05, 0xc5, 0x0e, 0xc6, 0x30, 0x33, 0x9c, 0x99, 0x49, 0xec, 0x5e, 0xbe, 0x83, 0xf0, 0xa9, 0xef, + 0x08, 0x10, 0x98, 0x81, 0xc6, 0x4e, 0x77, 0x36, 0xa3, 0x8c, 0xdd, 0xee, 0x6c, 0x3f, 0xf0, 0x96, + 0x7f, 0x3c, 0x08, 0x74, 0x0b, 0x04, 0xbe, 0x86, 0x69, 0xe7, 0x29, 0x9c, 0xf1, 0x81, 0xd3, 0xd2, + 0x39, 0x1f, 0x1a, 0x8d, 0x39, 0x78, 0x05, 0x81, 0xf1, 0x06, 0x46, 0xfc, 0xc0, 0x53, 0xe9, 0x09, + 0x3f, 0x34, 0x0d, 0x73, 0x90, 0x81, 0xaf, 0x6d, 0x81, 0x73, 0x3e, 0xb4, 0x47, 0x6a, 0xd7, 0x91, + 0x39, 0xd7, 0x2e, 0x5e, 0x41, 0xf8, 0x64, 0x15, 0x3c, 0xe5, 0x63, 0xdb, 0xa4, 0x47, 0x96, 0xd2, + 0xe2, 0x37, 0x70, 0x64, 0xf7, 0x16, 0x7b, 0x3e, 0x8d, 0xf9, 0x78, 0x95, 0x1d, 0x7c, 0xd5, 0xd7, + 0x8e, 0x76, 0x95, 0xd2, 0x13, 0x3e, 0xda, 0x6e, 0x2d, 0x32, 0x4d, 0x19, 0x88, 0x46, 0x0b, 0xaf, + 0x45, 0xa6, 0x5b, 0x03, 0xd1, 0xc8, 0x03, 0xce, 0xf7, 0x40, 0xff, 0xa5, 0xde, 0xff, 0x0d, 0x00, + 0x00, 0xff, 0xff, 0x20, 0xdd, 0x0c, 0xbd, 0xb5, 0x04, 0x00, 0x00, } diff --git a/network/router/proto/router.proto b/network/router/proto/router.proto index 77bfb58b..921e3e7e 100644 --- a/network/router/proto/router.proto +++ b/network/router/proto/router.proto @@ -91,6 +91,10 @@ message Event { message Query { // service to lookup string service = 1; + // gateway to lookup + string gateway = 2; + // network to lookup + string network = 3; } // Route is a service route diff --git a/network/router/service/service.go b/network/router/service/service.go index ed2d0bf3..cc79d5ce 100644 --- a/network/router/service/service.go +++ b/network/router/service/service.go @@ -1,6 +1,8 @@ package service import ( + "context" + "errors" "sync" "github.com/micro/go-micro/client" @@ -8,6 +10,11 @@ import ( pb "github.com/micro/go-micro/network/router/proto" ) +var ( + // ErrNotImplemented means the functionality has not been implemented + ErrNotImplemented = errors.New("not implemented") +) + type svc struct { router pb.RouterService opts router.Options @@ -63,27 +70,70 @@ func (s *svc) Process(a *router.Advert) error { // Create new route in the routing table func (s *svc) Create(r router.Route) error { - return nil + return ErrNotImplemented } // Delete deletes existing route from the routing table func (s *svc) Delete(r router.Route) error { - return nil + return ErrNotImplemented } // Update updates route in the routing table func (s *svc) Update(r router.Route) error { - return nil + return ErrNotImplemented } // List returns the list of all routes in the table func (s *svc) List() ([]router.Route, error) { - return nil, nil + resp, err := s.router.List(context.Background(), &pb.ListRequest{}) + if err != nil { + return nil, err + } + + routes := make([]router.Route, len(resp.Routes)) + for i, route := range resp.Routes { + routes[i] = router.Route{ + Service: route.Service, + Address: route.Address, + Gateway: route.Gateway, + Network: route.Network, + Link: route.Link, + Metric: int(route.Metric), + } + } + + return routes, nil } // Lookup looks up routes in the routing table and returns them func (s *svc) Lookup(q router.Query) ([]router.Route, error) { - return nil, nil + // call the router + resp, err := s.router.Lookup(context.Background(), &pb.LookupRequest{ + Query: &pb.Query{ + Service: q.Options().Service, + Gateway: q.Options().Gateway, + Network: q.Options().Network, + }, + }) + + // errored out + if err != nil { + return nil, err + } + + routes := make([]router.Route, len(resp.Routes)) + for i, route := range resp.Routes { + routes[i] = router.Route{ + Service: route.Service, + Address: route.Address, + Gateway: route.Gateway, + Network: route.Network, + Link: route.Link, + Metric: int(route.Metric), + } + } + + return routes, nil } // Watch returns a watcher which allows to track updates to the routing table From ddad43bd774408795c8973252dbc0de43edbc750 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Fri, 26 Jul 2019 14:05:03 +0100 Subject: [PATCH 213/287] Added service.Router Route CRUD. Outlined watcher and run() --- network/router/service/service.go | 94 +++++++++++++++++++++++++++---- network/router/service/watcher.go | 49 ++++++++++++++++ network/router/watcher.go | 7 ++- 3 files changed, 139 insertions(+), 11 deletions(-) create mode 100644 network/router/service/watcher.go diff --git a/network/router/service/service.go b/network/router/service/service.go index cc79d5ce..d1929b55 100644 --- a/network/router/service/service.go +++ b/network/router/service/service.go @@ -5,6 +5,7 @@ import ( "errors" "sync" + "github.com/google/uuid" "github.com/micro/go-micro/client" "github.com/micro/go-micro/network/router" pb "github.com/micro/go-micro/network/router/proto" @@ -16,9 +17,10 @@ var ( ) type svc struct { - router pb.RouterService - opts router.Options - status router.Status + opts router.Options + router pb.RouterService + status router.Status + watchers map[string]*svcWatcher sync.RWMutex } @@ -37,9 +39,10 @@ func NewRouter(opts ...router.Option) router.Router { // NOTE: should we have Client/Service option in router.Options? s := &svc{ - opts: options, - status: router.Status{Code: router.Stopped, Error: nil}, - router: pb.NewRouterService(router.DefaultName, client), + opts: options, + router: pb.NewRouterService(router.DefaultName, client), + status: router.Status{Code: router.Stopped, Error: nil}, + watchers: make(map[string]*svcWatcher), } return s @@ -58,8 +61,22 @@ func (s *svc) Options() router.Options { return s.opts } +// Run runs the router. +// It returns error if the router is already running. +func (s *svc) run() { + s.Lock() + defer s.Unlock() + + switch s.status.Code { + case router.Stopped, router.Error: + // TODO: start event stream watcher + // TODO: start watchError monitor + } +} + // Advertise advertises routes to the network func (s *svc) Advertise() (<-chan *router.Advert, error) { + // TODO: start advert stream watcher return nil, nil } @@ -70,17 +87,56 @@ func (s *svc) Process(a *router.Advert) error { // Create new route in the routing table func (s *svc) Create(r router.Route) error { - return ErrNotImplemented + route := &pb.Route{ + Service: r.Service, + Address: r.Address, + Gateway: r.Gateway, + Network: r.Network, + Link: r.Link, + Metric: int64(r.Metric), + } + + if _, err := s.router.Create(context.Background(), route); err != nil { + return err + } + + return nil } // Delete deletes existing route from the routing table func (s *svc) Delete(r router.Route) error { - return ErrNotImplemented + route := &pb.Route{ + Service: r.Service, + Address: r.Address, + Gateway: r.Gateway, + Network: r.Network, + Link: r.Link, + Metric: int64(r.Metric), + } + + if _, err := s.router.Delete(context.Background(), route); err != nil { + return err + } + + return nil } // Update updates route in the routing table func (s *svc) Update(r router.Route) error { - return ErrNotImplemented + route := &pb.Route{ + Service: r.Service, + Address: r.Address, + Gateway: r.Gateway, + Network: r.Network, + Link: r.Link, + Metric: int64(r.Metric), + } + + if _, err := s.router.Update(context.Background(), route); err != nil { + return err + } + + return nil } // List returns the list of all routes in the table @@ -138,7 +194,25 @@ func (s *svc) Lookup(q router.Query) ([]router.Route, error) { // Watch returns a watcher which allows to track updates to the routing table func (s *svc) Watch(opts ...router.WatchOption) (router.Watcher, error) { - return nil, nil + wopts := router.WatchOptions{ + Service: "*", + } + + for _, o := range opts { + o(&wopts) + } + + w := &svcWatcher{ + opts: wopts, + resChan: make(chan *router.Event, 10), + done: make(chan struct{}), + } + + s.Lock() + s.watchers[uuid.New().String()] = w + s.Unlock() + + return w, nil } // Status returns router status diff --git a/network/router/service/watcher.go b/network/router/service/watcher.go new file mode 100644 index 00000000..984c3439 --- /dev/null +++ b/network/router/service/watcher.go @@ -0,0 +1,49 @@ +package service + +import ( + "sync" + + "github.com/micro/go-micro/network/router" +) + +type svcWatcher struct { + opts router.WatchOptions + resChan chan *router.Event + done chan struct{} + sync.RWMutex +} + +// Next is a blocking call that returns watch result +func (w *svcWatcher) Next() (*router.Event, error) { + for { + select { + case res := <-w.resChan: + switch w.opts.Service { + case res.Route.Service, "*": + return res, nil + default: + continue + } + case <-w.done: + return nil, router.ErrWatcherStopped + } + } +} + +// Chan returns event channel +func (w *svcWatcher) Chan() (<-chan *router.Event, error) { + return w.resChan, nil +} + +// Stop stops watcher +func (w *svcWatcher) Stop() { + w.Lock() + defer w.Unlock() + + select { + case <-w.done: + return + default: + close(w.done) + } +} diff --git a/network/router/watcher.go b/network/router/watcher.go index d1ff3ea7..d1a9c017 100644 --- a/network/router/watcher.go +++ b/network/router/watcher.go @@ -2,6 +2,7 @@ package router import ( "errors" + "sync" "time" ) @@ -78,10 +79,11 @@ type tableWatcher struct { opts WatchOptions resChan chan *Event done chan struct{} + sync.RWMutex } // Next returns the next noticed action taken on table -// TODO: think this through properly; right now we only watch service +// TODO: right now we only allow to watch particular service func (w *tableWatcher) Next() (*Event, error) { for { select { @@ -105,6 +107,9 @@ func (w *tableWatcher) Chan() (<-chan *Event, error) { // Stop stops routing table watcher func (w *tableWatcher) Stop() { + w.Lock() + defer w.Unlock() + select { case <-w.done: return From c5740ae03149943891870024a12a5dffe5664cb9 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Fri, 26 Jul 2019 17:11:59 +0100 Subject: [PATCH 214/287] Outline of Advertise, Watch and start of the router. --- network/router/service/service.go | 197 ++++++++++++++++++++++++++++-- network/router/table.go | 6 +- 2 files changed, 192 insertions(+), 11 deletions(-) diff --git a/network/router/service/service.go b/network/router/service/service.go index d1929b55..c5a088f5 100644 --- a/network/router/service/service.go +++ b/network/router/service/service.go @@ -3,7 +3,10 @@ package service import ( "context" "errors" + "fmt" + "io" "sync" + "time" "github.com/google/uuid" "github.com/micro/go-micro/client" @@ -17,10 +20,14 @@ var ( ) type svc struct { - opts router.Options - router pb.RouterService - status router.Status - watchers map[string]*svcWatcher + opts router.Options + router pb.RouterService + status router.Status + watchers map[string]*svcWatcher + exit chan struct{} + errChan chan error + advertChan chan *router.Advert + wg *sync.WaitGroup sync.RWMutex } @@ -43,8 +50,11 @@ func NewRouter(opts ...router.Option) router.Router { router: pb.NewRouterService(router.DefaultName, client), status: router.Status{Code: router.Stopped, Error: nil}, watchers: make(map[string]*svcWatcher), + wg: &sync.WaitGroup{}, } + go s.run() + return s } @@ -61,6 +71,70 @@ func (s *svc) Options() router.Options { return s.opts } +// watchErrors watches router errors and takes appropriate actions +func (s *svc) watchErrors() { + var err error + + select { + case <-s.exit: + case err = <-s.errChan: + } + + s.Lock() + defer s.Unlock() + if s.status.Code != router.Stopped { + // notify all goroutines to finish + close(s.exit) + // TODO" might need to drain some channels here + } + + if err != nil { + s.status = router.Status{Code: router.Error, Error: err} + } +} + +// watchRouter watches router and send events to all registered watchers +func (s *svc) watchRouter(stream pb.Router_WatchService) error { + defer stream.Close() + var watchErr error + + for { + resp, err := stream.Recv() + if err != nil { + if err != io.EOF { + watchErr = err + } + break + } + + route := router.Route{ + Service: resp.Route.Service, + Address: resp.Route.Address, + Gateway: resp.Route.Gateway, + Network: resp.Route.Network, + Link: resp.Route.Link, + Metric: int(resp.Route.Metric), + } + + event := &router.Event{ + Type: router.EventType(resp.Type), + Timestamp: time.Unix(0, resp.Timestamp), + Route: route, + } + + s.RLock() + for _, w := range s.watchers { + select { + case w.resChan <- event: + case <-w.done: + } + } + s.RUnlock() + } + + return watchErr +} + // Run runs the router. // It returns error if the router is already running. func (s *svc) run() { @@ -69,15 +143,107 @@ func (s *svc) run() { switch s.status.Code { case router.Stopped, router.Error: - // TODO: start event stream watcher - // TODO: start watchError monitor + stream, err := s.router.Watch(context.Background(), &pb.WatchRequest{}) + if err != nil { + s.status = router.Status{Code: router.Error, Error: fmt.Errorf("failed getting router stream: %s", err)} + return + } + + // create error and exit channels + s.errChan = make(chan error, 1) + s.exit = make(chan struct{}) + + s.wg.Add(1) + go func() { + defer s.wg.Done() + select { + case s.errChan <- s.watchRouter(stream): + case <-s.exit: + } + }() + + // watch for errors and cleanup + s.wg.Add(1) + go func() { + defer s.wg.Done() + s.watchErrors() + }() + + // mark router as Running and set its Error to nil + s.status = router.Status{Code: router.Running, Error: nil} + + return } + + return +} + +func (s *svc) advertiseEvents(stream pb.Router_AdvertiseService) error { + defer stream.Close() + var advErr error + + for { + resp, err := stream.Recv() + if err != nil { + if err != io.EOF { + advErr = err + } + break + } + + // TODO: sort out events and TTL + advert := &router.Advert{ + Id: resp.Id, + Type: router.AdvertType(resp.Type), + Timestamp: time.Unix(0, resp.Timestamp), + //Events: events, + } + + select { + case s.advertChan <- advert: + case <-s.exit: + return nil + } + } + + return advErr } // Advertise advertises routes to the network func (s *svc) Advertise() (<-chan *router.Advert, error) { - // TODO: start advert stream watcher - return nil, nil + s.Lock() + defer s.Unlock() + + switch s.status.Code { + case router.Advertising: + return s.advertChan, nil + case router.Running: + stream, err := s.router.Advertise(context.Background(), &pb.AdvertiseRequest{}) + if err != nil { + return nil, fmt.Errorf("failed getting advert stream: %s", err) + } + + // create advertise and event channels + s.advertChan = make(chan *router.Advert) + + s.wg.Add(1) + go func() { + defer s.wg.Done() + select { + case s.errChan <- s.advertiseEvents(stream): + case <-s.exit: + } + }() + + // mark router as Running and set its Error to nil + s.status = router.Status{Code: router.Advertising, Error: nil} + + return s.advertChan, nil + case router.Stopped: + return nil, fmt.Errorf("not running") + } + + return nil, fmt.Errorf("error: %s", s.status.Error) } // Process processes incoming adverts @@ -228,6 +394,21 @@ func (s *svc) Status() router.Status { // Stop stops the router func (s *svc) Stop() error { + s.Lock() + // only close the channel if the router is running and/or advertising + if s.status.Code == router.Running || s.status.Code == router.Advertising { + // notify all goroutines to finish + close(s.exit) + // TODO: might need to drain some channels here + + // mark the router as Stopped and set its Error to nil + s.status = router.Status{Code: router.Stopped, Error: nil} + } + s.Unlock() + + // wait for all goroutines to finish + s.wg.Wait() + return nil } diff --git a/network/router/table.go b/network/router/table.go index cb746cbb..75b7a10d 100644 --- a/network/router/table.go +++ b/network/router/table.go @@ -179,14 +179,14 @@ func (t *Table) Watch(opts ...WatchOption) (Watcher, error) { return w, nil } -// sendEvent sends rules to all subscribe watchers -func (t *Table) sendEvent(r *Event) { +// sendEvent sends events to all subscribed watchers +func (t *Table) sendEvent(e *Event) { t.RLock() defer t.RUnlock() for _, w := range t.watchers { select { - case w.resChan <- r: + case w.resChan <- e: case <-w.done: } } From 002abca61f93ab3f7b33f598f95924085ee4ac48 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Sat, 27 Jul 2019 12:40:16 +0100 Subject: [PATCH 215/287] Finished Advertise(). Implemented Process() --- network/router/service/service.go | 53 +++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/network/router/service/service.go b/network/router/service/service.go index c5a088f5..f651131a 100644 --- a/network/router/service/service.go +++ b/network/router/service/service.go @@ -191,12 +191,30 @@ func (s *svc) advertiseEvents(stream pb.Router_AdvertiseService) error { break } - // TODO: sort out events and TTL + events := make([]*router.Event, len(resp.Events)) + for i, event := range resp.Events { + route := router.Route{ + Service: event.Route.Service, + Address: event.Route.Address, + Gateway: event.Route.Gateway, + Network: event.Route.Network, + Link: event.Route.Link, + Metric: int(event.Route.Metric), + } + + events[i] = &router.Event{ + Type: router.EventType(event.Type), + Timestamp: time.Unix(0, event.Timestamp), + Route: route, + } + } + advert := &router.Advert{ Id: resp.Id, Type: router.AdvertType(resp.Type), Timestamp: time.Unix(0, resp.Timestamp), - //Events: events, + TTL: time.Duration(resp.Ttl), + Events: events, } select { @@ -247,7 +265,36 @@ func (s *svc) Advertise() (<-chan *router.Advert, error) { } // Process processes incoming adverts -func (s *svc) Process(a *router.Advert) error { +func (s *svc) Process(advert *router.Advert) error { + var events []*pb.Event + for _, event := range advert.Events { + route := &pb.Route{ + Service: event.Route.Service, + Address: event.Route.Address, + Gateway: event.Route.Gateway, + Network: event.Route.Network, + Link: event.Route.Link, + Metric: int64(event.Route.Metric), + } + e := &pb.Event{ + Type: pb.EventType(event.Type), + Timestamp: event.Timestamp.UnixNano(), + Route: route, + } + events = append(events, e) + } + + advertReq := &pb.Advert{ + Id: s.Options().Id, + Type: pb.AdvertType(advert.Type), + Timestamp: advert.Timestamp.UnixNano(), + Events: events, + } + + if _, err := s.router.Process(context.Background(), advertReq); err != nil { + return err + } + return nil } From d8b00e801d230de80673abd06e254bf695502161 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Sat, 27 Jul 2019 13:08:54 +0100 Subject: [PATCH 216/287] Stop watcher when router stops. Drain advert channel when stopping. --- network/router/default.go | 1 - network/router/service/service.go | 70 +++++++++++++++++-------------- 2 files changed, 38 insertions(+), 33 deletions(-) diff --git a/network/router/default.go b/network/router/default.go index cf98da3c..0b8c41de 100644 --- a/network/router/default.go +++ b/network/router/default.go @@ -445,7 +445,6 @@ func (r *router) watchErrors() { } // Run runs the router. -// It returns error if the router is already running. func (r *router) run() { r.Lock() defer r.Unlock() diff --git a/network/router/service/service.go b/network/router/service/service.go index f651131a..5a6daeda 100644 --- a/network/router/service/service.go +++ b/network/router/service/service.go @@ -2,7 +2,6 @@ package service import ( "context" - "errors" "fmt" "io" "sync" @@ -14,11 +13,6 @@ import ( pb "github.com/micro/go-micro/network/router/proto" ) -var ( - // ErrNotImplemented means the functionality has not been implemented - ErrNotImplemented = errors.New("not implemented") -) - type svc struct { opts router.Options router pb.RouterService @@ -71,31 +65,10 @@ func (s *svc) Options() router.Options { return s.opts } -// watchErrors watches router errors and takes appropriate actions -func (s *svc) watchErrors() { - var err error - - select { - case <-s.exit: - case err = <-s.errChan: - } - - s.Lock() - defer s.Unlock() - if s.status.Code != router.Stopped { - // notify all goroutines to finish - close(s.exit) - // TODO" might need to drain some channels here - } - - if err != nil { - s.status = router.Status{Code: router.Error, Error: err} - } -} - // watchRouter watches router and send events to all registered watchers func (s *svc) watchRouter(stream pb.Router_WatchService) error { defer stream.Close() + var watchErr error for { @@ -122,6 +95,7 @@ func (s *svc) watchRouter(stream pb.Router_WatchService) error { Route: route, } + // TODO: might make this non-blocking s.RLock() for _, w := range s.watchers { select { @@ -135,8 +109,31 @@ func (s *svc) watchRouter(stream pb.Router_WatchService) error { return watchErr } +// watchErrors watches router errors and takes appropriate actions +func (s *svc) watchErrors() { + var err error + + select { + case <-s.exit: + case err = <-s.errChan: + } + + s.Lock() + defer s.Unlock() + if s.status.Code != router.Stopped { + // notify all goroutines to finish + close(s.exit) + // drain the advertise channel + for range s.advertChan { + } + } + + if err != nil { + s.status = router.Status{Code: router.Error, Error: err} + } +} + // Run runs the router. -// It returns error if the router is already running. func (s *svc) run() { s.Lock() defer s.Unlock() @@ -145,7 +142,7 @@ func (s *svc) run() { case router.Stopped, router.Error: stream, err := s.router.Watch(context.Background(), &pb.WatchRequest{}) if err != nil { - s.status = router.Status{Code: router.Error, Error: fmt.Errorf("failed getting router stream: %s", err)} + s.status = router.Status{Code: router.Error, Error: fmt.Errorf("failed getting event stream: %s", err)} return } @@ -425,6 +422,14 @@ func (s *svc) Watch(opts ...router.WatchOption) (router.Watcher, error) { s.watchers[uuid.New().String()] = w s.Unlock() + // when the router stops, stop the watcher and exit + s.wg.Add(1) + go func() { + defer s.wg.Done() + <-s.exit + w.Stop() + }() + return w, nil } @@ -446,8 +451,9 @@ func (s *svc) Stop() error { if s.status.Code == router.Running || s.status.Code == router.Advertising { // notify all goroutines to finish close(s.exit) - // TODO: might need to drain some channels here - + // drain the advertise channel + for range s.advertChan { + } // mark the router as Stopped and set its Error to nil s.status = router.Status{Code: router.Stopped, Error: nil} } From 2f1658c213cb62e2f170d8826df91d06343b0d19 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Sat, 27 Jul 2019 13:58:51 +0100 Subject: [PATCH 217/287] Table package is no more, hence removed references to it --- client/selector/router/router.go | 11 +++++------ network/proxy/mucp/mucp.go | 16 +++++++--------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/client/selector/router/router.go b/client/selector/router/router.go index 7f391f5b..1c03b9ec 100644 --- a/client/selector/router/router.go +++ b/client/selector/router/router.go @@ -11,7 +11,6 @@ import ( "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/network/router" pb "github.com/micro/go-micro/network/router/proto" - "github.com/micro/go-micro/network/router/table" "github.com/micro/go-micro/registry" ) @@ -41,11 +40,11 @@ type clientKey struct{} type routerKey struct{} // getRoutes returns the routes whether they are remote or local -func (r *routerSelector) getRoutes(service string) ([]table.Route, error) { +func (r *routerSelector) getRoutes(service string) ([]router.Route, error) { if !r.remote { // lookup router for routes for the service - return r.r.Lookup(table.NewQuery( - table.QueryService(service), + return r.r.Lookup(router.NewQuery( + router.QueryService(service), )) } @@ -102,11 +101,11 @@ func (r *routerSelector) getRoutes(service string) ([]table.Route, error) { return nil, selector.ErrNoneAvailable } - var routes []table.Route + var routes []router.Route // convert from pb to []*router.Route for _, r := range pbRoutes.Routes { - routes = append(routes, table.Route{ + routes = append(routes, router.Route{ Service: r.Service, Address: r.Address, Gateway: r.Gateway, diff --git a/network/proxy/mucp/mucp.go b/network/proxy/mucp/mucp.go index 10e3669b..d70c4f77 100644 --- a/network/proxy/mucp/mucp.go +++ b/network/proxy/mucp/mucp.go @@ -15,8 +15,6 @@ import ( "github.com/micro/go-micro/network/proxy" "github.com/micro/go-micro/network/router" "github.com/micro/go-micro/server" - - "github.com/micro/go-micro/network/router/table" ) // Proxy will transparently proxy requests to an endpoint. @@ -36,7 +34,7 @@ type Proxy struct { // A fib of routes service:address sync.RWMutex - Routes map[string]map[uint64]table.Route + Routes map[string]map[uint64]router.Route // The channel to monitor watcher errors errChan chan error @@ -78,7 +76,7 @@ func readLoop(r server.Request, s client.Stream) error { } // toNodes returns a list of node addresses from given routes -func toNodes(routes map[uint64]table.Route) []string { +func toNodes(routes map[uint64]router.Route) []string { var nodes []string for _, node := range routes { address := node.Address @@ -98,7 +96,7 @@ func (p *Proxy) getRoute(service string) ([]string, error) { p.Unlock() return toNodes(routes), nil } - p.Routes[service] = make(map[uint64]table.Route) + p.Routes[service] = make(map[uint64]router.Route) p.Unlock() // if the router is broken return error @@ -107,7 +105,7 @@ func (p *Proxy) getRoute(service string) ([]string, error) { } // lookup the routes in the router - results, err := p.Router.Lookup(table.NewQuery(table.QueryService(service))) + results, err := p.Router.Lookup(router.NewQuery(router.QueryService(service))) if err != nil { return nil, err } @@ -124,11 +122,11 @@ func (p *Proxy) getRoute(service string) ([]string, error) { } // manageRouteCache applies action on a given route to Proxy route cache -func (p *Proxy) manageRouteCache(route table.Route, action string) error { +func (p *Proxy) manageRouteCache(route router.Route, action string) error { switch action { case "create", "update": if _, ok := p.Routes[route.Service]; !ok { - p.Routes[route.Service] = make(map[uint64]table.Route) + p.Routes[route.Service] = make(map[uint64]router.Route) } p.Routes[route.Service][route.Hash()] = route case "delete": @@ -317,7 +315,7 @@ func NewProxy(opts ...options.Option) proxy.Proxy { } // routes cache - p.Routes = make(map[string]map[uint64]table.Route) + p.Routes = make(map[string]map[uint64]router.Route) // watch router service routes p.errChan = make(chan error, 1) From cb3052ce0461f9abe3d50105bfe1f94f5e61a440 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Sat, 27 Jul 2019 16:00:55 +0100 Subject: [PATCH 218/287] Proper stopping of service router --- network/router/service/service.go | 34 +++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/network/router/service/service.go b/network/router/service/service.go index 5a6daeda..004959cc 100644 --- a/network/router/service/service.go +++ b/network/router/service/service.go @@ -67,7 +67,12 @@ func (s *svc) Options() router.Options { // watchRouter watches router and send events to all registered watchers func (s *svc) watchRouter(stream pb.Router_WatchService) error { - defer stream.Close() + s.wg.Add(1) + go func() { + defer s.wg.Done() + <-s.exit + stream.Close() + }() var watchErr error @@ -123,9 +128,12 @@ func (s *svc) watchErrors() { if s.status.Code != router.Stopped { // notify all goroutines to finish close(s.exit) - // drain the advertise channel - for range s.advertChan { + if s.status.Code == router.Advertising { + // drain the advertise channel + for range s.advertChan { + } } + s.status = router.Status{Code: router.Stopped, Error: nil} } if err != nil { @@ -176,7 +184,13 @@ func (s *svc) run() { } func (s *svc) advertiseEvents(stream pb.Router_AdvertiseService) error { - defer stream.Close() + s.wg.Add(1) + go func() { + defer s.wg.Done() + <-s.exit + stream.Close() + }() + var advErr error for { @@ -217,10 +231,14 @@ func (s *svc) advertiseEvents(stream pb.Router_AdvertiseService) error { select { case s.advertChan <- advert: case <-s.exit: + close(s.advertChan) return nil } } + // close the channel on exit + close(s.advertChan) + return advErr } @@ -451,9 +469,13 @@ func (s *svc) Stop() error { if s.status.Code == router.Running || s.status.Code == router.Advertising { // notify all goroutines to finish close(s.exit) - // drain the advertise channel - for range s.advertChan { + + // drain the advertise channel only if advertising + if s.status.Code == router.Advertising { + for range s.advertChan { + } } + // mark the router as Stopped and set its Error to nil s.status = router.Status{Code: router.Stopped, Error: nil} } From 96f9ce1bd31b5a822e3cecf780c7e95eeb375cc3 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Sat, 27 Jul 2019 16:01:30 +0100 Subject: [PATCH 219/287] Proper router stopping. Printable router status. --- network/router/default.go | 31 +++++++++++++++++++++---------- network/router/router.go | 15 +++++++++++++++ 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/network/router/default.go b/network/router/default.go index 0b8c41de..8cf08e51 100644 --- a/network/router/default.go +++ b/network/router/default.go @@ -431,12 +431,19 @@ func (r *router) watchErrors() { if r.status.Code != Stopped { // notify all goroutines to finish close(r.exit) - // drain the advertise channel - for range r.advertChan { - } - // drain the event channel - for range r.eventChan { + + // drain the advertise channel only if advertising + if r.status.Code == Advertising { + // drain the advertise channel + for range r.advertChan { + } + // drain the event channel + for range r.eventChan { + } } + + // mark the router as Stopped and set its Error to nil + r.status = Status{Code: Stopped, Error: nil} } if err != nil { @@ -615,11 +622,15 @@ func (r *router) Stop() error { if r.status.Code == Running || r.status.Code == Advertising { // notify all goroutines to finish close(r.exit) - // drain the advertise channel - for range r.advertChan { - } - // drain the event channel - for range r.eventChan { + + // drain the advertise channel only if advertising + if r.status.Code == Advertising { + // drain the advertise channel + for range r.advertChan { + } + // drain the event channel + for range r.eventChan { + } } // mark the router as Stopped and set its Error to nil diff --git a/network/router/router.go b/network/router/router.go index f1041b63..80ad7e1c 100644 --- a/network/router/router.go +++ b/network/router/router.go @@ -59,6 +59,21 @@ const ( Error ) +func (s StatusCode) String() string { + switch s { + case Running: + return "running" + case Advertising: + return "advertising" + case Stopped: + return "stopped" + case Error: + return "error" + default: + return "unknown" + } +} + // Status is router status type Status struct { // Error is router error From 3d2ec5dbb168245a4e1c94706dfa93a5181b3fa5 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Sat, 27 Jul 2019 16:12:44 +0100 Subject: [PATCH 220/287] Regenerated proto because proto reasons. --- network/router/proto/router.pb.go | 77 ++++++++++++++++--------------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/network/router/proto/router.pb.go b/network/router/proto/router.pb.go index ae0b9a5c..1582776d 100644 --- a/network/router/proto/router.pb.go +++ b/network/router/proto/router.pb.go @@ -5,9 +5,8 @@ package go_micro_router import ( fmt "fmt" - math "math" - proto "github.com/golang/protobuf/proto" + math "math" ) // Reference imports to suppress errors if they are not otherwise used. @@ -723,40 +722,42 @@ func init() { func init() { proto.RegisterFile("router.proto", fileDescriptor_367072455c71aedc) } var fileDescriptor_367072455c71aedc = []byte{ - // 555 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0xdd, 0x6e, 0x94, 0x40, - 0x14, 0x06, 0x76, 0xa1, 0xe1, 0x74, 0x97, 0xd2, 0x73, 0x61, 0x08, 0x69, 0xea, 0x66, 0x8c, 0xa6, - 0x69, 0xe3, 0xd8, 0xac, 0x4f, 0xd0, 0xa8, 0x77, 0xbd, 0x50, 0x62, 0xe3, 0x35, 0xc2, 0x89, 0x92, - 0xee, 0x02, 0x9d, 0x99, 0xdd, 0x66, 0x1f, 0xc1, 0x67, 0xf0, 0x75, 0x7c, 0x30, 0xc3, 0xcc, 0xd0, - 0x65, 0x49, 0x6a, 0xbc, 0x9b, 0xef, 0x9b, 0x8f, 0x73, 0xe6, 0xfc, 0x7c, 0xc0, 0x4c, 0x34, 0x1b, - 0x45, 0x82, 0xb7, 0xa2, 0x51, 0x0d, 0x9b, 0xc3, 0xf1, 0x6d, 0x25, 0x55, 0x46, 0x0f, 0x1b, 0x92, - 0x8a, 0x71, 0x98, 0x19, 0x28, 0xdb, 0xa6, 0x96, 0x84, 0xe7, 0x10, 0x68, 0xb9, 0x4c, 0xdc, 0xc5, - 0xe4, 0xe2, 0x78, 0x19, 0xf0, 0xac, 0x83, 0x99, 0x65, 0xd9, 0x5b, 0x98, 0xdf, 0x36, 0xcd, 0xfd, - 0xa6, 0xb5, 0x01, 0xf0, 0x0c, 0xfc, 0x87, 0x0d, 0x89, 0x5d, 0xe2, 0x2e, 0x5c, 0xad, 0xff, 0xd2, - 0xa1, 0xcc, 0x90, 0xec, 0x1a, 0xa2, 0x5e, 0xfe, 0x9f, 0x09, 0x22, 0x98, 0x7d, 0xcb, 0x55, 0xf1, - 0xb3, 0x7f, 0x20, 0x42, 0x7c, 0x53, 0x6e, 0x49, 0xa8, 0x4a, 0x52, 0xcf, 0xfd, 0x72, 0x21, 0x30, - 0x24, 0x46, 0xe0, 0x55, 0xa5, 0xce, 0x1d, 0x66, 0x5e, 0x55, 0xe2, 0x4b, 0x98, 0xaa, 0x5d, 0x4b, - 0x89, 0xb7, 0x70, 0x2f, 0xa2, 0xe5, 0x31, 0x37, 0xb2, 0xaf, 0xbb, 0x96, 0x32, 0x7d, 0x81, 0x67, - 0x10, 0xaa, 0x6a, 0x4d, 0x52, 0xe5, 0xeb, 0x36, 0x99, 0x2c, 0xdc, 0x8b, 0x49, 0xb6, 0x27, 0x30, - 0x86, 0x89, 0x52, 0xab, 0x64, 0xaa, 0xf9, 0xee, 0xd8, 0xbd, 0x97, 0xb6, 0x54, 0x2b, 0x99, 0xf8, - 0xf6, 0xbd, 0x9f, 0x3a, 0x98, 0x59, 0x96, 0x9d, 0xc2, 0xc9, 0x67, 0xd1, 0x14, 0x24, 0x65, 0x5f, - 0x22, 0x8b, 0x21, 0xfa, 0x20, 0x28, 0x57, 0x34, 0x64, 0x3e, 0xd2, 0x8a, 0x0e, 0x99, 0xbb, 0xb6, - 0x1c, 0x6a, 0x0a, 0xf0, 0x75, 0x64, 0x3c, 0xb7, 0x25, 0xb8, 0xba, 0x04, 0x30, 0xf9, 0x9e, 0xab, - 0xc0, 0x1b, 0x57, 0x70, 0x06, 0xbe, 0xee, 0xa4, 0xae, 0x6d, 0xdf, 0x5e, 0x43, 0xb2, 0x3b, 0xf0, - 0xf5, 0x7c, 0x30, 0x81, 0x23, 0x49, 0x62, 0x5b, 0x15, 0x64, 0x9b, 0xd7, 0xc3, 0xee, 0xe6, 0x47, - 0xae, 0xe8, 0x31, 0xdf, 0xe9, 0xe0, 0x61, 0xd6, 0xc3, 0xee, 0xa6, 0x26, 0xf5, 0xd8, 0x88, 0x7b, - 0x1d, 0x3c, 0xcc, 0x7a, 0xc8, 0x7e, 0xbb, 0xe0, 0xeb, 0x3c, 0xff, 0x8e, 0x9b, 0x97, 0xa5, 0x20, - 0x29, 0xfb, 0xb8, 0x16, 0x0e, 0x33, 0x4e, 0x9e, 0xcd, 0x38, 0x3d, 0xc8, 0x88, 0x08, 0xd3, 0x55, - 0x55, 0xdf, 0x27, 0xbe, 0xa6, 0xf5, 0x19, 0x5f, 0x40, 0xb0, 0x26, 0x25, 0xaa, 0x22, 0x09, 0x74, - 0x57, 0x2c, 0xba, 0x5c, 0x02, 0xec, 0xd7, 0x00, 0x11, 0x22, 0x83, 0x6e, 0xea, 0xba, 0xd9, 0xd4, - 0x05, 0xc5, 0x0e, 0xc6, 0x30, 0x33, 0x9c, 0x99, 0x49, 0xec, 0x5e, 0xbe, 0x83, 0xf0, 0xa9, 0xef, - 0x08, 0x10, 0x98, 0x81, 0xc6, 0x4e, 0x77, 0x36, 0xa3, 0x8c, 0xdd, 0xee, 0x6c, 0x3f, 0xf0, 0x96, - 0x7f, 0x3c, 0x08, 0x74, 0x0b, 0x04, 0xbe, 0x86, 0x69, 0xe7, 0x29, 0x9c, 0xf1, 0x81, 0xd3, 0xd2, - 0x39, 0x1f, 0x1a, 0x8d, 0x39, 0x78, 0x05, 0x81, 0xf1, 0x06, 0x46, 0xfc, 0xc0, 0x53, 0xe9, 0x09, - 0x3f, 0x34, 0x0d, 0x73, 0x90, 0x81, 0xaf, 0x6d, 0x81, 0x73, 0x3e, 0xb4, 0x47, 0x6a, 0xd7, 0x91, - 0x39, 0xd7, 0x2e, 0x5e, 0x41, 0xf8, 0x64, 0x15, 0x3c, 0xe5, 0x63, 0xdb, 0xa4, 0x47, 0x96, 0xd2, - 0xe2, 0x37, 0x70, 0x64, 0xf7, 0x16, 0x7b, 0x3e, 0x8d, 0xf9, 0x78, 0x95, 0x1d, 0x7c, 0xd5, 0xd7, - 0x8e, 0x76, 0x95, 0xd2, 0x13, 0x3e, 0xda, 0x6e, 0x2d, 0x32, 0x4d, 0x19, 0x88, 0x46, 0x0b, 0xaf, - 0x45, 0xa6, 0x5b, 0x03, 0xd1, 0xc8, 0x03, 0xce, 0xf7, 0x40, 0xff, 0xa5, 0xde, 0xff, 0x0d, 0x00, - 0x00, 0xff, 0xff, 0x20, 0xdd, 0x0c, 0xbd, 0xb5, 0x04, 0x00, 0x00, + // 591 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0xc1, 0x6e, 0xd3, 0x40, + 0x10, 0xf5, 0x26, 0xb6, 0x2b, 0x4f, 0x53, 0xd7, 0xcc, 0xa1, 0x58, 0xa6, 0x40, 0xf0, 0xa9, 0xaa, + 0x2a, 0x17, 0x85, 0x33, 0x88, 0x52, 0xca, 0xa5, 0x3d, 0x80, 0x45, 0xc5, 0xd9, 0xd8, 0xa3, 0x62, + 0xb5, 0xb1, 0xdd, 0xdd, 0x4d, 0xab, 0x9c, 0xf9, 0x0c, 0xbe, 0x80, 0xff, 0xe0, 0xc3, 0x90, 0x77, + 0xed, 0xd6, 0x75, 0x62, 0xa4, 0x72, 0xca, 0xce, 0xcc, 0x9b, 0x37, 0x3b, 0x33, 0xfb, 0x62, 0x98, + 0xf0, 0x72, 0x21, 0x89, 0x47, 0x15, 0x2f, 0x65, 0x89, 0xdb, 0x17, 0x65, 0x34, 0xcf, 0x53, 0x5e, + 0x46, 0xda, 0x1d, 0x6e, 0xc1, 0xe6, 0x59, 0x2e, 0x64, 0x4c, 0xd7, 0x0b, 0x12, 0x32, 0x7c, 0x07, + 0x13, 0x6d, 0x8a, 0xaa, 0x2c, 0x04, 0x61, 0x04, 0xb6, 0x02, 0x0a, 0x9f, 0x4d, 0xc7, 0x7b, 0x9b, + 0xb3, 0x9d, 0xa8, 0x47, 0x10, 0xc5, 0xf5, 0x4f, 0xdc, 0xa0, 0xc2, 0xb7, 0xb0, 0x75, 0x56, 0x96, + 0x97, 0x8b, 0xaa, 0x21, 0xc4, 0x03, 0xb0, 0xae, 0x17, 0xc4, 0x97, 0x3e, 0x9b, 0xb2, 0xb5, 0xf9, + 0x5f, 0xea, 0x68, 0xac, 0x41, 0xe1, 0x7b, 0x70, 0xdb, 0xf4, 0xff, 0xbc, 0x80, 0x0b, 0x93, 0x6f, + 0x89, 0x4c, 0x7f, 0xb4, 0x0d, 0x21, 0x78, 0x47, 0xd9, 0x0d, 0x71, 0x99, 0x0b, 0x6a, 0x7d, 0xbf, + 0x19, 0xd8, 0xda, 0x89, 0x2e, 0x8c, 0xf2, 0x4c, 0xdd, 0xcd, 0x89, 0x47, 0x79, 0x86, 0x87, 0x60, + 0xca, 0x65, 0x45, 0xfe, 0x68, 0xca, 0xf6, 0xdc, 0xd9, 0xb3, 0x95, 0x62, 0x3a, 0xed, 0xeb, 0xb2, + 0xa2, 0x58, 0x01, 0x71, 0x17, 0x1c, 0x99, 0xcf, 0x49, 0xc8, 0x64, 0x5e, 0xf9, 0xe3, 0x29, 0xdb, + 0x1b, 0xc7, 0xf7, 0x0e, 0xf4, 0x60, 0x2c, 0xe5, 0x95, 0x6f, 0x2a, 0x7f, 0x7d, 0xac, 0xfb, 0xa1, + 0x1b, 0x2a, 0xa4, 0xf0, 0xad, 0x81, 0x7e, 0x4e, 0xea, 0x70, 0xdc, 0xa0, 0xc2, 0x27, 0xb0, 0xfd, + 0x99, 0x97, 0x29, 0x09, 0xd1, 0x8e, 0x24, 0xf4, 0xc0, 0x3d, 0xe6, 0x94, 0x48, 0xea, 0x7a, 0x3e, + 0xd2, 0x15, 0x3d, 0xf4, 0x9c, 0x57, 0x59, 0x17, 0xf3, 0x93, 0x81, 0xa5, 0xa8, 0x31, 0x6a, 0x7a, + 0x64, 0xaa, 0xc7, 0x60, 0xfd, 0x05, 0x86, 0x5a, 0x1c, 0xf5, 0x5b, 0x3c, 0x00, 0x4b, 0xe5, 0xa9, + 0xe6, 0x87, 0xf7, 0xa3, 0x41, 0xe1, 0x39, 0x58, 0x6a, 0xe1, 0xe8, 0xc3, 0x86, 0x20, 0x7e, 0x93, + 0xa7, 0xd4, 0x4c, 0xbf, 0x35, 0xeb, 0xc8, 0x45, 0x22, 0xe9, 0x36, 0x59, 0xaa, 0x62, 0x4e, 0xdc, + 0x9a, 0x75, 0xa4, 0x20, 0x79, 0x5b, 0xf2, 0x4b, 0x55, 0xcc, 0x89, 0x5b, 0x33, 0xfc, 0xc5, 0xc0, + 0x52, 0x75, 0xfe, 0xcd, 0x9b, 0x64, 0x19, 0x27, 0x21, 0x5a, 0xde, 0xc6, 0xec, 0x56, 0x1c, 0x0f, + 0x56, 0x34, 0x1f, 0x54, 0x44, 0x04, 0xf3, 0x2a, 0x2f, 0x2e, 0x7d, 0x4b, 0xb9, 0xd5, 0x19, 0x77, + 0xc0, 0x9e, 0x93, 0xe4, 0x79, 0xea, 0xdb, 0x6a, 0x4a, 0x8d, 0xb5, 0x3f, 0x03, 0xb8, 0x7f, 0x37, + 0x88, 0xe0, 0x6a, 0xeb, 0xa8, 0x28, 0xca, 0x45, 0x91, 0x92, 0x67, 0xa0, 0x07, 0x13, 0xed, 0xd3, + 0x4b, 0xf3, 0xd8, 0xfe, 0x21, 0x38, 0x77, 0x7b, 0x40, 0x00, 0x5b, 0x6f, 0xdc, 0x33, 0xea, 0xb3, + 0xde, 0xb5, 0xc7, 0xea, 0x73, 0x93, 0x30, 0x9a, 0xfd, 0x31, 0xc1, 0x56, 0x23, 0xe0, 0x78, 0x02, + 0x66, 0x2d, 0x62, 0xdc, 0x5d, 0xd9, 0x45, 0x47, 0xea, 0xc1, 0xf3, 0x81, 0x68, 0xf3, 0x5e, 0x0c, + 0x3c, 0x05, 0x5b, 0x8b, 0x11, 0x5f, 0xac, 0x42, 0xbb, 0x22, 0x0f, 0x5e, 0x0e, 0xc6, 0xef, 0xc8, + 0x3e, 0x80, 0xa5, 0x74, 0x89, 0xab, 0x65, 0xbb, 0x7a, 0x0d, 0x06, 0xf4, 0x10, 0x1a, 0xaf, 0x19, + 0x9e, 0x82, 0x73, 0xa7, 0x65, 0x7c, 0x35, 0xa0, 0xcd, 0x7b, 0x9d, 0x07, 0x4f, 0x07, 0x20, 0x8a, + 0xec, 0x13, 0x6c, 0x34, 0xc2, 0xc2, 0x21, 0x5c, 0x30, 0x5d, 0x09, 0xf4, 0xb5, 0x68, 0xe0, 0x71, + 0xbb, 0x1b, 0x1c, 0x78, 0xfa, 0x6b, 0xa6, 0xd3, 0x93, 0xaf, 0x22, 0xd1, 0x4b, 0x7d, 0x04, 0x49, + 0x4f, 0xf1, 0x8a, 0x44, 0xbf, 0x86, 0x47, 0x90, 0xf4, 0xfe, 0x24, 0x8c, 0xef, 0xb6, 0xfa, 0x4e, + 0xbc, 0xf9, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xbb, 0x08, 0x6d, 0x39, 0x37, 0x06, 0x00, 0x00, } From adb6760e2103d7c33cf163110489f8ec2f04fee8 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Sun, 28 Jul 2019 12:14:40 +0100 Subject: [PATCH 221/287] readd the resolver --- network/resolver/dns/dns.go | 30 ++++++++++++++ network/resolver/http/http.go | 59 +++++++++++++++++++++++++++ network/resolver/registry/registry.go | 37 +++++++++++++++++ network/resolver/resolver.go | 15 +++++++ 4 files changed, 141 insertions(+) create mode 100644 network/resolver/dns/dns.go create mode 100644 network/resolver/http/http.go create mode 100644 network/resolver/registry/registry.go create mode 100644 network/resolver/resolver.go diff --git a/network/resolver/dns/dns.go b/network/resolver/dns/dns.go new file mode 100644 index 00000000..c905df0e --- /dev/null +++ b/network/resolver/dns/dns.go @@ -0,0 +1,30 @@ +// Package dns resolves ids to dns srv records +package dns + +import ( + "fmt" + "net" + + "github.com/micro/go-micro/network/resolver" +) + +type Resolver struct{} + +// Resolve assumes ID is a domain name e.g micro.mu +func (r *Resolver) Resolve(id string) ([]*resolver.Record, error) { + _, addrs, err := net.LookupSRV("network", "udp", id) + if err != nil { + return nil, err + } + var records []*resolver.Record + for _, addr := range addrs { + address := addr.Target + if addr.Port > 0 { + address = fmt.Sprintf("%s:%d", addr.Target, addr.Port) + } + records = append(records, &resolver.Record{ + Address: address, + }) + } + return records, nil +} diff --git a/network/resolver/http/http.go b/network/resolver/http/http.go new file mode 100644 index 00000000..80ff4d61 --- /dev/null +++ b/network/resolver/http/http.go @@ -0,0 +1,59 @@ +// Package http resolves ids to network addresses using a http request +package http + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "net/url" + + "github.com/micro/go-micro/network/resolver" +) + +type Resolver struct { + // If not set, defaults to http + Proto string + + // Path sets the path to lookup. Defaults to /network + Path string +} + +// Resolve assumes ID is a domain which can be converted to a http://id/network request +func (r *Resolver) Resolve(id string) ([]*resolver.Record, error) { + proto := "http" + path := "/network" + + if len(r.Proto) > 0 { + proto = r.Proto + } + + if len(r.Path) > 0 { + path = r.Path + } + + uri := &url.URL{ + Scheme: proto, + Path: path, + Host: id, + } + + rsp, err := http.Get(uri.String()) + if err != nil { + return nil, err + } + defer rsp.Body.Close() + + b, err := ioutil.ReadAll(rsp.Body) + if err != nil { + return nil, err + } + + // encoding format is assumed to be json + var records []*resolver.Record + + if err := json.Unmarshal(b, &records); err != nil { + return nil, err + } + + return records, nil +} diff --git a/network/resolver/registry/registry.go b/network/resolver/registry/registry.go new file mode 100644 index 00000000..c7ef796a --- /dev/null +++ b/network/resolver/registry/registry.go @@ -0,0 +1,37 @@ +// Package registry resolves ids using the go-micro registry +package registry + +import ( + "github.com/micro/go-micro/network/resolver" + "github.com/micro/go-micro/registry" +) + +type Resolver struct { + // Registry is the registry to use otherwise we use the defaul + Registry registry.Registry +} + +// Resolve assumes ID is a domain name e.g micro.mu +func (r *Resolver) Resolve(id string) ([]*resolver.Record, error) { + reg := r.Registry + if reg == nil { + reg = registry.DefaultRegistry + } + + services, err := reg.GetService(id) + if err != nil { + return nil, err + } + + var records []*resolver.Record + + for _, service := range services { + for _, node := range service.Nodes { + records = append(records, &resolver.Record{ + Address: node.Address, + }) + } + } + + return records, nil +} diff --git a/network/resolver/resolver.go b/network/resolver/resolver.go new file mode 100644 index 00000000..6c54eb95 --- /dev/null +++ b/network/resolver/resolver.go @@ -0,0 +1,15 @@ +// Package resolver resolves network ids to addresses +package resolver + +// Resolver is network resolver. It's used to find network nodes +// via id to connect to. This is done based on Network.Id(). +// Before we can be part of any network, we have to connect to it. +type Resolver interface { + // Resolve returns a list of addresses for an id + Resolve(id string) ([]*Record, error) +} + +// A resolved record +type Record struct { + Address string `json:"address"` +} From f2669e7b1e62abc871987ed5e943043dca8b8484 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Sun, 28 Jul 2019 18:56:18 +0100 Subject: [PATCH 222/287] Move connection pool to own package --- client/pool/default.go | 114 ++++++++++++++++++ .../default_test.go} | 19 +-- client/pool/options.go | 33 +++++ client/pool/pool.go | 35 ++++++ client/rpc_client.go | 30 +++-- client/rpc_pool.go | 87 ------------- 6 files changed, 215 insertions(+), 103 deletions(-) create mode 100644 client/pool/default.go rename client/{rpc_pool_test.go => pool/default_test.go} (86%) create mode 100644 client/pool/options.go create mode 100644 client/pool/pool.go delete mode 100644 client/rpc_pool.go diff --git a/client/pool/default.go b/client/pool/default.go new file mode 100644 index 00000000..d625289c --- /dev/null +++ b/client/pool/default.go @@ -0,0 +1,114 @@ +package pool + +import ( + "sync" + "time" + + "github.com/google/uuid" + "github.com/micro/go-micro/transport" +) + +type pool struct { + size int + ttl time.Duration + tr transport.Transport + + sync.Mutex + conns map[string][]*poolConn +} + +type poolConn struct { + transport.Client + id string + created time.Time +} + +func newPool(options Options) *pool { + return &pool{ + size: options.Size, + tr: options.Transport, + ttl: options.TTL, + conns: make(map[string][]*poolConn), + } +} + +func (p *pool) Close() error { + p.Lock() + for k, c := range p.conns { + for _, conn := range c { + conn.Client.Close() + } + delete(p.conns, k) + } + p.Unlock() + return nil +} + +// NoOp the Close since we manage it +func (p *poolConn) Close() error { + return nil +} + +func (p *poolConn) Id() string { + return p.id +} + +func (p *poolConn) Created() time.Time { + return p.created +} + +func (p *pool) Get(addr string, opts ...transport.DialOption) (Conn, error) { + p.Lock() + conns := p.conns[addr] + + // while we have conns check age and then return one + // otherwise we'll create a new conn + for len(conns) > 0 { + conn := conns[len(conns)-1] + conns = conns[:len(conns)-1] + p.conns[addr] = conns + + // if conn is old kill it and move on + if d := time.Since(conn.Created()); d > p.ttl { + conn.Client.Close() + continue + } + + // we got a good conn, lets unlock and return it + p.Unlock() + + return conn, nil + } + + p.Unlock() + + // create new conn + c, err := p.tr.Dial(addr, opts...) + if err != nil { + return nil, err + } + return &poolConn{ + Client: c, + id: uuid.New().String(), + created: time.Now(), + }, nil +} + +func (p *pool) Release(conn Conn, err error) error { + // don't store the conn if it has errored + if err != nil { + return conn.(*poolConn).Client.Close() + } + + // otherwise put it back for reuse + p.Lock() + conns := p.conns[conn.Remote()] + if len(conns) >= p.size { + p.Unlock() + return conn.(*poolConn).Client.Close() + } + p.conns[conn.Remote()] = append(conns, conn.(*poolConn)) + p.Unlock() + + return nil +} diff --git a/client/rpc_pool_test.go b/client/pool/default_test.go similarity index 86% rename from client/rpc_pool_test.go rename to client/pool/default_test.go index 6c5875f1..4823e228 100644 --- a/client/rpc_pool_test.go +++ b/client/pool/default_test.go @@ -1,4 +1,4 @@ -package client +package pool import ( "testing" @@ -9,12 +9,17 @@ import ( ) func testPool(t *testing.T, size int, ttl time.Duration) { - // zero pool - p := newPool(size, ttl) - // mock transport tr := memory.NewTransport() + options := Options{ + TTL: ttl, + Size: size, + Transport: tr, + } + // zero pool + p := newPool(options) + // listen l, err := tr.Listen(":0") if err != nil { @@ -43,7 +48,7 @@ func testPool(t *testing.T, size int, ttl time.Duration) { for i := 0; i < 10; i++ { // get a conn - c, err := p.getConn(l.Addr(), tr) + c, err := p.Get(l.Addr()) if err != nil { t.Fatal(err) } @@ -67,7 +72,7 @@ func testPool(t *testing.T, size int, ttl time.Duration) { } // release the conn - p.release(l.Addr(), c, nil) + p.Release(c, nil) p.Lock() if i := len(p.conns[l.Addr()]); i > size { @@ -78,7 +83,7 @@ func testPool(t *testing.T, size int, ttl time.Duration) { } } -func TestRPCPool(t *testing.T) { +func TestClientPool(t *testing.T) { testPool(t, 0, time.Minute) testPool(t, 2, time.Minute) } diff --git a/client/pool/options.go b/client/pool/options.go new file mode 100644 index 00000000..ed3feda7 --- /dev/null +++ b/client/pool/options.go @@ -0,0 +1,33 @@ +package pool + +import ( + "time" + + "github.com/micro/go-micro/transport" +) + +type Options struct { + Transport transport.Transport + TTL time.Duration + Size int +} + +type Option func(*Options) + +func Size(i int) Option { + return func(o *Options) { + o.Size = i + } +} + +func Transport(t transport.Transport) Option { + return func(o *Options) { + o.Transport = t + } +} + +func TTL(t time.Duration) Option { + return func(o *Options) { + o.TTL = t + } +} diff --git a/client/pool/pool.go b/client/pool/pool.go new file mode 100644 index 00000000..79dd1a64 --- /dev/null +++ b/client/pool/pool.go @@ -0,0 +1,35 @@ +// Package pool is a connection pool +package pool + +import ( + "time" + + "github.com/micro/go-micro/transport" +) + +// Pool is an interface for connection pooling +type Pool interface { + // Close the pool + Close() error + // Get a connection + Get(addr string, opts ...transport.DialOption) (Conn, error) + // Releaes the connection + Release(c Conn, status error) error +} + +type Conn interface { + // unique id of connection + Id() string + // time it was created + Created() time.Time + // embedded connection + transport.Client +} + +func NewPool(opts ...Option) Pool { + var options Options + for _, o := range opts { + o(&options) + } + return newPool(options) +} diff --git a/client/rpc_client.go b/client/rpc_client.go index 39d044d9..724e3b89 100644 --- a/client/rpc_client.go +++ b/client/rpc_client.go @@ -11,6 +11,7 @@ import ( "github.com/google/uuid" "github.com/micro/go-micro/broker" + "github.com/micro/go-micro/client/pool" "github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/codec" "github.com/micro/go-micro/errors" @@ -22,17 +23,23 @@ import ( type rpcClient struct { once sync.Once opts Options - pool *pool + pool pool.Pool seq uint64 } func newRpcClient(opt ...Option) Client { opts := newOptions(opt...) + p := pool.NewPool( + pool.Size(opts.PoolSize), + pool.TTL(opts.PoolTTL), + pool.Transport(opts.Transport), + ) + rc := &rpcClient{ once: sync.Once{}, opts: opts, - pool: newPool(opts.PoolSize, opts.PoolTTL), + pool: p, seq: 0, } @@ -90,13 +97,13 @@ func (r *rpcClient) call(ctx context.Context, node *registry.Node, req Request, } var grr error - c, err := r.pool.getConn(address, r.opts.Transport, transport.WithTimeout(opts.DialTimeout)) + c, err := r.pool.Get(address, transport.WithTimeout(opts.DialTimeout)) if err != nil { return errors.InternalServerError("go.micro.client", "connection error: %v", err) } defer func() { // defer execution of release - r.pool.release(address, c, grr) + r.pool.Release(c, grr) }() seq := atomic.LoadUint64(&r.seq) @@ -245,17 +252,22 @@ func (r *rpcClient) stream(ctx context.Context, node *registry.Node, req Request func (r *rpcClient) Init(opts ...Option) error { size := r.opts.PoolSize ttl := r.opts.PoolTTL + tr := r.opts.Transport for _, o := range opts { o(&r.opts) } // update pool configuration if the options changed - if size != r.opts.PoolSize || ttl != r.opts.PoolTTL { - r.pool.Lock() - r.pool.size = r.opts.PoolSize - r.pool.ttl = int64(r.opts.PoolTTL.Seconds()) - r.pool.Unlock() + if size != r.opts.PoolSize || ttl != r.opts.PoolTTL || tr != r.opts.Transport { + // close existing pool + r.pool.Close() + // create new pool + r.pool = pool.NewPool( + pool.Size(r.opts.PoolSize), + pool.TTL(r.opts.PoolTTL), + pool.Transport(r.opts.Transport), + ) } return nil diff --git a/client/rpc_pool.go b/client/rpc_pool.go deleted file mode 100644 index 9fdd7736..00000000 --- a/client/rpc_pool.go +++ /dev/null @@ -1,87 +0,0 @@ -package client - -import ( - "sync" - "time" - - "github.com/micro/go-micro/transport" -) - -type pool struct { - size int - ttl int64 - - sync.Mutex - conns map[string][]*poolConn -} - -type poolConn struct { - transport.Client - created int64 -} - -func newPool(size int, ttl time.Duration) *pool { - return &pool{ - size: size, - ttl: int64(ttl.Seconds()), - conns: make(map[string][]*poolConn), - } -} - -// NoOp the Close since we manage it -func (p *poolConn) Close() error { - return nil -} - -func (p *pool) getConn(addr string, tr transport.Transport, opts ...transport.DialOption) (*poolConn, error) { - p.Lock() - conns := p.conns[addr] - now := time.Now().Unix() - - // while we have conns check age and then return one - // otherwise we'll create a new conn - for len(conns) > 0 { - conn := conns[len(conns)-1] - conns = conns[:len(conns)-1] - p.conns[addr] = conns - - // if conn is old kill it and move on - if d := now - conn.created; d > p.ttl { - conn.Client.Close() - continue - } - - // we got a good conn, lets unlock and return it - p.Unlock() - - return conn, nil - } - - p.Unlock() - - // create new conn - c, err := tr.Dial(addr, opts...) - if err != nil { - return nil, err - } - return &poolConn{c, time.Now().Unix()}, nil -} - -func (p *pool) release(addr string, conn *poolConn, err error) { - // don't store the conn if it has errored - if err != nil { - conn.Client.Close() - return - } - - // otherwise put it back for reuse - p.Lock() - conns := p.conns[addr] - if len(conns) >= p.size { - p.Unlock() - conn.Client.Close() - return - } - p.conns[addr] = append(conns, conn) - p.Unlock() -} From 1db98ee0f08c457c31a2c1c263d1e7cea453cec1 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Sun, 28 Jul 2019 19:33:24 +0100 Subject: [PATCH 223/287] move all the buffer references to util/buf --- client/grpc/buffer.go | 14 -------------- client/grpc/grpc.go | 5 +++-- client/rpc_client.go | 7 +++++-- server/buffer.go | 14 -------------- server/grpc/buffer.go | 14 -------------- server/grpc/subscriber.go | 3 ++- server/subscriber.go | 3 ++- transport/http_transport.go | 20 +++++--------------- client/buffer.go => util/buf/buf.go | 9 ++++++++- 9 files changed, 25 insertions(+), 64 deletions(-) delete mode 100644 client/grpc/buffer.go delete mode 100644 server/buffer.go delete mode 100644 server/grpc/buffer.go rename client/buffer.go => util/buf/buf.go (52%) diff --git a/client/grpc/buffer.go b/client/grpc/buffer.go deleted file mode 100644 index c43bb231..00000000 --- a/client/grpc/buffer.go +++ /dev/null @@ -1,14 +0,0 @@ -package grpc - -import ( - "bytes" -) - -type buffer struct { - *bytes.Buffer -} - -func (b *buffer) Close() error { - b.Buffer.Reset() - return nil -} diff --git a/client/grpc/grpc.go b/client/grpc/grpc.go index 6f5c3789..c6a3f5dd 100644 --- a/client/grpc/grpc.go +++ b/client/grpc/grpc.go @@ -2,7 +2,6 @@ package grpc import ( - "bytes" "context" "crypto/tls" "fmt" @@ -19,6 +18,7 @@ import ( "github.com/micro/go-micro/registry" "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/util/buf" "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/encoding" @@ -491,7 +491,8 @@ func (g *grpcClient) Publish(ctx context.Context, p client.Message, opts ...clie return errors.InternalServerError("go.micro.client", err.Error()) } - b := &buffer{bytes.NewBuffer(nil)} + b := buf.New(nil) + if err := cf(b).Write(&codec.Message{Type: codec.Event}, p.Payload()); err != nil { return errors.InternalServerError("go.micro.client", err.Error()) } diff --git a/client/rpc_client.go b/client/rpc_client.go index 724e3b89..a1f46dea 100644 --- a/client/rpc_client.go +++ b/client/rpc_client.go @@ -1,7 +1,6 @@ package client import ( - "bytes" "context" "fmt" "os" @@ -18,6 +17,7 @@ import ( "github.com/micro/go-micro/metadata" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/util/buf" ) type rpcClient struct { @@ -538,7 +538,10 @@ func (r *rpcClient) Publish(ctx context.Context, msg Message, opts ...PublishOpt if err != nil { return errors.InternalServerError("go.micro.client", err.Error()) } - b := &buffer{bytes.NewBuffer(nil)} + + // new buffer + b := buf.New(nil) + if err := cf(b).Write(&codec.Message{ Target: topic, Type: codec.Event, diff --git a/server/buffer.go b/server/buffer.go deleted file mode 100644 index 4df03c27..00000000 --- a/server/buffer.go +++ /dev/null @@ -1,14 +0,0 @@ -package server - -import ( - "bytes" -) - -type buffer struct { - *bytes.Buffer -} - -func (b *buffer) Close() error { - b.Buffer.Reset() - return nil -} diff --git a/server/grpc/buffer.go b/server/grpc/buffer.go deleted file mode 100644 index c43bb231..00000000 --- a/server/grpc/buffer.go +++ /dev/null @@ -1,14 +0,0 @@ -package grpc - -import ( - "bytes" -) - -type buffer struct { - *bytes.Buffer -} - -func (b *buffer) Close() error { - b.Buffer.Reset() - return nil -} diff --git a/server/grpc/subscriber.go b/server/grpc/subscriber.go index 97b9d75e..3bd4abef 100644 --- a/server/grpc/subscriber.go +++ b/server/grpc/subscriber.go @@ -12,6 +12,7 @@ import ( "github.com/micro/go-micro/metadata" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/server" + "github.com/micro/go-micro/util/buf" ) const ( @@ -204,7 +205,7 @@ func (g *grpcServer) createSubHandler(sb *subscriber, opts server.Options) broke req = req.Elem() } - b := &buffer{bytes.NewBuffer(msg.Body)} + b := buf.New(bytes.NewBuffer(msg.Body)) co := cf(b) defer co.Close() diff --git a/server/subscriber.go b/server/subscriber.go index 3d87fea1..e3f29286 100644 --- a/server/subscriber.go +++ b/server/subscriber.go @@ -11,6 +11,7 @@ import ( "github.com/micro/go-micro/codec" "github.com/micro/go-micro/metadata" "github.com/micro/go-micro/registry" + "github.com/micro/go-micro/util/buf" ) const ( @@ -210,7 +211,7 @@ func (s *rpcServer) createSubHandler(sb *subscriber, opts Options) broker.Handle req = req.Elem() } - b := &buffer{bytes.NewBuffer(msg.Body)} + b := buf.New(bytes.NewBuffer(msg.Body)) co := cf(b) defer co.Close() diff --git a/transport/http_transport.go b/transport/http_transport.go index ec098ca2..b1e760a4 100644 --- a/transport/http_transport.go +++ b/transport/http_transport.go @@ -14,16 +14,13 @@ import ( "time" maddr "github.com/micro/go-micro/util/addr" + "github.com/micro/go-micro/util/buf" mnet "github.com/micro/go-micro/util/net" mls "github.com/micro/go-micro/util/tls" "golang.org/x/net/http2" "golang.org/x/net/http2/h2c" ) -type buffer struct { - io.ReadWriter -} - type httpTransport struct { opts Options } @@ -65,10 +62,6 @@ type httpTransportListener struct { listener net.Listener } -func (b *buffer) Close() error { - return nil -} - func (h *httpTransportClient) Local() string { return h.local } @@ -84,11 +77,8 @@ func (h *httpTransportClient) Send(m *Message) error { header.Set(k, v) } - reqB := bytes.NewBuffer(m.Body) - defer reqB.Reset() - buf := &buffer{ - reqB, - } + b := buf.New(bytes.NewBuffer(m.Body)) + defer b.Close() req := &http.Request{ Method: "POST", @@ -97,8 +87,8 @@ func (h *httpTransportClient) Send(m *Message) error { Host: h.addr, }, Header: header, - Body: buf, - ContentLength: int64(reqB.Len()), + Body: b, + ContentLength: int64(b.Len()), Host: h.addr, } diff --git a/client/buffer.go b/util/buf/buf.go similarity index 52% rename from client/buffer.go rename to util/buf/buf.go index 9eee2b3d..14f07cd2 100644 --- a/client/buffer.go +++ b/util/buf/buf.go @@ -1,4 +1,4 @@ -package client +package buf import ( "bytes" @@ -12,3 +12,10 @@ func (b *buffer) Close() error { b.Buffer.Reset() return nil } + +func New(b *bytes.Buffer) *buffer { + if b == nil { + b = bytes.NewBuffer(nil) + } + return &buffer{b} +} From a63dcda0035eafab7fc583e9cd57424ded0a5b37 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Sun, 28 Jul 2019 19:43:50 +0100 Subject: [PATCH 224/287] Strip the verbosity of the debug handler --- server/debug.go | 7 +------ server/debug/debug.go | 9 +++++++-- server/grpc/debug.go | 7 +------ server/grpc/options.go | 2 +- server/options.go | 6 +++--- 5 files changed, 13 insertions(+), 18 deletions(-) diff --git a/server/debug.go b/server/debug.go index 18225cf7..72cc88a7 100644 --- a/server/debug.go +++ b/server/debug.go @@ -4,11 +4,6 @@ import ( "github.com/micro/go-micro/server/debug" ) -// We use this to wrap any debug handlers so we preserve the signature Debug.{Method} -type Debug struct { - debug.DebugHandler -} - func registerDebugHandler(s Server) { - s.Handle(s.NewHandler(&Debug{s.Options().DebugHandler}, InternalHandler(true))) + s.Handle(s.NewHandler(&debug.Debug{s.Options().DebugHandler}, InternalHandler(true))) } diff --git a/server/debug/debug.go b/server/debug/debug.go index f185209d..dc2fa8c7 100644 --- a/server/debug/debug.go +++ b/server/debug/debug.go @@ -12,7 +12,7 @@ import ( // used to determine health, status and env info about // a service node. It's akin to Google's /statusz, /healthz, // and /varz -type DebugHandler interface { +type Handler interface { Health(ctx context.Context, req *proto.HealthRequest, rsp *proto.HealthResponse) error Stats(ctx context.Context, req *proto.StatsRequest, rsp *proto.StatsResponse) error } @@ -22,8 +22,13 @@ type debug struct { started int64 } +// We use this to wrap any debug handlers so we preserve the signature Debug.{Method} +type Debug struct { + Handler +} + var ( - DefaultDebugHandler DebugHandler = newDebug() + DefaultHandler Handler = newDebug() ) func newDebug() *debug { diff --git a/server/grpc/debug.go b/server/grpc/debug.go index 5f235346..782b8b1e 100644 --- a/server/grpc/debug.go +++ b/server/grpc/debug.go @@ -5,11 +5,6 @@ import ( "github.com/micro/go-micro/server/debug" ) -// We use this to wrap any debug handlers so we preserve the signature Debug.{Method} -type Debug struct { - debug.DebugHandler -} - func registerDebugHandler(s server.Server) { - s.Handle(s.NewHandler(&Debug{s.Options().DebugHandler}, server.InternalHandler(true))) + s.Handle(s.NewHandler(&debug.Debug{s.Options().DebugHandler}, server.InternalHandler(true))) } diff --git a/server/grpc/options.go b/server/grpc/options.go index 65d82fcc..4a3bef1d 100644 --- a/server/grpc/options.go +++ b/server/grpc/options.go @@ -90,7 +90,7 @@ func newOptions(opt ...server.Option) server.Options { } if opts.DebugHandler == nil { - opts.DebugHandler = debug.DefaultDebugHandler + opts.DebugHandler = debug.DefaultHandler } if len(opts.Address) == 0 { diff --git a/server/options.go b/server/options.go index 15de9b83..0d0ee51f 100644 --- a/server/options.go +++ b/server/options.go @@ -37,7 +37,7 @@ type Options struct { Router Router // Debug Handler which can be set by a user - DebugHandler debug.DebugHandler + DebugHandler debug.Handler // Other options for implementations of the interface // can be stored in a context @@ -67,7 +67,7 @@ func newOptions(opt ...Option) Options { } if opts.DebugHandler == nil { - opts.DebugHandler = debug.DefaultDebugHandler + opts.DebugHandler = debug.DefaultHandler } if opts.RegisterCheck == nil { @@ -157,7 +157,7 @@ func Transport(t transport.Transport) Option { } // DebugHandler for this server -func DebugHandler(d debug.DebugHandler) Option { +func DebugHandler(d debug.Handler) Option { return func(o *Options) { o.DebugHandler = d } From b7b8f8bf111c6f9c5f96b8bb783902810dd40a40 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Sun, 28 Jul 2019 19:47:25 +0100 Subject: [PATCH 225/287] remove agent readme --- agent/README.md | 197 ------------------------------------------------ 1 file changed, 197 deletions(-) delete mode 100644 agent/README.md diff --git a/agent/README.md b/agent/README.md deleted file mode 100644 index 76e6dc23..00000000 --- a/agent/README.md +++ /dev/null @@ -1,197 +0,0 @@ -# Agent - -Agent is a library used to create commands, inputs and robot services - -## Getting Started - -- [Commands](#commands) - Commands are functions executed by the bot based on text based pattern matching. -- [Inputs](#inputs) - Inputs are plugins for communication e.g Slack, Telegram, IRC, etc. -- [Services](#services) - Write bots as micro services - -## Commands - -Commands are functions executed by the bot based on text based pattern matching. - -### Write a Command - -```go -import "github.com/micro/go-micro/agent/command" - -func Ping() command.Command { - usage := "ping" - description := "Returns pong" - - return command.NewCommand("ping", usage, desc, func(args ...string) ([]byte, error) { - return []byte("pong"), nil - }) -} -``` - -### Register the command - -Add the command to the Commands map with a pattern key that can be matched by golang/regexp.Match - -```go -import "github.com/micro/go-micro/agent/command" - -func init() { - command.Commands["^ping$"] = Ping() -} -``` - -### Rebuild Micro - -Build binary -```shell -cd github.com/micro/micro - -// For local use -go build -i -o micro ./main.go - -// For docker image -CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-w' -i -o micro ./main.go -``` - -## Inputs - -Inputs are plugins for communication e.g Slack, HipChat, XMPP, IRC, SMTP, etc, etc. - -New inputs can be added in the following way. - -### Write an Input - -Write an input that satisfies the Input interface. - -```go -type Input interface { - // Provide cli flags - Flags() []cli.Flag - // Initialise input using cli context - Init(*cli.Context) error - // Stream events from the input - Stream() (Conn, error) - // Start the input - Start() error - // Stop the input - Stop() error - // name of the input - String() string -} -``` - -### Register the input - -Add the input to the Inputs map. - -```go -import "github.com/micro/micro/bot/input" - -func init() { - input.Inputs["name"] = MyInput -} -``` - -### Rebuild Micro - -Build binary -```shell -cd github.com/micro/micro - -// For local use -go build -i -o micro ./main.go - -// For docker image -CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-w' -i -o micro ./main.go -``` - -## Services - -The micro bot supports the ability to create commands as micro services. - -### How does it work? - -The bot watches the service registry for services with it's namespace. The default namespace is `go.micro.bot`. -Any service within this namespace will automatically be added to the list of available commands. When a command -is executed, the bot will call the service with method `Command.Exec`. It also expects the method `Command.Help` -to exist for usage info. - - -The service interface is as follows and can be found at [go-micro/agent/proto](https://github.com/micro/go-micro/agent/blob/master/proto/bot.proto) - -``` -syntax = "proto3"; - -package go.micro.bot; - -service Command { - rpc Help(HelpRequest) returns (HelpResponse) {}; - rpc Exec(ExecRequest) returns (ExecResponse) {}; -} - -message HelpRequest { -} - -message HelpResponse { - string usage = 1; - string description = 2; -} - -message ExecRequest { - repeated string args = 1; -} - -message ExecResponse { - bytes result = 1; - string error = 2; -} -``` - -### Example - -Here's an example echo command as a microservice - -```go -package main - -import ( - "fmt" - "strings" - - "github.com/micro/go-micro" - "golang.org/x/net/context" - - proto "github.com/micro/go-micro/agent/proto" -) - -type Command struct{} - -// Help returns the command usage -func (c *Command) Help(ctx context.Context, req *proto.HelpRequest, rsp *proto.HelpResponse) error { - // Usage should include the name of the command - rsp.Usage = "echo" - rsp.Description = "This is an example bot command as a micro service which echos the message" - return nil -} - -// Exec executes the command -func (c *Command) Exec(ctx context.Context, req *proto.ExecRequest, rsp *proto.ExecResponse) error { - rsp.Result = []byte(strings.Join(req.Args, " ")) - // rsp.Error could be set to return an error instead - // the function error would only be used for service level issues - return nil -} - -func main() { - service := micro.NewService( - micro.Name("go.micro.bot.echo"), - ) - - service.Init() - - proto.RegisterCommandHandler(service.Server(), new(Command)) - - if err := service.Run(); err != nil { - fmt.Println(err) - } -} -``` From 2b5bf1154a891c872ba728e8aaee2902ebb17f06 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Sun, 28 Jul 2019 19:52:01 +0100 Subject: [PATCH 226/287] rename config tests --- config/default_test.go | 75 ++++++++++++++++++++++++++---------------- config/issue18_test.go | 60 --------------------------------- 2 files changed, 46 insertions(+), 89 deletions(-) delete mode 100644 config/issue18_test.go diff --git a/config/default_test.go b/config/default_test.go index 9d1bd03e..8a6adc73 100644 --- a/config/default_test.go +++ b/config/default_test.go @@ -8,9 +8,25 @@ import ( "testing" "time" + "github.com/micro/go-micro/config/source/env" "github.com/micro/go-micro/config/source/file" ) +func createFileForIssue18(t *testing.T, content string) *os.File { + data := []byte(content) + path := filepath.Join(os.TempDir(), fmt.Sprintf("file.%d", time.Now().UnixNano())) + fh, err := os.Create(path) + if err != nil { + t.Error(err) + } + _, err = fh.Write(data) + if err != nil { + t.Error(err) + } + + return fh +} + func createFileForTest(t *testing.T) *os.File { data := []byte(`{"foo": "bar"}`) path := filepath.Join(os.TempDir(), fmt.Sprintf("file.%d", time.Now().UnixNano())) @@ -26,7 +42,7 @@ func createFileForTest(t *testing.T) *os.File { return fh } -func TestLoadWithGoodFile(t *testing.T) { +func TestConfigLoadWithGoodFile(t *testing.T) { fh := createFileForTest(t) path := fh.Name() defer func() { @@ -44,7 +60,7 @@ func TestLoadWithGoodFile(t *testing.T) { } } -func TestLoadWithInvalidFile(t *testing.T) { +func TestConfigLoadWithInvalidFile(t *testing.T) { fh := createFileForTest(t) path := fh.Name() defer func() { @@ -68,34 +84,35 @@ func TestLoadWithInvalidFile(t *testing.T) { } } -func TestConsul(t *testing.T) { - /*consulSource := consul.NewSource( - // optionally specify consul address; default to localhost:8500 - consul.WithAddress("131.150.38.111:8500"), - // optionally specify prefix; defaults to /micro/config - consul.WithPrefix("/project"), - // optionally strip the provided prefix from the keys, defaults to false - consul.StripPrefix(true), - consul.WithDatacenter("dc1"), - consul.WithToken("xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"), +func TestConfigMerge(t *testing.T) { + fh := createFileForIssue18(t, `{ + "amqp": { + "host": "rabbit.platform", + "port": 80 + }, + "handler": { + "exchange": "springCloudBus" + } +}`) + path := fh.Name() + defer func() { + fh.Close() + os.Remove(path) + }() + os.Setenv("AMQP_HOST", "rabbit.testing.com") + + conf := NewConfig() + conf.Load( + file.NewSource( + file.WithPath(path), + ), + env.NewSource(), ) - // Create new config - conf := NewConfig() - - // Load file source - err := conf.Load(consulSource) - if err != nil { - t.Error(err) - return + actualHost := conf.Get("amqp", "host").String("backup") + if actualHost != "rabbit.testing.com" { + t.Fatalf("Expected %v but got %v", + "rabbit.testing.com", + actualHost) } - - m := conf.Map() - t.Log("m: ", m) - - v := conf.Get("project", "dc111", "port") - - t.Log("v: ", v.Int(13))*/ - - t.Log("OK") } diff --git a/config/issue18_test.go b/config/issue18_test.go deleted file mode 100644 index 5fed22bf..00000000 --- a/config/issue18_test.go +++ /dev/null @@ -1,60 +0,0 @@ -package config - -import ( - "fmt" - "os" - "path/filepath" - "testing" - "time" - - "github.com/micro/go-micro/config/source/env" - "github.com/micro/go-micro/config/source/file" -) - -func createFileForIssue18(t *testing.T, content string) *os.File { - data := []byte(content) - path := filepath.Join(os.TempDir(), fmt.Sprintf("file.%d", time.Now().UnixNano())) - fh, err := os.Create(path) - if err != nil { - t.Error(err) - } - _, err = fh.Write(data) - if err != nil { - t.Error(err) - } - - return fh -} - -func TestIssue18(t *testing.T) { - fh := createFileForIssue18(t, `{ - "amqp": { - "host": "rabbit.platform", - "port": 80 - }, - "handler": { - "exchange": "springCloudBus" - } -}`) - path := fh.Name() - defer func() { - fh.Close() - os.Remove(path) - }() - os.Setenv("AMQP_HOST", "rabbit.testing.com") - - conf := NewConfig() - conf.Load( - file.NewSource( - file.WithPath(path), - ), - env.NewSource(), - ) - - actualHost := conf.Get("amqp", "host").String("backup") - if actualHost != "rabbit.testing.com" { - t.Fatalf("Expected %v but got %v", - "rabbit.testing.com", - actualHost) - } -} From 5b327ce72374615404e2fac8c73aaaa7066ca22c Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Sun, 28 Jul 2019 20:00:09 +0100 Subject: [PATCH 227/287] change id to name in resolver --- network/resolver/dns/dns.go | 6 +++--- network/resolver/http/http.go | 8 ++++---- network/resolver/registry/registry.go | 6 +++--- network/resolver/resolver.go | 8 ++++---- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/network/resolver/dns/dns.go b/network/resolver/dns/dns.go index c905df0e..ba109656 100644 --- a/network/resolver/dns/dns.go +++ b/network/resolver/dns/dns.go @@ -1,4 +1,4 @@ -// Package dns resolves ids to dns srv records +// Package dns resolves names to dns srv records package dns import ( @@ -11,8 +11,8 @@ import ( type Resolver struct{} // Resolve assumes ID is a domain name e.g micro.mu -func (r *Resolver) Resolve(id string) ([]*resolver.Record, error) { - _, addrs, err := net.LookupSRV("network", "udp", id) +func (r *Resolver) Resolve(name string) ([]*resolver.Record, error) { + _, addrs, err := net.LookupSRV("network", "udp", name) if err != nil { return nil, err } diff --git a/network/resolver/http/http.go b/network/resolver/http/http.go index 80ff4d61..b6025a59 100644 --- a/network/resolver/http/http.go +++ b/network/resolver/http/http.go @@ -1,4 +1,4 @@ -// Package http resolves ids to network addresses using a http request +// Package http resolves names to network addresses using a http request package http import ( @@ -18,8 +18,8 @@ type Resolver struct { Path string } -// Resolve assumes ID is a domain which can be converted to a http://id/network request -func (r *Resolver) Resolve(id string) ([]*resolver.Record, error) { +// Resolve assumes ID is a domain which can be converted to a http://name/network request +func (r *Resolver) Resolve(name string) ([]*resolver.Record, error) { proto := "http" path := "/network" @@ -34,7 +34,7 @@ func (r *Resolver) Resolve(id string) ([]*resolver.Record, error) { uri := &url.URL{ Scheme: proto, Path: path, - Host: id, + Host: name, } rsp, err := http.Get(uri.String()) diff --git a/network/resolver/registry/registry.go b/network/resolver/registry/registry.go index c7ef796a..9fe80bc5 100644 --- a/network/resolver/registry/registry.go +++ b/network/resolver/registry/registry.go @@ -1,4 +1,4 @@ -// Package registry resolves ids using the go-micro registry +// Package registry resolves names using the go-micro registry package registry import ( @@ -12,13 +12,13 @@ type Resolver struct { } // Resolve assumes ID is a domain name e.g micro.mu -func (r *Resolver) Resolve(id string) ([]*resolver.Record, error) { +func (r *Resolver) Resolve(name string) ([]*resolver.Record, error) { reg := r.Registry if reg == nil { reg = registry.DefaultRegistry } - services, err := reg.GetService(id) + services, err := reg.GetService(name) if err != nil { return nil, err } diff --git a/network/resolver/resolver.go b/network/resolver/resolver.go index 6c54eb95..2eb0b2a2 100644 --- a/network/resolver/resolver.go +++ b/network/resolver/resolver.go @@ -1,12 +1,12 @@ -// Package resolver resolves network ids to addresses +// Package resolver resolves network names to addresses package resolver // Resolver is network resolver. It's used to find network nodes -// via id to connect to. This is done based on Network.Id(). +// via the name to connect to. This is done based on Network.Name(). // Before we can be part of any network, we have to connect to it. type Resolver interface { - // Resolve returns a list of addresses for an id - Resolve(id string) ([]*Record, error) + // Resolve returns a list of addresses for an name + Resolve(name string) ([]*Record, error) } // A resolved record From a5fb124b228eb54b64d7b5acba88995bb6733ac8 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 29 Jul 2019 12:34:00 +0100 Subject: [PATCH 228/287] update the mdns version --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 1872558f..a55d2f99 100644 --- a/go.mod +++ b/go.mod @@ -49,7 +49,7 @@ require ( github.com/mattn/go-colorable v0.1.2 // indirect github.com/mattn/go-runewidth v0.0.4 // indirect github.com/micro/cli v0.2.0 - github.com/micro/mdns v0.1.0 + github.com/micro/mdns v0.1.1-0.20190729112526-ef68c9635478 github.com/miekg/dns v1.1.15 // indirect github.com/mitchellh/gox v1.0.1 // indirect github.com/mitchellh/hashstructure v1.0.0 diff --git a/go.sum b/go.sum index 8f5526ee..e98bd464 100644 --- a/go.sum +++ b/go.sum @@ -215,6 +215,8 @@ github.com/micro/cli v0.2.0 h1:ut3rV5JWqZjsXIa2MvGF+qMUP8DAUTvHX9Br5gO4afA= github.com/micro/cli v0.2.0/go.mod h1:jRT9gmfVKWSS6pkKcXQ8YhUyj6bzwxK8Fp5b0Y7qNnk= github.com/micro/mdns v0.1.0 h1:fuLybUsfynbigJmCot/54i+gwe0hpc/vtCMvWt2WfDI= github.com/micro/mdns v0.1.0/go.mod h1:KJ0dW7KmicXU2BV++qkLlmHYcVv7/hHnbtguSWt9Aoc= +github.com/micro/mdns v0.1.1-0.20190729112526-ef68c9635478 h1:L6jnZZ763dMLlvst8P0dWHa1WbUu7ppUY1q3AY2hhIU= +github.com/micro/mdns v0.1.1-0.20190729112526-ef68c9635478/go.mod h1:KJ0dW7KmicXU2BV++qkLlmHYcVv7/hHnbtguSWt9Aoc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.3 h1:1g0r1IvskvgL8rR+AcHzUA+oFmGcQlaIm4IqakufeMM= github.com/miekg/dns v1.1.3/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= From 47acdf6a4b7fe2c63a05f5866a7a220aa9a34aad Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 29 Jul 2019 12:40:13 +0100 Subject: [PATCH 229/287] move Table to table --- network/router/default.go | 4 ++-- network/router/options.go | 10 ---------- network/router/router.go | 8 -------- network/router/table.go | 29 ++++++++++++----------------- network/router/table_test.go | 4 ++-- 5 files changed, 16 insertions(+), 39 deletions(-) diff --git a/network/router/default.go b/network/router/default.go index 8cf08e51..aa31688d 100644 --- a/network/router/default.go +++ b/network/router/default.go @@ -42,7 +42,7 @@ var ( // router implements default router type router struct { // embed the table - *Table + *table opts Options status Status exit chan struct{} @@ -65,7 +65,7 @@ func newRouter(opts ...Option) Router { } r := &router{ - Table: options.Table, + table: newTable(), opts: options, status: Status{Code: Stopped, Error: nil}, advertWg: &sync.WaitGroup{}, diff --git a/network/router/options.go b/network/router/options.go index ac108b32..240da437 100644 --- a/network/router/options.go +++ b/network/router/options.go @@ -24,8 +24,6 @@ type Options struct { Network string // Registry is the local registry Registry registry.Registry - // Table is routing table - Table *Table } // Id sets Router Id @@ -63,13 +61,6 @@ func Registry(r registry.Registry) Option { } } -// RoutingTable sets the routing table -func RoutingTable(t *Table) Option { - return func(o *Options) { - o.Table = t - } -} - // DefaultOptions returns router default options func DefaultOptions() Options { return Options{ @@ -77,6 +68,5 @@ func DefaultOptions() Options { Address: DefaultAddress, Network: DefaultNetwork, Registry: registry.DefaultRegistry, - Table: NewTable(), } } diff --git a/network/router/router.go b/network/router/router.go index 80ad7e1c..4740a915 100644 --- a/network/router/router.go +++ b/network/router/router.go @@ -22,14 +22,6 @@ type Router interface { Advertise() (<-chan *Advert, error) // Process processes incoming adverts Process(*Advert) error - // Create new route in the routing table - Create(Route) error - // Delete existing route from the routing table - Delete(Route) error - // Update exiting route in the routing table - Update(Route) error - // List lists all routes in the routing table - List() ([]Route, error) // Lookup queries routes in the routing table Lookup(Query) ([]Route, error) // Watch returns a watcher which tracks updates to the routing table diff --git a/network/router/table.go b/network/router/table.go index 75b7a10d..f9cfd23d 100644 --- a/network/router/table.go +++ b/network/router/table.go @@ -15,8 +15,8 @@ var ( ErrDuplicateRoute = errors.New("duplicate route") ) -// Table is an in memory routing table -type Table struct { +// table is an in memory routing table +type table struct { // routes stores service routes routes map[string]map[uint64]Route // watchers stores table watchers @@ -24,16 +24,16 @@ type Table struct { sync.RWMutex } -// NewTable creates a new routing table and returns it -func NewTable(opts ...Option) *Table { - return &Table{ +// newtable creates a new routing table and returns it +func newTable(opts ...Option) *table { + return &table{ routes: make(map[string]map[uint64]Route), watchers: make(map[string]*tableWatcher), } } // Create creates new route in the routing table -func (t *Table) Create(r Route) error { +func (t *table) Create(r Route) error { service := r.Service sum := r.Hash() @@ -59,7 +59,7 @@ func (t *Table) Create(r Route) error { } // Delete deletes the route from the routing table -func (t *Table) Delete(r Route) error { +func (t *table) Delete(r Route) error { service := r.Service sum := r.Hash() @@ -77,7 +77,7 @@ func (t *Table) Delete(r Route) error { } // Update updates routing table with the new route -func (t *Table) Update(r Route) error { +func (t *table) Update(r Route) error { service := r.Service sum := r.Hash() @@ -99,7 +99,7 @@ func (t *Table) Update(r Route) error { } // List returns a list of all routes in the table -func (t *Table) List() ([]Route, error) { +func (t *table) List() ([]Route, error) { t.RLock() defer t.RUnlock() @@ -135,7 +135,7 @@ func findRoutes(routes map[uint64]Route, network, router string) []Route { } // Lookup queries routing table and returns all routes that match the lookup query -func (t *Table) Lookup(q Query) ([]Route, error) { +func (t *table) Lookup(q Query) ([]Route, error) { t.RLock() defer t.RUnlock() @@ -156,7 +156,7 @@ func (t *Table) Lookup(q Query) ([]Route, error) { } // Watch returns routing table entry watcher -func (t *Table) Watch(opts ...WatchOption) (Watcher, error) { +func (t *table) Watch(opts ...WatchOption) (Watcher, error) { // by default watch everything wopts := WatchOptions{ Service: "*", @@ -180,7 +180,7 @@ func (t *Table) Watch(opts ...WatchOption) (Watcher, error) { } // sendEvent sends events to all subscribed watchers -func (t *Table) sendEvent(e *Event) { +func (t *table) sendEvent(e *Event) { t.RLock() defer t.RUnlock() @@ -191,8 +191,3 @@ func (t *Table) sendEvent(e *Event) { } } } - -// String returns debug information -func (t *Table) String() string { - return "table" -} diff --git a/network/router/table_test.go b/network/router/table_test.go index eee734a2..dc35a5f1 100644 --- a/network/router/table_test.go +++ b/network/router/table_test.go @@ -2,8 +2,8 @@ package router import "testing" -func testSetup() (*Table, Route) { - table := NewTable() +func testSetup() (*table, Route) { + table := newTable() route := Route{ Service: "dest.svc", From 8855beb62d89df4b106eeef969e98ca5e7927cc8 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 29 Jul 2019 12:43:20 +0100 Subject: [PATCH 230/287] syntactic changes --- network/router/options.go | 7 ------- network/router/router.go | 18 +++++++++++------- network/router/watcher.go | 13 ++++--------- 3 files changed, 15 insertions(+), 23 deletions(-) diff --git a/network/router/options.go b/network/router/options.go index 240da437..003e0b33 100644 --- a/network/router/options.go +++ b/network/router/options.go @@ -5,13 +5,6 @@ import ( "github.com/micro/go-micro/registry" ) -var ( - // DefaultAddress is default router address - DefaultAddress = ":9093" - // DefaultNetwork is default micro network - DefaultNetwork = "go.micro" -) - // Options are router options type Options struct { // Id is router id diff --git a/network/router/router.go b/network/router/router.go index 4740a915..30ea857a 100644 --- a/network/router/router.go +++ b/network/router/router.go @@ -5,13 +5,6 @@ import ( "time" ) -var ( - // DefaultRouter is default network router - DefaultRouter = NewRouter() - // DefaultName is default router service name - DefaultName = "go.micro.router" -) - // Router is an interface for a routing control plane type Router interface { // Init initializes the router with options @@ -110,6 +103,17 @@ type Advert struct { Events []*Event } +var ( + // DefaultAddress is default router address + DefaultAddress = ":9093" + // DefaultName is default router service name + DefaultName = "go.micro.router" + // DefaultNetwork is default micro network + DefaultNetwork = "go.micro" + // DefaultRouter is default network router + DefaultRouter = NewRouter() +) + // NewRouter creates new Router and returns it func NewRouter(opts ...Option) Router { return newRouter(opts...) diff --git a/network/router/watcher.go b/network/router/watcher.go index d1a9c017..d41b527c 100644 --- a/network/router/watcher.go +++ b/network/router/watcher.go @@ -6,11 +6,6 @@ import ( "time" ) -var ( - // ErrWatcherStopped is returned when routing table watcher has been stopped - ErrWatcherStopped = errors.New("watcher stopped") -) - // EventType defines routing table event type EventType int @@ -118,7 +113,7 @@ func (w *tableWatcher) Stop() { } } -// String prints debug information -func (w tableWatcher) String() string { - return "watcher" -} +var ( + // ErrWatcherStopped is returned when routing table watcher has been stopped + ErrWatcherStopped = errors.New("watcher stopped") +) From 8fdc050e2eeafb2a6dec379e7a7fa975f330937e Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 29 Jul 2019 12:44:28 +0100 Subject: [PATCH 231/287] syntactic changes --- network/router/default.go | 2 +- network/router/table.go | 2 +- network/router/watcher.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/network/router/default.go b/network/router/default.go index aa31688d..b1170796 100644 --- a/network/router/default.go +++ b/network/router/default.go @@ -41,6 +41,7 @@ var ( // router implements default router type router struct { + sync.RWMutex // embed the table *table opts Options @@ -51,7 +52,6 @@ type router struct { advertChan chan *Advert advertWg *sync.WaitGroup wg *sync.WaitGroup - sync.RWMutex } // newRouter creates new router and returns it diff --git a/network/router/table.go b/network/router/table.go index f9cfd23d..78c02c7c 100644 --- a/network/router/table.go +++ b/network/router/table.go @@ -17,11 +17,11 @@ var ( // table is an in memory routing table type table struct { + sync.RWMutex // routes stores service routes routes map[string]map[uint64]Route // watchers stores table watchers watchers map[string]*tableWatcher - sync.RWMutex } // newtable creates a new routing table and returns it diff --git a/network/router/watcher.go b/network/router/watcher.go index d41b527c..1530e72c 100644 --- a/network/router/watcher.go +++ b/network/router/watcher.go @@ -71,10 +71,10 @@ func WatchService(s string) WatchOption { } type tableWatcher struct { + sync.RWMutex opts WatchOptions resChan chan *Event done chan struct{} - sync.RWMutex } // Next returns the next noticed action taken on table From ae99b9a8870d374dbce5bcb377f777c052d239c2 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 29 Jul 2019 12:44:59 +0100 Subject: [PATCH 232/287] syntactic changes --- network/router/table.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/network/router/table.go b/network/router/table.go index 78c02c7c..931dcdca 100644 --- a/network/router/table.go +++ b/network/router/table.go @@ -8,13 +8,6 @@ import ( "github.com/google/uuid" ) -var ( - // ErrRouteNotFound is returned when no route was found in the routing table - ErrRouteNotFound = errors.New("route not found") - // ErrDuplicateRoute is returned when the route already exists - ErrDuplicateRoute = errors.New("duplicate route") -) - // table is an in memory routing table type table struct { sync.RWMutex @@ -191,3 +184,10 @@ func (t *table) sendEvent(e *Event) { } } } + +var ( + // ErrRouteNotFound is returned when no route was found in the routing table + ErrRouteNotFound = errors.New("route not found") + // ErrDuplicateRoute is returned when the route already exists + ErrDuplicateRoute = errors.New("duplicate route") +) From 104778e5e52fde844eb099711ac2a097e2faa286 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 29 Jul 2019 12:52:32 +0100 Subject: [PATCH 233/287] move lock --- network/router/service/service.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network/router/service/service.go b/network/router/service/service.go index 004959cc..09806cd3 100644 --- a/network/router/service/service.go +++ b/network/router/service/service.go @@ -14,6 +14,7 @@ import ( ) type svc struct { + sync.RWMutex opts router.Options router pb.RouterService status router.Status @@ -22,7 +23,6 @@ type svc struct { errChan chan error advertChan chan *router.Advert wg *sync.WaitGroup - sync.RWMutex } // NewRouter creates new service router and returns it From 11f80708ce81580459fcc0ee7fbc4dcde8bd7e8c Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 29 Jul 2019 12:52:52 +0100 Subject: [PATCH 234/287] move lock --- network/router/service/watcher.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network/router/service/watcher.go b/network/router/service/watcher.go index 984c3439..9ed37dab 100644 --- a/network/router/service/watcher.go +++ b/network/router/service/watcher.go @@ -7,10 +7,10 @@ import ( ) type svcWatcher struct { + sync.RWMutex opts router.WatchOptions resChan chan *router.Event done chan struct{} - sync.RWMutex } // Next is a blocking call that returns watch result From 852abcaaed5665656df6af55db2732d9f21bb8b3 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 29 Jul 2019 18:57:40 +0100 Subject: [PATCH 235/287] yolo commit functioning router code. all credit to the milos gajdos --- network/router/default.go | 106 ++-- network/router/options.go | 10 + network/router/proto/router.micro.go | 188 +++++-- network/router/proto/router.pb.go | 786 ++++++++++++++++++++++++--- network/router/proto/router.proto | 39 +- network/router/router.go | 15 + network/router/service/service.go | 399 ++++---------- network/router/service/table.go | 121 +++++ network/router/service/watcher.go | 76 ++- network/router/table.go | 2 +- network/router/table_test.go | 12 +- 11 files changed, 1277 insertions(+), 477 deletions(-) create mode 100644 network/router/service/table.go diff --git a/network/router/default.go b/network/router/default.go index b1170796..245a7b31 100644 --- a/network/router/default.go +++ b/network/router/default.go @@ -8,6 +8,7 @@ import ( "sync" "time" + "github.com/google/uuid" "github.com/micro/go-micro/registry" ) @@ -43,15 +44,17 @@ var ( type router struct { sync.RWMutex // embed the table - *table - opts Options - status Status - exit chan struct{} - errChan chan error - eventChan chan *Event - advertChan chan *Advert - advertWg *sync.WaitGroup - wg *sync.WaitGroup + table *table + opts Options + status Status + exit chan struct{} + errChan chan error + eventChan chan *Event + advertWg *sync.WaitGroup + wg *sync.WaitGroup + + // advert subscribers + subscribers map[string]chan *Advert } // newRouter creates new router and returns it @@ -65,11 +68,12 @@ func newRouter(opts ...Option) Router { } r := &router{ - table: newTable(), - opts: options, - status: Status{Code: Stopped, Error: nil}, - advertWg: &sync.WaitGroup{}, - wg: &sync.WaitGroup{}, + table: newTable(), + opts: options, + status: Status{Code: Stopped, Error: nil}, + advertWg: &sync.WaitGroup{}, + wg: &sync.WaitGroup{}, + subscribers: make(map[string]chan *Advert), } go r.run() @@ -90,19 +94,23 @@ func (r *router) Options() Options { return r.opts } +func (r *router) Table() Table { + return r.table +} + // manageRoute applies action on a given route func (r *router) manageRoute(route Route, action string) error { switch action { case "create": - if err := r.Create(route); err != nil && err != ErrDuplicateRoute { + if err := r.table.Create(route); err != nil && err != ErrDuplicateRoute { return fmt.Errorf("failed adding route for service %s: %s", route.Service, err) } case "update": - if err := r.Update(route); err != nil && err != ErrDuplicateRoute { + if err := r.table.Update(route); err != nil && err != ErrDuplicateRoute { return fmt.Errorf("failed updating route for service %s: %s", route.Service, err) } case "delete": - if err := r.Delete(route); err != nil && err != ErrRouteNotFound { + if err := r.table.Delete(route); err != nil && err != ErrRouteNotFound { return fmt.Errorf("failed deleting route for service %s: %s", route.Service, err) } default: @@ -244,11 +252,23 @@ func (r *router) publishAdvert(advType AdvertType, events []*Event) { Events: events, } - select { - case r.advertChan <- a: - case <-r.exit: - return + r.RLock() + for _, sub := range r.subscribers { + // check the exit chan first + select { + case <-r.exit: + r.RUnlock() + return + default: + } + + // now send the message + select { + case sub <- a: + default: + } } + r.RUnlock() } // advertiseTable advertises the whole routing table to the network @@ -260,7 +280,7 @@ func (r *router) advertiseTable() error { select { case <-ticker.C: // list routing table routes to announce - routes, err := r.List() + routes, err := r.table.List() if err != nil { return fmt.Errorf("failed listing routes: %s", err) } @@ -410,8 +430,6 @@ func (r *router) advertiseEvents() error { case <-r.exit: // first wait for the advertiser to finish r.advertWg.Wait() - // close the advert channel - close(r.advertChan) return nil } } @@ -434,9 +452,6 @@ func (r *router) watchErrors() { // drain the advertise channel only if advertising if r.status.Code == Advertising { - // drain the advertise channel - for range r.advertChan { - } // drain the event channel for range r.eventChan { } @@ -474,7 +489,7 @@ func (r *router) run() { Network: "*", Metric: DefaultLocalMetric, } - if err := r.Create(route); err != nil { + if err := r.table.Create(route); err != nil { r.status = Status{Code: Error, Error: fmt.Errorf("failed adding default gateway route: %s", err)} return } @@ -525,10 +540,12 @@ func (r *router) Advertise() (<-chan *Advert, error) { switch r.status.Code { case Advertising: - return r.advertChan, nil + advertChan := make(chan *Advert) + r.subscribers[uuid.New().String()] = advertChan + return advertChan, nil case Running: // list routing table routes to announce - routes, err := r.List() + routes, err := r.table.List() if err != nil { return nil, fmt.Errorf("failed listing routes: %s", err) } @@ -543,8 +560,7 @@ func (r *router) Advertise() (<-chan *Advert, error) { events[i] = event } - // create advertise and event channels - r.advertChan = make(chan *Advert) + // create event channels r.eventChan = make(chan *Event) // advertise your presence @@ -573,7 +589,11 @@ func (r *router) Advertise() (<-chan *Advert, error) { // mark router as Running and set its Error to nil r.status = Status{Code: Advertising, Error: nil} - return r.advertChan, nil + // create advert channel + advertChan := make(chan *Advert) + r.subscribers[uuid.New().String()] = advertChan + + return advertChan, nil case Stopped: return nil, fmt.Errorf("not running") } @@ -604,6 +624,14 @@ func (r *router) Process(a *Advert) error { return nil } +func (r *router) Lookup(q Query) ([]Route, error) { + return r.table.Query(q) +} + +func (r *router) Watch(opts ...WatchOption) (Watcher, error) { + return r.table.Watch(opts...) +} + // Status returns router status func (r *router) Status() Status { r.RLock() @@ -625,14 +653,20 @@ func (r *router) Stop() error { // drain the advertise channel only if advertising if r.status.Code == Advertising { - // drain the advertise channel - for range r.advertChan { - } // drain the event channel for range r.eventChan { } } + // close advert subscribers + for id, sub := range r.subscribers { + // close the channel + close(sub) + + // delete the subscriber + delete(r.subscribers, id) + } + // mark the router as Stopped and set its Error to nil r.status = Status{Code: Stopped, Error: nil} } diff --git a/network/router/options.go b/network/router/options.go index 003e0b33..13119e1b 100644 --- a/network/router/options.go +++ b/network/router/options.go @@ -2,6 +2,7 @@ package router import ( "github.com/google/uuid" + "github.com/micro/go-micro/client" "github.com/micro/go-micro/registry" ) @@ -17,6 +18,8 @@ type Options struct { Network string // Registry is the local registry Registry registry.Registry + // Client for calling router + Client client.Client } // Id sets Router Id @@ -33,6 +36,13 @@ func Address(a string) Option { } } +// Client to call router service +func Client(c client.Client) Option { + return func(o *Options) { + o.Client = c + } +} + // Gateway sets network gateway func Gateway(g string) Option { return func(o *Options) { diff --git a/network/router/proto/router.micro.go b/network/router/proto/router.micro.go index 96386187..ee5bbd51 100644 --- a/network/router/proto/router.micro.go +++ b/network/router/proto/router.micro.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-micro. DO NOT EDIT. -// source: router.proto +// source: go-micro/network/router/proto/router.proto package go_micro_router @@ -34,14 +34,11 @@ var _ server.Option // Client API for Router service type RouterService interface { - List(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*ListResponse, error) Lookup(ctx context.Context, in *LookupRequest, opts ...client.CallOption) (*LookupResponse, error) Watch(ctx context.Context, in *WatchRequest, opts ...client.CallOption) (Router_WatchService, error) Advertise(ctx context.Context, in *AdvertiseRequest, opts ...client.CallOption) (Router_AdvertiseService, error) Process(ctx context.Context, in *Advert, opts ...client.CallOption) (*ProcessResponse, error) - Create(ctx context.Context, in *Route, opts ...client.CallOption) (*CreateResponse, error) - Delete(ctx context.Context, in *Route, opts ...client.CallOption) (*DeleteResponse, error) - Update(ctx context.Context, in *Route, opts ...client.CallOption) (*UpdateResponse, error) + Status(ctx context.Context, in *Request, opts ...client.CallOption) (*StatusResponse, error) } type routerService struct { @@ -62,16 +59,6 @@ func NewRouterService(name string, c client.Client) RouterService { } } -func (c *routerService) List(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*ListResponse, error) { - req := c.c.NewRequest(c.name, "Router.List", in) - out := new(ListResponse) - err := c.c.Call(ctx, req, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *routerService) Lookup(ctx context.Context, in *LookupRequest, opts ...client.CallOption) (*LookupResponse, error) { req := c.c.NewRequest(c.name, "Router.Lookup", in) out := new(LookupResponse) @@ -180,29 +167,9 @@ func (c *routerService) Process(ctx context.Context, in *Advert, opts ...client. return out, nil } -func (c *routerService) Create(ctx context.Context, in *Route, opts ...client.CallOption) (*CreateResponse, error) { - req := c.c.NewRequest(c.name, "Router.Create", in) - out := new(CreateResponse) - err := c.c.Call(ctx, req, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *routerService) Delete(ctx context.Context, in *Route, opts ...client.CallOption) (*DeleteResponse, error) { - req := c.c.NewRequest(c.name, "Router.Delete", in) - out := new(DeleteResponse) - err := c.c.Call(ctx, req, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *routerService) Update(ctx context.Context, in *Route, opts ...client.CallOption) (*UpdateResponse, error) { - req := c.c.NewRequest(c.name, "Router.Update", in) - out := new(UpdateResponse) +func (c *routerService) Status(ctx context.Context, in *Request, opts ...client.CallOption) (*StatusResponse, error) { + req := c.c.NewRequest(c.name, "Router.Status", in) + out := new(StatusResponse) err := c.c.Call(ctx, req, out, opts...) if err != nil { return nil, err @@ -213,26 +180,20 @@ func (c *routerService) Update(ctx context.Context, in *Route, opts ...client.Ca // Server API for Router service type RouterHandler interface { - List(context.Context, *ListRequest, *ListResponse) error Lookup(context.Context, *LookupRequest, *LookupResponse) error Watch(context.Context, *WatchRequest, Router_WatchStream) error Advertise(context.Context, *AdvertiseRequest, Router_AdvertiseStream) error Process(context.Context, *Advert, *ProcessResponse) error - Create(context.Context, *Route, *CreateResponse) error - Delete(context.Context, *Route, *DeleteResponse) error - Update(context.Context, *Route, *UpdateResponse) error + Status(context.Context, *Request, *StatusResponse) error } func RegisterRouterHandler(s server.Server, hdlr RouterHandler, opts ...server.HandlerOption) error { type router interface { - List(ctx context.Context, in *ListRequest, out *ListResponse) error Lookup(ctx context.Context, in *LookupRequest, out *LookupResponse) error Watch(ctx context.Context, stream server.Stream) error Advertise(ctx context.Context, stream server.Stream) error Process(ctx context.Context, in *Advert, out *ProcessResponse) error - Create(ctx context.Context, in *Route, out *CreateResponse) error - Delete(ctx context.Context, in *Route, out *DeleteResponse) error - Update(ctx context.Context, in *Route, out *UpdateResponse) error + Status(ctx context.Context, in *Request, out *StatusResponse) error } type Router struct { router @@ -245,10 +206,6 @@ type routerHandler struct { RouterHandler } -func (h *routerHandler) List(ctx context.Context, in *ListRequest, out *ListResponse) error { - return h.RouterHandler.List(ctx, in, out) -} - func (h *routerHandler) Lookup(ctx context.Context, in *LookupRequest, out *LookupResponse) error { return h.RouterHandler.Lookup(ctx, in, out) } @@ -327,14 +284,133 @@ func (h *routerHandler) Process(ctx context.Context, in *Advert, out *ProcessRes return h.RouterHandler.Process(ctx, in, out) } -func (h *routerHandler) Create(ctx context.Context, in *Route, out *CreateResponse) error { - return h.RouterHandler.Create(ctx, in, out) +func (h *routerHandler) Status(ctx context.Context, in *Request, out *StatusResponse) error { + return h.RouterHandler.Status(ctx, in, out) } -func (h *routerHandler) Delete(ctx context.Context, in *Route, out *DeleteResponse) error { - return h.RouterHandler.Delete(ctx, in, out) +// Client API for Table service + +type TableService interface { + Create(ctx context.Context, in *Route, opts ...client.CallOption) (*CreateResponse, error) + Delete(ctx context.Context, in *Route, opts ...client.CallOption) (*DeleteResponse, error) + Update(ctx context.Context, in *Route, opts ...client.CallOption) (*UpdateResponse, error) + Query(ctx context.Context, in *QueryRequest, opts ...client.CallOption) (*QueryResponse, error) + List(ctx context.Context, in *Request, opts ...client.CallOption) (*ListResponse, error) } -func (h *routerHandler) Update(ctx context.Context, in *Route, out *UpdateResponse) error { - return h.RouterHandler.Update(ctx, in, out) +type tableService struct { + c client.Client + name string +} + +func NewTableService(name string, c client.Client) TableService { + if c == nil { + c = client.NewClient() + } + if len(name) == 0 { + name = "go.micro.router" + } + return &tableService{ + c: c, + name: name, + } +} + +func (c *tableService) Create(ctx context.Context, in *Route, opts ...client.CallOption) (*CreateResponse, error) { + req := c.c.NewRequest(c.name, "Table.Create", in) + out := new(CreateResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *tableService) Delete(ctx context.Context, in *Route, opts ...client.CallOption) (*DeleteResponse, error) { + req := c.c.NewRequest(c.name, "Table.Delete", in) + out := new(DeleteResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *tableService) Update(ctx context.Context, in *Route, opts ...client.CallOption) (*UpdateResponse, error) { + req := c.c.NewRequest(c.name, "Table.Update", in) + out := new(UpdateResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *tableService) Query(ctx context.Context, in *QueryRequest, opts ...client.CallOption) (*QueryResponse, error) { + req := c.c.NewRequest(c.name, "Table.Query", in) + out := new(QueryResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *tableService) List(ctx context.Context, in *Request, opts ...client.CallOption) (*ListResponse, error) { + req := c.c.NewRequest(c.name, "Table.List", in) + out := new(ListResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for Table service + +type TableHandler interface { + Create(context.Context, *Route, *CreateResponse) error + Delete(context.Context, *Route, *DeleteResponse) error + Update(context.Context, *Route, *UpdateResponse) error + Query(context.Context, *QueryRequest, *QueryResponse) error + List(context.Context, *Request, *ListResponse) error +} + +func RegisterTableHandler(s server.Server, hdlr TableHandler, opts ...server.HandlerOption) error { + type table interface { + Create(ctx context.Context, in *Route, out *CreateResponse) error + Delete(ctx context.Context, in *Route, out *DeleteResponse) error + Update(ctx context.Context, in *Route, out *UpdateResponse) error + Query(ctx context.Context, in *QueryRequest, out *QueryResponse) error + List(ctx context.Context, in *Request, out *ListResponse) error + } + type Table struct { + table + } + h := &tableHandler{hdlr} + return s.Handle(s.NewHandler(&Table{h}, opts...)) +} + +type tableHandler struct { + TableHandler +} + +func (h *tableHandler) Create(ctx context.Context, in *Route, out *CreateResponse) error { + return h.TableHandler.Create(ctx, in, out) +} + +func (h *tableHandler) Delete(ctx context.Context, in *Route, out *DeleteResponse) error { + return h.TableHandler.Delete(ctx, in, out) +} + +func (h *tableHandler) Update(ctx context.Context, in *Route, out *UpdateResponse) error { + return h.TableHandler.Update(ctx, in, out) +} + +func (h *tableHandler) Query(ctx context.Context, in *QueryRequest, out *QueryResponse) error { + return h.TableHandler.Query(ctx, in, out) +} + +func (h *tableHandler) List(ctx context.Context, in *Request, out *ListResponse) error { + return h.TableHandler.List(ctx, in, out) } diff --git a/network/router/proto/router.pb.go b/network/router/proto/router.pb.go index 1582776d..6b90c0c8 100644 --- a/network/router/proto/router.pb.go +++ b/network/router/proto/router.pb.go @@ -1,11 +1,13 @@ // Code generated by protoc-gen-go. DO NOT EDIT. -// source: router.proto +// source: go-micro/network/router/proto/router.proto package go_micro_router import ( + context "context" fmt "fmt" proto "github.com/golang/protobuf/proto" + grpc "google.golang.org/grpc" math "math" ) @@ -43,7 +45,7 @@ func (x AdvertType) String() string { } func (AdvertType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{0} + return fileDescriptor_fc08514fc6dadd29, []int{0} } // EventType defines the type of event @@ -72,40 +74,40 @@ func (x EventType) String() string { } func (EventType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{1} + return fileDescriptor_fc08514fc6dadd29, []int{1} } -// ListRequest is made to List routes -type ListRequest struct { +// Empty request +type Request struct { XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } -func (m *ListRequest) Reset() { *m = ListRequest{} } -func (m *ListRequest) String() string { return proto.CompactTextString(m) } -func (*ListRequest) ProtoMessage() {} -func (*ListRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{0} +func (m *Request) Reset() { *m = Request{} } +func (m *Request) String() string { return proto.CompactTextString(m) } +func (*Request) ProtoMessage() {} +func (*Request) Descriptor() ([]byte, []int) { + return fileDescriptor_fc08514fc6dadd29, []int{0} } -func (m *ListRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ListRequest.Unmarshal(m, b) +func (m *Request) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Request.Unmarshal(m, b) } -func (m *ListRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ListRequest.Marshal(b, m, deterministic) +func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Request.Marshal(b, m, deterministic) } -func (m *ListRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ListRequest.Merge(m, src) +func (m *Request) XXX_Merge(src proto.Message) { + xxx_messageInfo_Request.Merge(m, src) } -func (m *ListRequest) XXX_Size() int { - return xxx_messageInfo_ListRequest.Size(m) +func (m *Request) XXX_Size() int { + return xxx_messageInfo_Request.Size(m) } -func (m *ListRequest) XXX_DiscardUnknown() { - xxx_messageInfo_ListRequest.DiscardUnknown(m) +func (m *Request) XXX_DiscardUnknown() { + xxx_messageInfo_Request.DiscardUnknown(m) } -var xxx_messageInfo_ListRequest proto.InternalMessageInfo +var xxx_messageInfo_Request proto.InternalMessageInfo // ListResponse is returned by List type ListResponse struct { @@ -119,7 +121,7 @@ func (m *ListResponse) Reset() { *m = ListResponse{} } func (m *ListResponse) String() string { return proto.CompactTextString(m) } func (*ListResponse) ProtoMessage() {} func (*ListResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{1} + return fileDescriptor_fc08514fc6dadd29, []int{1} } func (m *ListResponse) XXX_Unmarshal(b []byte) error { @@ -159,7 +161,7 @@ func (m *LookupRequest) Reset() { *m = LookupRequest{} } func (m *LookupRequest) String() string { return proto.CompactTextString(m) } func (*LookupRequest) ProtoMessage() {} func (*LookupRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{2} + return fileDescriptor_fc08514fc6dadd29, []int{2} } func (m *LookupRequest) XXX_Unmarshal(b []byte) error { @@ -199,7 +201,7 @@ func (m *LookupResponse) Reset() { *m = LookupResponse{} } func (m *LookupResponse) String() string { return proto.CompactTextString(m) } func (*LookupResponse) ProtoMessage() {} func (*LookupResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{3} + return fileDescriptor_fc08514fc6dadd29, []int{3} } func (m *LookupResponse) XXX_Unmarshal(b []byte) error { @@ -227,6 +229,84 @@ func (m *LookupResponse) GetRoutes() []*Route { return nil } +type QueryRequest struct { + Query *Query `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *QueryRequest) Reset() { *m = QueryRequest{} } +func (m *QueryRequest) String() string { return proto.CompactTextString(m) } +func (*QueryRequest) ProtoMessage() {} +func (*QueryRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_fc08514fc6dadd29, []int{4} +} + +func (m *QueryRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_QueryRequest.Unmarshal(m, b) +} +func (m *QueryRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_QueryRequest.Marshal(b, m, deterministic) +} +func (m *QueryRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryRequest.Merge(m, src) +} +func (m *QueryRequest) XXX_Size() int { + return xxx_messageInfo_QueryRequest.Size(m) +} +func (m *QueryRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryRequest proto.InternalMessageInfo + +func (m *QueryRequest) GetQuery() *Query { + if m != nil { + return m.Query + } + return nil +} + +type QueryResponse struct { + Routes []*Route `protobuf:"bytes,1,rep,name=routes,proto3" json:"routes,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *QueryResponse) Reset() { *m = QueryResponse{} } +func (m *QueryResponse) String() string { return proto.CompactTextString(m) } +func (*QueryResponse) ProtoMessage() {} +func (*QueryResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_fc08514fc6dadd29, []int{5} +} + +func (m *QueryResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_QueryResponse.Unmarshal(m, b) +} +func (m *QueryResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_QueryResponse.Marshal(b, m, deterministic) +} +func (m *QueryResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryResponse.Merge(m, src) +} +func (m *QueryResponse) XXX_Size() int { + return xxx_messageInfo_QueryResponse.Size(m) +} +func (m *QueryResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryResponse proto.InternalMessageInfo + +func (m *QueryResponse) GetRoutes() []*Route { + if m != nil { + return m.Routes + } + return nil +} + // WatchRequest is made to Watch Router type WatchRequest struct { XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -238,7 +318,7 @@ func (m *WatchRequest) Reset() { *m = WatchRequest{} } func (m *WatchRequest) String() string { return proto.CompactTextString(m) } func (*WatchRequest) ProtoMessage() {} func (*WatchRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{4} + return fileDescriptor_fc08514fc6dadd29, []int{6} } func (m *WatchRequest) XXX_Unmarshal(b []byte) error { @@ -270,7 +350,7 @@ func (m *AdvertiseRequest) Reset() { *m = AdvertiseRequest{} } func (m *AdvertiseRequest) String() string { return proto.CompactTextString(m) } func (*AdvertiseRequest) ProtoMessage() {} func (*AdvertiseRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{5} + return fileDescriptor_fc08514fc6dadd29, []int{7} } func (m *AdvertiseRequest) XXX_Unmarshal(b []byte) error { @@ -312,7 +392,7 @@ func (m *Advert) Reset() { *m = Advert{} } func (m *Advert) String() string { return proto.CompactTextString(m) } func (*Advert) ProtoMessage() {} func (*Advert) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{6} + return fileDescriptor_fc08514fc6dadd29, []int{8} } func (m *Advert) XXX_Unmarshal(b []byte) error { @@ -379,7 +459,7 @@ func (m *ProcessResponse) Reset() { *m = ProcessResponse{} } func (m *ProcessResponse) String() string { return proto.CompactTextString(m) } func (*ProcessResponse) ProtoMessage() {} func (*ProcessResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{7} + return fileDescriptor_fc08514fc6dadd29, []int{9} } func (m *ProcessResponse) XXX_Unmarshal(b []byte) error { @@ -411,7 +491,7 @@ func (m *CreateResponse) Reset() { *m = CreateResponse{} } func (m *CreateResponse) String() string { return proto.CompactTextString(m) } func (*CreateResponse) ProtoMessage() {} func (*CreateResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{8} + return fileDescriptor_fc08514fc6dadd29, []int{10} } func (m *CreateResponse) XXX_Unmarshal(b []byte) error { @@ -443,7 +523,7 @@ func (m *DeleteResponse) Reset() { *m = DeleteResponse{} } func (m *DeleteResponse) String() string { return proto.CompactTextString(m) } func (*DeleteResponse) ProtoMessage() {} func (*DeleteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{9} + return fileDescriptor_fc08514fc6dadd29, []int{11} } func (m *DeleteResponse) XXX_Unmarshal(b []byte) error { @@ -475,7 +555,7 @@ func (m *UpdateResponse) Reset() { *m = UpdateResponse{} } func (m *UpdateResponse) String() string { return proto.CompactTextString(m) } func (*UpdateResponse) ProtoMessage() {} func (*UpdateResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{10} + return fileDescriptor_fc08514fc6dadd29, []int{12} } func (m *UpdateResponse) XXX_Unmarshal(b []byte) error { @@ -513,7 +593,7 @@ func (m *Event) Reset() { *m = Event{} } func (m *Event) String() string { return proto.CompactTextString(m) } func (*Event) ProtoMessage() {} func (*Event) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{11} + return fileDescriptor_fc08514fc6dadd29, []int{13} } func (m *Event) XXX_Unmarshal(b []byte) error { @@ -572,7 +652,7 @@ func (m *Query) Reset() { *m = Query{} } func (m *Query) String() string { return proto.CompactTextString(m) } func (*Query) ProtoMessage() {} func (*Query) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{12} + return fileDescriptor_fc08514fc6dadd29, []int{14} } func (m *Query) XXX_Unmarshal(b []byte) error { @@ -637,7 +717,7 @@ func (m *Route) Reset() { *m = Route{} } func (m *Route) String() string { return proto.CompactTextString(m) } func (*Route) ProtoMessage() {} func (*Route) Descriptor() ([]byte, []int) { - return fileDescriptor_367072455c71aedc, []int{13} + return fileDescriptor_fc08514fc6dadd29, []int{15} } func (m *Route) XXX_Unmarshal(b []byte) error { @@ -700,13 +780,101 @@ func (m *Route) GetMetric() int64 { return 0 } +type Status struct { + Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"` + Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Status) Reset() { *m = Status{} } +func (m *Status) String() string { return proto.CompactTextString(m) } +func (*Status) ProtoMessage() {} +func (*Status) Descriptor() ([]byte, []int) { + return fileDescriptor_fc08514fc6dadd29, []int{16} +} + +func (m *Status) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Status.Unmarshal(m, b) +} +func (m *Status) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Status.Marshal(b, m, deterministic) +} +func (m *Status) XXX_Merge(src proto.Message) { + xxx_messageInfo_Status.Merge(m, src) +} +func (m *Status) XXX_Size() int { + return xxx_messageInfo_Status.Size(m) +} +func (m *Status) XXX_DiscardUnknown() { + xxx_messageInfo_Status.DiscardUnknown(m) +} + +var xxx_messageInfo_Status proto.InternalMessageInfo + +func (m *Status) GetCode() string { + if m != nil { + return m.Code + } + return "" +} + +func (m *Status) GetError() string { + if m != nil { + return m.Error + } + return "" +} + +type StatusResponse struct { + Status *Status `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StatusResponse) Reset() { *m = StatusResponse{} } +func (m *StatusResponse) String() string { return proto.CompactTextString(m) } +func (*StatusResponse) ProtoMessage() {} +func (*StatusResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_fc08514fc6dadd29, []int{17} +} + +func (m *StatusResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StatusResponse.Unmarshal(m, b) +} +func (m *StatusResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StatusResponse.Marshal(b, m, deterministic) +} +func (m *StatusResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_StatusResponse.Merge(m, src) +} +func (m *StatusResponse) XXX_Size() int { + return xxx_messageInfo_StatusResponse.Size(m) +} +func (m *StatusResponse) XXX_DiscardUnknown() { + xxx_messageInfo_StatusResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_StatusResponse proto.InternalMessageInfo + +func (m *StatusResponse) GetStatus() *Status { + if m != nil { + return m.Status + } + return nil +} + func init() { proto.RegisterEnum("go.micro.router.AdvertType", AdvertType_name, AdvertType_value) proto.RegisterEnum("go.micro.router.EventType", EventType_name, EventType_value) - proto.RegisterType((*ListRequest)(nil), "go.micro.router.ListRequest") + proto.RegisterType((*Request)(nil), "go.micro.router.Request") proto.RegisterType((*ListResponse)(nil), "go.micro.router.ListResponse") proto.RegisterType((*LookupRequest)(nil), "go.micro.router.LookupRequest") proto.RegisterType((*LookupResponse)(nil), "go.micro.router.LookupResponse") + proto.RegisterType((*QueryRequest)(nil), "go.micro.router.QueryRequest") + proto.RegisterType((*QueryResponse)(nil), "go.micro.router.QueryResponse") proto.RegisterType((*WatchRequest)(nil), "go.micro.router.WatchRequest") proto.RegisterType((*AdvertiseRequest)(nil), "go.micro.router.AdvertiseRequest") proto.RegisterType((*Advert)(nil), "go.micro.router.Advert") @@ -717,47 +885,513 @@ func init() { proto.RegisterType((*Event)(nil), "go.micro.router.Event") proto.RegisterType((*Query)(nil), "go.micro.router.Query") proto.RegisterType((*Route)(nil), "go.micro.router.Route") + proto.RegisterType((*Status)(nil), "go.micro.router.Status") + proto.RegisterType((*StatusResponse)(nil), "go.micro.router.StatusResponse") } -func init() { proto.RegisterFile("router.proto", fileDescriptor_367072455c71aedc) } - -var fileDescriptor_367072455c71aedc = []byte{ - // 591 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0xc1, 0x6e, 0xd3, 0x40, - 0x10, 0xf5, 0x26, 0xb6, 0x2b, 0x4f, 0x53, 0xd7, 0xcc, 0xa1, 0x58, 0xa6, 0x40, 0xf0, 0xa9, 0xaa, - 0x2a, 0x17, 0x85, 0x33, 0x88, 0x52, 0xca, 0xa5, 0x3d, 0x80, 0x45, 0xc5, 0xd9, 0xd8, 0xa3, 0x62, - 0xb5, 0xb1, 0xdd, 0xdd, 0x4d, 0xab, 0x9c, 0xf9, 0x0c, 0xbe, 0x80, 0xff, 0xe0, 0xc3, 0x90, 0x77, - 0xed, 0xd6, 0x75, 0x62, 0xa4, 0x72, 0xca, 0xce, 0xcc, 0x9b, 0x37, 0x3b, 0x33, 0xfb, 0x62, 0x98, - 0xf0, 0x72, 0x21, 0x89, 0x47, 0x15, 0x2f, 0x65, 0x89, 0xdb, 0x17, 0x65, 0x34, 0xcf, 0x53, 0x5e, - 0x46, 0xda, 0x1d, 0x6e, 0xc1, 0xe6, 0x59, 0x2e, 0x64, 0x4c, 0xd7, 0x0b, 0x12, 0x32, 0x7c, 0x07, - 0x13, 0x6d, 0x8a, 0xaa, 0x2c, 0x04, 0x61, 0x04, 0xb6, 0x02, 0x0a, 0x9f, 0x4d, 0xc7, 0x7b, 0x9b, - 0xb3, 0x9d, 0xa8, 0x47, 0x10, 0xc5, 0xf5, 0x4f, 0xdc, 0xa0, 0xc2, 0xb7, 0xb0, 0x75, 0x56, 0x96, - 0x97, 0x8b, 0xaa, 0x21, 0xc4, 0x03, 0xb0, 0xae, 0x17, 0xc4, 0x97, 0x3e, 0x9b, 0xb2, 0xb5, 0xf9, - 0x5f, 0xea, 0x68, 0xac, 0x41, 0xe1, 0x7b, 0x70, 0xdb, 0xf4, 0xff, 0xbc, 0x80, 0x0b, 0x93, 0x6f, - 0x89, 0x4c, 0x7f, 0xb4, 0x0d, 0x21, 0x78, 0x47, 0xd9, 0x0d, 0x71, 0x99, 0x0b, 0x6a, 0x7d, 0xbf, - 0x19, 0xd8, 0xda, 0x89, 0x2e, 0x8c, 0xf2, 0x4c, 0xdd, 0xcd, 0x89, 0x47, 0x79, 0x86, 0x87, 0x60, - 0xca, 0x65, 0x45, 0xfe, 0x68, 0xca, 0xf6, 0xdc, 0xd9, 0xb3, 0x95, 0x62, 0x3a, 0xed, 0xeb, 0xb2, - 0xa2, 0x58, 0x01, 0x71, 0x17, 0x1c, 0x99, 0xcf, 0x49, 0xc8, 0x64, 0x5e, 0xf9, 0xe3, 0x29, 0xdb, - 0x1b, 0xc7, 0xf7, 0x0e, 0xf4, 0x60, 0x2c, 0xe5, 0x95, 0x6f, 0x2a, 0x7f, 0x7d, 0xac, 0xfb, 0xa1, - 0x1b, 0x2a, 0xa4, 0xf0, 0xad, 0x81, 0x7e, 0x4e, 0xea, 0x70, 0xdc, 0xa0, 0xc2, 0x27, 0xb0, 0xfd, - 0x99, 0x97, 0x29, 0x09, 0xd1, 0x8e, 0x24, 0xf4, 0xc0, 0x3d, 0xe6, 0x94, 0x48, 0xea, 0x7a, 0x3e, - 0xd2, 0x15, 0x3d, 0xf4, 0x9c, 0x57, 0x59, 0x17, 0xf3, 0x93, 0x81, 0xa5, 0xa8, 0x31, 0x6a, 0x7a, - 0x64, 0xaa, 0xc7, 0x60, 0xfd, 0x05, 0x86, 0x5a, 0x1c, 0xf5, 0x5b, 0x3c, 0x00, 0x4b, 0xe5, 0xa9, - 0xe6, 0x87, 0xf7, 0xa3, 0x41, 0xe1, 0x39, 0x58, 0x6a, 0xe1, 0xe8, 0xc3, 0x86, 0x20, 0x7e, 0x93, - 0xa7, 0xd4, 0x4c, 0xbf, 0x35, 0xeb, 0xc8, 0x45, 0x22, 0xe9, 0x36, 0x59, 0xaa, 0x62, 0x4e, 0xdc, - 0x9a, 0x75, 0xa4, 0x20, 0x79, 0x5b, 0xf2, 0x4b, 0x55, 0xcc, 0x89, 0x5b, 0x33, 0xfc, 0xc5, 0xc0, - 0x52, 0x75, 0xfe, 0xcd, 0x9b, 0x64, 0x19, 0x27, 0x21, 0x5a, 0xde, 0xc6, 0xec, 0x56, 0x1c, 0x0f, - 0x56, 0x34, 0x1f, 0x54, 0x44, 0x04, 0xf3, 0x2a, 0x2f, 0x2e, 0x7d, 0x4b, 0xb9, 0xd5, 0x19, 0x77, - 0xc0, 0x9e, 0x93, 0xe4, 0x79, 0xea, 0xdb, 0x6a, 0x4a, 0x8d, 0xb5, 0x3f, 0x03, 0xb8, 0x7f, 0x37, - 0x88, 0xe0, 0x6a, 0xeb, 0xa8, 0x28, 0xca, 0x45, 0x91, 0x92, 0x67, 0xa0, 0x07, 0x13, 0xed, 0xd3, - 0x4b, 0xf3, 0xd8, 0xfe, 0x21, 0x38, 0x77, 0x7b, 0x40, 0x00, 0x5b, 0x6f, 0xdc, 0x33, 0xea, 0xb3, - 0xde, 0xb5, 0xc7, 0xea, 0x73, 0x93, 0x30, 0x9a, 0xfd, 0x31, 0xc1, 0x56, 0x23, 0xe0, 0x78, 0x02, - 0x66, 0x2d, 0x62, 0xdc, 0x5d, 0xd9, 0x45, 0x47, 0xea, 0xc1, 0xf3, 0x81, 0x68, 0xf3, 0x5e, 0x0c, - 0x3c, 0x05, 0x5b, 0x8b, 0x11, 0x5f, 0xac, 0x42, 0xbb, 0x22, 0x0f, 0x5e, 0x0e, 0xc6, 0xef, 0xc8, - 0x3e, 0x80, 0xa5, 0x74, 0x89, 0xab, 0x65, 0xbb, 0x7a, 0x0d, 0x06, 0xf4, 0x10, 0x1a, 0xaf, 0x19, - 0x9e, 0x82, 0x73, 0xa7, 0x65, 0x7c, 0x35, 0xa0, 0xcd, 0x7b, 0x9d, 0x07, 0x4f, 0x07, 0x20, 0x8a, - 0xec, 0x13, 0x6c, 0x34, 0xc2, 0xc2, 0x21, 0x5c, 0x30, 0x5d, 0x09, 0xf4, 0xb5, 0x68, 0xe0, 0x71, - 0xbb, 0x1b, 0x1c, 0x78, 0xfa, 0x6b, 0xa6, 0xd3, 0x93, 0xaf, 0x22, 0xd1, 0x4b, 0x7d, 0x04, 0x49, - 0x4f, 0xf1, 0x8a, 0x44, 0xbf, 0x86, 0x47, 0x90, 0xf4, 0xfe, 0x24, 0x8c, 0xef, 0xb6, 0xfa, 0x4e, - 0xbc, 0xf9, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xbb, 0x08, 0x6d, 0x39, 0x37, 0x06, 0x00, 0x00, +func init() { + proto.RegisterFile("go-micro/network/router/proto/router.proto", fileDescriptor_fc08514fc6dadd29) +} + +var fileDescriptor_fc08514fc6dadd29 = []byte{ + // 702 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0xcd, 0x4e, 0xdb, 0x40, + 0x10, 0xb6, 0x93, 0xd8, 0xc8, 0xd3, 0x60, 0xdc, 0x51, 0x05, 0x56, 0x5a, 0x68, 0xea, 0x13, 0x42, + 0xd4, 0xa9, 0xd2, 0x6b, 0xff, 0x52, 0x4a, 0x55, 0x09, 0x0e, 0xad, 0x0b, 0xea, 0xd9, 0xd8, 0x2b, + 0x6a, 0x91, 0x78, 0xcd, 0xee, 0x06, 0x94, 0x73, 0x1f, 0xa3, 0x4f, 0xd0, 0xe7, 0xea, 0x33, 0xf4, + 0x5e, 0x79, 0x77, 0x1d, 0x92, 0x18, 0x23, 0xc1, 0xc9, 0x3b, 0x7f, 0xdf, 0xec, 0xcc, 0xce, 0x37, + 0x86, 0xbd, 0x73, 0xfa, 0x72, 0x92, 0x25, 0x8c, 0x0e, 0x72, 0x22, 0xae, 0x29, 0xbb, 0x18, 0x30, + 0x3a, 0x15, 0x84, 0x0d, 0x0a, 0x46, 0x05, 0xd5, 0x42, 0x28, 0x05, 0xdc, 0x38, 0xa7, 0xa1, 0xf4, + 0x0d, 0x95, 0x3a, 0x70, 0x60, 0x2d, 0x22, 0x97, 0x53, 0xc2, 0x45, 0xf0, 0x0e, 0xba, 0xc7, 0x19, + 0x17, 0x11, 0xe1, 0x05, 0xcd, 0x39, 0xc1, 0x10, 0x6c, 0xe9, 0xc4, 0x7d, 0xb3, 0xdf, 0xde, 0x7d, + 0x34, 0xdc, 0x0c, 0x57, 0x82, 0xc3, 0xa8, 0xfc, 0x44, 0xda, 0x2b, 0x78, 0x0b, 0xeb, 0xc7, 0x94, + 0x5e, 0x4c, 0x0b, 0x0d, 0x88, 0xfb, 0x60, 0x5d, 0x4e, 0x09, 0x9b, 0xf9, 0x66, 0xdf, 0xbc, 0x35, + 0xfe, 0x5b, 0x69, 0x8d, 0x94, 0x53, 0xf0, 0x01, 0xdc, 0x2a, 0xfc, 0x81, 0x17, 0x78, 0x03, 0x5d, + 0x85, 0xf8, 0xa0, 0xfc, 0xef, 0x61, 0x5d, 0x47, 0x3f, 0x30, 0xbd, 0x0b, 0xdd, 0x1f, 0xb1, 0x48, + 0x7e, 0x56, 0xfd, 0x44, 0xf0, 0x46, 0xe9, 0x15, 0x61, 0x22, 0xe3, 0xa4, 0xd2, 0xfd, 0x31, 0xc1, + 0x56, 0x4a, 0x74, 0xa1, 0x95, 0xa5, 0xf2, 0x6a, 0x4e, 0xd4, 0xca, 0x52, 0x1c, 0x40, 0x47, 0xcc, + 0x0a, 0xe2, 0xb7, 0xfa, 0xe6, 0xae, 0x3b, 0x7c, 0x5a, 0x4b, 0xa6, 0xc2, 0x4e, 0x66, 0x05, 0x89, + 0xa4, 0x23, 0x3e, 0x03, 0x47, 0x64, 0x13, 0xc2, 0x45, 0x3c, 0x29, 0xfc, 0x76, 0xdf, 0xdc, 0x6d, + 0x47, 0x37, 0x0a, 0xf4, 0xa0, 0x2d, 0xc4, 0xd8, 0xef, 0x48, 0x7d, 0x79, 0x2c, 0xeb, 0x21, 0x57, + 0x24, 0x17, 0xdc, 0xb7, 0x1a, 0xea, 0x39, 0x2c, 0xcd, 0x91, 0xf6, 0x0a, 0x1e, 0xc3, 0xc6, 0x57, + 0x46, 0x13, 0xc2, 0x79, 0xd5, 0x92, 0xc0, 0x03, 0xf7, 0x80, 0x91, 0x58, 0x90, 0x45, 0xcd, 0x27, + 0x32, 0x26, 0xcb, 0x9a, 0xd3, 0x22, 0x5d, 0xf4, 0xf9, 0x65, 0x82, 0x25, 0xa1, 0x31, 0xd4, 0x35, + 0x9a, 0xb2, 0xc6, 0xde, 0xed, 0x17, 0x68, 0x2a, 0xb1, 0xb5, 0x5a, 0xe2, 0x3e, 0x58, 0x32, 0x4e, + 0x16, 0xdf, 0xfc, 0x3e, 0xca, 0x29, 0x38, 0x05, 0x4b, 0xbe, 0x2f, 0xfa, 0xb0, 0xc6, 0x09, 0xbb, + 0xca, 0x12, 0xa2, 0xbb, 0x5f, 0x89, 0xa5, 0xe5, 0x3c, 0x16, 0xe4, 0x3a, 0x9e, 0xc9, 0x64, 0x4e, + 0x54, 0x89, 0xa5, 0x45, 0x93, 0x4b, 0x26, 0x73, 0xa2, 0x4a, 0x0c, 0x7e, 0x9b, 0x60, 0xc9, 0x3c, + 0x77, 0xe3, 0xc6, 0x69, 0xca, 0x08, 0xe7, 0x15, 0xae, 0x16, 0x17, 0x33, 0xb6, 0x1b, 0x33, 0x76, + 0x96, 0x32, 0x22, 0x42, 0x67, 0x9c, 0xe5, 0x17, 0xbe, 0x25, 0xd5, 0xf2, 0x8c, 0x9b, 0x60, 0x4f, + 0x88, 0x60, 0x59, 0xe2, 0xdb, 0xb2, 0x4b, 0x5a, 0x0a, 0x86, 0x60, 0x7f, 0x17, 0xb1, 0x98, 0xf2, + 0x32, 0x2a, 0xa1, 0x69, 0x75, 0x35, 0x79, 0xc6, 0x27, 0x60, 0x11, 0xc6, 0x28, 0xd3, 0xb7, 0x52, + 0x42, 0x30, 0x02, 0x57, 0xc5, 0xcc, 0x99, 0x30, 0x00, 0x9b, 0x4b, 0x8d, 0x66, 0xd2, 0x56, 0xad, + 0xd3, 0x3a, 0x40, 0xbb, 0xed, 0x0d, 0x01, 0x6e, 0xc6, 0x15, 0x11, 0x5c, 0x25, 0x8d, 0xf2, 0x9c, + 0x4e, 0xf3, 0x84, 0x78, 0x06, 0x7a, 0xd0, 0x55, 0x3a, 0x35, 0x2b, 0x9e, 0xb9, 0x37, 0x00, 0x67, + 0xfe, 0xfc, 0x08, 0x60, 0xab, 0x41, 0xf3, 0x8c, 0xf2, 0xac, 0x46, 0xcc, 0x33, 0xcb, 0xb3, 0x0e, + 0x68, 0x0d, 0xff, 0xb5, 0xc0, 0x96, 0x9d, 0x67, 0x78, 0x04, 0xb6, 0xda, 0x1d, 0xb8, 0x53, 0xbb, + 0xda, 0xd2, 0x4e, 0xea, 0x3d, 0x6f, 0xb4, 0xeb, 0x61, 0x35, 0xf0, 0x23, 0x58, 0x92, 0xc7, 0xb8, + 0x5d, 0xf3, 0x5d, 0xe4, 0x77, 0xaf, 0x81, 0x3f, 0x81, 0xf1, 0xca, 0xc4, 0x23, 0x70, 0xe6, 0xdc, + 0xc7, 0x17, 0x0d, 0x5c, 0xbe, 0xd9, 0x0b, 0xbd, 0xad, 0x06, 0x17, 0x09, 0xf6, 0x19, 0xd6, 0x34, + 0x11, 0xb1, 0xc9, 0xaf, 0xd7, 0xaf, 0x19, 0x56, 0xb9, 0x6b, 0xe0, 0xe1, 0x7c, 0x18, 0xfc, 0x3a, + 0x55, 0x1a, 0xfb, 0xb3, 0x3c, 0x0b, 0x81, 0x31, 0xfc, 0xdb, 0x02, 0xeb, 0x24, 0x3e, 0x1b, 0x13, + 0x3c, 0xa8, 0x5e, 0x09, 0x1b, 0xb8, 0x77, 0x0b, 0xdc, 0xca, 0xfe, 0x30, 0x4a, 0x10, 0xf5, 0xbc, + 0xf7, 0x00, 0x59, 0x59, 0x39, 0x12, 0x44, 0xcd, 0xc5, 0x3d, 0x40, 0x56, 0xb6, 0x94, 0x81, 0x5f, + 0xaa, 0x0d, 0xb1, 0xdd, 0xf0, 0xa7, 0xd0, 0x3d, 0xda, 0x69, 0x32, 0xcf, 0x91, 0x46, 0xd0, 0x29, + 0x7f, 0xa5, 0x77, 0xf4, 0xb9, 0x9e, 0x62, 0xf1, 0xdf, 0x1b, 0x18, 0x67, 0xb6, 0xfc, 0x61, 0xbf, + 0xfe, 0x1f, 0x00, 0x00, 0xff, 0xff, 0xa6, 0xfc, 0x65, 0xca, 0xde, 0x07, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// RouterClient is the client API for Router service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type RouterClient interface { + Lookup(ctx context.Context, in *LookupRequest, opts ...grpc.CallOption) (*LookupResponse, error) + Watch(ctx context.Context, in *WatchRequest, opts ...grpc.CallOption) (Router_WatchClient, error) + Advertise(ctx context.Context, in *AdvertiseRequest, opts ...grpc.CallOption) (Router_AdvertiseClient, error) + Process(ctx context.Context, in *Advert, opts ...grpc.CallOption) (*ProcessResponse, error) + Status(ctx context.Context, in *Request, opts ...grpc.CallOption) (*StatusResponse, error) +} + +type routerClient struct { + cc *grpc.ClientConn +} + +func NewRouterClient(cc *grpc.ClientConn) RouterClient { + return &routerClient{cc} +} + +func (c *routerClient) Lookup(ctx context.Context, in *LookupRequest, opts ...grpc.CallOption) (*LookupResponse, error) { + out := new(LookupResponse) + err := c.cc.Invoke(ctx, "/go.micro.router.Router/Lookup", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *routerClient) Watch(ctx context.Context, in *WatchRequest, opts ...grpc.CallOption) (Router_WatchClient, error) { + stream, err := c.cc.NewStream(ctx, &_Router_serviceDesc.Streams[0], "/go.micro.router.Router/Watch", opts...) + if err != nil { + return nil, err + } + x := &routerWatchClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type Router_WatchClient interface { + Recv() (*Event, error) + grpc.ClientStream +} + +type routerWatchClient struct { + grpc.ClientStream +} + +func (x *routerWatchClient) Recv() (*Event, error) { + m := new(Event) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *routerClient) Advertise(ctx context.Context, in *AdvertiseRequest, opts ...grpc.CallOption) (Router_AdvertiseClient, error) { + stream, err := c.cc.NewStream(ctx, &_Router_serviceDesc.Streams[1], "/go.micro.router.Router/Advertise", opts...) + if err != nil { + return nil, err + } + x := &routerAdvertiseClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type Router_AdvertiseClient interface { + Recv() (*Advert, error) + grpc.ClientStream +} + +type routerAdvertiseClient struct { + grpc.ClientStream +} + +func (x *routerAdvertiseClient) Recv() (*Advert, error) { + m := new(Advert) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *routerClient) Process(ctx context.Context, in *Advert, opts ...grpc.CallOption) (*ProcessResponse, error) { + out := new(ProcessResponse) + err := c.cc.Invoke(ctx, "/go.micro.router.Router/Process", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *routerClient) Status(ctx context.Context, in *Request, opts ...grpc.CallOption) (*StatusResponse, error) { + out := new(StatusResponse) + err := c.cc.Invoke(ctx, "/go.micro.router.Router/Status", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// RouterServer is the server API for Router service. +type RouterServer interface { + Lookup(context.Context, *LookupRequest) (*LookupResponse, error) + Watch(*WatchRequest, Router_WatchServer) error + Advertise(*AdvertiseRequest, Router_AdvertiseServer) error + Process(context.Context, *Advert) (*ProcessResponse, error) + Status(context.Context, *Request) (*StatusResponse, error) +} + +func RegisterRouterServer(s *grpc.Server, srv RouterServer) { + s.RegisterService(&_Router_serviceDesc, srv) +} + +func _Router_Lookup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(LookupRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RouterServer).Lookup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/go.micro.router.Router/Lookup", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RouterServer).Lookup(ctx, req.(*LookupRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Router_Watch_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(WatchRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(RouterServer).Watch(m, &routerWatchServer{stream}) +} + +type Router_WatchServer interface { + Send(*Event) error + grpc.ServerStream +} + +type routerWatchServer struct { + grpc.ServerStream +} + +func (x *routerWatchServer) Send(m *Event) error { + return x.ServerStream.SendMsg(m) +} + +func _Router_Advertise_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(AdvertiseRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(RouterServer).Advertise(m, &routerAdvertiseServer{stream}) +} + +type Router_AdvertiseServer interface { + Send(*Advert) error + grpc.ServerStream +} + +type routerAdvertiseServer struct { + grpc.ServerStream +} + +func (x *routerAdvertiseServer) Send(m *Advert) error { + return x.ServerStream.SendMsg(m) +} + +func _Router_Process_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Advert) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RouterServer).Process(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/go.micro.router.Router/Process", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RouterServer).Process(ctx, req.(*Advert)) + } + return interceptor(ctx, in, info, handler) +} + +func _Router_Status_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RouterServer).Status(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/go.micro.router.Router/Status", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RouterServer).Status(ctx, req.(*Request)) + } + return interceptor(ctx, in, info, handler) +} + +var _Router_serviceDesc = grpc.ServiceDesc{ + ServiceName: "go.micro.router.Router", + HandlerType: (*RouterServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Lookup", + Handler: _Router_Lookup_Handler, + }, + { + MethodName: "Process", + Handler: _Router_Process_Handler, + }, + { + MethodName: "Status", + Handler: _Router_Status_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "Watch", + Handler: _Router_Watch_Handler, + ServerStreams: true, + }, + { + StreamName: "Advertise", + Handler: _Router_Advertise_Handler, + ServerStreams: true, + }, + }, + Metadata: "go-micro/network/router/proto/router.proto", +} + +// TableClient is the client API for Table service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type TableClient interface { + Create(ctx context.Context, in *Route, opts ...grpc.CallOption) (*CreateResponse, error) + Delete(ctx context.Context, in *Route, opts ...grpc.CallOption) (*DeleteResponse, error) + Update(ctx context.Context, in *Route, opts ...grpc.CallOption) (*UpdateResponse, error) + Query(ctx context.Context, in *QueryRequest, opts ...grpc.CallOption) (*QueryResponse, error) + List(ctx context.Context, in *Request, opts ...grpc.CallOption) (*ListResponse, error) +} + +type tableClient struct { + cc *grpc.ClientConn +} + +func NewTableClient(cc *grpc.ClientConn) TableClient { + return &tableClient{cc} +} + +func (c *tableClient) Create(ctx context.Context, in *Route, opts ...grpc.CallOption) (*CreateResponse, error) { + out := new(CreateResponse) + err := c.cc.Invoke(ctx, "/go.micro.router.Table/Create", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *tableClient) Delete(ctx context.Context, in *Route, opts ...grpc.CallOption) (*DeleteResponse, error) { + out := new(DeleteResponse) + err := c.cc.Invoke(ctx, "/go.micro.router.Table/Delete", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *tableClient) Update(ctx context.Context, in *Route, opts ...grpc.CallOption) (*UpdateResponse, error) { + out := new(UpdateResponse) + err := c.cc.Invoke(ctx, "/go.micro.router.Table/Update", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *tableClient) Query(ctx context.Context, in *QueryRequest, opts ...grpc.CallOption) (*QueryResponse, error) { + out := new(QueryResponse) + err := c.cc.Invoke(ctx, "/go.micro.router.Table/Query", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *tableClient) List(ctx context.Context, in *Request, opts ...grpc.CallOption) (*ListResponse, error) { + out := new(ListResponse) + err := c.cc.Invoke(ctx, "/go.micro.router.Table/List", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// TableServer is the server API for Table service. +type TableServer interface { + Create(context.Context, *Route) (*CreateResponse, error) + Delete(context.Context, *Route) (*DeleteResponse, error) + Update(context.Context, *Route) (*UpdateResponse, error) + Query(context.Context, *QueryRequest) (*QueryResponse, error) + List(context.Context, *Request) (*ListResponse, error) +} + +func RegisterTableServer(s *grpc.Server, srv TableServer) { + s.RegisterService(&_Table_serviceDesc, srv) +} + +func _Table_Create_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Route) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TableServer).Create(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/go.micro.router.Table/Create", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TableServer).Create(ctx, req.(*Route)) + } + return interceptor(ctx, in, info, handler) +} + +func _Table_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Route) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TableServer).Delete(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/go.micro.router.Table/Delete", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TableServer).Delete(ctx, req.(*Route)) + } + return interceptor(ctx, in, info, handler) +} + +func _Table_Update_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Route) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TableServer).Update(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/go.micro.router.Table/Update", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TableServer).Update(ctx, req.(*Route)) + } + return interceptor(ctx, in, info, handler) +} + +func _Table_Query_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TableServer).Query(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/go.micro.router.Table/Query", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TableServer).Query(ctx, req.(*QueryRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Table_List_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TableServer).List(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/go.micro.router.Table/List", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TableServer).List(ctx, req.(*Request)) + } + return interceptor(ctx, in, info, handler) +} + +var _Table_serviceDesc = grpc.ServiceDesc{ + ServiceName: "go.micro.router.Table", + HandlerType: (*TableServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Create", + Handler: _Table_Create_Handler, + }, + { + MethodName: "Delete", + Handler: _Table_Delete_Handler, + }, + { + MethodName: "Update", + Handler: _Table_Update_Handler, + }, + { + MethodName: "Query", + Handler: _Table_Query_Handler, + }, + { + MethodName: "List", + Handler: _Table_List_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "go-micro/network/router/proto/router.proto", } diff --git a/network/router/proto/router.proto b/network/router/proto/router.proto index 921e3e7e..15ef2cd2 100644 --- a/network/router/proto/router.proto +++ b/network/router/proto/router.proto @@ -4,18 +4,23 @@ package go.micro.router; // Router service is used by the proxy to lookup routes service Router { - rpc List(ListRequest) returns (ListResponse) {}; rpc Lookup(LookupRequest) returns (LookupResponse) {}; rpc Watch(WatchRequest) returns (stream Event) {}; - rpc Advertise(AdvertiseRequest) returns (stream Advert) {}; + rpc Advertise(Request) returns (stream Advert) {}; rpc Process(Advert) returns (ProcessResponse) {}; - rpc Create(Route) returns (CreateResponse) {}; - rpc Delete(Route) returns (DeleteResponse) {}; - rpc Update(Route) returns (UpdateResponse) {}; + rpc Status(Request) returns (StatusResponse) {}; } -// ListRequest is made to List routes -message ListRequest {} +service Table { + rpc Create(Route) returns (CreateResponse) {}; + rpc Delete(Route) returns (DeleteResponse) {}; + rpc Update(Route) returns (UpdateResponse) {}; + rpc List(Request) returns (ListResponse) {}; + rpc Query(QueryRequest) returns (QueryResponse) {}; +} + +// Empty request +message Request {} // ListResponse is returned by List message ListResponse { @@ -32,12 +37,17 @@ message LookupResponse { repeated Route routes = 1; } +message QueryRequest{ + Query query = 1; +} + +message QueryResponse { + repeated Route routes = 1; +} + // WatchRequest is made to Watch Router message WatchRequest {} -// AdvertiseRequest request a stream of Adverts -message AdvertiseRequest {} - // AdvertType defines the type of advert enum AdvertType { AdvertAnnounce = 0; @@ -112,3 +122,12 @@ message Route { // the metric / score of this route int64 metric = 6; } + +message Status { + string code = 1; + string error = 2; +} + +message StatusResponse { + Status status = 1; +} diff --git a/network/router/router.go b/network/router/router.go index 30ea857a..af6f8bc3 100644 --- a/network/router/router.go +++ b/network/router/router.go @@ -11,6 +11,8 @@ type Router interface { Init(...Option) error // Options returns the router options Options() Options + // The routing table + Table() Table // Advertise advertises routes to the network Advertise() (<-chan *Advert, error) // Process processes incoming adverts @@ -27,6 +29,19 @@ type Router interface { String() string } +type Table interface { + // Create new route in the routing table + Create(Route) error + // Delete deletes existing route from the routing table + Delete(Route) error + // Update updates route in the routing table + Update(Route) error + // List returns the list of all routes in the table + List() ([]Route, error) + // Query queries routes in the routing table + Query(Query) ([]Route, error) +} + // Option used by the router type Option func(*Options) diff --git a/network/router/service/service.go b/network/router/service/service.go index 09806cd3..21d025d1 100644 --- a/network/router/service/service.go +++ b/network/router/service/service.go @@ -2,12 +2,12 @@ package service import ( "context" + "errors" "fmt" "io" "sync" "time" - "github.com/google/uuid" "github.com/micro/go-micro/client" "github.com/micro/go-micro/network/router" pb "github.com/micro/go-micro/network/router/proto" @@ -16,13 +16,13 @@ import ( type svc struct { sync.RWMutex opts router.Options + callOpts []client.CallOption router pb.RouterService - status router.Status - watchers map[string]*svcWatcher - exit chan struct{} + table *table + status *router.Status + exit chan bool errChan chan error advertChan chan *router.Advert - wg *sync.WaitGroup } // NewRouter creates new service router and returns it @@ -36,18 +36,27 @@ func NewRouter(opts ...router.Option) router.Router { } // NOTE: might need some client opts here - client := client.DefaultClient + cli := client.DefaultClient + + // set options client + if options.Client != nil { + cli = options.Client + } // NOTE: should we have Client/Service option in router.Options? s := &svc{ - opts: options, - router: pb.NewRouterService(router.DefaultName, client), - status: router.Status{Code: router.Stopped, Error: nil}, - watchers: make(map[string]*svcWatcher), - wg: &sync.WaitGroup{}, + opts: options, + router: pb.NewRouterService(router.DefaultName, cli), } - go s.run() + // set the router address to call + if len(options.Address) > 0 { + s.callOpts = []client.CallOption{ + client.WithAddress(options.Address), + } + } + // set the table + s.table = &table{pb.NewTableService(router.DefaultName, cli), s.callOpts} return s } @@ -65,128 +74,12 @@ func (s *svc) Options() router.Options { return s.opts } -// watchRouter watches router and send events to all registered watchers -func (s *svc) watchRouter(stream pb.Router_WatchService) error { - s.wg.Add(1) +func (s *svc) Table() router.Table { + return s.table +} + +func (s *svc) advertiseEvents(advertChan chan *router.Advert, stream pb.Router_AdvertiseService) error { go func() { - defer s.wg.Done() - <-s.exit - stream.Close() - }() - - var watchErr error - - for { - resp, err := stream.Recv() - if err != nil { - if err != io.EOF { - watchErr = err - } - break - } - - route := router.Route{ - Service: resp.Route.Service, - Address: resp.Route.Address, - Gateway: resp.Route.Gateway, - Network: resp.Route.Network, - Link: resp.Route.Link, - Metric: int(resp.Route.Metric), - } - - event := &router.Event{ - Type: router.EventType(resp.Type), - Timestamp: time.Unix(0, resp.Timestamp), - Route: route, - } - - // TODO: might make this non-blocking - s.RLock() - for _, w := range s.watchers { - select { - case w.resChan <- event: - case <-w.done: - } - } - s.RUnlock() - } - - return watchErr -} - -// watchErrors watches router errors and takes appropriate actions -func (s *svc) watchErrors() { - var err error - - select { - case <-s.exit: - case err = <-s.errChan: - } - - s.Lock() - defer s.Unlock() - if s.status.Code != router.Stopped { - // notify all goroutines to finish - close(s.exit) - if s.status.Code == router.Advertising { - // drain the advertise channel - for range s.advertChan { - } - } - s.status = router.Status{Code: router.Stopped, Error: nil} - } - - if err != nil { - s.status = router.Status{Code: router.Error, Error: err} - } -} - -// Run runs the router. -func (s *svc) run() { - s.Lock() - defer s.Unlock() - - switch s.status.Code { - case router.Stopped, router.Error: - stream, err := s.router.Watch(context.Background(), &pb.WatchRequest{}) - if err != nil { - s.status = router.Status{Code: router.Error, Error: fmt.Errorf("failed getting event stream: %s", err)} - return - } - - // create error and exit channels - s.errChan = make(chan error, 1) - s.exit = make(chan struct{}) - - s.wg.Add(1) - go func() { - defer s.wg.Done() - select { - case s.errChan <- s.watchRouter(stream): - case <-s.exit: - } - }() - - // watch for errors and cleanup - s.wg.Add(1) - go func() { - defer s.wg.Done() - s.watchErrors() - }() - - // mark router as Running and set its Error to nil - s.status = router.Status{Code: router.Running, Error: nil} - - return - } - - return -} - -func (s *svc) advertiseEvents(stream pb.Router_AdvertiseService) error { - s.wg.Add(1) - go func() { - defer s.wg.Done() <-s.exit stream.Close() }() @@ -229,15 +122,15 @@ func (s *svc) advertiseEvents(stream pb.Router_AdvertiseService) error { } select { - case s.advertChan <- advert: + case advertChan <- advert: case <-s.exit: - close(s.advertChan) + close(advertChan) return nil } } // close the channel on exit - close(s.advertChan) + close(advertChan) return advErr } @@ -247,33 +140,29 @@ func (s *svc) Advertise() (<-chan *router.Advert, error) { s.Lock() defer s.Unlock() - switch s.status.Code { - case router.Advertising: - return s.advertChan, nil - case router.Running: - stream, err := s.router.Advertise(context.Background(), &pb.AdvertiseRequest{}) + // get the status + status := s.Status() + + switch status.Code { + case router.Running, router.Advertising: + stream, err := s.router.Advertise(context.Background(), &pb.AdvertiseRequest{}, s.callOpts...) if err != nil { return nil, fmt.Errorf("failed getting advert stream: %s", err) } - // create advertise and event channels - s.advertChan = make(chan *router.Advert) - - s.wg.Add(1) - go func() { - defer s.wg.Done() - select { - case s.errChan <- s.advertiseEvents(stream): - case <-s.exit: - } - }() - - // mark router as Running and set its Error to nil - s.status = router.Status{Code: router.Advertising, Error: nil} - - return s.advertChan, nil + advertChan := make(chan *router.Advert) + go s.advertiseEvents(advertChan, stream) + return advertChan, nil case router.Stopped: - return nil, fmt.Errorf("not running") + // check if our router is stopped + select { + case <-s.exit: + s.exit = make(chan bool) + // call advertise again + return s.Advertise() + default: + return nil, fmt.Errorf("not running") + } } return nil, fmt.Errorf("error: %s", s.status.Error) @@ -306,87 +195,75 @@ func (s *svc) Process(advert *router.Advert) error { Events: events, } - if _, err := s.router.Process(context.Background(), advertReq); err != nil { + if _, err := s.router.Process(context.Background(), advertReq, s.callOpts...); err != nil { return err } return nil } -// Create new route in the routing table -func (s *svc) Create(r router.Route) error { - route := &pb.Route{ - Service: r.Service, - Address: r.Address, - Gateway: r.Gateway, - Network: r.Network, - Link: r.Link, - Metric: int64(r.Metric), +// Status returns router status +func (s *svc) Status() router.Status { + s.Lock() + defer s.Unlock() + + // check if its stopped + select { + case <-s.exit: + return router.Status{ + Code: router.Stopped, + Error: nil, + } + default: + // don't block } - if _, err := s.router.Create(context.Background(), route); err != nil { - return err - } - - return nil -} - -// Delete deletes existing route from the routing table -func (s *svc) Delete(r router.Route) error { - route := &pb.Route{ - Service: r.Service, - Address: r.Address, - Gateway: r.Gateway, - Network: r.Network, - Link: r.Link, - Metric: int64(r.Metric), - } - - if _, err := s.router.Delete(context.Background(), route); err != nil { - return err - } - - return nil -} - -// Update updates route in the routing table -func (s *svc) Update(r router.Route) error { - route := &pb.Route{ - Service: r.Service, - Address: r.Address, - Gateway: r.Gateway, - Network: r.Network, - Link: r.Link, - Metric: int64(r.Metric), - } - - if _, err := s.router.Update(context.Background(), route); err != nil { - return err - } - - return nil -} - -// List returns the list of all routes in the table -func (s *svc) List() ([]router.Route, error) { - resp, err := s.router.List(context.Background(), &pb.ListRequest{}) + // check the remote router + rsp, err := s.router.Status(context.Background(), &pb.Request{}, s.callOpts...) if err != nil { - return nil, err - } - - routes := make([]router.Route, len(resp.Routes)) - for i, route := range resp.Routes { - routes[i] = router.Route{ - Service: route.Service, - Address: route.Address, - Gateway: route.Gateway, - Network: route.Network, - Link: route.Link, - Metric: int(route.Metric), + return router.Status{ + Code: router.Error, + Error: err, } } - return routes, nil + code := router.Running + var serr error + + switch rsp.Status.Code { + case "running": + code = router.Running + case "advertising": + code = router.Advertising + case "stopped": + code = router.Stopped + case "error": + code = router.Error + } + + if len(rsp.Status.Error) > 0 { + serr = errors.New(rsp.Status.Error) + } + + return router.Status{ + Code: code, + Error: serr, + } +} + +// Remote router cannot be stopped +func (s *svc) Stop() error { + s.Lock() + defer s.Unlock() + + select { + case <-s.exit: + return nil + default: + close(s.exit) + } + + return nil } // Lookup looks up routes in the routing table and returns them @@ -398,7 +275,7 @@ func (s *svc) Lookup(q router.Query) ([]router.Route, error) { Gateway: q.Options().Gateway, Network: q.Options().Network, }, - }) + }, s.callOpts...) // errored out if err != nil { @@ -422,69 +299,15 @@ func (s *svc) Lookup(q router.Query) ([]router.Route, error) { // Watch returns a watcher which allows to track updates to the routing table func (s *svc) Watch(opts ...router.WatchOption) (router.Watcher, error) { - wopts := router.WatchOptions{ - Service: "*", + rsp, err := s.router.Watch(context.Background(), &pb.WatchRequest{}, s.callOpts...) + if err != nil { + return nil, err } - + var options router.WatchOptions for _, o := range opts { - o(&wopts) + o(&options) } - - w := &svcWatcher{ - opts: wopts, - resChan: make(chan *router.Event, 10), - done: make(chan struct{}), - } - - s.Lock() - s.watchers[uuid.New().String()] = w - s.Unlock() - - // when the router stops, stop the watcher and exit - s.wg.Add(1) - go func() { - defer s.wg.Done() - <-s.exit - w.Stop() - }() - - return w, nil -} - -// Status returns router status -func (s *svc) Status() router.Status { - s.RLock() - defer s.RUnlock() - - // make a copy of the status - status := s.status - - return status -} - -// Stop stops the router -func (s *svc) Stop() error { - s.Lock() - // only close the channel if the router is running and/or advertising - if s.status.Code == router.Running || s.status.Code == router.Advertising { - // notify all goroutines to finish - close(s.exit) - - // drain the advertise channel only if advertising - if s.status.Code == router.Advertising { - for range s.advertChan { - } - } - - // mark the router as Stopped and set its Error to nil - s.status = router.Status{Code: router.Stopped, Error: nil} - } - s.Unlock() - - // wait for all goroutines to finish - s.wg.Wait() - - return nil + return newWatcher(rsp, options) } // Returns the router implementation diff --git a/network/router/service/table.go b/network/router/service/table.go new file mode 100644 index 00000000..2843a8f6 --- /dev/null +++ b/network/router/service/table.go @@ -0,0 +1,121 @@ +package service + +import ( + "context" + + "github.com/micro/go-micro/client" + "github.com/micro/go-micro/network/router" + pb "github.com/micro/go-micro/network/router/proto" +) + +type table struct { + table pb.TableService + callOpts []client.CallOption +} + +// Create new route in the routing table +func (t *table) Create(r router.Route) error { + route := &pb.Route{ + Service: r.Service, + Address: r.Address, + Gateway: r.Gateway, + Network: r.Network, + Link: r.Link, + Metric: int64(r.Metric), + } + + if _, err := t.table.Create(context.Background(), route, t.callOpts...); err != nil { + return err + } + + return nil +} + +// Delete deletes existing route from the routing table +func (t *table) Delete(r router.Route) error { + route := &pb.Route{ + Service: r.Service, + Address: r.Address, + Gateway: r.Gateway, + Network: r.Network, + Link: r.Link, + Metric: int64(r.Metric), + } + + if _, err := t.table.Delete(context.Background(), route, t.callOpts...); err != nil { + return err + } + + return nil +} + +// Update updates route in the routing table +func (t *table) Update(r router.Route) error { + route := &pb.Route{ + Service: r.Service, + Address: r.Address, + Gateway: r.Gateway, + Network: r.Network, + Link: r.Link, + Metric: int64(r.Metric), + } + + if _, err := t.table.Update(context.Background(), route, t.callOpts...); err != nil { + return err + } + + return nil +} + +// List returns the list of all routes in the table +func (t *table) List() ([]router.Route, error) { + resp, err := t.table.List(context.Background(), &pb.Request{}, t.callOpts...) + if err != nil { + return nil, err + } + + routes := make([]router.Route, len(resp.Routes)) + for i, route := range resp.Routes { + routes[i] = router.Route{ + Service: route.Service, + Address: route.Address, + Gateway: route.Gateway, + Network: route.Network, + Link: route.Link, + Metric: int(route.Metric), + } + } + + return routes, nil +} + +// Lookup looks up routes in the routing table and returns them +func (t *table) Query(q router.Query) ([]router.Route, error) { + // call the router + resp, err := t.table.Query(context.Background(), &pb.QueryRequest{ + Query: &pb.Query{ + Service: q.Options().Service, + Gateway: q.Options().Gateway, + Network: q.Options().Network, + }, + }, t.callOpts...) + + // errored out + if err != nil { + return nil, err + } + + routes := make([]router.Route, len(resp.Routes)) + for i, route := range resp.Routes { + routes[i] = router.Route{ + Service: route.Service, + Address: route.Address, + Gateway: route.Gateway, + Network: route.Network, + Link: route.Link, + Metric: int(route.Metric), + } + } + + return routes, nil +} diff --git a/network/router/service/watcher.go b/network/router/service/watcher.go index 9ed37dab..53bb7648 100644 --- a/network/router/service/watcher.go +++ b/network/router/service/watcher.go @@ -1,20 +1,88 @@ package service import ( + "io" "sync" + "time" "github.com/micro/go-micro/network/router" + pb "github.com/micro/go-micro/network/router/proto" ) -type svcWatcher struct { +type watcher struct { sync.RWMutex opts router.WatchOptions resChan chan *router.Event done chan struct{} } +func newWatcher(rsp pb.Router_WatchService, opts router.WatchOptions) (*watcher, error) { + w := &watcher{ + opts: opts, + resChan: make(chan *router.Event), + done: make(chan struct{}), + } + + go func() { + for { + select { + case <-w.done: + return + default: + if err := w.watch(rsp); err != nil { + w.Stop() + return + } + } + } + }() + + return w, nil +} + +// watchRouter watches router and send events to all registered watchers +func (w *watcher) watch(stream pb.Router_WatchService) error { + defer stream.Close() + + var watchErr error + + for { + resp, err := stream.Recv() + if err != nil { + if err != io.EOF { + watchErr = err + } + break + } + + route := router.Route{ + Service: resp.Route.Service, + Address: resp.Route.Address, + Gateway: resp.Route.Gateway, + Network: resp.Route.Network, + Link: resp.Route.Link, + Metric: int(resp.Route.Metric), + } + + event := &router.Event{ + Type: router.EventType(resp.Type), + Timestamp: time.Unix(0, resp.Timestamp), + Route: route, + } + + for { + select { + case w.resChan <- event: + case <-w.done: + } + } + } + + return watchErr +} + // Next is a blocking call that returns watch result -func (w *svcWatcher) Next() (*router.Event, error) { +func (w *watcher) Next() (*router.Event, error) { for { select { case res := <-w.resChan: @@ -31,12 +99,12 @@ func (w *svcWatcher) Next() (*router.Event, error) { } // Chan returns event channel -func (w *svcWatcher) Chan() (<-chan *router.Event, error) { +func (w *watcher) Chan() (<-chan *router.Event, error) { return w.resChan, nil } // Stop stops watcher -func (w *svcWatcher) Stop() { +func (w *watcher) Stop() { w.Lock() defer w.Unlock() diff --git a/network/router/table.go b/network/router/table.go index 931dcdca..905944b7 100644 --- a/network/router/table.go +++ b/network/router/table.go @@ -128,7 +128,7 @@ func findRoutes(routes map[uint64]Route, network, router string) []Route { } // Lookup queries routing table and returns all routes that match the lookup query -func (t *table) Lookup(q Query) ([]Route, error) { +func (t *table) Query(q Query) ([]Route, error) { t.RLock() defer t.RUnlock() diff --git a/network/router/table_test.go b/network/router/table_test.go index dc35a5f1..16c73f2f 100644 --- a/network/router/table_test.go +++ b/network/router/table_test.go @@ -103,7 +103,7 @@ func TestList(t *testing.T) { } } -func TestLookup(t *testing.T) { +func TestQuery(t *testing.T) { table, route := testSetup() svc := []string{"svc1", "svc2", "svc3"} @@ -122,7 +122,7 @@ func TestLookup(t *testing.T) { // return all routes query := NewQuery() - routes, err := table.Lookup(query) + routes, err := table.Query(query) if err != nil { t.Errorf("error looking up routes: %s", err) } @@ -130,7 +130,7 @@ func TestLookup(t *testing.T) { // query particular net query = NewQuery(QueryNetwork("net1")) - routes, err = table.Lookup(query) + routes, err = table.Query(query) if err != nil { t.Errorf("error looking up routes: %s", err) } @@ -143,7 +143,7 @@ func TestLookup(t *testing.T) { gateway := "gw1" query = NewQuery(QueryGateway(gateway)) - routes, err = table.Lookup(query) + routes, err = table.Query(query) if err != nil { t.Errorf("error looking up routes: %s", err) } @@ -163,7 +163,7 @@ func TestLookup(t *testing.T) { QueryNetwork(network), ) - routes, err = table.Lookup(query) + routes, err = table.Query(query) if err != nil { t.Errorf("error looking up routes: %s", err) } @@ -183,7 +183,7 @@ func TestLookup(t *testing.T) { // bullshit route query query = NewQuery(QueryService("foobar")) - routes, err = table.Lookup(query) + routes, err = table.Query(query) if err != ErrRouteNotFound { t.Errorf("error looking up routes. Expected: %s, found: %s", ErrRouteNotFound, err) } From 0b2c8ee523f0ed663b595b564311298fa562fdd1 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 30 Jul 2019 16:47:18 +0100 Subject: [PATCH 236/287] Add top level data package comment --- data/data.go | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 data/data.go diff --git a/data/data.go b/data/data.go new file mode 100644 index 00000000..eb6157d2 --- /dev/null +++ b/data/data.go @@ -0,0 +1,2 @@ +// Package data is an interface for data access +package data From 89fc142e476f38759640d3ffb5c5b403e2f15fd6 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 31 Jul 2019 13:16:57 +0100 Subject: [PATCH 237/287] Update to use mdns 0.2.0 --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index a55d2f99..85f9b141 100644 --- a/go.mod +++ b/go.mod @@ -49,7 +49,7 @@ require ( github.com/mattn/go-colorable v0.1.2 // indirect github.com/mattn/go-runewidth v0.0.4 // indirect github.com/micro/cli v0.2.0 - github.com/micro/mdns v0.1.1-0.20190729112526-ef68c9635478 + github.com/micro/mdns v0.2.0 github.com/miekg/dns v1.1.15 // indirect github.com/mitchellh/gox v1.0.1 // indirect github.com/mitchellh/hashstructure v1.0.0 diff --git a/go.sum b/go.sum index e98bd464..2d9905ed 100644 --- a/go.sum +++ b/go.sum @@ -217,6 +217,8 @@ github.com/micro/mdns v0.1.0 h1:fuLybUsfynbigJmCot/54i+gwe0hpc/vtCMvWt2WfDI= github.com/micro/mdns v0.1.0/go.mod h1:KJ0dW7KmicXU2BV++qkLlmHYcVv7/hHnbtguSWt9Aoc= github.com/micro/mdns v0.1.1-0.20190729112526-ef68c9635478 h1:L6jnZZ763dMLlvst8P0dWHa1WbUu7ppUY1q3AY2hhIU= github.com/micro/mdns v0.1.1-0.20190729112526-ef68c9635478/go.mod h1:KJ0dW7KmicXU2BV++qkLlmHYcVv7/hHnbtguSWt9Aoc= +github.com/micro/mdns v0.2.0 h1:/+/n2PSiJURrXsBIGtfCz0hex/XYKqVsn51GAGdFrOE= +github.com/micro/mdns v0.2.0/go.mod h1:KJ0dW7KmicXU2BV++qkLlmHYcVv7/hHnbtguSWt9Aoc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.3 h1:1g0r1IvskvgL8rR+AcHzUA+oFmGcQlaIm4IqakufeMM= github.com/miekg/dns v1.1.3/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= From fca89e06efc7489d9cea74d60f28a78945304e08 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 31 Jul 2019 15:22:57 +0100 Subject: [PATCH 238/287] Some network inspiration --- network/default.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ network/network.go | 18 ++++++++++++++++++ network/options.go | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 network/default.go create mode 100644 network/network.go create mode 100644 network/options.go diff --git a/network/default.go b/network/default.go new file mode 100644 index 00000000..d384a5f4 --- /dev/null +++ b/network/default.go @@ -0,0 +1,45 @@ +package network + +import ( + "github.com/micro/go-micro/client" + "github.com/micro/go-micro/server" +) + +type network struct { + name string + options Options +} + +func (n *network) Name() string { + return n.name +} + +func (n *network) Connect() error { + return n.options.Server.Start() +} + +func (n *network) Close() error { + return n.options.Server.Stop() +} + +// NewNetwork returns a new network node +func NewNetwork(opts ...Option) Network { + options := Options{ + Name: DefaultName, + Client: client.DefaultClient, + Server: server.DefaultServer, + } + + for _, o := range opts { + o(&options) + } + + // set the server name + options.Server.Init( + server.Name(options.Name), + ) + + return &network{ + options: options, + } +} diff --git a/network/network.go b/network/network.go new file mode 100644 index 00000000..bf1a069b --- /dev/null +++ b/network/network.go @@ -0,0 +1,18 @@ +// Package network is for building peer to peer networks +package network + +// Network is a +type Network interface { + // Name of the network + Name() string + // Connect starts the network node + Connect() error + // Close shutsdown the network node + Close() error +} + +var ( + DefaultName = "go.micro.network" + + DefaultNetwork = NewNetwork() +) diff --git a/network/options.go b/network/options.go new file mode 100644 index 00000000..9dcbb1ed --- /dev/null +++ b/network/options.go @@ -0,0 +1,35 @@ +package network + +import ( + "github.com/micro/go-micro/client" + "github.com/micro/go-micro/server" +) + +type Option func(*Options) + +type Options struct { + Name string + Client client.Client + Server server.Server +} + +// The network name +func Name(n string) Option { + return func(o *Options) { + o.Name = n + } +} + +// The network client +func Client(c client.Client) Option { + return func(o *Options) { + o.Client = c + } +} + +// The network server +func Server(s server.Server) Option { + return func(o *Options) { + o.Server = s + } +} From 3e90d32f29b20ec5609e2716575505eda3a8218a Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 31 Jul 2019 15:30:51 +0100 Subject: [PATCH 239/287] Add proxy/router --- network/default.go | 5 +++++ network/options.go | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/network/default.go b/network/default.go index d384a5f4..13876e57 100644 --- a/network/default.go +++ b/network/default.go @@ -2,6 +2,8 @@ package network import ( "github.com/micro/go-micro/client" + "github.com/micro/go-micro/network/proxy/mucp" + "github.com/micro/go-micro/network/router" "github.com/micro/go-micro/server" ) @@ -28,6 +30,8 @@ func NewNetwork(opts ...Option) Network { Name: DefaultName, Client: client.DefaultClient, Server: server.DefaultServer, + Proxy: mucp.NewProxy(), + Router: router.DefaultRouter, } for _, o := range opts { @@ -37,6 +41,7 @@ func NewNetwork(opts ...Option) Network { // set the server name options.Server.Init( server.Name(options.Name), + server.WithRouter(options.Proxy), ) return &network{ diff --git a/network/options.go b/network/options.go index 9dcbb1ed..2a211ea5 100644 --- a/network/options.go +++ b/network/options.go @@ -2,6 +2,8 @@ package network import ( "github.com/micro/go-micro/client" + "github.com/micro/go-micro/network/proxy" + "github.com/micro/go-micro/network/router" "github.com/micro/go-micro/server" ) @@ -11,6 +13,8 @@ type Options struct { Name string Client client.Client Server server.Server + Proxy proxy.Proxy + Router router.Router } // The network name @@ -33,3 +37,19 @@ func Server(s server.Server) Option { o.Server = s } } + +// The proxy to use +func Proxy(p proxy.Proxy) Option { + return func(o *Options) { + o.Proxy = p + } + +} + +// The router to use +func Router(r router.Router) Option { + return func(o *Options) { + o.Router = r + } + +} From 2d09e74b0e0010f96e88423765f18a33b765c41f Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 31 Jul 2019 15:35:51 +0100 Subject: [PATCH 240/287] add address/advertise --- network/default.go | 13 ++++++++----- network/network.go | 4 ++-- network/options.go | 29 ++++++++++++++++++++++++----- 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/network/default.go b/network/default.go index 13876e57..ff1d6c4b 100644 --- a/network/default.go +++ b/network/default.go @@ -27,11 +27,12 @@ func (n *network) Close() error { // NewNetwork returns a new network node func NewNetwork(opts ...Option) Network { options := Options{ - Name: DefaultName, - Client: client.DefaultClient, - Server: server.DefaultServer, - Proxy: mucp.NewProxy(), - Router: router.DefaultRouter, + Name: DefaultName, + Address: DefaultAddress, + Client: client.DefaultClient, + Server: server.DefaultServer, + Proxy: mucp.NewProxy(), + Router: router.DefaultRouter, } for _, o := range opts { @@ -41,6 +42,8 @@ func NewNetwork(opts ...Option) Network { // set the server name options.Server.Init( server.Name(options.Name), + server.Address(options.Address), + server.Advertise(options.Advertise), server.WithRouter(options.Proxy), ) diff --git a/network/network.go b/network/network.go index bf1a069b..a4e21ca9 100644 --- a/network/network.go +++ b/network/network.go @@ -12,7 +12,7 @@ type Network interface { } var ( - DefaultName = "go.micro.network" - + DefaultName = "go.micro.network" + DefaultAddress = ":0" DefaultNetwork = NewNetwork() ) diff --git a/network/options.go b/network/options.go index 2a211ea5..fbf41884 100644 --- a/network/options.go +++ b/network/options.go @@ -10,11 +10,16 @@ import ( type Option func(*Options) type Options struct { - Name string - Client client.Client - Server server.Server - Proxy proxy.Proxy - Router router.Router + // Name of the network + Name string + // Address of the node + Address string + // Advertise a different address to the network + Advertise string + Client client.Client + Server server.Server + Proxy proxy.Proxy + Router router.Router } // The network name @@ -24,6 +29,20 @@ func Name(n string) Option { } } +// The network address +func Address(a string) Option { + return func(o *Options) { + o.Address = a + } +} + +// The network advertise address +func Advertise(a string) Option { + return func(o *Options) { + o.Advertise = a + } +} + // The network client func Client(c client.Client) Option { return func(o *Options) { From 318367cd71e187a83de19c1ec98a05ee488eb846 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 31 Jul 2019 15:37:12 +0100 Subject: [PATCH 241/287] move NewNetwork --- network/default.go | 4 ++-- network/network.go | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/network/default.go b/network/default.go index ff1d6c4b..42837536 100644 --- a/network/default.go +++ b/network/default.go @@ -24,8 +24,8 @@ func (n *network) Close() error { return n.options.Server.Stop() } -// NewNetwork returns a new network node -func NewNetwork(opts ...Option) Network { +// newNetwork returns a new network node +func newNetwork(opts ...Option) Network { options := Options{ Name: DefaultName, Address: DefaultAddress, diff --git a/network/network.go b/network/network.go index a4e21ca9..f7251d60 100644 --- a/network/network.go +++ b/network/network.go @@ -16,3 +16,8 @@ var ( DefaultAddress = ":0" DefaultNetwork = NewNetwork() ) + +// NewNetwork returns a new network interface +func NewNetwork(opts ...Option) Network { + return newNetwork(opts...) +} From b1c49a0ddc0da479e84e9cab41254db5f8115908 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 31 Jul 2019 16:10:04 +0100 Subject: [PATCH 242/287] Add router handler --- network/router/handler/router.go | 180 +++++++++++++++++++++++++++++++ network/router/handler/table.go | 114 ++++++++++++++++++++ 2 files changed, 294 insertions(+) create mode 100644 network/router/handler/router.go create mode 100644 network/router/handler/table.go diff --git a/network/router/handler/router.go b/network/router/handler/router.go new file mode 100644 index 00000000..ab82ed09 --- /dev/null +++ b/network/router/handler/router.go @@ -0,0 +1,180 @@ +package handler + +import ( + "context" + "io" + "time" + + "github.com/micro/go-micro/errors" + "github.com/micro/go-micro/network/router" + pb "github.com/micro/go-micro/network/router/proto" +) + +// Router implements router handler +type Router struct { + Router router.Router +} + +// Lookup looks up routes in the routing table and returns them +func (r *Router) Lookup(ctx context.Context, req *pb.LookupRequest, resp *pb.LookupResponse) error { + query := router.NewQuery( + router.QueryService(req.Query.Service), + ) + + routes, err := r.Router.Lookup(query) + if err != nil { + return errors.InternalServerError("go.micro.router", "failed to lookup routes: %v", err) + } + + var respRoutes []*pb.Route + for _, route := range routes { + respRoute := &pb.Route{ + Service: route.Service, + Address: route.Address, + Gateway: route.Gateway, + Network: route.Network, + Link: route.Link, + Metric: int64(route.Metric), + } + respRoutes = append(respRoutes, respRoute) + } + + resp.Routes = respRoutes + + return nil +} + +func (r *Router) Advertise(ctx context.Context, req *pb.AdvertiseRequest, stream pb.Router_AdvertiseStream) error { + advertChan, err := r.Router.Advertise() + if err != nil { + return errors.InternalServerError("go.micro.router", "failed to get adverts: %v", err) + } + + for advert := range advertChan { + var events []*pb.Event + for _, event := range advert.Events { + route := &pb.Route{ + Service: event.Route.Service, + Address: event.Route.Address, + Gateway: event.Route.Gateway, + Network: event.Route.Network, + Link: event.Route.Link, + Metric: int64(event.Route.Metric), + } + e := &pb.Event{ + Type: pb.EventType(event.Type), + Timestamp: event.Timestamp.UnixNano(), + Route: route, + } + events = append(events, e) + } + + advert := &pb.Advert{ + Id: advert.Id, + Type: pb.AdvertType(advert.Type), + Timestamp: advert.Timestamp.UnixNano(), + Events: events, + } + + // send the advert + err := stream.Send(advert) + if err == io.EOF { + return nil + } + if err != nil { + return errors.InternalServerError("go.micro.router", "error sending message %v", err) + } + } + + return nil +} + +func (r *Router) Process(ctx context.Context, req *pb.Advert, rsp *pb.ProcessResponse) error { + events := make([]*router.Event, len(req.Events)) + for i, event := range req.Events { + route := router.Route{ + Service: event.Route.Service, + Address: event.Route.Address, + Gateway: event.Route.Gateway, + Network: event.Route.Network, + Link: event.Route.Link, + Metric: int(event.Route.Metric), + } + + events[i] = &router.Event{ + Type: router.EventType(event.Type), + Timestamp: time.Unix(0, event.Timestamp), + Route: route, + } + } + + advert := &router.Advert{ + Id: req.Id, + Type: router.AdvertType(req.Type), + Timestamp: time.Unix(0, req.Timestamp), + TTL: time.Duration(req.Ttl), + Events: events, + } + + if err := r.Router.Process(advert); err != nil { + return errors.InternalServerError("go.micro.router", "error publishing advert: %v", err) + } + + return nil +} + +func (r *Router) Status(ctx context.Context, req *pb.Request, rsp *pb.StatusResponse) error { + status := r.Router.Status() + + rsp.Status = &pb.Status{ + Code: status.Code.String(), + } + + if status.Error != nil { + rsp.Status.Error = status.Error.Error() + } + + return nil +} + +// Watch streans routing table events +func (r *Router) Watch(ctx context.Context, req *pb.WatchRequest, stream pb.Router_WatchStream) error { + watcher, err := r.Router.Watch() + if err != nil { + return errors.InternalServerError("go.micro.router", "failed creating event watcher: %v", err) + } + + defer stream.Close() + + for { + event, err := watcher.Next() + if err == router.ErrWatcherStopped { + break + } + + if err != nil { + return errors.InternalServerError("go.micro.router", "error watching events: %v", err) + } + + route := &pb.Route{ + Service: event.Route.Service, + Address: event.Route.Address, + Gateway: event.Route.Gateway, + Network: event.Route.Network, + Link: event.Route.Link, + Metric: int64(event.Route.Metric), + } + + tableEvent := &pb.Event{ + Type: pb.EventType(event.Type), + Timestamp: event.Timestamp.UnixNano(), + Route: route, + } + + if err := stream.Send(tableEvent); err != nil { + return err + } + } + + return nil +} diff --git a/network/router/handler/table.go b/network/router/handler/table.go new file mode 100644 index 00000000..a1435511 --- /dev/null +++ b/network/router/handler/table.go @@ -0,0 +1,114 @@ +package handler + +import ( + "context" + + "github.com/micro/go-micro/errors" + "github.com/micro/go-micro/network/router" + pb "github.com/micro/go-micro/network/router/proto" +) + +type Table struct { + Router router.Router +} + +func (t *Table) Create(ctx context.Context, route *pb.Route, resp *pb.CreateResponse) error { + err := t.Router.Table().Create(router.Route{ + Service: route.Service, + Address: route.Address, + Gateway: route.Gateway, + Network: route.Network, + Link: route.Link, + Metric: int(route.Metric), + }) + if err != nil { + return errors.InternalServerError("go.micro.router", "failed to create route: %s", err) + } + + return nil +} + +func (t *Table) Update(ctx context.Context, route *pb.Route, resp *pb.UpdateResponse) error { + err := t.Router.Table().Update(router.Route{ + Service: route.Service, + Address: route.Address, + Gateway: route.Gateway, + Network: route.Network, + Link: route.Link, + Metric: int(route.Metric), + }) + if err != nil { + return errors.InternalServerError("go.micro.router", "failed to update route: %s", err) + } + + return nil +} + +func (t *Table) Delete(ctx context.Context, route *pb.Route, resp *pb.DeleteResponse) error { + err := t.Router.Table().Delete(router.Route{ + Service: route.Service, + Address: route.Address, + Gateway: route.Gateway, + Network: route.Network, + Link: route.Link, + Metric: int(route.Metric), + }) + if err != nil { + return errors.InternalServerError("go.micro.router", "failed to delete route: %s", err) + } + + return nil +} + +// List returns all routes in the routing table +func (t *Table) List(ctx context.Context, req *pb.Request, resp *pb.ListResponse) error { + routes, err := t.Router.Table().List() + if err != nil { + return errors.InternalServerError("go.micro.router", "failed to list routes: %s", err) + } + + var respRoutes []*pb.Route + for _, route := range routes { + respRoute := &pb.Route{ + Service: route.Service, + Address: route.Address, + Gateway: route.Gateway, + Network: route.Network, + Link: route.Link, + Metric: int64(route.Metric), + } + respRoutes = append(respRoutes, respRoute) + } + + resp.Routes = respRoutes + + return nil +} + +func (t *Table) Query(ctx context.Context, req *pb.QueryRequest, resp *pb.QueryResponse) error { + query := router.NewQuery( + router.QueryService(req.Query.Service), + ) + + routes, err := t.Router.Table().Query(query) + if err != nil { + return errors.InternalServerError("go.micro.router", "failed to lookup routes: %s", err) + } + + var respRoutes []*pb.Route + for _, route := range routes { + respRoute := &pb.Route{ + Service: route.Service, + Address: route.Address, + Gateway: route.Gateway, + Network: route.Network, + Link: route.Link, + Metric: int64(route.Metric), + } + respRoutes = append(respRoutes, respRoute) + } + + resp.Routes = respRoutes + + return nil +} From 7884e889f4c080333a4b6abb58b9a177e84c5fd5 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 31 Jul 2019 16:36:53 +0100 Subject: [PATCH 243/287] Don't publish the process rpc call and embed the router handler in the network --- network/default.go | 87 ++++++++++++++++++++++++++++++-- network/router/handler/router.go | 2 +- server/server.go | 5 ++ 3 files changed, 90 insertions(+), 4 deletions(-) diff --git a/network/default.go b/network/default.go index 42837536..838c35f5 100644 --- a/network/default.go +++ b/network/default.go @@ -1,19 +1,40 @@ package network import ( + "context" + "sync" + "github.com/micro/go-micro/client" "github.com/micro/go-micro/network/proxy/mucp" "github.com/micro/go-micro/network/router" + "github.com/micro/go-micro/network/router/handler" + pb "github.com/micro/go-micro/network/router/proto" "github.com/micro/go-micro/server" ) type network struct { - name string options Options + handler server.Router + router pb.RouterService + + sync.RWMutex + connected bool + exit chan bool } func (n *network) Name() string { - return n.name + return n.options.Name +} + +// Implements the server.ServeRequest method. +func (n *network) ServeRequest(ctx context.Context, req server.Request, rsp server.Response) error { + // If we're being called then execute our handlers + if req.Service() == n.options.Name { + return n.handler.ServeRequest(ctx, req, rsp) + } + + // execute the proxy + return n.options.Proxy.ServeRequest(ctx, req, rsp) } func (n *network) Connect() error { @@ -21,9 +42,60 @@ func (n *network) Connect() error { } func (n *network) Close() error { + n.Lock() + defer n.Unlock() + + // check if we're connected + if !n.connected { + return nil + } + + advertChan, err := n.options.Router.Advertise() + if err != nil { + return err + } + + go n.run(advertChan) + + // stop the server return n.options.Server.Stop() } +func (n *network) run(advertChan <-chan *router.Advert) { + for { + select { + // process local adverts and randomly fire them at other nodes + case a := <-advertChan: + // create a proto advert + var events []*pb.Event + for _, event := range a.Events { + route := &pb.Route{ + Service: event.Route.Service, + Address: event.Route.Address, + Gateway: event.Route.Gateway, + Network: event.Route.Network, + Link: event.Route.Link, + Metric: int64(event.Route.Metric), + } + e := &pb.Event{ + Type: pb.EventType(event.Type), + Timestamp: event.Timestamp.UnixNano(), + Route: route, + } + events = append(events, e) + } + + // fire the advert to a random network node + n.router.Process(context.Background(), &pb.Advert{ + Id: n.options.Router.Options().Id, + Type: pb.AdvertType(a.Type), + Timestamp: a.Timestamp.UnixNano(), + Events: events, + }) + } + } +} + // newNetwork returns a new network node func newNetwork(opts ...Option) Network { options := Options{ @@ -39,15 +111,24 @@ func newNetwork(opts ...Option) Network { o(&options) } + // get the default server handler + sr := server.DefaultRouter + // create new router handler + hd := sr.NewHandler(&handler.Router{options.Router}) + // register the router handler + sr.Handle(hd) + // set the server name options.Server.Init( server.Name(options.Name), server.Address(options.Address), server.Advertise(options.Advertise), - server.WithRouter(options.Proxy), + server.WithRouter(sr), ) return &network{ options: options, + handler: sr, + router: pb.NewRouterService(options.Name, options.Client), } } diff --git a/network/router/handler/router.go b/network/router/handler/router.go index ab82ed09..26344c64 100644 --- a/network/router/handler/router.go +++ b/network/router/handler/router.go @@ -12,7 +12,7 @@ import ( // Router implements router handler type Router struct { - Router router.Router + Router router.Router } // Lookup looks up routes in the routing table and returns them diff --git a/server/server.go b/server/server.go index 2e742f95..b13048a3 100644 --- a/server/server.go +++ b/server/server.go @@ -142,6 +142,11 @@ func NewServer(opt ...Option) Server { return newRpcServer(opt...) } +// NewRouter returns a new router +func NewRouter() *router { + return newRpcRouter() +} + // NewSubscriber creates a new subscriber interface with the given topic // and handler using the default server func NewSubscriber(topic string, h interface{}, opts ...SubscriberOption) Subscriber { From 873bfcc73ce9de46604997808150f4836457548a Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 31 Jul 2019 16:46:55 +0100 Subject: [PATCH 244/287] Process/Stop router --- network/default.go | 107 ++++++++++++++++++++++++++++----------------- 1 file changed, 67 insertions(+), 40 deletions(-) diff --git a/network/default.go b/network/default.go index 838c35f5..415824a9 100644 --- a/network/default.go +++ b/network/default.go @@ -22,46 +22,9 @@ type network struct { exit chan bool } -func (n *network) Name() string { - return n.options.Name -} - -// Implements the server.ServeRequest method. -func (n *network) ServeRequest(ctx context.Context, req server.Request, rsp server.Response) error { - // If we're being called then execute our handlers - if req.Service() == n.options.Name { - return n.handler.ServeRequest(ctx, req, rsp) - } - - // execute the proxy - return n.options.Proxy.ServeRequest(ctx, req, rsp) -} - -func (n *network) Connect() error { - return n.options.Server.Start() -} - -func (n *network) Close() error { - n.Lock() - defer n.Unlock() - - // check if we're connected - if !n.connected { - return nil - } - - advertChan, err := n.options.Router.Advertise() - if err != nil { - return err - } - - go n.run(advertChan) - - // stop the server - return n.options.Server.Stop() -} - -func (n *network) run(advertChan <-chan *router.Advert) { +// process processes router advertisements and randomly sends the advert +// to a node in the network. Over a period of time the routers should converge. +func (n *network) process(advertChan <-chan *router.Advert) { for { select { // process local adverts and randomly fire them at other nodes @@ -95,6 +58,70 @@ func (n *network) run(advertChan <-chan *router.Advert) { } } } +func (n *network) Name() string { + return n.options.Name +} + +// Implements the server.ServeRequest method. +func (n *network) ServeRequest(ctx context.Context, req server.Request, rsp server.Response) error { + // If we're being called then execute our handlers + if req.Service() == n.options.Name { + return n.handler.ServeRequest(ctx, req, rsp) + } + + // execute the proxy + return n.options.Proxy.ServeRequest(ctx, req, rsp) +} + +func (n *network) Connect() error { + n.Lock() + defer n.Unlock() + + // check if we're connected + if !n.connected { + return nil + } + + // start advertising + advertChan, err := n.options.Router.Advertise() + if err != nil { + return err + } + + // process the adverts + go n.process(advertChan) + + // start the server + if err := n.options.Server.Start(); err != nil { + return err + } + + // set connected to true + n.connected = true + + return nil +} + +func (n *network) Close() error { + n.Lock() + defer n.Unlock() + + // check if we're connected + if !n.connected { + return nil + } + + // set connected to false + n.connected = false + + // stop the router + if err := n.options.Router.Stop(); err != nil { + return err + } + + // stop the server + return n.options.Server.Stop() +} // newNetwork returns a new network node func newNetwork(opts ...Option) Network { From 679c5f0ccd091dd8d0b4727145519ddd2f668813 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 31 Jul 2019 16:49:48 +0100 Subject: [PATCH 245/287] Fix some connection bugs --- network/default.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/network/default.go b/network/default.go index 415824a9..78553653 100644 --- a/network/default.go +++ b/network/default.go @@ -55,6 +55,8 @@ func (n *network) process(advertChan <-chan *router.Advert) { Timestamp: a.Timestamp.UnixNano(), Events: events, }) + case <-n.exit: + return } } } @@ -78,10 +80,12 @@ func (n *network) Connect() error { defer n.Unlock() // check if we're connected - if !n.connected { + if n.connected { return nil } + n.exit = make(chan bool) + // start advertising advertChan, err := n.options.Router.Advertise() if err != nil { @@ -111,6 +115,8 @@ func (n *network) Close() error { return nil } + close(n.exit) + // set connected to false n.connected = false From cdf0f14d58551dd0acd2a9f335faf9bfd6a3a873 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 31 Jul 2019 17:19:49 +0100 Subject: [PATCH 246/287] remove this code --- network/default.go | 167 --------------------------------------------- network/network.go | 23 ------- network/options.go | 74 -------------------- 3 files changed, 264 deletions(-) delete mode 100644 network/default.go delete mode 100644 network/network.go delete mode 100644 network/options.go diff --git a/network/default.go b/network/default.go deleted file mode 100644 index 78553653..00000000 --- a/network/default.go +++ /dev/null @@ -1,167 +0,0 @@ -package network - -import ( - "context" - "sync" - - "github.com/micro/go-micro/client" - "github.com/micro/go-micro/network/proxy/mucp" - "github.com/micro/go-micro/network/router" - "github.com/micro/go-micro/network/router/handler" - pb "github.com/micro/go-micro/network/router/proto" - "github.com/micro/go-micro/server" -) - -type network struct { - options Options - handler server.Router - router pb.RouterService - - sync.RWMutex - connected bool - exit chan bool -} - -// process processes router advertisements and randomly sends the advert -// to a node in the network. Over a period of time the routers should converge. -func (n *network) process(advertChan <-chan *router.Advert) { - for { - select { - // process local adverts and randomly fire them at other nodes - case a := <-advertChan: - // create a proto advert - var events []*pb.Event - for _, event := range a.Events { - route := &pb.Route{ - Service: event.Route.Service, - Address: event.Route.Address, - Gateway: event.Route.Gateway, - Network: event.Route.Network, - Link: event.Route.Link, - Metric: int64(event.Route.Metric), - } - e := &pb.Event{ - Type: pb.EventType(event.Type), - Timestamp: event.Timestamp.UnixNano(), - Route: route, - } - events = append(events, e) - } - - // fire the advert to a random network node - n.router.Process(context.Background(), &pb.Advert{ - Id: n.options.Router.Options().Id, - Type: pb.AdvertType(a.Type), - Timestamp: a.Timestamp.UnixNano(), - Events: events, - }) - case <-n.exit: - return - } - } -} -func (n *network) Name() string { - return n.options.Name -} - -// Implements the server.ServeRequest method. -func (n *network) ServeRequest(ctx context.Context, req server.Request, rsp server.Response) error { - // If we're being called then execute our handlers - if req.Service() == n.options.Name { - return n.handler.ServeRequest(ctx, req, rsp) - } - - // execute the proxy - return n.options.Proxy.ServeRequest(ctx, req, rsp) -} - -func (n *network) Connect() error { - n.Lock() - defer n.Unlock() - - // check if we're connected - if n.connected { - return nil - } - - n.exit = make(chan bool) - - // start advertising - advertChan, err := n.options.Router.Advertise() - if err != nil { - return err - } - - // process the adverts - go n.process(advertChan) - - // start the server - if err := n.options.Server.Start(); err != nil { - return err - } - - // set connected to true - n.connected = true - - return nil -} - -func (n *network) Close() error { - n.Lock() - defer n.Unlock() - - // check if we're connected - if !n.connected { - return nil - } - - close(n.exit) - - // set connected to false - n.connected = false - - // stop the router - if err := n.options.Router.Stop(); err != nil { - return err - } - - // stop the server - return n.options.Server.Stop() -} - -// newNetwork returns a new network node -func newNetwork(opts ...Option) Network { - options := Options{ - Name: DefaultName, - Address: DefaultAddress, - Client: client.DefaultClient, - Server: server.DefaultServer, - Proxy: mucp.NewProxy(), - Router: router.DefaultRouter, - } - - for _, o := range opts { - o(&options) - } - - // get the default server handler - sr := server.DefaultRouter - // create new router handler - hd := sr.NewHandler(&handler.Router{options.Router}) - // register the router handler - sr.Handle(hd) - - // set the server name - options.Server.Init( - server.Name(options.Name), - server.Address(options.Address), - server.Advertise(options.Advertise), - server.WithRouter(sr), - ) - - return &network{ - options: options, - handler: sr, - router: pb.NewRouterService(options.Name, options.Client), - } -} diff --git a/network/network.go b/network/network.go deleted file mode 100644 index f7251d60..00000000 --- a/network/network.go +++ /dev/null @@ -1,23 +0,0 @@ -// Package network is for building peer to peer networks -package network - -// Network is a -type Network interface { - // Name of the network - Name() string - // Connect starts the network node - Connect() error - // Close shutsdown the network node - Close() error -} - -var ( - DefaultName = "go.micro.network" - DefaultAddress = ":0" - DefaultNetwork = NewNetwork() -) - -// NewNetwork returns a new network interface -func NewNetwork(opts ...Option) Network { - return newNetwork(opts...) -} diff --git a/network/options.go b/network/options.go deleted file mode 100644 index fbf41884..00000000 --- a/network/options.go +++ /dev/null @@ -1,74 +0,0 @@ -package network - -import ( - "github.com/micro/go-micro/client" - "github.com/micro/go-micro/network/proxy" - "github.com/micro/go-micro/network/router" - "github.com/micro/go-micro/server" -) - -type Option func(*Options) - -type Options struct { - // Name of the network - Name string - // Address of the node - Address string - // Advertise a different address to the network - Advertise string - Client client.Client - Server server.Server - Proxy proxy.Proxy - Router router.Router -} - -// The network name -func Name(n string) Option { - return func(o *Options) { - o.Name = n - } -} - -// The network address -func Address(a string) Option { - return func(o *Options) { - o.Address = a - } -} - -// The network advertise address -func Advertise(a string) Option { - return func(o *Options) { - o.Advertise = a - } -} - -// The network client -func Client(c client.Client) Option { - return func(o *Options) { - o.Client = c - } -} - -// The network server -func Server(s server.Server) Option { - return func(o *Options) { - o.Server = s - } -} - -// The proxy to use -func Proxy(p proxy.Proxy) Option { - return func(o *Options) { - o.Proxy = p - } - -} - -// The router to use -func Router(r router.Router) Option { - return func(o *Options) { - o.Router = r - } - -} From 2720c6f28e43998d3b37a9e0105b4fe9884dab14 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Thu, 1 Aug 2019 13:32:55 +0100 Subject: [PATCH 247/287] Removed trailing white characters --- network/router/proto/router.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network/router/proto/router.proto b/network/router/proto/router.proto index 15ef2cd2..3e18d456 100644 --- a/network/router/proto/router.proto +++ b/network/router/proto/router.proto @@ -11,7 +11,7 @@ service Router { rpc Status(Request) returns (StatusResponse) {}; } -service Table { +service Table { rpc Create(Route) returns (CreateResponse) {}; rpc Delete(Route) returns (DeleteResponse) {}; rpc Update(Route) returns (UpdateResponse) {}; From b806e7bdf50fed87f512df56094f2f7313b1706e Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 1 Aug 2019 23:03:11 +0100 Subject: [PATCH 248/287] Stop a goroutine leak in registy --- registry/cache/rcache.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/registry/cache/rcache.go b/registry/cache/rcache.go index e2e0da35..14bbbfb9 100644 --- a/registry/cache/rcache.go +++ b/registry/cache/rcache.go @@ -325,18 +325,27 @@ func (c *cache) run(service string) { // watch loops the next event and calls update // it returns if there's an error func (c *cache) watch(w registry.Watcher) error { - defer w.Stop() + // used to stop the watch + stop := make(chan bool) // manage this loop go func() { + defer w.Stop() + + select { // wait for exit - <-c.exit - w.Stop() + case <-c.exit: + return + // we've been stopped + case <-stop: + return + } }() for { res, err := w.Next() if err != nil { + close(stop) return err } c.update(res) From d7929ef8f37886169e80b79981b7de944f99e2f3 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 2 Aug 2019 14:44:11 +0100 Subject: [PATCH 249/287] Stop the ticker when exiting --- network/router/default.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/network/router/default.go b/network/router/default.go index 245a7b31..bee3d017 100644 --- a/network/router/default.go +++ b/network/router/default.go @@ -275,6 +275,7 @@ func (r *router) publishAdvert(advType AdvertType, events []*Event) { func (r *router) advertiseTable() error { // create table advertisement ticker ticker := time.NewTicker(AdvertiseTableTick) + defer ticker.Stop() for { select { @@ -324,6 +325,8 @@ type routeAdvert struct { func (r *router) advertiseEvents() error { // ticker to periodically scan event for advertising ticker := time.NewTicker(AdvertiseEventsTick) + defer ticker.Stop() + // advertMap is a map of advert events advertMap := make(map[uint64]*routeAdvert) @@ -426,7 +429,6 @@ func (r *router) advertiseEvents() error { // update event penalty and recorded timestamp advert.lastUpdate = time.Now() advert.penalty += penalty - case <-r.exit: // first wait for the advertiser to finish r.advertWg.Wait() From 6719f8d655a1e4c0fafdbbcb29572c50c9efc909 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 2 Aug 2019 14:59:08 +0100 Subject: [PATCH 250/287] Remove the table watcher when stopped --- network/router/table.go | 12 +++++++++++- network/router/watcher.go | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/network/router/table.go b/network/router/table.go index 905944b7..6b34bb00 100644 --- a/network/router/table.go +++ b/network/router/table.go @@ -160,13 +160,23 @@ func (t *table) Watch(opts ...WatchOption) (Watcher, error) { } w := &tableWatcher{ + id: uuid.New().String(), opts: wopts, resChan: make(chan *Event, 10), done: make(chan struct{}), } + // when the watcher is stopped delete it + go func() { + <-w.done + t.Lock() + delete(t.watchers, w.id) + t.Unlock() + }() + + // save the watcher t.Lock() - t.watchers[uuid.New().String()] = w + t.watchers[w.id] = w t.Unlock() return w, nil diff --git a/network/router/watcher.go b/network/router/watcher.go index 1530e72c..f2c8beac 100644 --- a/network/router/watcher.go +++ b/network/router/watcher.go @@ -72,6 +72,7 @@ func WatchService(s string) WatchOption { type tableWatcher struct { sync.RWMutex + id string opts WatchOptions resChan chan *Event done chan struct{} From d250ac736fa5b05797640896dd66c0321e811cb2 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 2 Aug 2019 15:17:48 +0100 Subject: [PATCH 251/287] In the event watchRegistry or watchTable exit then close the go routines --- network/router/default.go | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/network/router/default.go b/network/router/default.go index bee3d017..498539a1 100644 --- a/network/router/default.go +++ b/network/router/default.go @@ -177,10 +177,24 @@ func (r *router) watchRegistry(w registry.Watcher) error { // wait in the background for the router to stop // when the router stops, stop the watcher and exit r.wg.Add(1) + + exit := make(chan bool) + + defer func() { + // close the exit channel when the go routine finishes + close(exit) + r.wg.Done() + }() + go func() { - defer r.wg.Done() - <-r.exit - w.Stop() + defer w.Stop() + + select { + case <-r.exit: + return + case <-exit: + return + } }() var watchErr error @@ -208,10 +222,23 @@ func (r *router) watchTable(w Watcher) error { // wait in the background for the router to stop // when the router stops, stop the watcher and exit r.wg.Add(1) + exit := make(chan bool) + + defer func() { + // close the exit channel when the go routine finishes + close(exit) + r.wg.Done() + }() + go func() { - defer r.wg.Done() - <-r.exit - w.Stop() + defer w.Stop() + + select { + case <-r.exit: + return + case <-exit: + return + } }() var watchErr error From e1709026e46e616a0e6bad8aecc2cf703cedb7d2 Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Sat, 3 Aug 2019 15:39:44 +0300 Subject: [PATCH 252/287] transport memory: add Send/Recv Timeout Signed-off-by: Vasiliy Tolstov --- transport/memory/memory.go | 81 ++++++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 21 deletions(-) diff --git a/transport/memory/memory.go b/transport/memory/memory.go index 51f8d01a..ed269367 100644 --- a/transport/memory/memory.go +++ b/transport/memory/memory.go @@ -2,6 +2,7 @@ package memory import ( + "context" "errors" "fmt" "math/rand" @@ -24,6 +25,10 @@ type memorySocket struct { local string remote string + + // for send/recv transport.Timeout + timeout time.Duration + ctx context.Context sync.RWMutex } @@ -33,11 +38,13 @@ type memoryClient struct { } type memoryListener struct { - addr string - exit chan bool - conn chan *memorySocket - opts transport.ListenOptions + addr string + exit chan bool + conn chan *memorySocket + lopts transport.ListenOptions + topts transport.Options sync.RWMutex + ctx context.Context } type memoryTransport struct { @@ -49,7 +56,17 @@ type memoryTransport struct { func (ms *memorySocket) Recv(m *transport.Message) error { ms.RLock() defer ms.RUnlock() + + ctx := ms.ctx + if ms.timeout > 0 { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ms.ctx, ms.timeout) + defer cancel() + } + select { + case <-ctx.Done(): + return ctx.Err() case <-ms.exit: return errors.New("connection closed") case <-ms.lexit: @@ -71,7 +88,17 @@ func (ms *memorySocket) Remote() string { func (ms *memorySocket) Send(m *transport.Message) error { ms.RLock() defer ms.RUnlock() + + ctx := ms.ctx + if ms.timeout > 0 { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ms.ctx, ms.timeout) + defer cancel() + } + select { + case <-ctx.Done(): + return ctx.Err() case <-ms.exit: return errors.New("connection closed") case <-ms.lexit: @@ -116,12 +143,14 @@ func (m *memoryListener) Accept(fn func(transport.Socket)) error { return nil case c := <-m.conn: go fn(&memorySocket{ - lexit: c.lexit, - exit: c.exit, - send: c.recv, - recv: c.send, - local: c.Remote(), - remote: c.Local(), + lexit: c.lexit, + exit: c.exit, + send: c.recv, + recv: c.send, + local: c.Remote(), + remote: c.Local(), + timeout: m.topts.Timeout, + ctx: m.topts.Context, }) } } @@ -143,12 +172,14 @@ func (m *memoryTransport) Dial(addr string, opts ...transport.DialOption) (trans client := &memoryClient{ &memorySocket{ - send: make(chan *transport.Message), - recv: make(chan *transport.Message), - exit: make(chan bool), - lexit: listener.exit, - local: addr, - remote: addr, + send: make(chan *transport.Message), + recv: make(chan *transport.Message), + exit: make(chan bool), + lexit: listener.exit, + local: addr, + remote: addr, + timeout: m.opts.Timeout, + ctx: m.opts.Context, }, options, } @@ -196,10 +227,12 @@ func (m *memoryTransport) Listen(addr string, opts ...transport.ListenOption) (t } listener := &memoryListener{ - opts: options, - addr: addr, - conn: make(chan *memorySocket), - exit: make(chan bool), + lopts: options, + topts: m.opts, + addr: addr, + conn: make(chan *memorySocket), + exit: make(chan bool), + ctx: m.opts.Context, } m.listeners[addr] = listener @@ -223,12 +256,18 @@ func (m *memoryTransport) String() string { } func NewTransport(opts ...transport.Option) transport.Transport { - rand.Seed(time.Now().UnixNano()) var options transport.Options + + rand.Seed(time.Now().UnixNano()) + for _, o := range opts { o(&options) } + if options.Context == nil { + options.Context = context.Background() + } + return &memoryTransport{ opts: options, listeners: make(map[string]*memoryListener), From 2e67e23a23bae5471d2f66a6834ef7f212e87733 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Sat, 3 Aug 2019 15:16:30 +0100 Subject: [PATCH 253/287] Update .travis.yml --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 3a827c94..62ca1e1f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,3 +7,6 @@ env: notifications: slack: secure: aEvhLbhujaGaKSrOokiG3//PaVHTIrc3fBpoRbCRqfZpyq6WREoapJJhF+tIpWWOwaC9GmChbD6aHo/jMUgwKXVyPSaNjiEL87YzUUpL8B2zslNp1rgfTg/LrzthOx3Q1TYwpaAl3to0fuHUVFX4yMeC2vuThq7WSXgMMxFCtbc= +cache: + directories: + - $GOPATH/pkg/mod From 4030ccc27bff9409bca1bd8f07782e79bb71a4d7 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 5 Aug 2019 17:44:33 +0100 Subject: [PATCH 254/287] Move proxy/router --- client/selector/router/router.go | 4 +- network/tunnel/default.go | 337 ------------------ network/tunnel/listener.go | 101 ------ network/tunnel/socket.go | 90 ----- network/tunnel/tunnel.go | 44 --- network/tunnel/tunnel_test.go | 113 ------ {network/proxy => proxy}/grpc/grpc.go | 2 +- {network/proxy => proxy}/http/http.go | 2 +- {network/proxy => proxy}/http/http_test.go | 0 {network/proxy => proxy}/mucp/mucp.go | 4 +- {network/proxy => proxy}/proxy.go | 2 +- {network/router => router}/default.go | 0 {network/router => router}/handler/router.go | 4 +- {network/router => router}/handler/table.go | 4 +- {network/router => router}/options.go | 0 .../router => router}/proto/router.micro.go | 38 +- {network/router => router}/proto/router.pb.go | 237 ++++++------ {network/router => router}/proto/router.proto | 0 {network/router => router}/query.go | 0 {network/router => router}/route.go | 0 {network/router => router}/route_test.go | 0 {network/router => router}/router.go | 0 {network/router => router}/service/service.go | 4 +- {network/router => router}/service/table.go | 4 +- {network/router => router}/service/watcher.go | 4 +- {network/router => router}/table.go | 0 {network/router => router}/table_test.go | 0 {network/router => router}/watcher.go | 0 28 files changed, 138 insertions(+), 856 deletions(-) delete mode 100644 network/tunnel/default.go delete mode 100644 network/tunnel/listener.go delete mode 100644 network/tunnel/socket.go delete mode 100644 network/tunnel/tunnel.go delete mode 100644 network/tunnel/tunnel_test.go rename {network/proxy => proxy}/grpc/grpc.go (98%) rename {network/proxy => proxy}/http/http.go (98%) rename {network/proxy => proxy}/http/http_test.go (100%) rename {network/proxy => proxy}/mucp/mucp.go (98%) rename {network/proxy => proxy}/proxy.go (95%) rename {network/router => router}/default.go (100%) rename {network/router => router}/handler/router.go (97%) rename {network/router => router}/handler/table.go (96%) rename {network/router => router}/options.go (100%) rename {network/router => router}/proto/router.micro.go (95%) rename {network/router => router}/proto/router.pb.go (84%) rename {network/router => router}/proto/router.proto (100%) rename {network/router => router}/query.go (100%) rename {network/router => router}/route.go (100%) rename {network/router => router}/route_test.go (100%) rename {network/router => router}/router.go (100%) rename {network/router => router}/service/service.go (98%) rename {network/router => router}/service/table.go (96%) rename {network/router => router}/service/watcher.go (95%) rename {network/router => router}/table.go (100%) rename {network/router => router}/table_test.go (100%) rename {network/router => router}/watcher.go (100%) diff --git a/client/selector/router/router.go b/client/selector/router/router.go index 1c03b9ec..90f74a9a 100644 --- a/client/selector/router/router.go +++ b/client/selector/router/router.go @@ -9,9 +9,9 @@ import ( "github.com/micro/go-micro/client" "github.com/micro/go-micro/client/selector" - "github.com/micro/go-micro/network/router" - pb "github.com/micro/go-micro/network/router/proto" "github.com/micro/go-micro/registry" + "github.com/micro/go-micro/router" + pb "github.com/micro/go-micro/router/proto" ) type routerSelector struct { diff --git a/network/tunnel/default.go b/network/tunnel/default.go deleted file mode 100644 index a810783e..00000000 --- a/network/tunnel/default.go +++ /dev/null @@ -1,337 +0,0 @@ -package tunnel - -import ( - "crypto/sha256" - "errors" - "fmt" - "sync" - - "github.com/google/uuid" - "github.com/micro/go-micro/network/link" - "github.com/micro/go-micro/transport" -) - -// tun represents a network tunnel -type tun struct { - // the link on top of which we build a tunnel - link link.Link - - sync.RWMutex - - // to indicate if we're connected or not - connected bool - - // the send channel for all messages - send chan *message - - // close channel - closed chan bool - - // a map of sockets based on Micro-Tunnel-Id - sockets map[string]*socket -} - -// create new tunnel on top of a link -func newTunnel(link link.Link) *tun { - return &tun{ - link: link, - send: make(chan *message, 128), - closed: make(chan bool), - sockets: make(map[string]*socket), - } -} - -// getSocket returns a socket from the internal socket map. -// It does this based on the Micro-Tunnel-Id and Micro-Tunnel-Session -func (t *tun) getSocket(id, session string) (*socket, bool) { - // get the socket - t.RLock() - s, ok := t.sockets[id+session] - t.RUnlock() - return s, ok -} - -// newSocket creates a new socket and saves it -func (t *tun) newSocket(id, session string) (*socket, bool) { - // hash the id - h := sha256.New() - h.Write([]byte(id)) - id = fmt.Sprintf("%x", h.Sum(nil)) - - // new socket - s := &socket{ - id: id, - session: session, - closed: make(chan bool), - recv: make(chan *message, 128), - send: t.send, - wait: make(chan bool), - } - - // save socket - t.Lock() - _, ok := t.sockets[id+session] - if ok { - // socket already exists - t.Unlock() - return nil, false - } - t.sockets[id+session] = s - t.Unlock() - - // return socket - return s, true -} - -// TODO: use tunnel id as part of the session -func (t *tun) newSession() string { - return uuid.New().String() -} - -// process outgoing messages sent by all local sockets -func (t *tun) process() { - // manage the send buffer - // all pseudo sockets throw everything down this - for { - select { - case msg := <-t.send: - nmsg := &transport.Message{ - Header: msg.data.Header, - Body: msg.data.Body, - } - - // set the tunnel id on the outgoing message - nmsg.Header["Micro-Tunnel-Id"] = msg.id - - // set the session id - nmsg.Header["Micro-Tunnel-Session"] = msg.session - - // send the message via the interface - if err := t.link.Send(nmsg); err != nil { - // no op - // TODO: do something - } - case <-t.closed: - return - } - } -} - -// process incoming messages -func (t *tun) listen() { - for { - // process anything via the net interface - msg := new(transport.Message) - err := t.link.Recv(msg) - if err != nil { - return - } - - // first check Micro-Tunnel - switch msg.Header["Micro-Tunnel"] { - case "connect": - // assuming new connection - // TODO: do something with this - continue - case "close": - // assuming connection closed - // TODO: do something with this - continue - } - - // the tunnel id - id := msg.Header["Micro-Tunnel-Id"] - - // the session id - session := msg.Header["Micro-Tunnel-Session"] - - // if the session id is blank there's nothing we can do - // TODO: check this is the case, is there any reason - // why we'd have a blank session? Is the tunnel - // used for some other purpose? - if len(id) == 0 || len(session) == 0 { - continue - } - - // get the socket based on the tunnel id and session - // this could be something we dialed in which case - // we have a session for it otherwise its a listener - s, exists := t.getSocket(id, session) - if !exists { - // try get it based on just the tunnel id - // the assumption here is that a listener - // has no session but its set a listener session - s, exists = t.getSocket(id, "listener") - if !exists { - // drop it, we don't care about - // messages we don't know about - continue - } - } - - // is the socket closed? - select { - case <-s.closed: - // closed - delete(t.sockets, id) - continue - default: - // process - } - - // is the socket new? - select { - // if its new the socket is actually blocked waiting - // for a connection. so we check if its waiting. - case <-s.wait: - // if its waiting e.g its new then we close it - default: - // set remote address of the socket - s.remote = msg.Header["Remote"] - close(s.wait) - } - - // construct a new transport message - tmsg := &transport.Message{ - Header: msg.Header, - Body: msg.Body, - } - - // construct the internal message - imsg := &message{ - id: id, - session: session, - data: tmsg, - } - - // append to recv backlog - // we don't block if we can't pass it on - select { - case s.recv <- imsg: - default: - } - } -} - -func (t *tun) connect() error { - return t.link.Send(&transport.Message{ - Header: map[string]string{ - "Micro-Tunnel": "connect", - }, - }) -} - -func (t *tun) close() error { - return t.link.Send(&transport.Message{ - Header: map[string]string{ - "Micro-Tunnel": "close", - }, - }) -} - -// Close the tunnel -func (t *tun) Close() error { - t.Lock() - defer t.Unlock() - - if !t.connected { - return nil - } - - select { - case <-t.closed: - return nil - default: - // close all the sockets - for _, s := range t.sockets { - s.Close() - } - // close the connection - close(t.closed) - t.connected = false - - // send a close message - // we don't close the link - // just the tunnel - return t.close() - } - - return nil -} - -// Connect the tunnel -func (t *tun) Connect() error { - t.Lock() - defer t.Unlock() - - // already connected - if t.connected { - return nil - } - - // send the connect message - if err := t.connect(); err != nil { - return err - } - - // set as connected - t.connected = true - // create new close channel - t.closed = make(chan bool) - - // process messages to be sent - go t.process() - // process incoming messages - go t.listen() - - return nil -} - -// Dial an address -func (t *tun) Dial(addr string) (Conn, error) { - c, ok := t.newSocket(addr, t.newSession()) - if !ok { - return nil, errors.New("error dialing " + addr) - } - // set remote - c.remote = addr - // set local - c.local = t.link.Local() - - return c, nil -} - -// Accept a connection on the address -func (t *tun) Listen(addr string) (Listener, error) { - // create a new socket by hashing the address - c, ok := t.newSocket(addr, "listener") - if !ok { - return nil, errors.New("already listening on " + addr) - } - - // set remote. it will be replaced by the first message received - c.remote = t.link.Remote() - // set local - c.local = addr - - tl := &tunListener{ - addr: addr, - // the accept channel - accept: make(chan *socket, 128), - // the channel to close - closed: make(chan bool), - // the connection - conn: c, - // the listener socket - socket: c, - } - - // this kicks off the internal message processor - // for the listener so it can create pseudo sockets - // per session if they do not exist or pass messages - // to the existign sessions - go tl.process() - - // return the listener - return tl, nil -} diff --git a/network/tunnel/listener.go b/network/tunnel/listener.go deleted file mode 100644 index 6c803eb9..00000000 --- a/network/tunnel/listener.go +++ /dev/null @@ -1,101 +0,0 @@ -package tunnel - -import ( - "io" -) - -type tunListener struct { - // address of the listener - addr string - // the accept channel - accept chan *socket - // the channel to close - closed chan bool - // the connection - conn Conn - // the listener socket - socket *socket -} - -func (t *tunListener) process() { - // our connection map for session - conns := make(map[string]*socket) - - for { - select { - case <-t.closed: - return - // receive a new message - case m := <-t.socket.recv: - // get a socket - sock, ok := conns[m.session] - if !ok { - // create a new socket session - sock = &socket{ - // our tunnel id - id: m.id, - // the session id - session: m.session, - // close chan - closed: make(chan bool), - // recv called by the acceptor - recv: make(chan *message, 128), - // use the internal send buffer - send: t.socket.send, - // wait - wait: make(chan bool), - } - - // first message - sock.recv <- m - - // save the socket - conns[m.session] = sock - - // send to accept chan - select { - case <-t.closed: - return - case t.accept <- sock: - } - } - - // send this to the accept chan - select { - case <-sock.closed: - delete(conns, m.session) - case sock.recv <- m: - } - } - } -} - -func (t *tunListener) Addr() string { - return t.addr -} - -func (t *tunListener) Close() error { - select { - case <-t.closed: - return nil - default: - close(t.closed) - } - return nil -} - -// Everytime accept is called we essentially block till we get a new connection -func (t *tunListener) Accept() (Conn, error) { - select { - // if the socket is closed return - case <-t.closed: - return nil, io.EOF - // wait for a new connection - case c, ok := <-t.accept: - if !ok { - return nil, io.EOF - } - return c, nil - } - return nil, nil -} diff --git a/network/tunnel/socket.go b/network/tunnel/socket.go deleted file mode 100644 index b1c55797..00000000 --- a/network/tunnel/socket.go +++ /dev/null @@ -1,90 +0,0 @@ -package tunnel - -import ( - "errors" - - "github.com/micro/go-micro/transport" -) - -// socket is our pseudo socket for transport.Socket -type socket struct { - // socket id based on Micro-Tunnel - id string - // the session id based on Micro.Tunnel-Session - session string - // closed - closed chan bool - // remote addr - remote string - // local addr - local string - // send chan - send chan *message - // recv chan - recv chan *message - // wait until we have a connection - wait chan bool -} - -// message is sent over the send channel -type message struct { - // tunnel id - id string - // the session id - session string - // transport data - data *transport.Message -} - -func (s *socket) Remote() string { - return s.remote -} - -func (s *socket) Local() string { - return s.local -} - -func (s *socket) Id() string { - return s.id -} - -func (s *socket) Session() string { - return s.session -} - -func (s *socket) Send(m *transport.Message) error { - select { - case <-s.closed: - return errors.New("socket is closed") - default: - // no op - } - // append to backlog - s.send <- &message{id: s.id, session: s.session, data: m} - return nil -} - -func (s *socket) Recv(m *transport.Message) error { - select { - case <-s.closed: - return errors.New("socket is closed") - default: - // no op - } - // recv from backlog - msg := <-s.recv - // set message - *m = *msg.data - // return nil - return nil -} - -func (s *socket) Close() error { - select { - case <-s.closed: - // no op - default: - close(s.closed) - } - return nil -} diff --git a/network/tunnel/tunnel.go b/network/tunnel/tunnel.go deleted file mode 100644 index 6d879521..00000000 --- a/network/tunnel/tunnel.go +++ /dev/null @@ -1,44 +0,0 @@ -// Package tunnel provides gre network tunnelling -package tunnel - -import ( - "github.com/micro/go-micro/network/link" - "github.com/micro/go-micro/transport" -) - -// Tunnel creates a gre network tunnel on top of a link. -// It establishes multiple streams using the Micro-Tunnel-Id header -// and Micro-Tunnel-Session header. The tunnel id is a hash of -// the address being requested. -type Tunnel interface { - // Connect connects the tunnel - Connect() error - // Close closes the tunnel - Close() error - // Dial an endpoint - Dial(addr string) (Conn, error) - // Accept connections - Listen(addr string) (Listener, error) -} - -// The listener provides similar constructs to the transport.Listener -type Listener interface { - Addr() string - Close() error - Accept() (Conn, error) -} - -// Conn is a connection dialed or accepted which includes the tunnel id and session -type Conn interface { - // Specifies the tunnel id - Id() string - // The session - Session() string - // a transport socket - transport.Socket -} - -// NewTunnel creates a new tunnel on top of a link -func NewTunnel(l link.Link) Tunnel { - return newTunnel(l) -} diff --git a/network/tunnel/tunnel_test.go b/network/tunnel/tunnel_test.go deleted file mode 100644 index 99146c3f..00000000 --- a/network/tunnel/tunnel_test.go +++ /dev/null @@ -1,113 +0,0 @@ -package tunnel - -import ( - "testing" - - "github.com/micro/go-micro/network/link" - "github.com/micro/go-micro/transport" -) - -// testAccept will accept connections on the transport, create a new link and tunnel on top -func testAccept(t *testing.T, l transport.Listener, wait chan bool) error { - // accept new connections on the transport - // establish a link and tunnel - return l.Accept(func(s transport.Socket) { - // convert the socket into a link - li := link.NewLink( - link.Socket(s), - ) - - // connect the link e.g start internal buffers - if err := li.Connect(); err != nil { - t.Fatal(err) - } - - // create a new tunnel - tun := NewTunnel(li) - - // connect the tunnel - if err := tun.Connect(); err != nil { - t.Fatal(err) - } - - // listen on some virtual address - tl, err := tun.Listen("test-tunnel") - if err != nil { - t.Fatal(err) - return - } - - // accept a connection - c, err := tl.Accept() - if err != nil { - t.Fatal(err) - } - - // get a message - for { - m := new(transport.Message) - if err := c.Recv(m); err != nil { - t.Fatal(err) - } - close(wait) - return - } - }) -} - -// testSend will create a new link to an address and then a tunnel on top -func testSend(t *testing.T, addr string) { - // create a new link - l := link.NewLink( - link.Address(addr), - ) - - // connect the link, this includes dialing - if err := l.Connect(); err != nil { - t.Fatal(err) - } - - // create a tunnel on the link - tun := NewTunnel(l) - - // connect the tunnel with the remote side - if err := tun.Connect(); err != nil { - t.Fatal(err) - } - - // dial a new session - c, err := tun.Dial("test-tunnel") - if err != nil { - t.Fatal(err) - } - - m := transport.Message{ - Header: map[string]string{ - "test": "header", - }, - } - if err := c.Send(&m); err != nil { - t.Fatal(err) - } -} - -func TestTunnel(t *testing.T) { - // create a new listener - tr := transport.NewTransport() - l, err := tr.Listen(":0") - if err != nil { - t.Fatal(err) - } - defer l.Close() - - wait := make(chan bool) - - // start accepting connections - go testAccept(t, l, wait) - - // send a message - testSend(t, l.Addr()) - - // wait until message is received - <-wait -} diff --git a/network/proxy/grpc/grpc.go b/proxy/grpc/grpc.go similarity index 98% rename from network/proxy/grpc/grpc.go rename to proxy/grpc/grpc.go index 7aceb289..afb2453c 100644 --- a/network/proxy/grpc/grpc.go +++ b/proxy/grpc/grpc.go @@ -10,7 +10,7 @@ import ( "github.com/micro/go-micro/client/grpc" "github.com/micro/go-micro/codec" "github.com/micro/go-micro/config/options" - "github.com/micro/go-micro/network/proxy" + "github.com/micro/go-micro/proxy" "github.com/micro/go-micro/server" ) diff --git a/network/proxy/http/http.go b/proxy/http/http.go similarity index 98% rename from network/proxy/http/http.go rename to proxy/http/http.go index 7c19b6e1..61a6fc06 100644 --- a/network/proxy/http/http.go +++ b/proxy/http/http.go @@ -12,7 +12,7 @@ import ( "github.com/micro/go-micro/config/options" "github.com/micro/go-micro/errors" - "github.com/micro/go-micro/network/proxy" + "github.com/micro/go-micro/proxy" "github.com/micro/go-micro/server" ) diff --git a/network/proxy/http/http_test.go b/proxy/http/http_test.go similarity index 100% rename from network/proxy/http/http_test.go rename to proxy/http/http_test.go diff --git a/network/proxy/mucp/mucp.go b/proxy/mucp/mucp.go similarity index 98% rename from network/proxy/mucp/mucp.go rename to proxy/mucp/mucp.go index d70c4f77..4de363d6 100644 --- a/network/proxy/mucp/mucp.go +++ b/proxy/mucp/mucp.go @@ -12,8 +12,8 @@ import ( "github.com/micro/go-micro/codec" "github.com/micro/go-micro/codec/bytes" "github.com/micro/go-micro/config/options" - "github.com/micro/go-micro/network/proxy" - "github.com/micro/go-micro/network/router" + "github.com/micro/go-micro/proxy" + "github.com/micro/go-micro/router" "github.com/micro/go-micro/server" ) diff --git a/network/proxy/proxy.go b/proxy/proxy.go similarity index 95% rename from network/proxy/proxy.go rename to proxy/proxy.go index 22d485e8..cec226ba 100644 --- a/network/proxy/proxy.go +++ b/proxy/proxy.go @@ -6,7 +6,7 @@ import ( "github.com/micro/go-micro/client" "github.com/micro/go-micro/config/options" - "github.com/micro/go-micro/network/router" + "github.com/micro/go-micro/router" "github.com/micro/go-micro/server" ) diff --git a/network/router/default.go b/router/default.go similarity index 100% rename from network/router/default.go rename to router/default.go diff --git a/network/router/handler/router.go b/router/handler/router.go similarity index 97% rename from network/router/handler/router.go rename to router/handler/router.go index 26344c64..1b02b939 100644 --- a/network/router/handler/router.go +++ b/router/handler/router.go @@ -6,8 +6,8 @@ import ( "time" "github.com/micro/go-micro/errors" - "github.com/micro/go-micro/network/router" - pb "github.com/micro/go-micro/network/router/proto" + "github.com/micro/go-micro/router" + pb "github.com/micro/go-micro/router/proto" ) // Router implements router handler diff --git a/network/router/handler/table.go b/router/handler/table.go similarity index 96% rename from network/router/handler/table.go rename to router/handler/table.go index a1435511..ad17fa51 100644 --- a/network/router/handler/table.go +++ b/router/handler/table.go @@ -4,8 +4,8 @@ import ( "context" "github.com/micro/go-micro/errors" - "github.com/micro/go-micro/network/router" - pb "github.com/micro/go-micro/network/router/proto" + "github.com/micro/go-micro/router" + pb "github.com/micro/go-micro/router/proto" ) type Table struct { diff --git a/network/router/options.go b/router/options.go similarity index 100% rename from network/router/options.go rename to router/options.go diff --git a/network/router/proto/router.micro.go b/router/proto/router.micro.go similarity index 95% rename from network/router/proto/router.micro.go rename to router/proto/router.micro.go index ee5bbd51..b55c3043 100644 --- a/network/router/proto/router.micro.go +++ b/router/proto/router.micro.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-micro. DO NOT EDIT. -// source: go-micro/network/router/proto/router.proto +// source: micro/go-micro/router/proto/router.proto package go_micro_router @@ -36,7 +36,7 @@ var _ server.Option type RouterService interface { Lookup(ctx context.Context, in *LookupRequest, opts ...client.CallOption) (*LookupResponse, error) Watch(ctx context.Context, in *WatchRequest, opts ...client.CallOption) (Router_WatchService, error) - Advertise(ctx context.Context, in *AdvertiseRequest, opts ...client.CallOption) (Router_AdvertiseService, error) + Advertise(ctx context.Context, in *Request, opts ...client.CallOption) (Router_AdvertiseService, error) Process(ctx context.Context, in *Advert, opts ...client.CallOption) (*ProcessResponse, error) Status(ctx context.Context, in *Request, opts ...client.CallOption) (*StatusResponse, error) } @@ -113,8 +113,8 @@ func (x *routerServiceWatch) Recv() (*Event, error) { return m, nil } -func (c *routerService) Advertise(ctx context.Context, in *AdvertiseRequest, opts ...client.CallOption) (Router_AdvertiseService, error) { - req := c.c.NewRequest(c.name, "Router.Advertise", &AdvertiseRequest{}) +func (c *routerService) Advertise(ctx context.Context, in *Request, opts ...client.CallOption) (Router_AdvertiseService, error) { + req := c.c.NewRequest(c.name, "Router.Advertise", &Request{}) stream, err := c.c.Stream(ctx, req, opts...) if err != nil { return nil, err @@ -182,7 +182,7 @@ func (c *routerService) Status(ctx context.Context, in *Request, opts ...client. type RouterHandler interface { Lookup(context.Context, *LookupRequest, *LookupResponse) error Watch(context.Context, *WatchRequest, Router_WatchStream) error - Advertise(context.Context, *AdvertiseRequest, Router_AdvertiseStream) error + Advertise(context.Context, *Request, Router_AdvertiseStream) error Process(context.Context, *Advert, *ProcessResponse) error Status(context.Context, *Request, *StatusResponse) error } @@ -246,7 +246,7 @@ func (x *routerWatchStream) Send(m *Event) error { } func (h *routerHandler) Advertise(ctx context.Context, stream server.Stream) error { - m := new(AdvertiseRequest) + m := new(Request) if err := stream.Recv(m); err != nil { return err } @@ -294,8 +294,8 @@ type TableService interface { Create(ctx context.Context, in *Route, opts ...client.CallOption) (*CreateResponse, error) Delete(ctx context.Context, in *Route, opts ...client.CallOption) (*DeleteResponse, error) Update(ctx context.Context, in *Route, opts ...client.CallOption) (*UpdateResponse, error) - Query(ctx context.Context, in *QueryRequest, opts ...client.CallOption) (*QueryResponse, error) List(ctx context.Context, in *Request, opts ...client.CallOption) (*ListResponse, error) + Query(ctx context.Context, in *QueryRequest, opts ...client.CallOption) (*QueryResponse, error) } type tableService struct { @@ -346,9 +346,9 @@ func (c *tableService) Update(ctx context.Context, in *Route, opts ...client.Cal return out, nil } -func (c *tableService) Query(ctx context.Context, in *QueryRequest, opts ...client.CallOption) (*QueryResponse, error) { - req := c.c.NewRequest(c.name, "Table.Query", in) - out := new(QueryResponse) +func (c *tableService) List(ctx context.Context, in *Request, opts ...client.CallOption) (*ListResponse, error) { + req := c.c.NewRequest(c.name, "Table.List", in) + out := new(ListResponse) err := c.c.Call(ctx, req, out, opts...) if err != nil { return nil, err @@ -356,9 +356,9 @@ func (c *tableService) Query(ctx context.Context, in *QueryRequest, opts ...clie return out, nil } -func (c *tableService) List(ctx context.Context, in *Request, opts ...client.CallOption) (*ListResponse, error) { - req := c.c.NewRequest(c.name, "Table.List", in) - out := new(ListResponse) +func (c *tableService) Query(ctx context.Context, in *QueryRequest, opts ...client.CallOption) (*QueryResponse, error) { + req := c.c.NewRequest(c.name, "Table.Query", in) + out := new(QueryResponse) err := c.c.Call(ctx, req, out, opts...) if err != nil { return nil, err @@ -372,8 +372,8 @@ type TableHandler interface { Create(context.Context, *Route, *CreateResponse) error Delete(context.Context, *Route, *DeleteResponse) error Update(context.Context, *Route, *UpdateResponse) error - Query(context.Context, *QueryRequest, *QueryResponse) error List(context.Context, *Request, *ListResponse) error + Query(context.Context, *QueryRequest, *QueryResponse) error } func RegisterTableHandler(s server.Server, hdlr TableHandler, opts ...server.HandlerOption) error { @@ -381,8 +381,8 @@ func RegisterTableHandler(s server.Server, hdlr TableHandler, opts ...server.Han Create(ctx context.Context, in *Route, out *CreateResponse) error Delete(ctx context.Context, in *Route, out *DeleteResponse) error Update(ctx context.Context, in *Route, out *UpdateResponse) error - Query(ctx context.Context, in *QueryRequest, out *QueryResponse) error List(ctx context.Context, in *Request, out *ListResponse) error + Query(ctx context.Context, in *QueryRequest, out *QueryResponse) error } type Table struct { table @@ -407,10 +407,10 @@ func (h *tableHandler) Update(ctx context.Context, in *Route, out *UpdateRespons return h.TableHandler.Update(ctx, in, out) } -func (h *tableHandler) Query(ctx context.Context, in *QueryRequest, out *QueryResponse) error { - return h.TableHandler.Query(ctx, in, out) -} - func (h *tableHandler) List(ctx context.Context, in *Request, out *ListResponse) error { return h.TableHandler.List(ctx, in, out) } + +func (h *tableHandler) Query(ctx context.Context, in *QueryRequest, out *QueryResponse) error { + return h.TableHandler.Query(ctx, in, out) +} diff --git a/network/router/proto/router.pb.go b/router/proto/router.pb.go similarity index 84% rename from network/router/proto/router.pb.go rename to router/proto/router.pb.go index 6b90c0c8..c448e484 100644 --- a/network/router/proto/router.pb.go +++ b/router/proto/router.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-go. DO NOT EDIT. -// source: go-micro/network/router/proto/router.proto +// source: micro/go-micro/router/proto/router.proto package go_micro_router @@ -45,7 +45,7 @@ func (x AdvertType) String() string { } func (AdvertType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{0} + return fileDescriptor_6a36eee0b1adf739, []int{0} } // EventType defines the type of event @@ -74,7 +74,7 @@ func (x EventType) String() string { } func (EventType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{1} + return fileDescriptor_6a36eee0b1adf739, []int{1} } // Empty request @@ -88,7 +88,7 @@ func (m *Request) Reset() { *m = Request{} } func (m *Request) String() string { return proto.CompactTextString(m) } func (*Request) ProtoMessage() {} func (*Request) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{0} + return fileDescriptor_6a36eee0b1adf739, []int{0} } func (m *Request) XXX_Unmarshal(b []byte) error { @@ -121,7 +121,7 @@ func (m *ListResponse) Reset() { *m = ListResponse{} } func (m *ListResponse) String() string { return proto.CompactTextString(m) } func (*ListResponse) ProtoMessage() {} func (*ListResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{1} + return fileDescriptor_6a36eee0b1adf739, []int{1} } func (m *ListResponse) XXX_Unmarshal(b []byte) error { @@ -161,7 +161,7 @@ func (m *LookupRequest) Reset() { *m = LookupRequest{} } func (m *LookupRequest) String() string { return proto.CompactTextString(m) } func (*LookupRequest) ProtoMessage() {} func (*LookupRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{2} + return fileDescriptor_6a36eee0b1adf739, []int{2} } func (m *LookupRequest) XXX_Unmarshal(b []byte) error { @@ -201,7 +201,7 @@ func (m *LookupResponse) Reset() { *m = LookupResponse{} } func (m *LookupResponse) String() string { return proto.CompactTextString(m) } func (*LookupResponse) ProtoMessage() {} func (*LookupResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{3} + return fileDescriptor_6a36eee0b1adf739, []int{3} } func (m *LookupResponse) XXX_Unmarshal(b []byte) error { @@ -240,7 +240,7 @@ func (m *QueryRequest) Reset() { *m = QueryRequest{} } func (m *QueryRequest) String() string { return proto.CompactTextString(m) } func (*QueryRequest) ProtoMessage() {} func (*QueryRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{4} + return fileDescriptor_6a36eee0b1adf739, []int{4} } func (m *QueryRequest) XXX_Unmarshal(b []byte) error { @@ -279,7 +279,7 @@ func (m *QueryResponse) Reset() { *m = QueryResponse{} } func (m *QueryResponse) String() string { return proto.CompactTextString(m) } func (*QueryResponse) ProtoMessage() {} func (*QueryResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{5} + return fileDescriptor_6a36eee0b1adf739, []int{5} } func (m *QueryResponse) XXX_Unmarshal(b []byte) error { @@ -318,7 +318,7 @@ func (m *WatchRequest) Reset() { *m = WatchRequest{} } func (m *WatchRequest) String() string { return proto.CompactTextString(m) } func (*WatchRequest) ProtoMessage() {} func (*WatchRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{6} + return fileDescriptor_6a36eee0b1adf739, []int{6} } func (m *WatchRequest) XXX_Unmarshal(b []byte) error { @@ -339,38 +339,6 @@ func (m *WatchRequest) XXX_DiscardUnknown() { var xxx_messageInfo_WatchRequest proto.InternalMessageInfo -// AdvertiseRequest request a stream of Adverts -type AdvertiseRequest struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *AdvertiseRequest) Reset() { *m = AdvertiseRequest{} } -func (m *AdvertiseRequest) String() string { return proto.CompactTextString(m) } -func (*AdvertiseRequest) ProtoMessage() {} -func (*AdvertiseRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{7} -} - -func (m *AdvertiseRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_AdvertiseRequest.Unmarshal(m, b) -} -func (m *AdvertiseRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_AdvertiseRequest.Marshal(b, m, deterministic) -} -func (m *AdvertiseRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_AdvertiseRequest.Merge(m, src) -} -func (m *AdvertiseRequest) XXX_Size() int { - return xxx_messageInfo_AdvertiseRequest.Size(m) -} -func (m *AdvertiseRequest) XXX_DiscardUnknown() { - xxx_messageInfo_AdvertiseRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_AdvertiseRequest proto.InternalMessageInfo - // Advert is router advertsement streamed by Watch type Advert struct { // id of the advertising router @@ -392,7 +360,7 @@ func (m *Advert) Reset() { *m = Advert{} } func (m *Advert) String() string { return proto.CompactTextString(m) } func (*Advert) ProtoMessage() {} func (*Advert) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{8} + return fileDescriptor_6a36eee0b1adf739, []int{7} } func (m *Advert) XXX_Unmarshal(b []byte) error { @@ -459,7 +427,7 @@ func (m *ProcessResponse) Reset() { *m = ProcessResponse{} } func (m *ProcessResponse) String() string { return proto.CompactTextString(m) } func (*ProcessResponse) ProtoMessage() {} func (*ProcessResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{9} + return fileDescriptor_6a36eee0b1adf739, []int{8} } func (m *ProcessResponse) XXX_Unmarshal(b []byte) error { @@ -491,7 +459,7 @@ func (m *CreateResponse) Reset() { *m = CreateResponse{} } func (m *CreateResponse) String() string { return proto.CompactTextString(m) } func (*CreateResponse) ProtoMessage() {} func (*CreateResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{10} + return fileDescriptor_6a36eee0b1adf739, []int{9} } func (m *CreateResponse) XXX_Unmarshal(b []byte) error { @@ -523,7 +491,7 @@ func (m *DeleteResponse) Reset() { *m = DeleteResponse{} } func (m *DeleteResponse) String() string { return proto.CompactTextString(m) } func (*DeleteResponse) ProtoMessage() {} func (*DeleteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{11} + return fileDescriptor_6a36eee0b1adf739, []int{10} } func (m *DeleteResponse) XXX_Unmarshal(b []byte) error { @@ -555,7 +523,7 @@ func (m *UpdateResponse) Reset() { *m = UpdateResponse{} } func (m *UpdateResponse) String() string { return proto.CompactTextString(m) } func (*UpdateResponse) ProtoMessage() {} func (*UpdateResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{12} + return fileDescriptor_6a36eee0b1adf739, []int{11} } func (m *UpdateResponse) XXX_Unmarshal(b []byte) error { @@ -593,7 +561,7 @@ func (m *Event) Reset() { *m = Event{} } func (m *Event) String() string { return proto.CompactTextString(m) } func (*Event) ProtoMessage() {} func (*Event) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{13} + return fileDescriptor_6a36eee0b1adf739, []int{12} } func (m *Event) XXX_Unmarshal(b []byte) error { @@ -652,7 +620,7 @@ func (m *Query) Reset() { *m = Query{} } func (m *Query) String() string { return proto.CompactTextString(m) } func (*Query) ProtoMessage() {} func (*Query) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{14} + return fileDescriptor_6a36eee0b1adf739, []int{13} } func (m *Query) XXX_Unmarshal(b []byte) error { @@ -717,7 +685,7 @@ func (m *Route) Reset() { *m = Route{} } func (m *Route) String() string { return proto.CompactTextString(m) } func (*Route) ProtoMessage() {} func (*Route) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{15} + return fileDescriptor_6a36eee0b1adf739, []int{14} } func (m *Route) XXX_Unmarshal(b []byte) error { @@ -792,7 +760,7 @@ func (m *Status) Reset() { *m = Status{} } func (m *Status) String() string { return proto.CompactTextString(m) } func (*Status) ProtoMessage() {} func (*Status) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{16} + return fileDescriptor_6a36eee0b1adf739, []int{15} } func (m *Status) XXX_Unmarshal(b []byte) error { @@ -838,7 +806,7 @@ func (m *StatusResponse) Reset() { *m = StatusResponse{} } func (m *StatusResponse) String() string { return proto.CompactTextString(m) } func (*StatusResponse) ProtoMessage() {} func (*StatusResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_fc08514fc6dadd29, []int{17} + return fileDescriptor_6a36eee0b1adf739, []int{16} } func (m *StatusResponse) XXX_Unmarshal(b []byte) error { @@ -876,7 +844,6 @@ func init() { proto.RegisterType((*QueryRequest)(nil), "go.micro.router.QueryRequest") proto.RegisterType((*QueryResponse)(nil), "go.micro.router.QueryResponse") proto.RegisterType((*WatchRequest)(nil), "go.micro.router.WatchRequest") - proto.RegisterType((*AdvertiseRequest)(nil), "go.micro.router.AdvertiseRequest") proto.RegisterType((*Advert)(nil), "go.micro.router.Advert") proto.RegisterType((*ProcessResponse)(nil), "go.micro.router.ProcessResponse") proto.RegisterType((*CreateResponse)(nil), "go.micro.router.CreateResponse") @@ -890,55 +857,55 @@ func init() { } func init() { - proto.RegisterFile("go-micro/network/router/proto/router.proto", fileDescriptor_fc08514fc6dadd29) + proto.RegisterFile("micro/go-micro/router/proto/router.proto", fileDescriptor_6a36eee0b1adf739) } -var fileDescriptor_fc08514fc6dadd29 = []byte{ - // 702 bytes of a gzipped FileDescriptorProto +var fileDescriptor_6a36eee0b1adf739 = []byte{ + // 689 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0xcd, 0x4e, 0xdb, 0x40, - 0x10, 0xb6, 0x93, 0xd8, 0xc8, 0xd3, 0x60, 0xdc, 0x51, 0x05, 0x56, 0x5a, 0x68, 0xea, 0x13, 0x42, - 0xd4, 0xa9, 0xd2, 0x6b, 0xff, 0x52, 0x4a, 0x55, 0x09, 0x0e, 0xad, 0x0b, 0xea, 0xd9, 0xd8, 0x2b, - 0x6a, 0x91, 0x78, 0xcd, 0xee, 0x06, 0x94, 0x73, 0x1f, 0xa3, 0x4f, 0xd0, 0xe7, 0xea, 0x33, 0xf4, - 0x5e, 0x79, 0x77, 0x1d, 0x92, 0x18, 0x23, 0xc1, 0xc9, 0x3b, 0x7f, 0xdf, 0xec, 0xcc, 0xce, 0x37, - 0x86, 0xbd, 0x73, 0xfa, 0x72, 0x92, 0x25, 0x8c, 0x0e, 0x72, 0x22, 0xae, 0x29, 0xbb, 0x18, 0x30, - 0x3a, 0x15, 0x84, 0x0d, 0x0a, 0x46, 0x05, 0xd5, 0x42, 0x28, 0x05, 0xdc, 0x38, 0xa7, 0xa1, 0xf4, - 0x0d, 0x95, 0x3a, 0x70, 0x60, 0x2d, 0x22, 0x97, 0x53, 0xc2, 0x45, 0xf0, 0x0e, 0xba, 0xc7, 0x19, - 0x17, 0x11, 0xe1, 0x05, 0xcd, 0x39, 0xc1, 0x10, 0x6c, 0xe9, 0xc4, 0x7d, 0xb3, 0xdf, 0xde, 0x7d, - 0x34, 0xdc, 0x0c, 0x57, 0x82, 0xc3, 0xa8, 0xfc, 0x44, 0xda, 0x2b, 0x78, 0x0b, 0xeb, 0xc7, 0x94, - 0x5e, 0x4c, 0x0b, 0x0d, 0x88, 0xfb, 0x60, 0x5d, 0x4e, 0x09, 0x9b, 0xf9, 0x66, 0xdf, 0xbc, 0x35, - 0xfe, 0x5b, 0x69, 0x8d, 0x94, 0x53, 0xf0, 0x01, 0xdc, 0x2a, 0xfc, 0x81, 0x17, 0x78, 0x03, 0x5d, - 0x85, 0xf8, 0xa0, 0xfc, 0xef, 0x61, 0x5d, 0x47, 0x3f, 0x30, 0xbd, 0x0b, 0xdd, 0x1f, 0xb1, 0x48, - 0x7e, 0x56, 0xfd, 0x44, 0xf0, 0x46, 0xe9, 0x15, 0x61, 0x22, 0xe3, 0xa4, 0xd2, 0xfd, 0x31, 0xc1, - 0x56, 0x4a, 0x74, 0xa1, 0x95, 0xa5, 0xf2, 0x6a, 0x4e, 0xd4, 0xca, 0x52, 0x1c, 0x40, 0x47, 0xcc, - 0x0a, 0xe2, 0xb7, 0xfa, 0xe6, 0xae, 0x3b, 0x7c, 0x5a, 0x4b, 0xa6, 0xc2, 0x4e, 0x66, 0x05, 0x89, - 0xa4, 0x23, 0x3e, 0x03, 0x47, 0x64, 0x13, 0xc2, 0x45, 0x3c, 0x29, 0xfc, 0x76, 0xdf, 0xdc, 0x6d, - 0x47, 0x37, 0x0a, 0xf4, 0xa0, 0x2d, 0xc4, 0xd8, 0xef, 0x48, 0x7d, 0x79, 0x2c, 0xeb, 0x21, 0x57, - 0x24, 0x17, 0xdc, 0xb7, 0x1a, 0xea, 0x39, 0x2c, 0xcd, 0x91, 0xf6, 0x0a, 0x1e, 0xc3, 0xc6, 0x57, - 0x46, 0x13, 0xc2, 0x79, 0xd5, 0x92, 0xc0, 0x03, 0xf7, 0x80, 0x91, 0x58, 0x90, 0x45, 0xcd, 0x27, - 0x32, 0x26, 0xcb, 0x9a, 0xd3, 0x22, 0x5d, 0xf4, 0xf9, 0x65, 0x82, 0x25, 0xa1, 0x31, 0xd4, 0x35, - 0x9a, 0xb2, 0xc6, 0xde, 0xed, 0x17, 0x68, 0x2a, 0xb1, 0xb5, 0x5a, 0xe2, 0x3e, 0x58, 0x32, 0x4e, - 0x16, 0xdf, 0xfc, 0x3e, 0xca, 0x29, 0x38, 0x05, 0x4b, 0xbe, 0x2f, 0xfa, 0xb0, 0xc6, 0x09, 0xbb, - 0xca, 0x12, 0xa2, 0xbb, 0x5f, 0x89, 0xa5, 0xe5, 0x3c, 0x16, 0xe4, 0x3a, 0x9e, 0xc9, 0x64, 0x4e, - 0x54, 0x89, 0xa5, 0x45, 0x93, 0x4b, 0x26, 0x73, 0xa2, 0x4a, 0x0c, 0x7e, 0x9b, 0x60, 0xc9, 0x3c, - 0x77, 0xe3, 0xc6, 0x69, 0xca, 0x08, 0xe7, 0x15, 0xae, 0x16, 0x17, 0x33, 0xb6, 0x1b, 0x33, 0x76, - 0x96, 0x32, 0x22, 0x42, 0x67, 0x9c, 0xe5, 0x17, 0xbe, 0x25, 0xd5, 0xf2, 0x8c, 0x9b, 0x60, 0x4f, - 0x88, 0x60, 0x59, 0xe2, 0xdb, 0xb2, 0x4b, 0x5a, 0x0a, 0x86, 0x60, 0x7f, 0x17, 0xb1, 0x98, 0xf2, - 0x32, 0x2a, 0xa1, 0x69, 0x75, 0x35, 0x79, 0xc6, 0x27, 0x60, 0x11, 0xc6, 0x28, 0xd3, 0xb7, 0x52, - 0x42, 0x30, 0x02, 0x57, 0xc5, 0xcc, 0x99, 0x30, 0x00, 0x9b, 0x4b, 0x8d, 0x66, 0xd2, 0x56, 0xad, - 0xd3, 0x3a, 0x40, 0xbb, 0xed, 0x0d, 0x01, 0x6e, 0xc6, 0x15, 0x11, 0x5c, 0x25, 0x8d, 0xf2, 0x9c, - 0x4e, 0xf3, 0x84, 0x78, 0x06, 0x7a, 0xd0, 0x55, 0x3a, 0x35, 0x2b, 0x9e, 0xb9, 0x37, 0x00, 0x67, - 0xfe, 0xfc, 0x08, 0x60, 0xab, 0x41, 0xf3, 0x8c, 0xf2, 0xac, 0x46, 0xcc, 0x33, 0xcb, 0xb3, 0x0e, - 0x68, 0x0d, 0xff, 0xb5, 0xc0, 0x96, 0x9d, 0x67, 0x78, 0x04, 0xb6, 0xda, 0x1d, 0xb8, 0x53, 0xbb, - 0xda, 0xd2, 0x4e, 0xea, 0x3d, 0x6f, 0xb4, 0xeb, 0x61, 0x35, 0xf0, 0x23, 0x58, 0x92, 0xc7, 0xb8, - 0x5d, 0xf3, 0x5d, 0xe4, 0x77, 0xaf, 0x81, 0x3f, 0x81, 0xf1, 0xca, 0xc4, 0x23, 0x70, 0xe6, 0xdc, - 0xc7, 0x17, 0x0d, 0x5c, 0xbe, 0xd9, 0x0b, 0xbd, 0xad, 0x06, 0x17, 0x09, 0xf6, 0x19, 0xd6, 0x34, - 0x11, 0xb1, 0xc9, 0xaf, 0xd7, 0xaf, 0x19, 0x56, 0xb9, 0x6b, 0xe0, 0xe1, 0x7c, 0x18, 0xfc, 0x3a, - 0x55, 0x1a, 0xfb, 0xb3, 0x3c, 0x0b, 0x81, 0x31, 0xfc, 0xdb, 0x02, 0xeb, 0x24, 0x3e, 0x1b, 0x13, - 0x3c, 0xa8, 0x5e, 0x09, 0x1b, 0xb8, 0x77, 0x0b, 0xdc, 0xca, 0xfe, 0x30, 0x4a, 0x10, 0xf5, 0xbc, - 0xf7, 0x00, 0x59, 0x59, 0x39, 0x12, 0x44, 0xcd, 0xc5, 0x3d, 0x40, 0x56, 0xb6, 0x94, 0x81, 0x5f, - 0xaa, 0x0d, 0xb1, 0xdd, 0xf0, 0xa7, 0xd0, 0x3d, 0xda, 0x69, 0x32, 0xcf, 0x91, 0x46, 0xd0, 0x29, - 0x7f, 0xa5, 0x77, 0xf4, 0xb9, 0x9e, 0x62, 0xf1, 0xdf, 0x1b, 0x18, 0x67, 0xb6, 0xfc, 0x61, 0xbf, - 0xfe, 0x1f, 0x00, 0x00, 0xff, 0xff, 0xa6, 0xfc, 0x65, 0xca, 0xde, 0x07, 0x00, 0x00, + 0x10, 0xb6, 0x93, 0xd8, 0x28, 0xd3, 0x10, 0xdc, 0x51, 0x05, 0x56, 0x5a, 0x20, 0xf2, 0x29, 0x42, + 0xd4, 0xa9, 0xd2, 0x6b, 0xff, 0x02, 0xa5, 0xaa, 0x54, 0x0e, 0xad, 0x0b, 0xea, 0xd9, 0xd8, 0x23, + 0x6a, 0x91, 0xd8, 0x66, 0x77, 0x03, 0xca, 0xb9, 0x8f, 0xd1, 0x27, 0xe8, 0x73, 0xf5, 0xda, 0x87, + 0xa8, 0xbc, 0xbb, 0x0e, 0x21, 0xc6, 0x48, 0x70, 0xf2, 0xce, 0xdf, 0x37, 0xff, 0x63, 0x18, 0x4c, + 0x93, 0x88, 0x65, 0xc3, 0xf3, 0xec, 0xa5, 0x7a, 0xb0, 0x6c, 0x26, 0x88, 0x0d, 0x73, 0x96, 0x89, + 0x92, 0xf0, 0x25, 0x81, 0x1b, 0xe7, 0x99, 0x2f, 0x75, 0x7c, 0xc5, 0xf6, 0xda, 0xb0, 0x16, 0xd0, + 0xe5, 0x8c, 0xb8, 0xf0, 0xde, 0x41, 0xe7, 0x38, 0xe1, 0x22, 0x20, 0x9e, 0x67, 0x29, 0x27, 0xf4, + 0xc1, 0x96, 0x4a, 0xdc, 0x35, 0xfb, 0xcd, 0xc1, 0x93, 0xd1, 0xa6, 0xbf, 0x62, 0xec, 0x07, 0xc5, + 0x27, 0xd0, 0x5a, 0xde, 0x5b, 0x58, 0x3f, 0xce, 0xb2, 0x8b, 0x59, 0xae, 0x01, 0x71, 0x1f, 0xac, + 0xcb, 0x19, 0xb1, 0xb9, 0x6b, 0xf6, 0xcd, 0x3b, 0xed, 0xbf, 0x15, 0xd2, 0x40, 0x29, 0x79, 0x1f, + 0xa0, 0x5b, 0x9a, 0x3f, 0x32, 0x80, 0x37, 0xd0, 0x51, 0x88, 0x8f, 0xf2, 0xff, 0x1e, 0xd6, 0xb5, + 0xf5, 0x23, 0xdd, 0x77, 0xa1, 0xf3, 0x23, 0x14, 0xd1, 0xcf, 0xb2, 0x9e, 0x7f, 0x4c, 0xb0, 0xc7, + 0xf1, 0x15, 0x31, 0x81, 0x5d, 0x68, 0x24, 0xb1, 0x0c, 0xa3, 0x1d, 0x34, 0x92, 0x18, 0x87, 0xd0, + 0x12, 0xf3, 0x9c, 0xdc, 0x46, 0xdf, 0x1c, 0x74, 0x47, 0xcf, 0x2b, 0xc0, 0xca, 0xec, 0x64, 0x9e, + 0x53, 0x20, 0x15, 0xf1, 0x05, 0xb4, 0x45, 0x32, 0x25, 0x2e, 0xc2, 0x69, 0xee, 0x36, 0xfb, 0xe6, + 0xa0, 0x19, 0xdc, 0x30, 0xd0, 0x81, 0xa6, 0x10, 0x13, 0xb7, 0x25, 0xf9, 0xc5, 0xb3, 0x88, 0x9d, + 0xae, 0x28, 0x15, 0xdc, 0xb5, 0x6a, 0x62, 0x3f, 0x2a, 0xc4, 0x81, 0xd6, 0xf2, 0x9e, 0xc2, 0xc6, + 0x57, 0x96, 0x45, 0xc4, 0x79, 0x99, 0xbe, 0xe7, 0x40, 0xf7, 0x90, 0x51, 0x28, 0x68, 0x99, 0xf3, + 0x91, 0x26, 0x74, 0x9b, 0x73, 0x9a, 0xc7, 0xcb, 0x3a, 0xbf, 0x4c, 0xb0, 0x24, 0x34, 0xfa, 0x3a, + 0x47, 0x53, 0xe6, 0xd8, 0xbb, 0x3b, 0x80, 0xba, 0x14, 0x1b, 0xab, 0x29, 0xee, 0x83, 0x25, 0xed, + 0x64, 0xf2, 0xf5, 0xbd, 0x50, 0x4a, 0xde, 0x29, 0x58, 0xb2, 0x97, 0xe8, 0xc2, 0x1a, 0x27, 0x76, + 0x95, 0x44, 0xa4, 0xab, 0x5f, 0x92, 0x85, 0xe4, 0x3c, 0x14, 0x74, 0x1d, 0xce, 0xa5, 0xb3, 0x76, + 0x50, 0x92, 0x85, 0x24, 0x25, 0x71, 0x9d, 0xb1, 0x0b, 0xe9, 0xac, 0x1d, 0x94, 0xa4, 0xf7, 0xdb, + 0x04, 0x4b, 0xfa, 0xb9, 0x1f, 0x37, 0x8c, 0x63, 0x46, 0x9c, 0x97, 0xb8, 0x9a, 0x5c, 0xf6, 0xd8, + 0xac, 0xf5, 0xd8, 0xba, 0xe5, 0x11, 0x11, 0x5a, 0x93, 0x24, 0xbd, 0x70, 0x2d, 0xc9, 0x96, 0x6f, + 0xdc, 0x04, 0x7b, 0x4a, 0x82, 0x25, 0x91, 0x6b, 0xcb, 0x2a, 0x69, 0xca, 0x1b, 0x81, 0xfd, 0x5d, + 0x84, 0x62, 0xc6, 0x0b, 0xab, 0x28, 0x8b, 0xcb, 0xd0, 0xe4, 0x1b, 0x9f, 0x81, 0x45, 0x8c, 0x65, + 0x4c, 0x47, 0xa5, 0x08, 0x6f, 0x0c, 0x5d, 0x65, 0xb3, 0x98, 0xfa, 0x21, 0xd8, 0x5c, 0x72, 0xf4, + 0xd6, 0x6c, 0x55, 0x2a, 0xad, 0x0d, 0xb4, 0xda, 0xde, 0x08, 0xe0, 0x66, 0x5c, 0x11, 0xa1, 0xab, + 0xa8, 0x71, 0x9a, 0x66, 0xb3, 0x34, 0x22, 0xc7, 0x40, 0x07, 0x3a, 0x8a, 0xa7, 0x66, 0xc5, 0x31, + 0xf7, 0x86, 0xd0, 0x5e, 0xb4, 0x1f, 0x01, 0x6c, 0x35, 0x68, 0x8e, 0x51, 0xbc, 0xd5, 0x88, 0x39, + 0x66, 0xf1, 0xd6, 0x06, 0x8d, 0xd1, 0xbf, 0x06, 0xd8, 0xb2, 0xf2, 0x0c, 0xbf, 0x80, 0xad, 0xee, + 0x04, 0xee, 0x54, 0x42, 0xbb, 0x75, 0x7f, 0x7a, 0xbb, 0xb5, 0x72, 0x3d, 0xac, 0x06, 0x1e, 0x80, + 0x25, 0x77, 0x16, 0xb7, 0x2b, 0xba, 0xcb, 0xbb, 0xdc, 0xab, 0xd9, 0x1f, 0xcf, 0x78, 0x65, 0xe2, + 0x01, 0xb4, 0x55, 0x7a, 0x09, 0x27, 0x74, 0xab, 0x83, 0xa9, 0x21, 0xb6, 0x6a, 0xb6, 0x5c, 0x62, + 0x7c, 0x82, 0x35, 0xbd, 0x7f, 0x58, 0xa7, 0xd7, 0xeb, 0x57, 0x04, 0xab, 0x2b, 0x6b, 0xe0, 0xd1, + 0x62, 0x06, 0xea, 0x03, 0xd9, 0xad, 0xeb, 0xe8, 0x02, 0x66, 0xf4, 0xb7, 0x01, 0xd6, 0x49, 0x78, + 0x36, 0x21, 0x3c, 0x2c, 0x9b, 0x83, 0x35, 0x2b, 0x77, 0x07, 0xdc, 0xca, 0xd9, 0x30, 0x0a, 0x10, + 0xd5, 0xd5, 0x07, 0x80, 0xac, 0x5c, 0x1a, 0x09, 0xa2, 0xc6, 0xe1, 0x01, 0x20, 0x2b, 0xc7, 0xc9, + 0xc0, 0x31, 0xb4, 0x8a, 0x7f, 0xdc, 0x3d, 0xd5, 0xa9, 0x0e, 0xc2, 0xf2, 0x4f, 0xd1, 0x33, 0xf0, + 0x73, 0x79, 0x5b, 0xb6, 0x6b, 0xfe, 0x27, 0x1a, 0x68, 0xa7, 0x4e, 0x5c, 0x22, 0x9d, 0xd9, 0xf2, + 0x9f, 0xfc, 0xfa, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x8c, 0xd0, 0xc0, 0x27, 0xbf, 0x07, 0x00, + 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -955,7 +922,7 @@ const _ = grpc.SupportPackageIsVersion4 type RouterClient interface { Lookup(ctx context.Context, in *LookupRequest, opts ...grpc.CallOption) (*LookupResponse, error) Watch(ctx context.Context, in *WatchRequest, opts ...grpc.CallOption) (Router_WatchClient, error) - Advertise(ctx context.Context, in *AdvertiseRequest, opts ...grpc.CallOption) (Router_AdvertiseClient, error) + Advertise(ctx context.Context, in *Request, opts ...grpc.CallOption) (Router_AdvertiseClient, error) Process(ctx context.Context, in *Advert, opts ...grpc.CallOption) (*ProcessResponse, error) Status(ctx context.Context, in *Request, opts ...grpc.CallOption) (*StatusResponse, error) } @@ -1009,7 +976,7 @@ func (x *routerWatchClient) Recv() (*Event, error) { return m, nil } -func (c *routerClient) Advertise(ctx context.Context, in *AdvertiseRequest, opts ...grpc.CallOption) (Router_AdvertiseClient, error) { +func (c *routerClient) Advertise(ctx context.Context, in *Request, opts ...grpc.CallOption) (Router_AdvertiseClient, error) { stream, err := c.cc.NewStream(ctx, &_Router_serviceDesc.Streams[1], "/go.micro.router.Router/Advertise", opts...) if err != nil { return nil, err @@ -1063,7 +1030,7 @@ func (c *routerClient) Status(ctx context.Context, in *Request, opts ...grpc.Cal type RouterServer interface { Lookup(context.Context, *LookupRequest) (*LookupResponse, error) Watch(*WatchRequest, Router_WatchServer) error - Advertise(*AdvertiseRequest, Router_AdvertiseServer) error + Advertise(*Request, Router_AdvertiseServer) error Process(context.Context, *Advert) (*ProcessResponse, error) Status(context.Context, *Request) (*StatusResponse, error) } @@ -1112,7 +1079,7 @@ func (x *routerWatchServer) Send(m *Event) error { } func _Router_Advertise_Handler(srv interface{}, stream grpc.ServerStream) error { - m := new(AdvertiseRequest) + m := new(Request) if err := stream.RecvMsg(m); err != nil { return err } @@ -1197,7 +1164,7 @@ var _Router_serviceDesc = grpc.ServiceDesc{ ServerStreams: true, }, }, - Metadata: "go-micro/network/router/proto/router.proto", + Metadata: "micro/go-micro/router/proto/router.proto", } // TableClient is the client API for Table service. @@ -1207,8 +1174,8 @@ type TableClient interface { Create(ctx context.Context, in *Route, opts ...grpc.CallOption) (*CreateResponse, error) Delete(ctx context.Context, in *Route, opts ...grpc.CallOption) (*DeleteResponse, error) Update(ctx context.Context, in *Route, opts ...grpc.CallOption) (*UpdateResponse, error) - Query(ctx context.Context, in *QueryRequest, opts ...grpc.CallOption) (*QueryResponse, error) List(ctx context.Context, in *Request, opts ...grpc.CallOption) (*ListResponse, error) + Query(ctx context.Context, in *QueryRequest, opts ...grpc.CallOption) (*QueryResponse, error) } type tableClient struct { @@ -1246,18 +1213,18 @@ func (c *tableClient) Update(ctx context.Context, in *Route, opts ...grpc.CallOp return out, nil } -func (c *tableClient) Query(ctx context.Context, in *QueryRequest, opts ...grpc.CallOption) (*QueryResponse, error) { - out := new(QueryResponse) - err := c.cc.Invoke(ctx, "/go.micro.router.Table/Query", in, out, opts...) +func (c *tableClient) List(ctx context.Context, in *Request, opts ...grpc.CallOption) (*ListResponse, error) { + out := new(ListResponse) + err := c.cc.Invoke(ctx, "/go.micro.router.Table/List", in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *tableClient) List(ctx context.Context, in *Request, opts ...grpc.CallOption) (*ListResponse, error) { - out := new(ListResponse) - err := c.cc.Invoke(ctx, "/go.micro.router.Table/List", in, out, opts...) +func (c *tableClient) Query(ctx context.Context, in *QueryRequest, opts ...grpc.CallOption) (*QueryResponse, error) { + out := new(QueryResponse) + err := c.cc.Invoke(ctx, "/go.micro.router.Table/Query", in, out, opts...) if err != nil { return nil, err } @@ -1269,8 +1236,8 @@ type TableServer interface { Create(context.Context, *Route) (*CreateResponse, error) Delete(context.Context, *Route) (*DeleteResponse, error) Update(context.Context, *Route) (*UpdateResponse, error) - Query(context.Context, *QueryRequest) (*QueryResponse, error) List(context.Context, *Request) (*ListResponse, error) + Query(context.Context, *QueryRequest) (*QueryResponse, error) } func RegisterTableServer(s *grpc.Server, srv TableServer) { @@ -1331,24 +1298,6 @@ func _Table_Update_Handler(srv interface{}, ctx context.Context, dec func(interf return interceptor(ctx, in, info, handler) } -func _Table_Query_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(TableServer).Query(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/go.micro.router.Table/Query", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(TableServer).Query(ctx, req.(*QueryRequest)) - } - return interceptor(ctx, in, info, handler) -} - func _Table_List_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(Request) if err := dec(in); err != nil { @@ -1367,6 +1316,24 @@ func _Table_List_Handler(srv interface{}, ctx context.Context, dec func(interfac return interceptor(ctx, in, info, handler) } +func _Table_Query_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TableServer).Query(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/go.micro.router.Table/Query", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TableServer).Query(ctx, req.(*QueryRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Table_serviceDesc = grpc.ServiceDesc{ ServiceName: "go.micro.router.Table", HandlerType: (*TableServer)(nil), @@ -1383,15 +1350,15 @@ var _Table_serviceDesc = grpc.ServiceDesc{ MethodName: "Update", Handler: _Table_Update_Handler, }, - { - MethodName: "Query", - Handler: _Table_Query_Handler, - }, { MethodName: "List", Handler: _Table_List_Handler, }, + { + MethodName: "Query", + Handler: _Table_Query_Handler, + }, }, Streams: []grpc.StreamDesc{}, - Metadata: "go-micro/network/router/proto/router.proto", + Metadata: "micro/go-micro/router/proto/router.proto", } diff --git a/network/router/proto/router.proto b/router/proto/router.proto similarity index 100% rename from network/router/proto/router.proto rename to router/proto/router.proto diff --git a/network/router/query.go b/router/query.go similarity index 100% rename from network/router/query.go rename to router/query.go diff --git a/network/router/route.go b/router/route.go similarity index 100% rename from network/router/route.go rename to router/route.go diff --git a/network/router/route_test.go b/router/route_test.go similarity index 100% rename from network/router/route_test.go rename to router/route_test.go diff --git a/network/router/router.go b/router/router.go similarity index 100% rename from network/router/router.go rename to router/router.go diff --git a/network/router/service/service.go b/router/service/service.go similarity index 98% rename from network/router/service/service.go rename to router/service/service.go index 21d025d1..cdae90e5 100644 --- a/network/router/service/service.go +++ b/router/service/service.go @@ -9,8 +9,8 @@ import ( "time" "github.com/micro/go-micro/client" - "github.com/micro/go-micro/network/router" - pb "github.com/micro/go-micro/network/router/proto" + "github.com/micro/go-micro/router" + pb "github.com/micro/go-micro/router/proto" ) type svc struct { diff --git a/network/router/service/table.go b/router/service/table.go similarity index 96% rename from network/router/service/table.go rename to router/service/table.go index 2843a8f6..a6c44fd3 100644 --- a/network/router/service/table.go +++ b/router/service/table.go @@ -4,8 +4,8 @@ import ( "context" "github.com/micro/go-micro/client" - "github.com/micro/go-micro/network/router" - pb "github.com/micro/go-micro/network/router/proto" + "github.com/micro/go-micro/router" + pb "github.com/micro/go-micro/router/proto" ) type table struct { diff --git a/network/router/service/watcher.go b/router/service/watcher.go similarity index 95% rename from network/router/service/watcher.go rename to router/service/watcher.go index 53bb7648..f0fb3d5c 100644 --- a/network/router/service/watcher.go +++ b/router/service/watcher.go @@ -5,8 +5,8 @@ import ( "sync" "time" - "github.com/micro/go-micro/network/router" - pb "github.com/micro/go-micro/network/router/proto" + "github.com/micro/go-micro/router" + pb "github.com/micro/go-micro/router/proto" ) type watcher struct { diff --git a/network/router/table.go b/router/table.go similarity index 100% rename from network/router/table.go rename to router/table.go diff --git a/network/router/table_test.go b/router/table_test.go similarity index 100% rename from network/router/table_test.go rename to router/table_test.go diff --git a/network/router/watcher.go b/router/watcher.go similarity index 100% rename from network/router/watcher.go rename to router/watcher.go From f1b670972216afed1f5aa634dcf4551c7ef8353c Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 5 Aug 2019 17:47:50 +0100 Subject: [PATCH 255/287] Fix breaking api changes --- router/handler/router.go | 2 +- router/service/service.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/router/handler/router.go b/router/handler/router.go index 1b02b939..a7571024 100644 --- a/router/handler/router.go +++ b/router/handler/router.go @@ -44,7 +44,7 @@ func (r *Router) Lookup(ctx context.Context, req *pb.LookupRequest, resp *pb.Loo return nil } -func (r *Router) Advertise(ctx context.Context, req *pb.AdvertiseRequest, stream pb.Router_AdvertiseStream) error { +func (r *Router) Advertise(ctx context.Context, req *pb.Request, stream pb.Router_AdvertiseStream) error { advertChan, err := r.Router.Advertise() if err != nil { return errors.InternalServerError("go.micro.router", "failed to get adverts: %v", err) diff --git a/router/service/service.go b/router/service/service.go index cdae90e5..b06de9c8 100644 --- a/router/service/service.go +++ b/router/service/service.go @@ -145,7 +145,7 @@ func (s *svc) Advertise() (<-chan *router.Advert, error) { switch status.Code { case router.Running, router.Advertising: - stream, err := s.router.Advertise(context.Background(), &pb.AdvertiseRequest{}, s.callOpts...) + stream, err := s.router.Advertise(context.Background(), &pb.Request{}, s.callOpts...) if err != nil { return nil, fmt.Errorf("failed getting advert stream: %s", err) } From e1ecd728c59558999430a3654de6a236013cb5f7 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Mon, 5 Aug 2019 17:52:57 +0100 Subject: [PATCH 256/287] Adds outline of go-micro Tunnel interface --- tunnel/options.go | 63 +++++++++++++++++++++++++++++++++++++++++++++++ tunnel/tunnel.go | 15 +++++++++++ 2 files changed, 78 insertions(+) create mode 100644 tunnel/options.go create mode 100644 tunnel/tunnel.go diff --git a/tunnel/options.go b/tunnel/options.go new file mode 100644 index 00000000..86db722e --- /dev/null +++ b/tunnel/options.go @@ -0,0 +1,63 @@ +package tunnel + +import ( + "github.com/google/uuid" + "github.com/micro/go-micro/transport" +) + +var ( + // DefaultAddress is default tunnel bind address + DefaultAddress = ":9096" +) + +type Option func(*Options) + +// Options provides network configuration options +type Options struct { + // Id is tunnel id + Id string + // Address is tunnel address + Address string + // Nodes are remote nodes + Nodes []string + // Transport listens to incoming connections + Transport transport.Transport +} + +// The tunnel id +func Id(id string) Option { + return func(o *Options) { + o.Id = id + } +} + +// The tunnel address +func Address(a string) Option { + return func(o *Options) { + o.Address = a + } +} + +// Nodes specify remote network nodes +func Nodes(n []string) Option { + return func(o *Options) { + o.Nodes = n + } +} + +// Transport listens for incoming connections +func Transport(t transport.Transport) Option { + return func(o *Options) { + o.Transport = t + } +} + +// DefaultOptions returns router default options +func DefaultOptions() Options { + return Options{ + Id: uuid.New().String(), + Address: DefaultAddress, + Nodes: make([]string, 0), + Transport: transport.DefaultTransport, + } +} diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go new file mode 100644 index 00000000..e208157b --- /dev/null +++ b/tunnel/tunnel.go @@ -0,0 +1,15 @@ +// Package tunnel provides micro network tunnelling +package tunnel + +import ( + "github.com/micro/go-micro/transport" +) + +// Tunnel creates a p2p network tunnel. +type Tunnel interface { + transport.Transport + // Connect connects the tunnel + Connect() error + // Close closes the tunnel + Close() error +} From 34381213e769a45fd45878ebb7d43204a0c29270 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 5 Aug 2019 18:04:47 +0100 Subject: [PATCH 257/287] Package comment --- network/network.go | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 network/network.go diff --git a/network/network.go b/network/network.go new file mode 100644 index 00000000..15d8155f --- /dev/null +++ b/network/network.go @@ -0,0 +1,2 @@ +// Package network is for creating internetworks +package network From 6b5dcbf8148f4ab7406b3c1446f90fb65aad60f0 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Mon, 5 Aug 2019 19:41:48 +0100 Subject: [PATCH 258/287] Tunnel no longer embeds transport --- tunnel/default.go | 67 +++++++++++++++++++++++++++++++++++++++++++++++ tunnel/tunnel.go | 24 ++++++++++++++++- 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 tunnel/default.go diff --git a/tunnel/default.go b/tunnel/default.go new file mode 100644 index 00000000..a7386ffd --- /dev/null +++ b/tunnel/default.go @@ -0,0 +1,67 @@ +package tunnel + +import ( + "sync" + + "github.com/micro/go-micro/transport" +) + +type tun struct { + options Options + sync.RWMutex + connected bool + closed chan bool +} + +func newTunnel(opts ...Option) Tunnel { + // initialize default options + options := DefaultOptions() + + for _, o := range opts { + o(&options) + } + + t := &tun{ + options: options, + closed: make(chan bool), + } + + return t +} + +func (t *tun) Id() string { + return t.options.Id +} + +func (t *tun) Address() string { + return t.options.Address +} + +func (t *tun) Transport() transport.Transport { + return t.options.Transport +} + +func (t *tun) Options() transport.Options { + return transport.Options{} +} + +func (t *tun) Connect() error { + return nil +} + +func (t *tun) Close() error { + return nil +} + +func (t *tun) Status() Status { + select { + case <-t.closed: + return Closed + default: + return Connected + } +} + +func (t *tun) String() string { + return "micro" +} diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index e208157b..2adc4447 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -5,11 +5,33 @@ import ( "github.com/micro/go-micro/transport" ) +// Status is tunnel status +type Status int + +const ( + // Connected means the tunnel is alive + Connected Status = iota + // Closed meands the tunnel has been disconnected + Closed +) + // Tunnel creates a p2p network tunnel. type Tunnel interface { - transport.Transport + // Id returns tunnel id + Id() string + // Address returns tunnel address + Address() string + // Tramsport returns tunnel transport + Transport() transport.Transport // Connect connects the tunnel Connect() error // Close closes the tunnel Close() error + // Status returns tunnel status + Status() Status +} + +// NewTunnel creates a new tunnel on top of a link +func NewTunnel(opts ...Option) Tunnel { + return newTunnel(opts...) } From 52d8d260181f2cf20c7ddb56a7b250a61385e1d6 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Mon, 5 Aug 2019 21:09:46 +0100 Subject: [PATCH 259/287] Transport() will return tunnel (pseudo) Transport --- tunnel/default.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tunnel/default.go b/tunnel/default.go index a7386ffd..127785d3 100644 --- a/tunnel/default.go +++ b/tunnel/default.go @@ -38,7 +38,7 @@ func (t *tun) Address() string { } func (t *tun) Transport() transport.Transport { - return t.options.Transport + return nil } func (t *tun) Options() transport.Options { From e16420fdbdec17e1b0e40e8d8a21303a482e2dad Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 6 Aug 2019 09:15:38 +0100 Subject: [PATCH 260/287] Consul config fix https://github.com/micro/go-micro/pull/641 --- registry/consul/consul.go | 54 +++++++++++++++++++++++--------- registry/consul/registry_test.go | 28 +++++++++-------- registry/consul/watcher.go | 4 +-- 3 files changed, 56 insertions(+), 30 deletions(-) diff --git a/registry/consul/consul.go b/registry/consul/consul.go index 9a15c826..32360987 100644 --- a/registry/consul/consul.go +++ b/registry/consul/consul.go @@ -17,10 +17,12 @@ import ( ) type consulRegistry struct { - Address string - Client *consul.Client + Address []string opts registry.Options + client *consul.Client + config *consul.Config + // connect enabled connect bool @@ -123,12 +125,12 @@ func configure(c *consulRegistry, opts ...registry.Option) { config.HttpClient.Timeout = c.opts.Timeout } - // create the client - client, _ := consul.NewClient(config) + // set address + c.Address = c.opts.Addrs - // set address/client - c.Address = config.Address - c.Client = client + c.config = config + + c.Client() } func (c *consulRegistry) Init(opts ...registry.Option) error { @@ -148,7 +150,7 @@ func (c *consulRegistry) Deregister(s *registry.Service) error { c.Unlock() node := s.Nodes[0] - return c.Client.Agent().ServiceDeregister(node.Id) + return c.Client().Agent().ServiceDeregister(node.Id) } func (c *consulRegistry) Register(s *registry.Service, opts ...registry.RegisterOption) error { @@ -193,7 +195,7 @@ func (c *consulRegistry) Register(s *registry.Service, opts ...registry.Register if time.Since(lastChecked) <= getDeregisterTTL(regInterval) { return nil } - services, _, err := c.Client.Health().Checks(s.Name, c.queryOptions) + services, _, err := c.Client().Health().Checks(s.Name, c.queryOptions) if err == nil { for _, v := range services { if v.ServiceID == node.Id { @@ -204,7 +206,7 @@ func (c *consulRegistry) Register(s *registry.Service, opts ...registry.Register } else { // if the err is nil we're all good, bail out // if not, we don't know what the state is, so full re-register - if err := c.Client.Agent().PassTTL("service:"+node.Id, ""); err == nil { + if err := c.Client().Agent().PassTTL("service:"+node.Id, ""); err == nil { return nil } } @@ -256,7 +258,7 @@ func (c *consulRegistry) Register(s *registry.Service, opts ...registry.Register } } - if err := c.Client.Agent().ServiceRegister(asr); err != nil { + if err := c.Client().Agent().ServiceRegister(asr); err != nil { return err } @@ -272,7 +274,7 @@ func (c *consulRegistry) Register(s *registry.Service, opts ...registry.Register } // pass the healthcheck - return c.Client.Agent().PassTTL("service:"+node.Id, "") + return c.Client().Agent().PassTTL("service:"+node.Id, "") } func (c *consulRegistry) GetService(name string) ([]*registry.Service, error) { @@ -281,9 +283,9 @@ func (c *consulRegistry) GetService(name string) ([]*registry.Service, error) { // if we're connect enabled only get connect services if c.connect { - rsp, _, err = c.Client.Health().Connect(name, "", false, c.queryOptions) + rsp, _, err = c.Client().Health().Connect(name, "", false, c.queryOptions) } else { - rsp, _, err = c.Client.Health().Service(name, "", false, c.queryOptions) + rsp, _, err = c.Client().Health().Service(name, "", false, c.queryOptions) } if err != nil { return nil, err @@ -351,7 +353,7 @@ func (c *consulRegistry) GetService(name string) ([]*registry.Service, error) { } func (c *consulRegistry) ListServices() ([]*registry.Service, error) { - rsp, _, err := c.Client.Catalog().Services(c.queryOptions) + rsp, _, err := c.Client().Catalog().Services(c.queryOptions) if err != nil { return nil, err } @@ -377,6 +379,28 @@ func (c *consulRegistry) Options() registry.Options { return c.opts } +func (c *consulRegistry) Client() *consul.Client { + if c.client != nil { + return c.client + } + + if len(c.Address) == 0 { + tmp, _ := consul.NewClient(c.config) + return tmp + } + + c.config.Address = c.Address[0] + tmpClint, _ := consul.NewClient(c.config) + _, err := tmpClint.Agent().Host() + if err != nil { + c.Address = c.Address[1:] + return c.Client() + } + + c.client = tmpClint + return c.client +} + func NewRegistry(opts ...registry.Option) registry.Registry { cr := &consulRegistry{ opts: registry.Options{}, diff --git a/registry/consul/registry_test.go b/registry/consul/registry_test.go index 37eabd17..3a275030 100644 --- a/registry/consul/registry_test.go +++ b/registry/consul/registry_test.go @@ -50,22 +50,24 @@ func newConsulTestRegistry(r *mockRegistry) (*consulRegistry, func()) { } cfg := consul.DefaultConfig() cfg.Address = l.Addr().String() - cl, _ := consul.NewClient(cfg) go newMockServer(r, l) - return &consulRegistry{ - Address: cfg.Address, - Client: cl, - opts: registry.Options{}, - register: make(map[string]uint64), - lastChecked: make(map[string]time.Time), - queryOptions: &consul.QueryOptions{ - AllowStale: true, - }, - }, func() { - l.Close() - } + var cr = &consulRegistry{ + config: cfg, + Address: []string{cfg.Address}, + opts: registry.Options{}, + register: make(map[string]uint64), + lastChecked: make(map[string]time.Time), + queryOptions: &consul.QueryOptions{ + AllowStale: true, + }, + } + cr.Client() + + return cr, func() { + l.Close() + } } func newServiceList(svc []*consul.ServiceEntry) []byte { diff --git a/registry/consul/watcher.go b/registry/consul/watcher.go index 03140355..031d02b7 100644 --- a/registry/consul/watcher.go +++ b/registry/consul/watcher.go @@ -45,7 +45,7 @@ func newConsulWatcher(cr *consulRegistry, opts ...registry.WatchOption) (registr } wp.Handler = cw.handle - go wp.RunWithClientAndLogger(cr.Client, log.New(os.Stderr, "", log.LstdFlags)) + go wp.RunWithClientAndLogger(cr.Client(), log.New(os.Stderr, "", log.LstdFlags)) cw.wp = wp return cw, nil @@ -209,7 +209,7 @@ func (cw *consulWatcher) handle(idx uint64, data interface{}) { }) if err == nil { wp.Handler = cw.serviceHandler - go wp.RunWithClientAndLogger(cw.r.Client, log.New(os.Stderr, "", log.LstdFlags)) + go wp.RunWithClientAndLogger(cw.r.Client(), log.New(os.Stderr, "", log.LstdFlags)) cw.watchers[service] = wp cw.next <- ®istry.Result{Action: "create", Service: ®istry.Service{Name: service}} } From 000431f489b1d348e6f1c8497456c0e342f8fbee Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 6 Aug 2019 09:15:54 +0100 Subject: [PATCH 261/287] Nats addr fix https://github.com/micro/go-micro/pull/648 --- util/net/net.go | 6 ++++++ util/net/net_test.go | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/util/net/net.go b/util/net/net.go index 7f0f4643..678e2568 100644 --- a/util/net/net.go +++ b/util/net/net.go @@ -14,6 +14,12 @@ func HostPort(addr string, port interface{}) string { if strings.Count(addr, ":") > 0 { host = fmt.Sprintf("[%s]", addr) } + // TODO check for NATS case + if v, ok := port.(string); ok { + if v == "" { + return fmt.Sprintf("%s", host) + } + } return fmt.Sprintf("%s:%v", host, port) } diff --git a/util/net/net_test.go b/util/net/net_test.go index a9fca743..d8516d88 100644 --- a/util/net/net_test.go +++ b/util/net/net_test.go @@ -18,4 +18,9 @@ func TestListen(t *testing.T) { } defer l.Close() } + + // TODO nats case test + // natsAddr := "_INBOX.bID2CMRvlNp0vt4tgNBHWf" + // Expect addr DO NOT has extra ":" at the end! + } From 4074cce397b5285d6bb7a2070f0fe47d29e2cf62 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Tue, 6 Aug 2019 11:45:25 +0100 Subject: [PATCH 262/287] Rough outline of tunnel types --- tunnel/default.go | 24 +++++++++++++++------ tunnel/socket.go | 25 ++++++++++++++++++++++ tunnel/transport.go | 51 +++++++++++++++++++++++++++++++++++++++++++++ tunnel/tunnel.go | 4 +++- 4 files changed, 97 insertions(+), 7 deletions(-) create mode 100644 tunnel/socket.go create mode 100644 tunnel/transport.go diff --git a/tunnel/default.go b/tunnel/default.go index 127785d3..d0eecf51 100644 --- a/tunnel/default.go +++ b/tunnel/default.go @@ -7,8 +7,9 @@ import ( ) type tun struct { - options Options sync.RWMutex + tr transport.Transport + options Options connected bool closed chan bool } @@ -21,7 +22,11 @@ func newTunnel(opts ...Option) Tunnel { o(&options) } + // tunnel transport + tr := newTransport() + t := &tun{ + tr: tr, options: options, closed: make(chan bool), } @@ -29,30 +34,37 @@ func newTunnel(opts ...Option) Tunnel { return t } +// Id returns tunnel id func (t *tun) Id() string { return t.options.Id } +// Options returns tunnel options +func (t *tun) Options() Options { + return t.options +} + +// Address returns tunnel listen address func (t *tun) Address() string { return t.options.Address } +// Transport returns tunnel client transport func (t *tun) Transport() transport.Transport { - return nil -} - -func (t *tun) Options() transport.Options { - return transport.Options{} + return t.tr } +// Connect connects establishes point to point tunnel func (t *tun) Connect() error { return nil } +// Close closes the tunnel func (t *tun) Close() error { return nil } +// Status returns tunnel status func (t *tun) Status() Status { select { case <-t.closed: diff --git a/tunnel/socket.go b/tunnel/socket.go new file mode 100644 index 00000000..ad98287f --- /dev/null +++ b/tunnel/socket.go @@ -0,0 +1,25 @@ +package tunnel + +import "github.com/micro/go-micro/transport" + +type tunSocket struct{} + +func (s *tunSocket) Recv(m *transport.Message) error { + return nil +} + +func (s *tunSocket) Send(m *transport.Message) error { + return nil +} + +func (s *tunSocket) Close() error { + return nil +} + +func (s *tunSocket) Local() string { + return "" +} + +func (s *tunSocket) Remote() string { + return "" +} diff --git a/tunnel/transport.go b/tunnel/transport.go new file mode 100644 index 00000000..fc03398a --- /dev/null +++ b/tunnel/transport.go @@ -0,0 +1,51 @@ +package tunnel + +import "github.com/micro/go-micro/transport" + +type tunTransport struct { + options transport.Options +} + +type tunClient struct { + *tunSocket + options transport.DialOptions +} + +type tunListener struct { + conn chan *tunSocket +} + +func newTransport(opts ...transport.Option) transport.Transport { + var options transport.Options + + for _, o := range opts { + o(&options) + } + + return &tunTransport{ + options: options, + } +} + +func (t *tunTransport) Init(opts ...transport.Option) error { + for _, o := range opts { + o(&t.options) + } + return nil +} + +func (t *tunTransport) Options() transport.Options { + return t.options +} + +func (t *tunTransport) Dial(addr string, opts ...transport.DialOption) (transport.Client, error) { + return nil, nil +} + +func (t *tunTransport) Listen(addr string, opts ...transport.ListenOption) (transport.Listener, error) { + return nil, nil +} + +func (t *tunTransport) String() string { + return "micro" +} diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 2adc4447..55bcd809 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -19,9 +19,11 @@ const ( type Tunnel interface { // Id returns tunnel id Id() string + // Options returns the tunnel options + Options() Options // Address returns tunnel address Address() string - // Tramsport returns tunnel transport + // Transport to use by tunne clients Transport() transport.Transport // Connect connects the tunnel Connect() error From beffa625f89378b75b6ba9b5f01704172793ec2f Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 6 Aug 2019 12:25:51 +0100 Subject: [PATCH 263/287] fix broker log line --- server/grpc/grpc.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/grpc/grpc.go b/server/grpc/grpc.go index f92048f1..de283043 100644 --- a/server/grpc/grpc.go +++ b/server/grpc/grpc.go @@ -719,10 +719,10 @@ func (g *grpcServer) Start() error { return err } - baddr := strings.Join(config.Broker.Options().Addrs, ",") + baddr := config.Broker.Address() bname := config.Broker.String() - log.Logf("Broker [%s] Listening on %s", bname, baddr) + log.Logf("Broker [%s] Connected to %s", bname, baddr) // announce self to the world if err := g.Register(); err != nil { From c3ea25225c9bbfc91c7e8ae05a88569617715a97 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 6 Aug 2019 14:49:42 +0100 Subject: [PATCH 264/287] Don't check value name on extraction --- server/extractor.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/server/extractor.go b/server/extractor.go index 0a4297e4..636f20ed 100644 --- a/server/extractor.go +++ b/server/extractor.go @@ -20,10 +20,6 @@ func extractValue(v reflect.Type, d int) *registry.Value { v = v.Elem() } - if len(v.Name()) == 0 { - return nil - } - arg := ®istry.Value{ Name: v.Name(), Type: v.Name(), From bb01b3ed7806f4c114dcb175d6e46db5085989ea Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 6 Aug 2019 14:52:15 +0100 Subject: [PATCH 265/287] Don't extract repeated value --- server/extractor.go | 4 ---- server/grpc/extractor.go | 4 ---- 2 files changed, 8 deletions(-) diff --git a/server/extractor.go b/server/extractor.go index 636f20ed..52ce0056 100644 --- a/server/extractor.go +++ b/server/extractor.go @@ -61,10 +61,6 @@ func extractValue(v reflect.Type, d int) *registry.Value { p = p.Elem() } arg.Type = "[]" + p.Name() - val := extractValue(v.Elem(), d+1) - if val != nil { - arg.Values = append(arg.Values, val) - } } return arg diff --git a/server/grpc/extractor.go b/server/grpc/extractor.go index 89c00ce9..753cc175 100644 --- a/server/grpc/extractor.go +++ b/server/grpc/extractor.go @@ -56,10 +56,6 @@ func extractValue(v reflect.Type, d int) *registry.Value { p = p.Elem() } arg.Type = "[]" + p.Name() - val := extractValue(v.Elem(), d+1) - if val != nil { - arg.Values = append(arg.Values, val) - } } return arg From 3adce58eb2d572cd6cd9d5f21969cd3601046b04 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 6 Aug 2019 17:53:14 +0100 Subject: [PATCH 266/287] Add monitor/debug packages --- debug/handler/debug.go | 41 +++ debug/proto/debug.micro.go | 108 +++++++ debug/proto/debug.pb.go | 336 ++++++++++++++++++++++ {server/debug => debug}/proto/debug.proto | 12 +- function_test.go | 2 +- monitor/default.go | 213 ++++++++++++++ monitor/default_test.go | 19 ++ monitor/monitor.go | 39 +++ monitor/options.go | 25 ++ server/debug.go | 9 - server/debug/debug.go | 55 ---- server/debug/proto/debug.pb.go | 100 ------- server/grpc/debug.go | 10 - server/grpc/grpc.go | 1 - server/grpc/options.go | 5 - server/options.go | 15 - server/rpc_server.go | 1 - service.go | 9 + service/options.go | 220 ++++++++++++++ service/service.go | 14 + service_test.go | 2 +- 21 files changed, 1030 insertions(+), 206 deletions(-) create mode 100644 debug/handler/debug.go create mode 100644 debug/proto/debug.micro.go create mode 100644 debug/proto/debug.pb.go rename {server/debug => debug}/proto/debug.proto (59%) create mode 100644 monitor/default.go create mode 100644 monitor/default_test.go create mode 100644 monitor/monitor.go create mode 100644 monitor/options.go delete mode 100644 server/debug.go delete mode 100644 server/debug/debug.go delete mode 100644 server/debug/proto/debug.pb.go delete mode 100644 server/grpc/debug.go create mode 100644 service/options.go diff --git a/debug/handler/debug.go b/debug/handler/debug.go new file mode 100644 index 00000000..973a6fc4 --- /dev/null +++ b/debug/handler/debug.go @@ -0,0 +1,41 @@ +package handler + +import ( + "context" + "runtime" + "time" + + proto "github.com/micro/go-micro/debug/proto" +) + +type Debug struct { + proto.DebugHandler + started int64 +} + +var ( + DefaultHandler = newDebug() +) + +func newDebug() *Debug { + return &Debug{ + started: time.Now().Unix(), + } +} + +func (d *Debug) Health(ctx context.Context, req *proto.HealthRequest, rsp *proto.HealthResponse) error { + rsp.Status = "ok" + return nil +} + +func (d *Debug) Stats(ctx context.Context, req *proto.StatsRequest, rsp *proto.StatsResponse) error { + var mstat runtime.MemStats + runtime.ReadMemStats(&mstat) + + rsp.Started = uint64(d.started) + rsp.Uptime = uint64(time.Now().Unix() - d.started) + rsp.Memory = mstat.Alloc + rsp.Gc = mstat.PauseTotalNs + rsp.Threads = uint64(runtime.NumGoroutine()) + return nil +} diff --git a/debug/proto/debug.micro.go b/debug/proto/debug.micro.go new file mode 100644 index 00000000..baa06cee --- /dev/null +++ b/debug/proto/debug.micro.go @@ -0,0 +1,108 @@ +// Code generated by protoc-gen-micro. DO NOT EDIT. +// source: micro/go-micro/debug/proto/debug.proto + +package debug + +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" +) + +import ( + context "context" + client "github.com/micro/go-micro/client" + server "github.com/micro/go-micro/server" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ client.Option +var _ server.Option + +// Client API for Debug service + +type DebugService interface { + Health(ctx context.Context, in *HealthRequest, opts ...client.CallOption) (*HealthResponse, error) + Stats(ctx context.Context, in *StatsRequest, opts ...client.CallOption) (*StatsResponse, error) +} + +type debugService struct { + c client.Client + name string +} + +func NewDebugService(name string, c client.Client) DebugService { + if c == nil { + c = client.NewClient() + } + if len(name) == 0 { + name = "debug" + } + return &debugService{ + c: c, + name: name, + } +} + +func (c *debugService) Health(ctx context.Context, in *HealthRequest, opts ...client.CallOption) (*HealthResponse, error) { + req := c.c.NewRequest(c.name, "Debug.Health", in) + out := new(HealthResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *debugService) Stats(ctx context.Context, in *StatsRequest, opts ...client.CallOption) (*StatsResponse, error) { + req := c.c.NewRequest(c.name, "Debug.Stats", in) + out := new(StatsResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for Debug service + +type DebugHandler interface { + Health(context.Context, *HealthRequest, *HealthResponse) error + Stats(context.Context, *StatsRequest, *StatsResponse) error +} + +func RegisterDebugHandler(s server.Server, hdlr DebugHandler, opts ...server.HandlerOption) error { + type debug interface { + Health(ctx context.Context, in *HealthRequest, out *HealthResponse) error + Stats(ctx context.Context, in *StatsRequest, out *StatsResponse) error + } + type Debug struct { + debug + } + h := &debugHandler{hdlr} + return s.Handle(s.NewHandler(&Debug{h}, opts...)) +} + +type debugHandler struct { + DebugHandler +} + +func (h *debugHandler) Health(ctx context.Context, in *HealthRequest, out *HealthResponse) error { + return h.DebugHandler.Health(ctx, in, out) +} + +func (h *debugHandler) Stats(ctx context.Context, in *StatsRequest, out *StatsResponse) error { + return h.DebugHandler.Stats(ctx, in, out) +} diff --git a/debug/proto/debug.pb.go b/debug/proto/debug.pb.go new file mode 100644 index 00000000..5ba4f8c9 --- /dev/null +++ b/debug/proto/debug.pb.go @@ -0,0 +1,336 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: micro/go-micro/debug/proto/debug.proto + +package debug + +import ( + context "context" + fmt "fmt" + proto "github.com/golang/protobuf/proto" + grpc "google.golang.org/grpc" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +type HealthRequest struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *HealthRequest) Reset() { *m = HealthRequest{} } +func (m *HealthRequest) String() string { return proto.CompactTextString(m) } +func (*HealthRequest) ProtoMessage() {} +func (*HealthRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_f25415e61bccfa1f, []int{0} +} + +func (m *HealthRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_HealthRequest.Unmarshal(m, b) +} +func (m *HealthRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_HealthRequest.Marshal(b, m, deterministic) +} +func (m *HealthRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_HealthRequest.Merge(m, src) +} +func (m *HealthRequest) XXX_Size() int { + return xxx_messageInfo_HealthRequest.Size(m) +} +func (m *HealthRequest) XXX_DiscardUnknown() { + xxx_messageInfo_HealthRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_HealthRequest proto.InternalMessageInfo + +type HealthResponse struct { + // default: ok + Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *HealthResponse) Reset() { *m = HealthResponse{} } +func (m *HealthResponse) String() string { return proto.CompactTextString(m) } +func (*HealthResponse) ProtoMessage() {} +func (*HealthResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_f25415e61bccfa1f, []int{1} +} + +func (m *HealthResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_HealthResponse.Unmarshal(m, b) +} +func (m *HealthResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_HealthResponse.Marshal(b, m, deterministic) +} +func (m *HealthResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_HealthResponse.Merge(m, src) +} +func (m *HealthResponse) XXX_Size() int { + return xxx_messageInfo_HealthResponse.Size(m) +} +func (m *HealthResponse) XXX_DiscardUnknown() { + xxx_messageInfo_HealthResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_HealthResponse proto.InternalMessageInfo + +func (m *HealthResponse) GetStatus() string { + if m != nil { + return m.Status + } + return "" +} + +type StatsRequest struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StatsRequest) Reset() { *m = StatsRequest{} } +func (m *StatsRequest) String() string { return proto.CompactTextString(m) } +func (*StatsRequest) ProtoMessage() {} +func (*StatsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_f25415e61bccfa1f, []int{2} +} + +func (m *StatsRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StatsRequest.Unmarshal(m, b) +} +func (m *StatsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StatsRequest.Marshal(b, m, deterministic) +} +func (m *StatsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_StatsRequest.Merge(m, src) +} +func (m *StatsRequest) XXX_Size() int { + return xxx_messageInfo_StatsRequest.Size(m) +} +func (m *StatsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_StatsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_StatsRequest proto.InternalMessageInfo + +type StatsResponse struct { + // unix timestamp + Started uint64 `protobuf:"varint,1,opt,name=started,proto3" json:"started,omitempty"` + // in seconds + Uptime uint64 `protobuf:"varint,2,opt,name=uptime,proto3" json:"uptime,omitempty"` + // in bytes + Memory uint64 `protobuf:"varint,3,opt,name=memory,proto3" json:"memory,omitempty"` + // num threads + Threads uint64 `protobuf:"varint,4,opt,name=threads,proto3" json:"threads,omitempty"` + // total gc in nanoseconds + Gc uint64 `protobuf:"varint,5,opt,name=gc,proto3" json:"gc,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StatsResponse) Reset() { *m = StatsResponse{} } +func (m *StatsResponse) String() string { return proto.CompactTextString(m) } +func (*StatsResponse) ProtoMessage() {} +func (*StatsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_f25415e61bccfa1f, []int{3} +} + +func (m *StatsResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StatsResponse.Unmarshal(m, b) +} +func (m *StatsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StatsResponse.Marshal(b, m, deterministic) +} +func (m *StatsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_StatsResponse.Merge(m, src) +} +func (m *StatsResponse) XXX_Size() int { + return xxx_messageInfo_StatsResponse.Size(m) +} +func (m *StatsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_StatsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_StatsResponse proto.InternalMessageInfo + +func (m *StatsResponse) GetStarted() uint64 { + if m != nil { + return m.Started + } + return 0 +} + +func (m *StatsResponse) GetUptime() uint64 { + if m != nil { + return m.Uptime + } + return 0 +} + +func (m *StatsResponse) GetMemory() uint64 { + if m != nil { + return m.Memory + } + return 0 +} + +func (m *StatsResponse) GetThreads() uint64 { + if m != nil { + return m.Threads + } + return 0 +} + +func (m *StatsResponse) GetGc() uint64 { + if m != nil { + return m.Gc + } + return 0 +} + +func init() { + proto.RegisterType((*HealthRequest)(nil), "HealthRequest") + proto.RegisterType((*HealthResponse)(nil), "HealthResponse") + proto.RegisterType((*StatsRequest)(nil), "StatsRequest") + proto.RegisterType((*StatsResponse)(nil), "StatsResponse") +} + +func init() { + proto.RegisterFile("micro/go-micro/debug/proto/debug.proto", fileDescriptor_f25415e61bccfa1f) +} + +var fileDescriptor_f25415e61bccfa1f = []byte{ + // 230 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x90, 0x41, 0x4b, 0xc4, 0x30, + 0x10, 0x85, 0xb7, 0x75, 0x5b, 0x71, 0xb0, 0x59, 0xc8, 0x41, 0xc2, 0x9e, 0x24, 0x07, 0x29, 0x88, + 0x59, 0xd0, 0xbf, 0xe0, 0xc1, 0x73, 0xbd, 0x0b, 0xd9, 0x76, 0xe8, 0x16, 0xac, 0xa9, 0x99, 0xe9, + 0xc1, 0xb3, 0x7f, 0x5c, 0x9a, 0xa4, 0x60, 0x6f, 0xef, 0xbd, 0xf0, 0x1e, 0xf9, 0x06, 0x1e, 0xc6, + 0xa1, 0xf5, 0xee, 0xd4, 0xbb, 0xa7, 0x28, 0x3a, 0x3c, 0xcf, 0xfd, 0x69, 0xf2, 0x8e, 0x93, 0x36, + 0x41, 0xeb, 0x03, 0x54, 0x6f, 0x68, 0x3f, 0xf9, 0xd2, 0xe0, 0xf7, 0x8c, 0xc4, 0xba, 0x06, 0xb1, + 0x06, 0x34, 0xb9, 0x2f, 0x42, 0x79, 0x07, 0x25, 0xb1, 0xe5, 0x99, 0x54, 0x76, 0x9f, 0xd5, 0x37, + 0x4d, 0x72, 0x5a, 0xc0, 0xed, 0x3b, 0x5b, 0xa6, 0xb5, 0xf9, 0x9b, 0x41, 0x95, 0x82, 0xd4, 0x54, + 0x70, 0x4d, 0x6c, 0x3d, 0x63, 0x17, 0xaa, 0xfb, 0x66, 0xb5, 0xcb, 0xe6, 0x3c, 0xf1, 0x30, 0xa2, + 0xca, 0xc3, 0x43, 0x72, 0x4b, 0x3e, 0xe2, 0xe8, 0xfc, 0x8f, 0xba, 0x8a, 0x79, 0x74, 0xcb, 0x12, + 0x5f, 0x3c, 0xda, 0x8e, 0xd4, 0x3e, 0x2e, 0x25, 0x2b, 0x05, 0xe4, 0x7d, 0xab, 0x8a, 0x10, 0xe6, + 0x7d, 0xfb, 0xfc, 0x01, 0xc5, 0xeb, 0xc2, 0x27, 0x1f, 0xa1, 0x8c, 0x20, 0x52, 0x98, 0x0d, 0xe2, + 0xf1, 0x60, 0xb6, 0x84, 0x7a, 0x27, 0x6b, 0x28, 0xc2, 0xd7, 0x65, 0x65, 0xfe, 0x33, 0x1d, 0x85, + 0xd9, 0x10, 0xe9, 0xdd, 0xb9, 0x0c, 0x77, 0x7b, 0xf9, 0x0b, 0x00, 0x00, 0xff, 0xff, 0xfe, 0xb9, + 0x5f, 0xf7, 0x61, 0x01, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// DebugClient is the client API for Debug service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type DebugClient interface { + Health(ctx context.Context, in *HealthRequest, opts ...grpc.CallOption) (*HealthResponse, error) + Stats(ctx context.Context, in *StatsRequest, opts ...grpc.CallOption) (*StatsResponse, error) +} + +type debugClient struct { + cc *grpc.ClientConn +} + +func NewDebugClient(cc *grpc.ClientConn) DebugClient { + return &debugClient{cc} +} + +func (c *debugClient) Health(ctx context.Context, in *HealthRequest, opts ...grpc.CallOption) (*HealthResponse, error) { + out := new(HealthResponse) + err := c.cc.Invoke(ctx, "/Debug/Health", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *debugClient) Stats(ctx context.Context, in *StatsRequest, opts ...grpc.CallOption) (*StatsResponse, error) { + out := new(StatsResponse) + err := c.cc.Invoke(ctx, "/Debug/Stats", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// DebugServer is the server API for Debug service. +type DebugServer interface { + Health(context.Context, *HealthRequest) (*HealthResponse, error) + Stats(context.Context, *StatsRequest) (*StatsResponse, error) +} + +func RegisterDebugServer(s *grpc.Server, srv DebugServer) { + s.RegisterService(&_Debug_serviceDesc, srv) +} + +func _Debug_Health_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(HealthRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DebugServer).Health(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/Debug/Health", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DebugServer).Health(ctx, req.(*HealthRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Debug_Stats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StatsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DebugServer).Stats(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/Debug/Stats", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DebugServer).Stats(ctx, req.(*StatsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Debug_serviceDesc = grpc.ServiceDesc{ + ServiceName: "Debug", + HandlerType: (*DebugServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Health", + Handler: _Debug_Health_Handler, + }, + { + MethodName: "Stats", + Handler: _Debug_Stats_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "micro/go-micro/debug/proto/debug.proto", +} diff --git a/server/debug/proto/debug.proto b/debug/proto/debug.proto similarity index 59% rename from server/debug/proto/debug.proto rename to debug/proto/debug.proto index 8d96192e..b642cd41 100644 --- a/server/debug/proto/debug.proto +++ b/debug/proto/debug.proto @@ -1,13 +1,9 @@ syntax = "proto3"; -// This is commented out due to import cycles. -// But its what we expect the RPC service to -// return. -// -// service Debug { -// rpc Health(HealthRequest) returns (HealthResponse) {} -// rpc Stats(StatsRequest) returns (StatsResponse) {} -// } +service Debug { + rpc Health(HealthRequest) returns (HealthResponse) {} + rpc Stats(StatsRequest) returns (StatsResponse) {} +} message HealthRequest { } diff --git a/function_test.go b/function_test.go index dd85590f..a7d1b18d 100644 --- a/function_test.go +++ b/function_test.go @@ -5,8 +5,8 @@ import ( "sync" "testing" + proto "github.com/micro/go-micro/debug/proto" "github.com/micro/go-micro/registry/memory" - proto "github.com/micro/go-micro/server/debug/proto" ) func TestFunction(t *testing.T) { diff --git a/monitor/default.go b/monitor/default.go new file mode 100644 index 00000000..307ec36e --- /dev/null +++ b/monitor/default.go @@ -0,0 +1,213 @@ +package monitor + +import ( + "context" + "errors" + "sync" + "time" + + "github.com/micro/go-micro/client" + pb "github.com/micro/go-micro/debug/proto" + "github.com/micro/go-micro/registry" + "github.com/micro/go-micro/registry/cache" +) + +type monitor struct { + options Options + + exit chan bool + registry cache.Cache + client client.Client + + sync.RWMutex + services map[string]*Status +} + +// check provides binary running/failed status. +// In the event Debug.Health cannot be called on a service we reap the node. +func (m *monitor) check(service string) (*Status, error) { + services, err := m.registry.GetService(service) + if err != nil { + return nil, err + } + + // create debug client + debug := pb.NewDebugService(service, m.client) + + var status *Status + var gerr error + + // iterate through multiple versions of a service + for _, service := range services { + for _, node := range service.Nodes { + rsp, err := debug.Health( + context.Background(), + // empty health request + &pb.HealthRequest{}, + // call this specific node + client.WithAddress(node.Address), + // retry in the event of failure + client.WithRetries(3), + ) + if err != nil { + // reap the dead node + m.registry.Deregister(®istry.Service{ + Name: service.Name, + Version: service.Version, + Nodes: []*registry.Node{node}, + }) + + // save the error + gerr = err + continue + } + + // expecting ok response status + if rsp.Status != "ok" { + gerr = errors.New(rsp.Status) + continue + } + + // no error set status + status = &Status{ + Code: StatusRunning, + Info: "running", + } + } + } + + // if we got the success case return it + if status != nil { + return status, nil + } + + // if gerr is not nil return it + if gerr != nil { + return &Status{ + Code: StatusFailed, + Info: "not running", + Error: gerr.Error(), + }, nil + } + + // otherwise unknown status + return &Status{ + Code: StatusUnknown, + Info: "unknown status", + }, nil +} + +func (m *monitor) Status(service string) (Status, error) { + m.RLock() + defer m.RUnlock() + if status, ok := m.services[service]; ok { + return *status, nil + } + return Status{}, ErrNotWatching +} + +func (m *monitor) Watch(service string) error { + m.Lock() + defer m.Unlock() + + // check if we're watching + if _, ok := m.services[service]; ok { + return nil + } + + // get the status + status, err := m.check(service) + if err != nil { + return err + } + + // set the status + m.services[service] = status + return nil +} + +func (m *monitor) Stop() error { + m.Lock() + defer m.RUnlock() + + select { + case <-m.exit: + return nil + default: + close(m.exit) + for s, _ := range m.services { + delete(m.services, s) + } + m.registry.Stop() + return nil + } + + return nil +} + +func (m *monitor) run() { + // check the status every tick + t := time.NewTicker(time.Minute) + defer t.Stop() + + check := make(chan string) + + for { + select { + case <-m.exit: + return + case service := <-check: + // check the status + status, err := m.check(service) + if err != nil { + status = &Status{ + Code: StatusUnknown, + Info: "unknown status", + } + } + + // save the status + m.Lock() + m.services[service] = status + m.Unlock() + case <-t.C: + // create a list of services + var services []string + m.RLock() + for service, _ := range m.services { + services = append(services, service) + } + m.RUnlock() + + // check the status of all watched services + for _, service := range services { + select { + case <-m.exit: + return + case check <- service: + } + } + } + } +} + +func newMonitor(opts ...Option) Monitor { + options := Options{ + Client: client.DefaultClient, + Registry: registry.DefaultRegistry, + } + + for _, o := range opts { + o(&options) + } + + m := &monitor{ + options: options, + client: options.Client, + registry: cache.New(options.Registry), + services: make(map[string]*Status), + } + + go m.run() + return m +} diff --git a/monitor/default_test.go b/monitor/default_test.go new file mode 100644 index 00000000..6910cdac --- /dev/null +++ b/monitor/default_test.go @@ -0,0 +1,19 @@ +package monitor + +import ( + "testing" +) + +func TestMonitor(t *testing.T) { + // create new monitor + m := NewMonitor() + + services := []string{"foo", "bar", "baz"} + + for _, service := range services { + _, err := m.Status(service) + if err != nil { + t.Fatal("expected status error for unknown service") + } + } +} diff --git a/monitor/monitor.go b/monitor/monitor.go new file mode 100644 index 00000000..41fd17cd --- /dev/null +++ b/monitor/monitor.go @@ -0,0 +1,39 @@ +// Package monitor monitors service health +package monitor + +import ( + "errors" +) + +const ( + StatusUnknown StatusCode = iota + StatusRunning + StatusFailed +) + +type StatusCode int + +// Monitor monitors a service and reaps dead instances +type Monitor interface { + // Status of the service + Status(service string) (Status, error) + // Watch starts watching the service + Watch(service string) error + // Stop monitoring + Stop() error +} + +type Status struct { + Code StatusCode + Info string + Error string +} + +var ( + ErrNotWatching = errors.New("not watching") +) + +// NewMonitor returns a new monitor +func NewMonitor(opts ...Option) Monitor { + return newMonitor(opts...) +} diff --git a/monitor/options.go b/monitor/options.go new file mode 100644 index 00000000..445d39d9 --- /dev/null +++ b/monitor/options.go @@ -0,0 +1,25 @@ +package monitor + +import ( + "github.com/micro/go-micro/client" + "github.com/micro/go-micro/registry" +) + +type Options struct { + Client client.Client + Registry registry.Registry +} + +type Option func(*Options) + +func Client(c client.Client) Option { + return func(o *Options) { + o.Client = c + } +} + +func Registry(r registry.Registry) Option { + return func(o *Options) { + o.Registry = r + } +} diff --git a/server/debug.go b/server/debug.go deleted file mode 100644 index 72cc88a7..00000000 --- a/server/debug.go +++ /dev/null @@ -1,9 +0,0 @@ -package server - -import ( - "github.com/micro/go-micro/server/debug" -) - -func registerDebugHandler(s Server) { - s.Handle(s.NewHandler(&debug.Debug{s.Options().DebugHandler}, InternalHandler(true))) -} diff --git a/server/debug/debug.go b/server/debug/debug.go deleted file mode 100644 index dc2fa8c7..00000000 --- a/server/debug/debug.go +++ /dev/null @@ -1,55 +0,0 @@ -package debug - -import ( - "context" - "runtime" - "time" - - proto "github.com/micro/go-micro/server/debug/proto" -) - -// The debug handler represents an internal server handler -// used to determine health, status and env info about -// a service node. It's akin to Google's /statusz, /healthz, -// and /varz -type Handler interface { - Health(ctx context.Context, req *proto.HealthRequest, rsp *proto.HealthResponse) error - Stats(ctx context.Context, req *proto.StatsRequest, rsp *proto.StatsResponse) error -} - -// Our own internal handler -type debug struct { - started int64 -} - -// We use this to wrap any debug handlers so we preserve the signature Debug.{Method} -type Debug struct { - Handler -} - -var ( - DefaultHandler Handler = newDebug() -) - -func newDebug() *debug { - return &debug{ - started: time.Now().Unix(), - } -} - -func (d *debug) Health(ctx context.Context, req *proto.HealthRequest, rsp *proto.HealthResponse) error { - rsp.Status = "ok" - return nil -} - -func (d *debug) Stats(ctx context.Context, req *proto.StatsRequest, rsp *proto.StatsResponse) error { - var mstat runtime.MemStats - runtime.ReadMemStats(&mstat) - - rsp.Started = uint64(d.started) - rsp.Uptime = uint64(time.Now().Unix() - d.started) - rsp.Memory = mstat.Alloc - rsp.Gc = mstat.PauseTotalNs - rsp.Threads = uint64(runtime.NumGoroutine()) - return nil -} diff --git a/server/debug/proto/debug.pb.go b/server/debug/proto/debug.pb.go deleted file mode 100644 index 7cfa7d5e..00000000 --- a/server/debug/proto/debug.pb.go +++ /dev/null @@ -1,100 +0,0 @@ -// Code generated by protoc-gen-go. -// source: github.com/micro/go-micro/server/debug/proto/debug.proto -// DO NOT EDIT! - -/* -Package debug is a generated protocol buffer package. - -It is generated from these files: - github.com/micro/go-micro/server/debug/proto/debug.proto - -It has these top-level messages: - HealthRequest - HealthResponse - StatsRequest - StatsResponse -*/ -package debug - -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package - -type HealthRequest struct { -} - -func (m *HealthRequest) Reset() { *m = HealthRequest{} } -func (m *HealthRequest) String() string { return proto.CompactTextString(m) } -func (*HealthRequest) ProtoMessage() {} -func (*HealthRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } - -type HealthResponse struct { - // default: ok - Status string `protobuf:"bytes,1,opt,name=status" json:"status,omitempty"` -} - -func (m *HealthResponse) Reset() { *m = HealthResponse{} } -func (m *HealthResponse) String() string { return proto.CompactTextString(m) } -func (*HealthResponse) ProtoMessage() {} -func (*HealthResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } - -type StatsRequest struct { -} - -func (m *StatsRequest) Reset() { *m = StatsRequest{} } -func (m *StatsRequest) String() string { return proto.CompactTextString(m) } -func (*StatsRequest) ProtoMessage() {} -func (*StatsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } - -type StatsResponse struct { - // unix timestamp - Started uint64 `protobuf:"varint,1,opt,name=started" json:"started,omitempty"` - // in seconds - Uptime uint64 `protobuf:"varint,2,opt,name=uptime" json:"uptime,omitempty"` - // in bytes - Memory uint64 `protobuf:"varint,3,opt,name=memory" json:"memory,omitempty"` - // num threads - Threads uint64 `protobuf:"varint,4,opt,name=threads" json:"threads,omitempty"` - // in nanoseconds - Gc uint64 `protobuf:"varint,5,opt,name=gc" json:"gc,omitempty"` -} - -func (m *StatsResponse) Reset() { *m = StatsResponse{} } -func (m *StatsResponse) String() string { return proto.CompactTextString(m) } -func (*StatsResponse) ProtoMessage() {} -func (*StatsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } - -func init() { - proto.RegisterType((*HealthRequest)(nil), "HealthRequest") - proto.RegisterType((*HealthResponse)(nil), "HealthResponse") - proto.RegisterType((*StatsRequest)(nil), "StatsRequest") - proto.RegisterType((*StatsResponse)(nil), "StatsResponse") -} - -var fileDescriptor0 = []byte{ - // 201 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x34, 0x8f, 0xbd, 0x6e, 0x83, 0x30, - 0x14, 0x85, 0x05, 0xa5, 0x54, 0xbd, 0x2a, 0x54, 0x62, 0xa8, 0x3c, 0x56, 0x4c, 0x2c, 0xc5, 0x43, - 0x97, 0x3e, 0x42, 0x67, 0xf2, 0x04, 0xfc, 0x5c, 0x19, 0xa4, 0x38, 0x26, 0xbe, 0xd7, 0x91, 0x32, - 0xe7, 0xc5, 0x03, 0xb6, 0xd9, 0xce, 0xf7, 0xd9, 0xe7, 0x48, 0x17, 0xfe, 0xd4, 0xc2, 0xb3, 0x1b, - 0xda, 0xd1, 0x68, 0xa9, 0x97, 0xd1, 0x1a, 0xa9, 0xcc, 0x4f, 0x08, 0x84, 0xf6, 0x86, 0x56, 0x4e, - 0x38, 0x38, 0x25, 0x57, 0x6b, 0xd8, 0x84, 0xdc, 0xfa, 0x5c, 0x7f, 0x42, 0xf1, 0x8f, 0xfd, 0x99, - 0xe7, 0x0e, 0xaf, 0x0e, 0x89, 0xeb, 0x06, 0xca, 0x43, 0xd0, 0x6a, 0x2e, 0x84, 0xd5, 0x17, 0xe4, - 0xc4, 0x3d, 0x3b, 0x12, 0xc9, 0x77, 0xd2, 0xbc, 0x77, 0x91, 0xea, 0x12, 0x3e, 0x4e, 0x5b, 0xa2, - 0xa3, 0xf9, 0x48, 0xa0, 0x88, 0x22, 0x36, 0x05, 0xbc, 0x6d, 0x7f, 0x2d, 0xe3, 0xe4, 0xab, 0x59, - 0x77, 0xe0, 0xbe, 0xe9, 0x56, 0x5e, 0x34, 0x8a, 0xd4, 0x3f, 0x44, 0xda, 0xbd, 0x46, 0x6d, 0xec, - 0x5d, 0xbc, 0x04, 0x1f, 0x68, 0x5f, 0xe2, 0xd9, 0x62, 0x3f, 0x91, 0xc8, 0xc2, 0x52, 0xc4, 0xaa, - 0x84, 0x54, 0x8d, 0xe2, 0xd5, 0xcb, 0x2d, 0x0d, 0xb9, 0xbf, 0xeb, 0xf7, 0x19, 0x00, 0x00, 0xff, - 0xff, 0xc6, 0x75, 0x51, 0x35, 0x13, 0x01, 0x00, 0x00, -} diff --git a/server/grpc/debug.go b/server/grpc/debug.go deleted file mode 100644 index 782b8b1e..00000000 --- a/server/grpc/debug.go +++ /dev/null @@ -1,10 +0,0 @@ -package grpc - -import ( - "github.com/micro/go-micro/server" - "github.com/micro/go-micro/server/debug" -) - -func registerDebugHandler(s server.Server) { - s.Handle(s.NewHandler(&debug.Debug{s.Options().DebugHandler}, server.InternalHandler(true))) -} diff --git a/server/grpc/grpc.go b/server/grpc/grpc.go index de283043..2aefc6f1 100644 --- a/server/grpc/grpc.go +++ b/server/grpc/grpc.go @@ -700,7 +700,6 @@ func (g *grpcServer) Deregister() error { } func (g *grpcServer) Start() error { - registerDebugHandler(g) config := g.opts // micro: config.Transport.Listen(config.Address) diff --git a/server/grpc/options.go b/server/grpc/options.go index 4a3bef1d..c57c022e 100644 --- a/server/grpc/options.go +++ b/server/grpc/options.go @@ -8,7 +8,6 @@ import ( "github.com/micro/go-micro/codec" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/server" - "github.com/micro/go-micro/server/debug" "github.com/micro/go-micro/transport" "google.golang.org/grpc" "google.golang.org/grpc/encoding" @@ -89,10 +88,6 @@ func newOptions(opt ...server.Option) server.Options { opts.Transport = transport.DefaultTransport } - if opts.DebugHandler == nil { - opts.DebugHandler = debug.DefaultHandler - } - if len(opts.Address) == 0 { opts.Address = server.DefaultAddress } diff --git a/server/options.go b/server/options.go index 0d0ee51f..c75ed4d1 100644 --- a/server/options.go +++ b/server/options.go @@ -8,7 +8,6 @@ import ( "github.com/micro/go-micro/broker" "github.com/micro/go-micro/codec" "github.com/micro/go-micro/registry" - "github.com/micro/go-micro/server/debug" "github.com/micro/go-micro/transport" ) @@ -36,9 +35,6 @@ type Options struct { // The router for requests Router Router - // Debug Handler which can be set by a user - DebugHandler debug.Handler - // Other options for implementations of the interface // can be stored in a context Context context.Context @@ -66,10 +62,6 @@ func newOptions(opt ...Option) Options { opts.Transport = transport.DefaultTransport } - if opts.DebugHandler == nil { - opts.DebugHandler = debug.DefaultHandler - } - if opts.RegisterCheck == nil { opts.RegisterCheck = DefaultRegisterCheck } @@ -156,13 +148,6 @@ func Transport(t transport.Transport) Option { } } -// DebugHandler for this server -func DebugHandler(d debug.Handler) Option { - return func(o *Options) { - o.DebugHandler = d - } -} - // Metadata associated with the server func Metadata(md map[string]string) Option { return func(o *Options) { diff --git a/server/rpc_server.go b/server/rpc_server.go index daa28faf..b68e6425 100644 --- a/server/rpc_server.go +++ b/server/rpc_server.go @@ -485,7 +485,6 @@ func (s *rpcServer) Deregister() error { } func (s *rpcServer) Start() error { - registerDebugHandler(s) config := s.Options() // start listening on the transport diff --git a/service.go b/service.go index 01c82e9c..e612a4b3 100644 --- a/service.go +++ b/service.go @@ -8,6 +8,7 @@ import ( "github.com/micro/go-micro/client" "github.com/micro/go-micro/config/cmd" + "github.com/micro/go-micro/debug/handler" "github.com/micro/go-micro/metadata" "github.com/micro/go-micro/server" ) @@ -113,6 +114,14 @@ func (s *service) Stop() error { } func (s *service) Run() error { + // register the debug handler + s.opts.Server.Handle( + s.opts.Server.NewHandler( + handler.DefaultHandler, + server.InternalHandler(true), + ), + ) + if err := s.Start(); err != nil { return err } diff --git a/service/options.go b/service/options.go new file mode 100644 index 00000000..9a077629 --- /dev/null +++ b/service/options.go @@ -0,0 +1,220 @@ +package service + +import ( + "context" + "time" + + "github.com/micro/go-micro/broker" + "github.com/micro/go-micro/client" + "github.com/micro/go-micro/registry" + "github.com/micro/go-micro/server" + "github.com/micro/go-micro/transport" +) + +type Options struct { + Broker broker.Broker + Client client.Client + Server server.Server + Registry registry.Registry + Transport transport.Transport + + // Before and After funcs + BeforeStart []func() error + BeforeStop []func() error + AfterStart []func() error + AfterStop []func() error + + // Other options for implementations of the interface + // can be stored in a context + Context context.Context +} + +type Option func(*Options) + +func newOptions(opts ...Option) Options { + opt := Options{ + Broker: broker.DefaultBroker, + Client: client.DefaultClient, + Server: server.DefaultServer, + Registry: registry.DefaultRegistry, + Transport: transport.DefaultTransport, + Context: context.Background(), + } + + for _, o := range opts { + o(&opt) + } + + return opt +} + +func Broker(b broker.Broker) Option { + return func(o *Options) { + o.Broker = b + // Update Client and Server + o.Client.Init(client.Broker(b)) + o.Server.Init(server.Broker(b)) + } +} + +func Client(c client.Client) Option { + return func(o *Options) { + o.Client = c + } +} + +// Context specifies a context for the service. +// Can be used to signal shutdown of the service. +// Can be used for extra option values. +func Context(ctx context.Context) Option { + return func(o *Options) { + o.Context = ctx + } +} + +func Server(s server.Server) Option { + return func(o *Options) { + o.Server = s + } +} + +// Registry sets the registry for the service +// and the underlying components +func Registry(r registry.Registry) Option { + return func(o *Options) { + o.Registry = r + // Update Client and Server + o.Client.Init(client.Registry(r)) + o.Server.Init(server.Registry(r)) + // Update Broker + o.Broker.Init(broker.Registry(r)) + } +} + +// Transport sets the transport for the service +// and the underlying components +func Transport(t transport.Transport) Option { + return func(o *Options) { + o.Transport = t + // Update Client and Server + o.Client.Init(client.Transport(t)) + o.Server.Init(server.Transport(t)) + } +} + +// Convenience options + +// Address sets the address of the server +func Address(addr string) Option { + return func(o *Options) { + o.Server.Init(server.Address(addr)) + } +} + +// Name of the service +func Name(n string) Option { + return func(o *Options) { + o.Server.Init(server.Name(n)) + } +} + +// Version of the service +func Version(v string) Option { + return func(o *Options) { + o.Server.Init(server.Version(v)) + } +} + +// Metadata associated with the service +func Metadata(md map[string]string) Option { + return func(o *Options) { + o.Server.Init(server.Metadata(md)) + } +} + +// RegisterTTL specifies the TTL to use when registering the service +func RegisterTTL(t time.Duration) Option { + return func(o *Options) { + o.Server.Init(server.RegisterTTL(t)) + } +} + +// RegisterInterval specifies the interval on which to re-register +func RegisterInterval(t time.Duration) Option { + return func(o *Options) { + o.Server.Init(server.RegisterInterval(t)) + } +} + +// WrapClient is a convenience method for wrapping a Client with +// some middleware component. A list of wrappers can be provided. +// Wrappers are applied in reverse order so the last is executed first. +func WrapClient(w ...client.Wrapper) Option { + return func(o *Options) { + // apply in reverse + for i := len(w); i > 0; i-- { + o.Client = w[i-1](o.Client) + } + } +} + +// WrapCall is a convenience method for wrapping a Client CallFunc +func WrapCall(w ...client.CallWrapper) Option { + return func(o *Options) { + o.Client.Init(client.WrapCall(w...)) + } +} + +// WrapHandler adds a handler Wrapper to a list of options passed into the server +func WrapHandler(w ...server.HandlerWrapper) Option { + return func(o *Options) { + var wrappers []server.Option + + for _, wrap := range w { + wrappers = append(wrappers, server.WrapHandler(wrap)) + } + + // Init once + o.Server.Init(wrappers...) + } +} + +// WrapSubscriber adds a subscriber Wrapper to a list of options passed into the server +func WrapSubscriber(w ...server.SubscriberWrapper) Option { + return func(o *Options) { + var wrappers []server.Option + + for _, wrap := range w { + wrappers = append(wrappers, server.WrapSubscriber(wrap)) + } + + // Init once + o.Server.Init(wrappers...) + } +} + +// Before and Afters + +func BeforeStart(fn func() error) Option { + return func(o *Options) { + o.BeforeStart = append(o.BeforeStart, fn) + } +} + +func BeforeStop(fn func() error) Option { + return func(o *Options) { + o.BeforeStop = append(o.BeforeStop, fn) + } +} + +func AfterStart(fn func() error) Option { + return func(o *Options) { + o.AfterStart = append(o.AfterStart, fn) + } +} + +func AfterStop(fn func() error) Option { + return func(o *Options) { + o.AfterStop = append(o.AfterStop, fn) + } +} diff --git a/service/service.go b/service/service.go index 4dc92031..5b9d3027 100644 --- a/service/service.go +++ b/service/service.go @@ -1,2 +1,16 @@ // Package service encapsulates the client, server and other interfaces to provide a complete micro service. package service + +import ( + "github.com/micro/go-micro/client" + "github.com/micro/go-micro/server" +) + +type Service interface { + Init(...Option) + Options() Options + Client() client.Client + Server() server.Server + Run() error + String() string +} diff --git a/service_test.go b/service_test.go index 8d4c4316..82195aed 100644 --- a/service_test.go +++ b/service_test.go @@ -8,8 +8,8 @@ import ( glog "github.com/go-log/log" "github.com/micro/go-micro/client" + proto "github.com/micro/go-micro/debug/proto" "github.com/micro/go-micro/registry/memory" - proto "github.com/micro/go-micro/server/debug/proto" "github.com/micro/go-micro/util/log" ) From 91f2af91de1c55bb2e68640fea2d5d0abef11aff Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 6 Aug 2019 18:05:05 +0100 Subject: [PATCH 267/287] Fix bugs in monitor --- monitor/default.go | 3 ++- monitor/default_test.go | 14 +++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/monitor/default.go b/monitor/default.go index 307ec36e..f534ad53 100644 --- a/monitor/default.go +++ b/monitor/default.go @@ -128,7 +128,7 @@ func (m *monitor) Watch(service string) error { func (m *monitor) Stop() error { m.Lock() - defer m.RUnlock() + defer m.Unlock() select { case <-m.exit: @@ -203,6 +203,7 @@ func newMonitor(opts ...Option) Monitor { m := &monitor{ options: options, + exit: make(chan bool), client: options.Client, registry: cache.New(options.Registry), services: make(map[string]*Status), diff --git a/monitor/default_test.go b/monitor/default_test.go index 6910cdac..da8ff1f3 100644 --- a/monitor/default_test.go +++ b/monitor/default_test.go @@ -12,8 +12,20 @@ func TestMonitor(t *testing.T) { for _, service := range services { _, err := m.Status(service) - if err != nil { + if err == nil { t.Fatal("expected status error for unknown service") } + + if err := m.Watch(service); err == nil { + t.Fatal("expected watch error for unknown service") + } + + // TODO: + // 1. start a service + // 2. watch service + // 3. get service status } + + // stop monitor + m.Stop() } From eae32176c40be227697349d49136f4544dc150a1 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 6 Aug 2019 19:02:57 +0100 Subject: [PATCH 268/287] Monitor all services in the monitor --- monitor/default.go | 197 ++++++++++++++++++++++++++++++---------- monitor/default_test.go | 8 +- monitor/monitor.go | 4 + 3 files changed, 158 insertions(+), 51 deletions(-) diff --git a/monitor/default.go b/monitor/default.go index f534ad53..ac89d2e3 100644 --- a/monitor/default.go +++ b/monitor/default.go @@ -20,6 +20,7 @@ type monitor struct { client client.Client sync.RWMutex + running bool services map[string]*Status } @@ -97,6 +98,124 @@ func (m *monitor) check(service string) (*Status, error) { }, nil } +func (m *monitor) reap() { + services, err := m.registry.ListServices() + if err != nil { + return + } + + serviceMap := make(map[string]bool) + for _, service := range services { + serviceMap[service.Name] = true + } + + m.Lock() + defer m.Unlock() + + // range over our watched services + for service, _ := range m.services { + // check if the service exists in the registry + if !serviceMap[service] { + // if not, delete it in our status map + delete(m.services, service) + } + } +} + +func (m *monitor) run() { + // check the status every tick + t := time.NewTicker(time.Minute) + defer t.Stop() + + // reap dead services + t2 := time.NewTicker(time.Hour) + defer t2.Stop() + + // list the known services + services, _ := m.registry.ListServices() + + // create a check chan of same length + check := make(chan string, len(services)) + + // front-load the services to watch + for _, service := range services { + check <- service.Name + } + + for { + select { + // exit if we're told to + case <-m.exit: + return + // check a service when told to + case service := <-check: + // check the status + status, err := m.check(service) + if err != nil { + status = &Status{ + Code: StatusUnknown, + Info: "unknown status", + } + } + + // save the status + m.Lock() + m.services[service] = status + m.Unlock() + // on the tick interval get all services and issue a check + case <-t.C: + // create a list of services + serviceMap := make(map[string]bool) + + m.RLock() + for service, _ := range m.services { + serviceMap[service] = true + } + m.RUnlock() + + go func() { + // check the status of all watched services + for service, _ := range serviceMap { + select { + case <-m.exit: + return + case check <- service: + default: + // barf if we block + } + } + + // list services + services, _ := m.registry.ListServices() + + for _, service := range services { + // start watching the service + if ok := serviceMap[service.Name]; !ok { + m.Watch(service.Name) + } + } + }() + case <-t2.C: + // reap any dead/non-existent services + m.reap() + } + } +} + +func (m *monitor) Reap(service string) error { + services, err := m.registry.GetService(service) + if err != nil { + return nil + } + m.Lock() + defer m.Unlock() + delete(m.services, service) + for _, service := range services { + m.registry.Deregister(service) + } + return nil +} + func (m *monitor) Status(service string) (Status, error) { m.RLock() defer m.RUnlock() @@ -126,10 +245,36 @@ func (m *monitor) Watch(service string) error { return nil } +func (m *monitor) Run() error { + m.Lock() + defer m.Unlock() + + if m.running { + return nil + } + + // reset the exit channel + m.exit = make(chan bool) + // setup a new cache + m.registry = cache.New(m.options.Registry) + + // start running + go m.run() + + // set to running + m.running = true + + return nil +} + func (m *monitor) Stop() error { m.Lock() defer m.Unlock() + if !m.running { + return nil + } + select { case <-m.exit: return nil @@ -139,58 +284,13 @@ func (m *monitor) Stop() error { delete(m.services, s) } m.registry.Stop() + m.running = false return nil } return nil } -func (m *monitor) run() { - // check the status every tick - t := time.NewTicker(time.Minute) - defer t.Stop() - - check := make(chan string) - - for { - select { - case <-m.exit: - return - case service := <-check: - // check the status - status, err := m.check(service) - if err != nil { - status = &Status{ - Code: StatusUnknown, - Info: "unknown status", - } - } - - // save the status - m.Lock() - m.services[service] = status - m.Unlock() - case <-t.C: - // create a list of services - var services []string - m.RLock() - for service, _ := range m.services { - services = append(services, service) - } - m.RUnlock() - - // check the status of all watched services - for _, service := range services { - select { - case <-m.exit: - return - case check <- service: - } - } - } - } -} - func newMonitor(opts ...Option) Monitor { options := Options{ Client: client.DefaultClient, @@ -201,14 +301,11 @@ func newMonitor(opts ...Option) Monitor { o(&options) } - m := &monitor{ + return &monitor{ options: options, exit: make(chan bool), client: options.Client, registry: cache.New(options.Registry), services: make(map[string]*Status), } - - go m.run() - return m } diff --git a/monitor/default_test.go b/monitor/default_test.go index da8ff1f3..335df305 100644 --- a/monitor/default_test.go +++ b/monitor/default_test.go @@ -8,6 +8,10 @@ func TestMonitor(t *testing.T) { // create new monitor m := NewMonitor() + if err := m.Run(); err != nil { + t.Fatalf("failed to stop monitor: %v", err) + } + services := []string{"foo", "bar", "baz"} for _, service := range services { @@ -27,5 +31,7 @@ func TestMonitor(t *testing.T) { } // stop monitor - m.Stop() + if err := m.Stop(); err != nil { + t.Fatalf("failed to stop monitor: %v", err) + } } diff --git a/monitor/monitor.go b/monitor/monitor.go index 41fd17cd..711d7d03 100644 --- a/monitor/monitor.go +++ b/monitor/monitor.go @@ -15,10 +15,14 @@ type StatusCode int // Monitor monitors a service and reaps dead instances type Monitor interface { + // Reap a service and stop monitoring + Reap(service string) error // Status of the service Status(service string) (Status, error) // Watch starts watching the service Watch(service string) error + // Run the monitor to watch all services + Run() error // Stop monitoring Stop() error } From edb0fe4b167a9c0e393b6edf3b8aa727aff2754d Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Tue, 6 Aug 2019 19:43:46 +0100 Subject: [PATCH 269/287] fix the consul setup code --- registry/consul/consul.go | 59 ++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 20 deletions(-) diff --git a/registry/consul/consul.go b/registry/consul/consul.go index 32360987..4b6fa770 100644 --- a/registry/consul/consul.go +++ b/registry/consul/consul.go @@ -97,24 +97,33 @@ func configure(c *consulRegistry, opts ...registry.Option) { } // check if there are any addrs - if len(c.opts.Addrs) > 0 { - addr, port, err := net.SplitHostPort(c.opts.Addrs[0]) + var addrs []string + + // iterate the options addresses + for _, address := range c.opts.Addrs { + // check we have a port + addr, port, err := net.SplitHostPort(address) if ae, ok := err.(*net.AddrError); ok && ae.Err == "missing port in address" { port = "8500" - addr = c.opts.Addrs[0] - config.Address = fmt.Sprintf("%s:%s", addr, port) + addr = address + addrs = append(addrs, fmt.Sprintf("%s:%s", addr, port)) } else if err == nil { - config.Address = fmt.Sprintf("%s:%s", addr, port) + addrs = append(addrs, fmt.Sprintf("%s:%s", addr, port)) } } + // set the addrs + if len(addrs) > 0 { + c.Address = addrs + config.Address = c.Address[0] + } + if config.HttpClient == nil { config.HttpClient = new(http.Client) } // requires secure connection? if c.opts.Secure || c.opts.TLSConfig != nil { - config.Scheme = "https" // We're going to support InsecureSkipVerify config.HttpClient.Transport = newTransport(c.opts.TLSConfig) @@ -125,11 +134,13 @@ func configure(c *consulRegistry, opts ...registry.Option) { config.HttpClient.Timeout = c.opts.Timeout } - // set address - c.Address = c.opts.Addrs - + // set the config c.config = config + // remove client + c.client = nil + + // setup the client c.Client() } @@ -384,20 +395,28 @@ func (c *consulRegistry) Client() *consul.Client { return c.client } - if len(c.Address) == 0 { - tmp, _ := consul.NewClient(c.config) - return tmp + for _, addr := range c.Address { + // set the address + c.config.Address = addr + + // create a new client + tmpClient, _ := consul.NewClient(c.config) + + // test the client + _, err := tmpClient.Agent().Host() + if err != nil { + continue + } + + // set the client + c.client = tmpClient + return c.client } - c.config.Address = c.Address[0] - tmpClint, _ := consul.NewClient(c.config) - _, err := tmpClint.Agent().Host() - if err != nil { - c.Address = c.Address[1:] - return c.Client() - } + // set the default + c.client, _ = consul.NewClient(c.config) - c.client = tmpClint + // return the client return c.client } From 0baea58938b31db97c52afa6333e9421d3552610 Mon Sep 17 00:00:00 2001 From: magodo Date: Wed, 7 Aug 2019 17:58:45 +0800 Subject: [PATCH 270/287] wait nats drain since it's asynchronous 1. nats subscription draining is removed, since it is asynchronous, and there is no reliable way to detect when it is finished. Remove this option to avoid confusion. 2. nats connection draining is kept, and use 2 callbacks to detect draining timeout (timeout is set via `nats.Options`) or finish. 3. Also honour options passed in `broker.Init()` (previously only `broker.New()` is honoured). --- broker/nats/nats.go | 96 +++++++++++++++++++++++------------------- broker/nats/options.go | 8 +--- 2 files changed, 54 insertions(+), 50 deletions(-) diff --git a/broker/nats/nats.go b/broker/nats/nats.go index 027f1dac..eecb16ec 100644 --- a/broker/nats/nats.go +++ b/broker/nats/nats.go @@ -13,18 +13,19 @@ import ( ) type natsBroker struct { + sync.Once sync.RWMutex - addrs []string - conn *nats.Conn - opts broker.Options - nopts nats.Options - drain bool + addrs []string + conn *nats.Conn + opts broker.Options + nopts nats.Options + drain bool + closeCh chan (error) } type subscriber struct { - s *nats.Subscription - opts broker.SubscribeOptions - drain bool + s *nats.Subscription + opts broker.SubscribeOptions } type publication struct { @@ -54,9 +55,6 @@ func (s *subscriber) Topic() string { } func (s *subscriber) Unsubscribe() error { - if s.drain { - return s.s.Drain() - } return s.s.Unsubscribe() } @@ -122,20 +120,17 @@ func (n *natsBroker) Connect() error { func (n *natsBroker) Disconnect() error { n.RLock() + defer n.RUnlock() if n.drain { n.conn.Drain() - } else { - n.conn.Close() + return <-n.closeCh } - n.RUnlock() + n.conn.Close() return nil } func (n *natsBroker) Init(opts ...broker.Option) error { - for _, o := range opts { - o(&n.opts) - } - n.addrs = setAddrs(n.opts.Addrs) + n.setOption(opts...) return nil } @@ -167,11 +162,6 @@ func (n *natsBroker) Subscribe(topic string, handler broker.Handler, opts ...bro o(&opt) } - var drain bool - if _, ok := opt.Context.Value(drainSubscriptionKey{}).(bool); ok { - drain = true - } - fn := func(msg *nats.Msg) { var m broker.Message if err := n.opts.Codec.Unmarshal(msg.Data, &m); err != nil { @@ -193,7 +183,7 @@ func (n *natsBroker) Subscribe(topic string, handler broker.Handler, opts ...bro if err != nil { return nil, err } - return &subscriber{s: sub, opts: opt, drain: drain}, nil + return &subscriber{s: sub, opts: opt}, nil } func (n *natsBroker) String() string { @@ -207,39 +197,59 @@ func NewBroker(opts ...broker.Option) broker.Broker { Context: context.Background(), } + n := &natsBroker{ + opts: options, + } + n.setOption(opts...) + + return n +} + +func (n *natsBroker) setOption(opts ...broker.Option) { for _, o := range opts { - o(&options) + o(&n.opts) } - natsOpts := nats.GetDefaultOptions() - if n, ok := options.Context.Value(optionsKey{}).(nats.Options); ok { - natsOpts = n - } + n.Once.Do(func() { + n.nopts = nats.GetDefaultOptions() + }) - var drain bool - if _, ok := options.Context.Value(drainSubscriptionKey{}).(bool); ok { - drain = true + if nopts, ok := n.opts.Context.Value(optionsKey{}).(nats.Options); ok { + n.nopts = nopts } // broker.Options have higher priority than nats.Options // only if Addrs, Secure or TLSConfig were not set through a broker.Option // we read them from nats.Option - if len(options.Addrs) == 0 { - options.Addrs = natsOpts.Servers + if len(n.opts.Addrs) == 0 { + n.opts.Addrs = n.nopts.Servers } - if !options.Secure { - options.Secure = natsOpts.Secure + if !n.opts.Secure { + n.opts.Secure = n.nopts.Secure } - if options.TLSConfig == nil { - options.TLSConfig = natsOpts.TLSConfig + if n.opts.TLSConfig == nil { + n.opts.TLSConfig = n.nopts.TLSConfig } + n.addrs = setAddrs(n.opts.Addrs) - return &natsBroker{ - opts: options, - nopts: natsOpts, - addrs: setAddrs(options.Addrs), - drain: drain, + if n.opts.Context.Value(drainConnectionKey{}) != nil { + n.drain = true + n.closeCh = make(chan error) + n.nopts.ClosedCB = n.onClose + n.nopts.AsyncErrorCB = n.onAsyncError + } +} + +func (n *natsBroker) onClose(conn *nats.Conn) { + n.closeCh <- nil +} + +func (n *natsBroker) onAsyncError(conn *nats.Conn, sub *nats.Subscription, err error) { + // There are kinds of different async error nats might callback, but we are interested + // in ErrDrainTimeout only here. + if err == nats.ErrDrainTimeout { + n.closeCh <- err } } diff --git a/broker/nats/options.go b/broker/nats/options.go index 47431606..b5b106c0 100644 --- a/broker/nats/options.go +++ b/broker/nats/options.go @@ -7,7 +7,6 @@ import ( type optionsKey struct{} type drainConnectionKey struct{} -type drainSubscriptionKey struct{} // Options accepts nats.Options func Options(opts nats.Options) broker.Option { @@ -16,10 +15,5 @@ func Options(opts nats.Options) broker.Option { // DrainConnection will drain subscription on close func DrainConnection() broker.Option { - return setBrokerOption(drainConnectionKey{}, true) -} - -// DrainSubscription will drain pending messages when unsubscribe -func DrainSubscription() broker.SubscribeOption { - return setSubscribeOption(drainSubscriptionKey{}, true) + return setBrokerOption(drainConnectionKey{}, struct{}{}) } From 380d9790e603530aae4b5d7f6286ecce7e415206 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 7 Aug 2019 15:02:00 +0100 Subject: [PATCH 271/287] add io.ReadWriteCloser ontop of transport.Socket --- util/io/io.go | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 util/io/io.go diff --git a/util/io/io.go b/util/io/io.go new file mode 100644 index 00000000..133ba6b8 --- /dev/null +++ b/util/io/io.go @@ -0,0 +1,40 @@ +// Package io is for io management +package io + +import ( + "io" + + "github.com/micro/go-micro/transport" +) + +type rwc struct { + socket transport.Socket +} + +func (r *rwc) Read(p []byte) (n int, err error) { + m := new(transport.Message) + if err := r.socket.Recv(m); err != nil { + return 0, err + } + copy(p, m.Body) + return len(m.Body), nil +} + +func (r *rwc) Write(p []byte) (n int, err error) { + err = r.socket.Send(&transport.Message{ + Body: p, + }) + if err != nil { + return 0, err + } + return len(p), nil +} + +func (r *rwc) Close() error { + return r.socket.Close() +} + +// NewRWC returns a new ReadWriteCloser +func NewRWC(sock transport.Socket) io.ReadWriteCloser { + return &rwc{sock} +} From 117376a9226f8ac4514cfe1e7768378104c18f7f Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 7 Aug 2019 18:44:33 +0100 Subject: [PATCH 272/287] Add back the old tunnel interface --- tunnel/default.go | 429 ++++++++++++++++++++++++++++++++++++++---- tunnel/listener.go | 101 ++++++++++ tunnel/options.go | 6 +- tunnel/socket.go | 91 +++++++-- tunnel/transport.go | 51 ----- tunnel/tunnel.go | 50 ++--- tunnel/tunnel_test.go | 73 +++++++ 7 files changed, 675 insertions(+), 126 deletions(-) create mode 100644 tunnel/listener.go delete mode 100644 tunnel/transport.go create mode 100644 tunnel/tunnel_test.go diff --git a/tunnel/default.go b/tunnel/default.go index d0eecf51..eb26eaa1 100644 --- a/tunnel/default.go +++ b/tunnel/default.go @@ -1,79 +1,436 @@ package tunnel import ( + "crypto/sha256" + "errors" + "fmt" "sync" + "github.com/google/uuid" "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/util/log" ) +// tun represents a network tunnel type tun struct { + options Options + sync.RWMutex - tr transport.Transport - options Options + + // to indicate if we're connected or not connected bool - closed chan bool + + // the send channel for all messages + send chan *message + + // close channel + closed chan bool + + // a map of sockets based on Micro-Tunnel-Id + sockets map[string]*socket + + // outbound links + links map[string]*link + + // listener + listener transport.Listener } -func newTunnel(opts ...Option) Tunnel { - // initialize default options - options := DefaultOptions() +type link struct { + transport.Socket + id string +} +// create new tunnel on top of a link +func newTunnel(opts ...Option) *tun { + options := DefaultOptions() for _, o := range opts { o(&options) } - // tunnel transport - tr := newTransport() - - t := &tun{ - tr: tr, + return &tun{ options: options, + send: make(chan *message, 128), closed: make(chan bool), + sockets: make(map[string]*socket), + links: make(map[string]*link), + } +} + +// getSocket returns a socket from the internal socket map. +// It does this based on the Micro-Tunnel-Id and Micro-Tunnel-Session +func (t *tun) getSocket(id, session string) (*socket, bool) { + // get the socket + t.RLock() + s, ok := t.sockets[id+session] + t.RUnlock() + return s, ok +} + +// newSocket creates a new socket and saves it +func (t *tun) newSocket(id, session string) (*socket, bool) { + // hash the id + h := sha256.New() + h.Write([]byte(id)) + id = fmt.Sprintf("%x", h.Sum(nil)) + + // new socket + s := &socket{ + id: id, + session: session, + closed: make(chan bool), + recv: make(chan *message, 128), + send: t.send, + wait: make(chan bool), } - return t + // save socket + t.Lock() + _, ok := t.sockets[id+session] + if ok { + // socket already exists + t.Unlock() + return nil, false + } + t.sockets[id+session] = s + t.Unlock() + + // return socket + return s, true } -// Id returns tunnel id -func (t *tun) Id() string { - return t.options.Id +// TODO: use tunnel id as part of the session +func (t *tun) newSession() string { + return uuid.New().String() } -// Options returns tunnel options -func (t *tun) Options() Options { - return t.options +// process outgoing messages sent by all local sockets +func (t *tun) process() { + // manage the send buffer + // all pseudo sockets throw everything down this + for { + select { + case msg := <-t.send: + nmsg := &transport.Message{ + Header: msg.data.Header, + Body: msg.data.Body, + } + + // set the tunnel id on the outgoing message + nmsg.Header["Micro-Tunnel-Id"] = msg.id + + // set the session id + nmsg.Header["Micro-Tunnel-Session"] = msg.session + + // send the message via the interface + t.RLock() + for _, link := range t.links { + link.Send(nmsg) + } + t.RUnlock() + case <-t.closed: + return + } + } } -// Address returns tunnel listen address -func (t *tun) Address() string { - return t.options.Address +// process incoming messages +func (t *tun) listen(link transport.Socket, listener bool) { + for { + // process anything via the net interface + msg := new(transport.Message) + err := link.Recv(msg) + if err != nil { + return + } + + // first check Micro-Tunnel + switch msg.Header["Micro-Tunnel"] { + case "connect": + // assuming new connection + // TODO: do something with this + continue + case "close": + // assuming connection closed + // TODO: do something with this + continue + } + + // the tunnel id + id := msg.Header["Micro-Tunnel-Id"] + + // the session id + session := msg.Header["Micro-Tunnel-Session"] + + // if the session id is blank there's nothing we can do + // TODO: check this is the case, is there any reason + // why we'd have a blank session? Is the tunnel + // used for some other purpose? + if len(id) == 0 || len(session) == 0 { + continue + } + + var s *socket + var exists bool + + // if its a local listener then we use that as the session id + // e.g we're using a loopback connecting to ourselves + if listener { + s, exists = t.getSocket(id, "listener") + } else { + // get the socket based on the tunnel id and session + // this could be something we dialed in which case + // we have a session for it otherwise its a listener + s, exists = t.getSocket(id, session) + if !exists { + // try get it based on just the tunnel id + // the assumption here is that a listener + // has no session but its set a listener session + s, exists = t.getSocket(id, "listener") + } + } + + // no socket in existence + if !exists { + // drop it, we don't care about + // messages we don't know about + continue + } + + // is the socket closed? + select { + case <-s.closed: + // closed + delete(t.sockets, id) + continue + default: + // process + } + + // is the socket new? + select { + // if its new the socket is actually blocked waiting + // for a connection. so we check if its waiting. + case <-s.wait: + // if its waiting e.g its new then we close it + default: + // set remote address of the socket + s.remote = msg.Header["Remote"] + close(s.wait) + } + + // construct a new transport message + tmsg := &transport.Message{ + Header: msg.Header, + Body: msg.Body, + } + + // construct the internal message + imsg := &message{ + id: id, + session: session, + data: tmsg, + } + + // append to recv backlog + // we don't block if we can't pass it on + select { + case s.recv <- imsg: + default: + } + } } -// Transport returns tunnel client transport -func (t *tun) Transport() transport.Transport { - return t.tr -} +func (t *tun) connect() error { + l, err := t.options.Transport.Listen(t.options.Address) + if err != nil { + return err + } + + // save the listener + t.listener = l + + go func() { + // accept inbound connections + err := l.Accept(func(sock transport.Socket) { + // save the link + id := uuid.New().String() + t.Lock() + t.links[id] = &link{ + Socket: sock, + id: id, + } + t.Unlock() + + // delete the link + defer func() { + t.Lock() + delete(t.links, id) + t.Unlock() + }() + + // listen for inbound messages + t.listen(sock, true) + }) + + t.Lock() + defer t.Unlock() + + // still connected but the tunnel died + if err != nil && t.connected { + log.Logf("Tunnel listener died: %v", err) + } + }() + + for _, node := range t.options.Nodes { + c, err := t.options.Transport.Dial(node) + if err != nil { + log.Debugf("Tunnel failed to connect to %s: %v", node, err) + continue + } + + err = c.Send(&transport.Message{ + Header: map[string]string{ + "Micro-Tunnel": "connect", + }, + }) + + if err != nil { + continue + } + + // process incoming messages + go t.listen(c, false) + + // save the link + id := uuid.New().String() + t.links[id] = &link{ + Socket: c, + id: id, + } + } + + // process outbound messages to be sent + // process sends to all links + go t.process() -// Connect connects establishes point to point tunnel -func (t *tun) Connect() error { return nil } -// Close closes the tunnel +func (t *tun) close() error { + // close all the links + for id, link := range t.links { + link.Send(&transport.Message{ + Header: map[string]string{ + "Micro-Tunnel": "close", + }, + }) + link.Close() + delete(t.links, id) + } + + // close the listener + return t.listener.Close() +} + +// Close the tunnel func (t *tun) Close() error { - return nil -} + t.Lock() + defer t.Unlock() + + if !t.connected { + return nil + } -// Status returns tunnel status -func (t *tun) Status() Status { select { case <-t.closed: - return Closed + return nil default: - return Connected + // close all the sockets + for _, s := range t.sockets { + s.Close() + } + // close the connection + close(t.closed) + t.connected = false + + // send a close message + // we don't close the link + // just the tunnel + return t.close() } + + return nil } -func (t *tun) String() string { - return "micro" +// Connect the tunnel +func (t *tun) Connect() error { + t.Lock() + defer t.Unlock() + + // already connected + if t.connected { + return nil + } + + // send the connect message + if err := t.connect(); err != nil { + return err + } + + // set as connected + t.connected = true + // create new close channel + t.closed = make(chan bool) + + return nil +} + +// Dial an address +func (t *tun) Dial(addr string) (Conn, error) { + c, ok := t.newSocket(addr, t.newSession()) + if !ok { + return nil, errors.New("error dialing " + addr) + } + // set remote + c.remote = addr + // set local + c.local = "local" + + return c, nil +} + +// Accept a connection on the address +func (t *tun) Listen(addr string) (Listener, error) { + // create a new socket by hashing the address + c, ok := t.newSocket(addr, "listener") + if !ok { + return nil, errors.New("already listening on " + addr) + } + + // set remote. it will be replaced by the first message received + c.remote = "remote" + // set local + c.local = addr + + tl := &tunListener{ + addr: addr, + // the accept channel + accept: make(chan *socket, 128), + // the channel to close + closed: make(chan bool), + // the connection + conn: c, + // the listener socket + socket: c, + } + + // this kicks off the internal message processor + // for the listener so it can create pseudo sockets + // per session if they do not exist or pass messages + // to the existign sessions + go tl.process() + + // return the listener + return tl, nil } diff --git a/tunnel/listener.go b/tunnel/listener.go new file mode 100644 index 00000000..6c803eb9 --- /dev/null +++ b/tunnel/listener.go @@ -0,0 +1,101 @@ +package tunnel + +import ( + "io" +) + +type tunListener struct { + // address of the listener + addr string + // the accept channel + accept chan *socket + // the channel to close + closed chan bool + // the connection + conn Conn + // the listener socket + socket *socket +} + +func (t *tunListener) process() { + // our connection map for session + conns := make(map[string]*socket) + + for { + select { + case <-t.closed: + return + // receive a new message + case m := <-t.socket.recv: + // get a socket + sock, ok := conns[m.session] + if !ok { + // create a new socket session + sock = &socket{ + // our tunnel id + id: m.id, + // the session id + session: m.session, + // close chan + closed: make(chan bool), + // recv called by the acceptor + recv: make(chan *message, 128), + // use the internal send buffer + send: t.socket.send, + // wait + wait: make(chan bool), + } + + // first message + sock.recv <- m + + // save the socket + conns[m.session] = sock + + // send to accept chan + select { + case <-t.closed: + return + case t.accept <- sock: + } + } + + // send this to the accept chan + select { + case <-sock.closed: + delete(conns, m.session) + case sock.recv <- m: + } + } + } +} + +func (t *tunListener) Addr() string { + return t.addr +} + +func (t *tunListener) Close() error { + select { + case <-t.closed: + return nil + default: + close(t.closed) + } + return nil +} + +// Everytime accept is called we essentially block till we get a new connection +func (t *tunListener) Accept() (Conn, error) { + select { + // if the socket is closed return + case <-t.closed: + return nil, io.EOF + // wait for a new connection + case c, ok := <-t.accept: + if !ok { + return nil, io.EOF + } + return c, nil + } + return nil, nil +} diff --git a/tunnel/options.go b/tunnel/options.go index 86db722e..f152c8ac 100644 --- a/tunnel/options.go +++ b/tunnel/options.go @@ -3,6 +3,7 @@ package tunnel import ( "github.com/google/uuid" "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/transport/quic" ) var ( @@ -39,7 +40,7 @@ func Address(a string) Option { } // Nodes specify remote network nodes -func Nodes(n []string) Option { +func Nodes(n ...string) Option { return func(o *Options) { o.Nodes = n } @@ -57,7 +58,6 @@ func DefaultOptions() Options { return Options{ Id: uuid.New().String(), Address: DefaultAddress, - Nodes: make([]string, 0), - Transport: transport.DefaultTransport, + Transport: quic.NewTransport(), } } diff --git a/tunnel/socket.go b/tunnel/socket.go index ad98287f..b1c55797 100644 --- a/tunnel/socket.go +++ b/tunnel/socket.go @@ -1,25 +1,90 @@ package tunnel -import "github.com/micro/go-micro/transport" +import ( + "errors" -type tunSocket struct{} + "github.com/micro/go-micro/transport" +) -func (s *tunSocket) Recv(m *transport.Message) error { +// socket is our pseudo socket for transport.Socket +type socket struct { + // socket id based on Micro-Tunnel + id string + // the session id based on Micro.Tunnel-Session + session string + // closed + closed chan bool + // remote addr + remote string + // local addr + local string + // send chan + send chan *message + // recv chan + recv chan *message + // wait until we have a connection + wait chan bool +} + +// message is sent over the send channel +type message struct { + // tunnel id + id string + // the session id + session string + // transport data + data *transport.Message +} + +func (s *socket) Remote() string { + return s.remote +} + +func (s *socket) Local() string { + return s.local +} + +func (s *socket) Id() string { + return s.id +} + +func (s *socket) Session() string { + return s.session +} + +func (s *socket) Send(m *transport.Message) error { + select { + case <-s.closed: + return errors.New("socket is closed") + default: + // no op + } + // append to backlog + s.send <- &message{id: s.id, session: s.session, data: m} return nil } -func (s *tunSocket) Send(m *transport.Message) error { +func (s *socket) Recv(m *transport.Message) error { + select { + case <-s.closed: + return errors.New("socket is closed") + default: + // no op + } + // recv from backlog + msg := <-s.recv + // set message + *m = *msg.data + // return nil return nil } -func (s *tunSocket) Close() error { +func (s *socket) Close() error { + select { + case <-s.closed: + // no op + default: + close(s.closed) + } return nil } - -func (s *tunSocket) Local() string { - return "" -} - -func (s *tunSocket) Remote() string { - return "" -} diff --git a/tunnel/transport.go b/tunnel/transport.go deleted file mode 100644 index fc03398a..00000000 --- a/tunnel/transport.go +++ /dev/null @@ -1,51 +0,0 @@ -package tunnel - -import "github.com/micro/go-micro/transport" - -type tunTransport struct { - options transport.Options -} - -type tunClient struct { - *tunSocket - options transport.DialOptions -} - -type tunListener struct { - conn chan *tunSocket -} - -func newTransport(opts ...transport.Option) transport.Transport { - var options transport.Options - - for _, o := range opts { - o(&options) - } - - return &tunTransport{ - options: options, - } -} - -func (t *tunTransport) Init(opts ...transport.Option) error { - for _, o := range opts { - o(&t.options) - } - return nil -} - -func (t *tunTransport) Options() transport.Options { - return t.options -} - -func (t *tunTransport) Dial(addr string, opts ...transport.DialOption) (transport.Client, error) { - return nil, nil -} - -func (t *tunTransport) Listen(addr string, opts ...transport.ListenOption) (transport.Listener, error) { - return nil, nil -} - -func (t *tunTransport) String() string { - return "micro" -} diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 55bcd809..bcb54fd1 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -1,39 +1,43 @@ -// Package tunnel provides micro network tunnelling +// Package tunnel provides gre network tunnelling package tunnel import ( "github.com/micro/go-micro/transport" ) -// Status is tunnel status -type Status int - -const ( - // Connected means the tunnel is alive - Connected Status = iota - // Closed meands the tunnel has been disconnected - Closed -) - -// Tunnel creates a p2p network tunnel. +// Tunnel creates a gre network tunnel on top of a link. +// It establishes multiple streams using the Micro-Tunnel-Id header +// and Micro-Tunnel-Session header. The tunnel id is a hash of +// the address being requested. type Tunnel interface { - // Id returns tunnel id - Id() string - // Options returns the tunnel options - Options() Options - // Address returns tunnel address - Address() string - // Transport to use by tunne clients - Transport() transport.Transport // Connect connects the tunnel Connect() error // Close closes the tunnel Close() error - // Status returns tunnel status - Status() Status + // Dial an endpoint + Dial(addr string) (Conn, error) + // Accept connections + Listen(addr string) (Listener, error) } -// NewTunnel creates a new tunnel on top of a link +// The listener provides similar constructs to the transport.Listener +type Listener interface { + Addr() string + Close() error + Accept() (Conn, error) +} + +// Conn is a connection dialed or accepted which includes the tunnel id and session +type Conn interface { + // Specifies the tunnel id + Id() string + // The session + Session() string + // a transport socket + transport.Socket +} + +// NewTunnel creates a new tunnel func NewTunnel(opts ...Option) Tunnel { return newTunnel(opts...) } diff --git a/tunnel/tunnel_test.go b/tunnel/tunnel_test.go new file mode 100644 index 00000000..5dd527c5 --- /dev/null +++ b/tunnel/tunnel_test.go @@ -0,0 +1,73 @@ +package tunnel + +import ( + "testing" + + "github.com/micro/go-micro/transport" +) + +// testAccept will accept connections on the transport, create a new link and tunnel on top +func testAccept(t *testing.T, tun Tunnel, wait chan bool) { + // listen on some virtual address + tl, err := tun.Listen("test-tunnel") + if err != nil { + t.Fatal(err) + } + + // accept a connection + c, err := tl.Accept() + if err != nil { + t.Fatal(err) + } + + // get a message + for { + m := new(transport.Message) + if err := c.Recv(m); err != nil { + t.Fatal(err) + } + close(wait) + return + } +} + +// testSend will create a new link to an address and then a tunnel on top +func testSend(t *testing.T, tun Tunnel) { + // dial a new session + c, err := tun.Dial("test-tunnel") + if err != nil { + t.Fatal(err) + } + //defer c.Close() + + m := transport.Message{ + Header: map[string]string{ + "test": "header", + }, + } + + if err := c.Send(&m); err != nil { + t.Fatal(err) + } +} + +func TestTunnel(t *testing.T) { + // create a new listener + tun := NewTunnel(Nodes(":9096")) + err := tun.Connect() + if err != nil { + t.Fatal(err) + } + //defer tun.Close() + + wait := make(chan bool) + + // start accepting connections + go testAccept(t, tun, wait) + + // send a message + testSend(t, tun) + + // wait until message is received + <-wait +} From dcf4fed6a3384f185e9b1ba034342e086b17542e Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 7 Aug 2019 18:56:21 +0100 Subject: [PATCH 273/287] Add a second test for two tunnels --- tunnel/tunnel_test.go | 61 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/tunnel/tunnel_test.go b/tunnel/tunnel_test.go index 5dd527c5..8577d89f 100644 --- a/tunnel/tunnel_test.go +++ b/tunnel/tunnel_test.go @@ -1,13 +1,14 @@ package tunnel import ( + "sync" "testing" "github.com/micro/go-micro/transport" ) // testAccept will accept connections on the transport, create a new link and tunnel on top -func testAccept(t *testing.T, tun Tunnel, wait chan bool) { +func testAccept(t *testing.T, tun Tunnel, wg *sync.WaitGroup) { // listen on some virtual address tl, err := tun.Listen("test-tunnel") if err != nil { @@ -26,7 +27,7 @@ func testAccept(t *testing.T, tun Tunnel, wait chan bool) { if err := c.Recv(m); err != nil { t.Fatal(err) } - close(wait) + wg.Done() return } } @@ -38,7 +39,7 @@ func testSend(t *testing.T, tun Tunnel) { if err != nil { t.Fatal(err) } - //defer c.Close() + defer c.Close() m := transport.Message{ Header: map[string]string{ @@ -58,16 +59,62 @@ func TestTunnel(t *testing.T) { if err != nil { t.Fatal(err) } - //defer tun.Close() + defer tun.Close() - wait := make(chan bool) + var wg sync.WaitGroup // start accepting connections - go testAccept(t, tun, wait) + wg.Add(1) + go testAccept(t, tun, &wg) // send a message testSend(t, tun) // wait until message is received - <-wait + wg.Wait() +} + +func TestTwoTunnel(t *testing.T) { + // create a new tunnel client + tunA := NewTunnel( + Address(":9096"), + Nodes(":9097"), + ) + + // create a new tunnel server + tunB := NewTunnel( + Address(":9097"), + ) + + // start tunB + err := tunB.Connect() + if err != nil { + t.Fatal(err) + } + defer tunB.Close() + + // start tunA + err = tunA.Connect() + if err != nil { + t.Fatal(err) + } + defer tunA.Close() + + var wg sync.WaitGroup + + // start accepting connections + wg.Add(1) + go testAccept(t, tunA, &wg) + + wg.Add(1) + go testAccept(t, tunB, &wg) + + // send a message + testSend(t, tunA) + + // send a message + testSend(t, tunB) + + // wait until done + wg.Wait() } From fc379f2d2c3fedf54b7072bc14001f5097891564 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 7 Aug 2019 19:03:45 +0100 Subject: [PATCH 274/287] Remove other accept --- tunnel/tunnel_test.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tunnel/tunnel_test.go b/tunnel/tunnel_test.go index 8577d89f..d90d9551 100644 --- a/tunnel/tunnel_test.go +++ b/tunnel/tunnel_test.go @@ -103,18 +103,12 @@ func TestTwoTunnel(t *testing.T) { var wg sync.WaitGroup // start accepting connections - wg.Add(1) - go testAccept(t, tunA, &wg) - wg.Add(1) go testAccept(t, tunB, &wg) // send a message testSend(t, tunA) - // send a message - testSend(t, tunB) - // wait until done wg.Wait() } From a894b4f3545275e06f4c4c07b189e574b36074ca Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 7 Aug 2019 21:58:25 +0100 Subject: [PATCH 275/287] add tunnel/transport package --- tunnel/default.go | 7 +++ tunnel/transport/listener.go | 30 +++++++++ tunnel/transport/transport.go | 113 ++++++++++++++++++++++++++++++++++ tunnel/tunnel.go | 1 + 4 files changed, 151 insertions(+) create mode 100644 tunnel/transport/listener.go create mode 100644 tunnel/transport/transport.go diff --git a/tunnel/default.go b/tunnel/default.go index eb26eaa1..ff86bb6b 100644 --- a/tunnel/default.go +++ b/tunnel/default.go @@ -386,6 +386,13 @@ func (t *tun) Connect() error { return nil } +func (t *tun) Init(opts ...Option) error { + for _, o := range opts { + o(&t.options) + } + return nil +} + // Dial an address func (t *tun) Dial(addr string) (Conn, error) { c, ok := t.newSocket(addr, t.newSession()) diff --git a/tunnel/transport/listener.go b/tunnel/transport/listener.go new file mode 100644 index 00000000..b7a7280c --- /dev/null +++ b/tunnel/transport/listener.go @@ -0,0 +1,30 @@ +package transport + +import ( + "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/tunnel" +) + +type tunListener struct { + l tunnel.Listener +} + +func (t *tunListener) Addr() string { + return t.l.Addr() +} + +func (t *tunListener) Close() error { + return t.l.Close() +} + +func (t *tunListener) Accept(fn func(socket transport.Socket)) error { + for { + // accept connection + c, err := t.l.Accept() + if err != nil { + return err + } + // execute the function + go fn(c) + } +} diff --git a/tunnel/transport/transport.go b/tunnel/transport/transport.go new file mode 100644 index 00000000..d37468d2 --- /dev/null +++ b/tunnel/transport/transport.go @@ -0,0 +1,113 @@ +// Package transport provides a tunnel transport +package transport + +import ( + "context" + + "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/tunnel" +) + +type tunTransport struct { + options transport.Options + + tunnel tunnel.Tunnel +} + +type tunnelKey struct{} + +type transportKey struct{} + +func (t *tunTransport) Init(opts ...transport.Option) error { + for _, o := range opts { + o(&t.options) + } + + // close the existing tunnel + if t.tunnel != nil { + t.tunnel.Close() + } + + // get the tunnel + tun, ok := t.options.Context.Value(tunnelKey{}).(tunnel.Tunnel) + if !ok { + tun = tunnel.NewTunnel() + } + + // get the transport + tr, ok := t.options.Context.Value(transportKey{}).(transport.Transport) + if ok { + tun.Init(tunnel.Transport(tr)) + } + + // set the tunnel + t.tunnel = tun + + return nil +} + +func (t *tunTransport) Dial(addr string, opts ...transport.DialOption) (transport.Client, error) { + if err := t.tunnel.Connect(); err != nil { + return nil, err + } + + c, err := t.tunnel.Dial(addr) + if err != nil { + return nil, err + } + + return c, nil +} + +func (t *tunTransport) Listen(addr string, opts ...transport.ListenOption) (transport.Listener, error) { + if err := t.tunnel.Connect(); err != nil { + return nil, err + } + + l, err := t.tunnel.Listen(addr) + if err != nil { + return nil, err + } + + return &tunListener{l}, nil +} + +func (t *tunTransport) Options() transport.Options { + return t.options +} + +func (t *tunTransport) String() string { + return "tunnel" +} + +// NewTransport honours the initialiser used in +func NewTransport(opts ...transport.Option) transport.Transport { + t := &tunTransport{ + options: transport.Options{}, + } + + // initialise + t.Init(opts...) + + return t +} + +// WithTransport sets the internal tunnel +func WithTunnel(t tunnel.Tunnel) transport.Option { + return func(o *transport.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, tunnelKey{}, t) + } +} + +// WithTransport sets the internal transport +func WithTransport(t transport.Transport) transport.Option { + return func(o *transport.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, transportKey{}, t) + } +} diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index bcb54fd1..3c84c7eb 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -10,6 +10,7 @@ import ( // and Micro-Tunnel-Session header. The tunnel id is a hash of // the address being requested. type Tunnel interface { + Init(opts ...Option) error // Connect connects the tunnel Connect() error // Close closes the tunnel From a3b962f37b7aae398f0d1fd0f10f4abdf4049541 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 7 Aug 2019 22:02:58 +0100 Subject: [PATCH 276/287] Fix travis test? --- tunnel/tunnel_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tunnel/tunnel_test.go b/tunnel/tunnel_test.go index d90d9551..b29af5bc 100644 --- a/tunnel/tunnel_test.go +++ b/tunnel/tunnel_test.go @@ -54,7 +54,7 @@ func testSend(t *testing.T, tun Tunnel) { func TestTunnel(t *testing.T) { // create a new listener - tun := NewTunnel(Nodes(":9096")) + tun := NewTunnel(Nodes("127.0.0.1:9096")) err := tun.Connect() if err != nil { t.Fatal(err) @@ -77,13 +77,13 @@ func TestTunnel(t *testing.T) { func TestTwoTunnel(t *testing.T) { // create a new tunnel client tunA := NewTunnel( - Address(":9096"), - Nodes(":9097"), + Address("127.0.0.1:9096"), + Nodes("127.0.0.1:9097"), ) // create a new tunnel server tunB := NewTunnel( - Address(":9097"), + Address("127.0.0.1:9097"), ) // start tunB From 4370f03e04a8bc3abaa71339e4046e899110a8d6 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 7 Aug 2019 22:11:52 +0100 Subject: [PATCH 277/287] update go modules --- go.mod | 46 +++++++++++++++++++++------------------------- go.sum | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 25 deletions(-) diff --git a/go.mod b/go.mod index 85f9b141..83d4af10 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,9 @@ module github.com/micro/go-micro go 1.12 require ( - cloud.google.com/go v0.41.0 // indirect + cloud.google.com/go v0.43.0 // indirect github.com/BurntSushi/toml v0.3.1 + github.com/Microsoft/go-winio v0.4.14 // indirect github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 // indirect github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 // indirect github.com/armon/go-radix v1.0.0 // indirect @@ -14,17 +15,16 @@ require ( github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc // indirect github.com/forestgiant/sliceutil v0.0.0-20160425183142-94783f95db6c github.com/fsnotify/fsnotify v1.4.7 - github.com/fsouza/go-dockerclient v1.4.1 + github.com/fsouza/go-dockerclient v1.4.2 github.com/ghodss/yaml v1.0.0 - github.com/gliderlabs/ssh v0.2.2 // indirect github.com/go-kit/kit v0.9.0 // indirect github.com/go-log/log v0.1.0 github.com/go-playground/locales v0.12.1 // indirect github.com/go-playground/universal-translator v0.16.0 // indirect github.com/golang/protobuf v1.3.2 + github.com/google/pprof v0.0.0-20190723021845-34ac40c74b70 // indirect github.com/google/uuid v1.1.1 - github.com/gorilla/handlers v1.4.1 - github.com/gorilla/mux v1.7.3 // indirect + github.com/gorilla/handlers v1.4.2 github.com/gorilla/websocket v1.4.0 github.com/hashicorp/consul/api v1.1.0 github.com/hashicorp/go-immutable-radix v1.1.0 // indirect @@ -33,19 +33,18 @@ require ( github.com/hashicorp/go-rootcerts v1.0.1 // indirect github.com/hashicorp/go-sockaddr v1.0.2 // indirect github.com/hashicorp/go-version v1.2.0 // indirect + github.com/hashicorp/golang-lru v0.5.3 // indirect github.com/hashicorp/hcl v1.0.0 github.com/hashicorp/mdns v1.0.1 // indirect github.com/hashicorp/memberlist v0.1.4 github.com/hashicorp/serf v0.8.3 // indirect github.com/imdario/mergo v0.3.7 github.com/joncalhoun/qson v0.0.0-20170526102502-8a9cab3a62b1 - github.com/json-iterator/go v1.1.6 - github.com/kevinburke/ssh_config v0.0.0-20190630040420-2e50c441276c // indirect + github.com/json-iterator/go v1.1.7 github.com/kisielk/errcheck v1.2.0 // indirect github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect - github.com/kr/pty v1.1.8 // indirect github.com/leodido/go-urn v1.1.0 // indirect - github.com/lucas-clemente/quic-go v0.7.1-0.20190710050138-1441923ab031 + github.com/lucas-clemente/quic-go v0.12.0 github.com/mattn/go-colorable v0.1.2 // indirect github.com/mattn/go-runewidth v0.0.4 // indirect github.com/micro/cli v0.2.0 @@ -53,6 +52,9 @@ require ( github.com/miekg/dns v1.1.15 // indirect github.com/mitchellh/gox v1.0.1 // indirect github.com/mitchellh/hashstructure v1.0.0 + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/nats-io/nats.go v1.8.1 github.com/nats-io/nkeys v0.1.0 // indirect github.com/nlopes/slack v0.5.0 @@ -61,24 +63,18 @@ require ( github.com/onsi/gomega v1.5.0 // indirect github.com/pkg/errors v0.8.1 github.com/posener/complete v1.2.1 // indirect - github.com/prometheus/common v0.6.0 // indirect - github.com/prometheus/procfs v0.0.3 // indirect + github.com/prometheus/client_golang v1.1.0 // indirect github.com/sirupsen/logrus v1.4.2 // indirect - github.com/stretchr/objx v0.2.0 // indirect github.com/technoweenie/multipartstreamer v1.0.1 // indirect golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 - golang.org/x/exp v0.0.0-20190627132806-fd42eb6b336f // indirect - golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9 // indirect - golang.org/x/mobile v0.0.0-20190711165009-e47acb2ca7f9 // indirect - golang.org/x/mod v0.1.0 // indirect - golang.org/x/net v0.0.0-20190628185345-da137c7871d7 - golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 // indirect - golang.org/x/tools v0.0.0-20190711191110-9a621aea19f8 // indirect - google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532 // indirect - google.golang.org/grpc v1.22.0 - gopkg.in/go-playground/validator.v9 v9.29.0 - gopkg.in/src-d/go-billy.v4 v4.3.1 // indirect - gopkg.in/src-d/go-git.v4 v4.12.0 + golang.org/x/mobile v0.0.0-20190806162312-597adff16ade // indirect + golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 + golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa // indirect + golang.org/x/tools v0.0.0-20190807201305-8be58fba6352 // indirect + google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64 // indirect + google.golang.org/grpc v1.22.1 + gopkg.in/go-playground/validator.v9 v9.29.1 + gopkg.in/src-d/go-git.v4 v4.13.1 gopkg.in/telegram-bot-api.v4 v4.6.4 - honnef.co/go/tools v0.0.0-20190614002413-cb51c254f01b // indirect + honnef.co/go/tools v0.0.1-2019.2.2 // indirect ) diff --git a/go.sum b/go.sum index 2d9905ed..fbe88f4c 100644 --- a/go.sum +++ b/go.sum @@ -3,15 +3,21 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.40.0/go.mod h1:Tk58MuI9rbLMKlAjeO/bDnteAx7tX2gJIXw4T5Jwlro= cloud.google.com/go v0.41.0/go.mod h1:OauMR7DV8fzvZIl2qg6rkaIhD/vmgk4iwEw/h6ercmg= +cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/Microsoft/go-winio v0.4.13/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= @@ -26,6 +32,7 @@ github.com/beevik/ntp v0.2.0 h1:sGsd+kAXzT0bfVfzJfce04g+dSRfrs+tbQW8lweuYgw= github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y= github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= @@ -43,8 +50,12 @@ github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v0.7.3-0.20190309235953-33c3200e0d16 h1:dmUn0SuGx7unKFwxyeQ/oLUHhEfZosEDrpmYM+6MTuc= github.com/docker/docker v0.7.3-0.20190309235953-33c3200e0d16/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20190710153559-aa8249ae1b8b h1:+Ga+YpCDpcY1fln6GI0fiiirpqHGcob5/Vk3oKNuGdU= +github.com/docker/docker v1.4.2-0.20190710153559-aa8249ae1b8b/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= @@ -61,6 +72,8 @@ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsouza/go-dockerclient v1.4.1 h1:W7wuJ3IB48WYZv/UBk9dCTIb9oX805+L9KIm65HcUYs= github.com/fsouza/go-dockerclient v1.4.1/go.mod h1:PUNHxbowDqRXfRgZqMz1OeGtbWC6VKyZvJ99hDjB0qs= +github.com/fsouza/go-dockerclient v1.4.2 h1:dl6GfIWS5Qn4C6OfSnnoe6YuOV8lvKAE8W/YD1Q7udo= +github.com/fsouza/go-dockerclient v1.4.2/go.mod h1:COunfLZrsdwX/j3YVDAG8gIw3KutrI0x1+vGEJ5zxdI= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= @@ -96,9 +109,11 @@ github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 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/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190723021845-34ac40c74b70/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -108,6 +123,8 @@ github.com/gorilla/handlers v1.4.0 h1:XulKRWSQK5uChr4pEgSE4Tc/OcmnU9GJuSwdog/tZs github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/handlers v1.4.1 h1:BHvcRGJe/TrL+OqFxoKQGddTgeibiOjaBssV5a/N9sw= github.com/gorilla/handlers v1.4.1/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg= +github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= @@ -150,6 +167,8 @@ github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCO github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= @@ -174,12 +193,16 @@ github.com/joncalhoun/qson v0.0.0-20170526102502-8a9cab3a62b1 h1:lnrOS18wZBYrzdD github.com/joncalhoun/qson v0.0.0-20170526102502-8a9cab3a62b1/go.mod h1:DFXrEwSRX0p/aSvxE21319menCBFeQO0jXpRj7LEZUA= github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e h1:RgQk53JHp/Cjunrr1WlsXSZpqXn+uREuHvUVcK82CV8= github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kevinburke/ssh_config v0.0.0-20190630040420-2e50c441276c h1:VAx3LRNjVNvjtgO7KFRuT/3aye/0zJvwn01rHSfoolo= github.com/kevinburke/ssh_config v0.0.0-20190630040420-2e50c441276c/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY= +github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= @@ -197,6 +220,8 @@ github.com/lucas-clemente/quic-go v0.7.1-0.20190710050138-1441923ab031 h1:wjcGvg github.com/lucas-clemente/quic-go v0.7.1-0.20190710050138-1441923ab031/go.mod h1:lb5aAxL68VvhZ00e7yYuQVK/9FLggtYy4qo7oI5qzqA= github.com/lucas-clemente/quic-go v0.11.2 h1:Mop0ac3zALaBR3wGs6j8OYe/tcFvFsxTUFMkE/7yUOI= github.com/lucas-clemente/quic-go v0.11.2/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw= +github.com/lucas-clemente/quic-go v0.12.0 h1:dYHUyB50gEQlK3KqytmNySzuyzAcaQ3iuI2ZReAfVrE= +github.com/lucas-clemente/quic-go v0.12.0/go.mod h1:UXJJPE4RfFef/xPO5wQm0tITK8gNfqwTxjbE7s3Vb8s= github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI= github.com/marten-seemann/qtls v0.2.3 h1:0yWJ43C62LsZt08vuQJDK1uC1czUc3FJeCLPoNAI4vA= github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= @@ -204,6 +229,8 @@ github.com/marten-seemann/qtls v0.2.4 h1:mCJ6i1jAqcsm9XODrSGvXECodoAb1STta+TkxJC github.com/marten-seemann/qtls v0.2.4/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= github.com/marten-seemann/qtls v0.3.1 h1:ySYIvhFjFY2JsNHY6VACvomMEDy3EvdPA6yciUFAiHw= github.com/marten-seemann/qtls v0.3.1/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= +github.com/marten-seemann/qtls v0.3.2 h1:O7awy4bHEzSX/K3h+fZig3/Vo03s/RxlxgsAk9sYamI= +github.com/marten-seemann/qtls v0.3.2/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= @@ -241,11 +268,14 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nats-io/nats.go v1.8.1 h1:6lF/f1/NN6kzUDBz6pyvQDEXO39jqXcWRLu/tKjtOUQ= github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= github.com/nats-io/nkeys v0.0.2 h1:+qM7QpgXnvDDixitZtQUBDY9w/s9mu1ghS+JIbsrx6M= @@ -282,6 +312,7 @@ github.com/posener/complete v1.2.1/go.mod h1:6gapUrK/U1TAN7ciCoNRIdVC5sbdBTUh1DK github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= @@ -301,6 +332,7 @@ github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAm github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME= github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= @@ -339,9 +371,11 @@ golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190627132806-fd42eb6b336f/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190618124811-92942e4437e2/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -350,6 +384,7 @@ golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190607214518-6fa95d984e88/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mobile v0.0.0-20190711165009-e47acb2ca7f9/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mobile v0.0.0-20190806162312-597adff16ade/go.mod h1:AlhUtkH4DA4asiFC5RgK7ZKmauvtkAVcy9L0epCzlWo= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -375,6 +410,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8j4DQRpdYMnGn/bJUEU= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -408,6 +445,10 @@ golang.org/x/sys v0.0.0-20190621062556-bf70e4678053/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa h1:KIDDMLT1O0Nr7TSxp8xM5tJcdn8tgyAONntO829og1M= +golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= 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= @@ -429,9 +470,14 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190530171427-2b03ca6e44eb/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190620191750-1fa568393b23/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624190245-7f2218787638/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190710184609-286818132824/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190711191110-9a621aea19f8/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190807201305-8be58fba6352/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -452,12 +498,17 @@ google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601/go.mod h1:z3L6/3dT google.golang.org/genproto v0.0.0-20190626174449-989357319d63/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532 h1:5pOB7se0B2+IssELuQUs6uoBgYJenkU2AQlvopc2sRw= google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64 h1:iKtrH9Y8mcbADOP0YFaEMth7OfuHY9xHOwNj4znpM1A= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1 h1:j6XxA85m/6txkUCHvzlV5f+HBNl/1r5cZ2A/3IEFOO8= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.22.0 h1:J0UbZOIrCAl+fpTOf8YLs4dJo8L/owV4LYVtAXQoPkw= google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.22.1 h1:/7cs52RnTJmD43s3uxzlq2U7nqVTd/37viQwMrMNlOM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 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= @@ -465,18 +516,24 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-playground/validator.v9 v9.29.0 h1:5ofssLNYgAA/inWn6rTZ4juWpRJUwEnXc1LG2IeXwgQ= gopkg.in/go-playground/validator.v9 v9.29.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= +gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc= +gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/src-d/go-billy.v4 v4.2.1 h1:omN5CrMrMcQ+4I8bJ0wEhOBPanIRWzFC953IiXKdYzo= gopkg.in/src-d/go-billy.v4 v4.2.1/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk= gopkg.in/src-d/go-billy.v4 v4.3.0 h1:KtlZ4c1OWbIs4jCv5ZXrTqG8EQocr0g/d4DjNg70aek= gopkg.in/src-d/go-billy.v4 v4.3.0/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk= gopkg.in/src-d/go-billy.v4 v4.3.1 h1:OkK1DmefDy1Z6Veu82wdNj/cLpYORhdX4qdaYCPwc7s= gopkg.in/src-d/go-billy.v4 v4.3.1/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk= +gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg= +gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= gopkg.in/src-d/go-git-fixtures.v3 v3.1.1/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= gopkg.in/src-d/go-git.v4 v4.11.0 h1:cJwWgJ0DXifrNrXM6RGN1Y2yR60Rr1zQ9Q5DX5S9qgU= gopkg.in/src-d/go-git.v4 v4.11.0/go.mod h1:Vtut8izDyrM8BUVQnzJ+YvmNcem2J89EmfZYCkLokZk= gopkg.in/src-d/go-git.v4 v4.12.0 h1:CKgvBCJCcdfNnyXPYI4Cp8PaDDAmAPEN0CtfEdEAbd8= gopkg.in/src-d/go-git.v4 v4.12.0/go.mod h1:zjlNnzc1Wjn43v3Mtii7RVxiReNP0fIu9npcXKzuNp4= +gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE= +gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= gopkg.in/telegram-bot-api.v4 v4.6.4 h1:hpHWhzn4jTCsAJZZ2loNKfy2QWyPDRJVl3aTFXeMW8g= gopkg.in/telegram-bot-api.v4 v4.6.4/go.mod h1:5DpGO5dbumb40px+dXcwCpcjmeHNYLpk0bp3XRNvWDM= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= @@ -491,4 +548,5 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190614002413-cb51c254f01b/go.mod h1:JlmFZigtG9vBVR3QGIQ9g/Usz4BzH+Xm6Z8iHQWRYUw= +honnef.co/go/tools v0.0.1-2019.2.2/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= From 9c2b8820089e2056879fb05771e9f724db9288fa Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 7 Aug 2019 22:27:03 +0100 Subject: [PATCH 278/287] Bump travis go --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 62ca1e1f..ff6d2694 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: go go: -- 1.11.x - 1.12.x +- master env: - GO111MODULE=on notifications: From 243d43df92e45f7ea8160ab616328e56db1a023e Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Wed, 7 Aug 2019 22:32:16 +0100 Subject: [PATCH 279/287] Strip master from travis --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ff6d2694..211cb587 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: go go: - 1.12.x -- master env: - GO111MODULE=on notifications: From 3fc7d9ea503ff042cce90a6f643fbf7e16b7c250 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 8 Aug 2019 00:19:16 +0100 Subject: [PATCH 280/287] Quic requires an initial message to start the session so we need connect --- tunnel/default.go | 16 ++++------------ tunnel/tunnel_test.go | 14 +++++++++++--- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/tunnel/default.go b/tunnel/default.go index ff86bb6b..7d2d3984 100644 --- a/tunnel/default.go +++ b/tunnel/default.go @@ -144,15 +144,8 @@ func (t *tun) listen(link transport.Socket, listener bool) { return } - // first check Micro-Tunnel switch msg.Header["Micro-Tunnel"] { - case "connect": - // assuming new connection - // TODO: do something with this - continue - case "close": - // assuming connection closed - // TODO: do something with this + case "connect", "close": continue } @@ -289,13 +282,11 @@ func (t *tun) connect() error { continue } - err = c.Send(&transport.Message{ + if err := c.Send(&transport.Message{ Header: map[string]string{ "Micro-Tunnel": "connect", }, - }) - - if err != nil { + }); err != nil { continue } @@ -399,6 +390,7 @@ func (t *tun) Dial(addr string) (Conn, error) { if !ok { return nil, errors.New("error dialing " + addr) } + // set remote c.remote = addr // set local diff --git a/tunnel/tunnel_test.go b/tunnel/tunnel_test.go index b29af5bc..1580d4a9 100644 --- a/tunnel/tunnel_test.go +++ b/tunnel/tunnel_test.go @@ -3,6 +3,7 @@ package tunnel import ( "sync" "testing" + "time" "github.com/micro/go-micro/transport" ) @@ -93,6 +94,8 @@ func TestTwoTunnel(t *testing.T) { } defer tunB.Close() + time.Sleep(time.Millisecond * 50) + // start tunA err = tunA.Connect() if err != nil { @@ -100,14 +103,19 @@ func TestTwoTunnel(t *testing.T) { } defer tunA.Close() + time.Sleep(time.Millisecond * 50) + var wg sync.WaitGroup // start accepting connections + // on tunnel A wg.Add(1) - go testAccept(t, tunB, &wg) + go testAccept(t, tunA, &wg) - // send a message - testSend(t, tunA) + time.Sleep(time.Millisecond * 50) + + // dial and send via B + testSend(t, tunB) // wait until done wg.Wait() From cb1c1afc84a5318065824a60e7e0c49c165be914 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 8 Aug 2019 00:19:30 +0100 Subject: [PATCH 281/287] add quic to defaults --- config/cmd/cmd.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/cmd/cmd.go b/config/cmd/cmd.go index 8d7c3c03..beb4ba97 100644 --- a/config/cmd/cmd.go +++ b/config/cmd/cmd.go @@ -42,6 +42,7 @@ import ( tgrpc "github.com/micro/go-micro/transport/grpc" thttp "github.com/micro/go-micro/transport/http" tmem "github.com/micro/go-micro/transport/memory" + "github.com/micro/go-micro/transport/quic" ) type Cmd interface { @@ -211,6 +212,7 @@ var ( "memory": tmem.NewTransport, "http": thttp.NewTransport, "grpc": tgrpc.NewTransport, + "quic": quic.NewTransport, } // used for default selection as the fall back From 11795071fb8f78a268522a90691887d679685f53 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 8 Aug 2019 12:45:37 +0100 Subject: [PATCH 282/287] Fix panic --- tunnel/default.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tunnel/default.go b/tunnel/default.go index 7d2d3984..12468f74 100644 --- a/tunnel/default.go +++ b/tunnel/default.go @@ -116,6 +116,10 @@ func (t *tun) process() { Body: msg.data.Body, } + if nmsg.Header == nil { + nmsg.Header = make(map[string]string) + } + // set the tunnel id on the outgoing message nmsg.Header["Micro-Tunnel-Id"] = msg.id From fbc1d523d76f96e2cecb943117a216a4ea20c79e Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 8 Aug 2019 13:07:04 +0100 Subject: [PATCH 283/287] add ability to set log level via env var --- util/log/log.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/util/log/log.go b/util/log/log.go index f7ad8324..4374aa1b 100644 --- a/util/log/log.go +++ b/util/log/log.go @@ -26,6 +26,19 @@ var ( level = info ) +func init() { + switch os.Getenv("MICRO_LOG_LEVEL") { + case "debug": + level = debug + case "info": + level = info + case "trace": + level = trace + case "fatal": + level = fatal + } +} + // Log makes use of github.com/go-log/log.Log func Log(v ...interface{}) { logger.Log(v...) From 1e496938b716aabb2928a9c863a75f43f5a696b6 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 8 Aug 2019 13:07:13 +0100 Subject: [PATCH 284/287] more tunnel logging --- tunnel/default.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tunnel/default.go b/tunnel/default.go index 12468f74..d52d2d59 100644 --- a/tunnel/default.go +++ b/tunnel/default.go @@ -250,6 +250,7 @@ func (t *tun) connect() error { go func() { // accept inbound connections err := l.Accept(func(sock transport.Socket) { + log.Debugf("Accepted connection from %s", sock.Remote()) // save the link id := uuid.New().String() t.Lock() @@ -280,11 +281,13 @@ func (t *tun) connect() error { }() for _, node := range t.options.Nodes { + log.Debugf("Dialing %s", node) c, err := t.options.Transport.Dial(node) if err != nil { log.Debugf("Tunnel failed to connect to %s: %v", node, err) continue } + log.Debugf("Connected to %s", node) if err := c.Send(&transport.Message{ Header: map[string]string{ From 59b13aef229c193ca8692faf113ac8f9a9f12cc1 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 8 Aug 2019 13:15:30 +0100 Subject: [PATCH 285/287] tunnel skip zero length nodes --- tunnel/default.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tunnel/default.go b/tunnel/default.go index d52d2d59..58b390bf 100644 --- a/tunnel/default.go +++ b/tunnel/default.go @@ -250,7 +250,7 @@ func (t *tun) connect() error { go func() { // accept inbound connections err := l.Accept(func(sock transport.Socket) { - log.Debugf("Accepted connection from %s", sock.Remote()) + log.Debugf("Tunnel accepted connection from %s", sock.Remote()) // save the link id := uuid.New().String() t.Lock() @@ -281,13 +281,18 @@ func (t *tun) connect() error { }() for _, node := range t.options.Nodes { - log.Debugf("Dialing %s", node) + // skip zero length nodes + if len(node) == 0 { + continue + } + + log.Debugf("Tunnel dialing %s", node) c, err := t.options.Transport.Dial(node) if err != nil { log.Debugf("Tunnel failed to connect to %s: %v", node, err) continue } - log.Debugf("Connected to %s", node) + log.Debugf("Tunnel connected to %s", node) if err := c.Send(&transport.Message{ Header: map[string]string{ From 9eb45dac82531e701d63bcf204f2a8f3e0c11319 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Thu, 8 Aug 2019 15:20:53 +0100 Subject: [PATCH 286/287] Close the tunnel listener when the tunnel is cloed. --- tunnel/default.go | 2 ++ tunnel/listener.go | 7 +++++++ tunnel/socket.go | 1 + 3 files changed, 10 insertions(+) diff --git a/tunnel/default.go b/tunnel/default.go index 7d2d3984..92821589 100644 --- a/tunnel/default.go +++ b/tunnel/default.go @@ -418,6 +418,8 @@ func (t *tun) Listen(addr string) (Listener, error) { accept: make(chan *socket, 128), // the channel to close closed: make(chan bool), + // tunnel closed channel + tunClosed: t.closed, // the connection conn: c, // the listener socket diff --git a/tunnel/listener.go b/tunnel/listener.go index 6c803eb9..070b313b 100644 --- a/tunnel/listener.go +++ b/tunnel/listener.go @@ -11,6 +11,8 @@ type tunListener struct { accept chan *socket // the channel to close closed chan bool + // the tunnel closed channel + tunClosed chan bool // the connection conn Conn // the listener socket @@ -74,6 +76,7 @@ func (t *tunListener) Addr() string { return t.addr } +// Close closes tunnel listener func (t *tunListener) Close() error { select { case <-t.closed: @@ -90,6 +93,10 @@ func (t *tunListener) Accept() (Conn, error) { // if the socket is closed return case <-t.closed: return nil, io.EOF + case <-t.tunClosed: + // close the listener when the tunnel closes + close(t.closed) + return nil, io.EOF // wait for a new connection case c, ok := <-t.accept: if !ok { diff --git a/tunnel/socket.go b/tunnel/socket.go index b1c55797..ac738efc 100644 --- a/tunnel/socket.go +++ b/tunnel/socket.go @@ -79,6 +79,7 @@ func (s *socket) Recv(m *transport.Message) error { return nil } +// Close closes the socket func (s *socket) Close() error { select { case <-s.closed: From 7bd6d1b549063b9073dfc4dea854139f6920d57b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E5=B0=8F=E4=B9=90?= Date: Fri, 9 Aug 2019 12:45:59 +0800 Subject: [PATCH 287/287] no more `WithData` method, instead of `WithJSON` --- config/source/memory/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/source/memory/README.md b/config/source/memory/README.md index 2c8038d8..7f1a4008 100644 --- a/config/source/memory/README.md +++ b/config/source/memory/README.md @@ -27,7 +27,7 @@ Specify source with data ```go memorySource := memory.NewSource( - memory.WithData(data), + memory.WithJSON(data), ) ```