From f0a1031e973e4f83c9862817e257dc76b5531670 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Mon, 9 Sep 2019 18:47:10 +0100 Subject: [PATCH 01/20] Adding new peers up to given depth. Outline of node gaph Update --- network/default.go | 112 ++++++++++++++++++++++------ network/handler/handler.go | 2 +- network/proto/network.micro.go | 34 ++++----- network/proto/network.pb.go | 131 ++++++++++++++++++++++----------- network/proto/network.proto | 13 +++- 5 files changed, 207 insertions(+), 85 deletions(-) diff --git a/network/default.go b/network/default.go index 23c924f6..e6dff7c5 100644 --- a/network/default.go +++ b/network/default.go @@ -27,6 +27,8 @@ var ( ControlChannel = "control" // DefaultLink is default network link DefaultLink = "network" + // MaxDepth defines max depth of neighbourhood topology + MaxDepth = 3 ) var ( @@ -85,6 +87,69 @@ func (n *node) Neighbourhood() []Node { return nodes } +// getNeighbours collects node neighbours up to given depth into pbNeighbours +// NOTE: this method is not thread safe, so make sure you serialize access to it +// NOTE: we should be able to read-Lock this, even though it's recursive +// TODO: we should rework this so it returns pbNeighbours along with error +func (n *node) getNeighbours(pbNeighbours *pbNet.Neighbour, depth int) error { + if pbNeighbours == nil { + return errors.New("neighbours not initialized") + } + + // return if have either reached the depth or have no more neighbours + if depth == 0 || len(n.neighbours) == 0 { + return nil + } + + // decrement the depth + depth-- + + var neighbours []*pbNet.Neighbour + for _, neighbour := range n.neighbours { + // node + node := &pbNet.Node{ + Id: neighbour.id, + Address: neighbour.address, + } + // create new neighbour + pbNodeNeighbour := &pbNet.Neighbour{ + Node: node, + Neighbours: make([]*pbNet.Neighbour, 0), + } + // get neighbours of the neighbour + // NOTE: this is [not] a recursive call + if err := neighbour.getNeighbours(pbNodeNeighbour, depth); err != nil { + return err + } + // add current neighbour to explored neighbours + neighbours = append(neighbours, pbNodeNeighbour) + } + + // add neighbours to the parent topology + pbNeighbours.Neighbours = neighbours + + return nil +} + +// updateNeighbour updates node neighbour up to given depth +func (n *node) updateNeighbour(neighbour *pbNet.Neighbour, depth int) error { + if neighbour == nil { + return errors.New("neighbour not initialized") + } + + // return if have either reached the depth or have no more neighbours + if depth == 0 { + return nil + } + + // decrement the depth + depth-- + + // TODO: implement this + + return nil +} + // network implements Network interface type network struct { // node is network node @@ -363,18 +428,18 @@ func (n *network) processNetChan(client transport.Client, listener tunnel.Listen if n.neighbours[pbNetNeighbour.Node.Id].lastSeen.Before(now) { n.neighbours[pbNetNeighbour.Node.Id].lastSeen = now } - // update/store the neighbour node neighbours + // update/store the node neighbour neighbours up to TopologyDepth // NOTE: * we do NOT update lastSeen time for the neighbours of the neighbour - // * even though we are NOT interested in neighbours of neighbours here + // * even though we are NOT interested in neighbours over TopologyDepth // we still allocate the map of neighbours for each of them - for _, pbNeighbour := range pbNetNeighbour.Neighbours { - neighbourNode := &node{ - id: pbNeighbour.Id, - address: pbNeighbour.Address, - neighbours: make(map[string]*node), - } - n.neighbours[pbNetNeighbour.Node.Id].neighbours[pbNeighbour.Id] = neighbourNode - } + //for _, pbNeighbour := range pbNetNeighbour.Neighbours { + // neighbourNode := &node{ + // id: pbNeighbour.Node.Id, + // address: pbNeighbour.Node.Address, + // neighbours: make(map[string]*node), + // } + // n.neighbours[pbNetNeighbour.Node.Id].neighbours[pbNeighbour.Node.Id] = neighbourNode + //} n.Unlock() // send a solicit message when discovering a new node // NOTE: we need to send the solicit message here after the Lock is released as sendMsg locks, too @@ -431,20 +496,22 @@ func (n *network) sendMsg(msgType string, channel string) error { } case "neighbour": n.RLock() - nodes := make([]*pbNet.Node, len(n.neighbours)) - i := 0 - for id := range n.neighbours { - nodes[i] = &pbNet.Node{ - Id: id, - Address: n.neighbours[id].address, - } - i++ + node := &pbNet.Node{ + Id: n.node.id, + Address: n.node.address, } - n.RUnlock() - protoMsg = &pbNet.Neighbour{ + nodeNeighbour := &pbNet.Neighbour{ Node: node, - Neighbours: nodes, + Neighbours: make([]*pbNet.Neighbour, 0), } + // get all the neighbours down to MaxNeighbourDepth + if err := n.node.getNeighbours(nodeNeighbour, MaxDepth); err != nil { + log.Debugf("Network unable to retrieve node neighbours: %s", err) + return err + } + // set protoMsg for serialization + protoMsg = nodeNeighbour + n.RUnlock() default: return ErrMsgUnknown } @@ -461,9 +528,10 @@ func (n *network) sendMsg(msgType string, channel string) error { Body: body, } + // check if the channel client is initialized n.RLock() client, ok := n.tunClient[channel] - if !ok { + if !ok || client == nil { n.RUnlock() return ErrClientNotFound } diff --git a/network/handler/handler.go b/network/handler/handler.go index 1d8d74a8..d85a8446 100644 --- a/network/handler/handler.go +++ b/network/handler/handler.go @@ -100,7 +100,7 @@ func (n *Network) Neighbourhood(ctx context.Context, req *pbNet.NeighbourhoodReq } // creaate neighbourhood answer - neighbourhood := &pbNet.Neighbour{ + neighbourhood := &pbNet.Neighbourhood{ Node: node, Neighbours: neighbours, } diff --git a/network/proto/network.micro.go b/network/proto/network.micro.go index c114ee96..0e52b20c 100644 --- a/network/proto/network.micro.go +++ b/network/proto/network.micro.go @@ -35,9 +35,9 @@ var _ server.Option // Client API for Network service type NetworkService interface { - ListRoutes(ctx context.Context, in *proto1.Request, opts ...client.CallOption) (*proto1.ListResponse, error) ListNodes(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*ListResponse, error) Neighbourhood(ctx context.Context, in *NeighbourhoodRequest, opts ...client.CallOption) (*NeighbourhoodResponse, error) + ListRoutes(ctx context.Context, in *proto1.Request, opts ...client.CallOption) (*proto1.ListResponse, error) } type networkService struct { @@ -58,16 +58,6 @@ func NewNetworkService(name string, c client.Client) NetworkService { } } -func (c *networkService) ListRoutes(ctx context.Context, in *proto1.Request, opts ...client.CallOption) (*proto1.ListResponse, error) { - req := c.c.NewRequest(c.name, "Network.ListRoutes", in) - out := new(proto1.ListResponse) - err := c.c.Call(ctx, req, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *networkService) ListNodes(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*ListResponse, error) { req := c.c.NewRequest(c.name, "Network.ListNodes", in) out := new(ListResponse) @@ -88,19 +78,29 @@ func (c *networkService) Neighbourhood(ctx context.Context, in *NeighbourhoodReq return out, nil } +func (c *networkService) ListRoutes(ctx context.Context, in *proto1.Request, opts ...client.CallOption) (*proto1.ListResponse, error) { + req := c.c.NewRequest(c.name, "Network.ListRoutes", in) + out := new(proto1.ListResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // Server API for Network service type NetworkHandler interface { - ListRoutes(context.Context, *proto1.Request, *proto1.ListResponse) error ListNodes(context.Context, *ListRequest, *ListResponse) error Neighbourhood(context.Context, *NeighbourhoodRequest, *NeighbourhoodResponse) error + ListRoutes(context.Context, *proto1.Request, *proto1.ListResponse) error } func RegisterNetworkHandler(s server.Server, hdlr NetworkHandler, opts ...server.HandlerOption) error { type network interface { - ListRoutes(ctx context.Context, in *proto1.Request, out *proto1.ListResponse) error ListNodes(ctx context.Context, in *ListRequest, out *ListResponse) error Neighbourhood(ctx context.Context, in *NeighbourhoodRequest, out *NeighbourhoodResponse) error + ListRoutes(ctx context.Context, in *proto1.Request, out *proto1.ListResponse) error } type Network struct { network @@ -113,10 +113,6 @@ type networkHandler struct { NetworkHandler } -func (h *networkHandler) ListRoutes(ctx context.Context, in *proto1.Request, out *proto1.ListResponse) error { - return h.NetworkHandler.ListRoutes(ctx, in, out) -} - func (h *networkHandler) ListNodes(ctx context.Context, in *ListRequest, out *ListResponse) error { return h.NetworkHandler.ListNodes(ctx, in, out) } @@ -124,3 +120,7 @@ func (h *networkHandler) ListNodes(ctx context.Context, in *ListRequest, out *Li func (h *networkHandler) Neighbourhood(ctx context.Context, in *NeighbourhoodRequest, out *NeighbourhoodResponse) error { return h.NetworkHandler.Neighbourhood(ctx, in, out) } + +func (h *networkHandler) ListRoutes(ctx context.Context, in *proto1.Request, out *proto1.ListResponse) error { + return h.NetworkHandler.ListRoutes(ctx, in, out) +} diff --git a/network/proto/network.pb.go b/network/proto/network.pb.go index dc6c0d48..d55c8839 100644 --- a/network/proto/network.pb.go +++ b/network/proto/network.pb.go @@ -133,12 +133,12 @@ func (m *NeighbourhoodRequest) GetId() string { return "" } -// NeighbourhoodResponse contains node neighbourhood hierarchy +// NeighbourhoodResponse returns node neighbourhood type NeighbourhoodResponse struct { - Neighbourhood *Neighbour `protobuf:"bytes,1,opt,name=neighbourhood,proto3" json:"neighbourhood,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Neighbourhoodi *Neighbourhood `protobuf:"bytes,1,opt,name=neighbourhoodi,proto3" json:"neighbourhoodi,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *NeighbourhoodResponse) Reset() { *m = NeighbourhoodResponse{} } @@ -166,9 +166,56 @@ func (m *NeighbourhoodResponse) XXX_DiscardUnknown() { var xxx_messageInfo_NeighbourhoodResponse proto.InternalMessageInfo -func (m *NeighbourhoodResponse) GetNeighbourhood() *Neighbour { +func (m *NeighbourhoodResponse) GetNeighbourhoodi() *Neighbourhood { if m != nil { - return m.Neighbourhood + return m.Neighbourhoodi + } + return nil +} + +type Neighbourhood struct { + Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` + Neighbours []*Node `protobuf:"bytes,2,rep,name=neighbours,proto3" json:"neighbours,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Neighbourhood) Reset() { *m = Neighbourhood{} } +func (m *Neighbourhood) String() string { return proto.CompactTextString(m) } +func (*Neighbourhood) ProtoMessage() {} +func (*Neighbourhood) Descriptor() ([]byte, []int) { + return fileDescriptor_8571034d60397816, []int{4} +} + +func (m *Neighbourhood) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Neighbourhood.Unmarshal(m, b) +} +func (m *Neighbourhood) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Neighbourhood.Marshal(b, m, deterministic) +} +func (m *Neighbourhood) XXX_Merge(src proto.Message) { + xxx_messageInfo_Neighbourhood.Merge(m, src) +} +func (m *Neighbourhood) XXX_Size() int { + return xxx_messageInfo_Neighbourhood.Size(m) +} +func (m *Neighbourhood) XXX_DiscardUnknown() { + xxx_messageInfo_Neighbourhood.DiscardUnknown(m) +} + +var xxx_messageInfo_Neighbourhood proto.InternalMessageInfo + +func (m *Neighbourhood) GetNode() *Node { + if m != nil { + return m.Node + } + return nil +} + +func (m *Neighbourhood) GetNeighbours() []*Node { + if m != nil { + return m.Neighbours } return nil } @@ -188,7 +235,7 @@ 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_8571034d60397816, []int{4} + return fileDescriptor_8571034d60397816, []int{5} } func (m *Node) XXX_Unmarshal(b []byte) error { @@ -236,7 +283,7 @@ 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_8571034d60397816, []int{5} + return fileDescriptor_8571034d60397816, []int{6} } func (m *Connect) XXX_Unmarshal(b []byte) error { @@ -277,7 +324,7 @@ func (m *Close) Reset() { *m = Close{} } func (m *Close) String() string { return proto.CompactTextString(m) } func (*Close) ProtoMessage() {} func (*Close) Descriptor() ([]byte, []int) { - return fileDescriptor_8571034d60397816, []int{6} + return fileDescriptor_8571034d60397816, []int{7} } func (m *Close) XXX_Unmarshal(b []byte) error { @@ -318,7 +365,7 @@ func (m *Solicit) Reset() { *m = Solicit{} } func (m *Solicit) String() string { return proto.CompactTextString(m) } func (*Solicit) ProtoMessage() {} func (*Solicit) Descriptor() ([]byte, []int) { - return fileDescriptor_8571034d60397816, []int{7} + return fileDescriptor_8571034d60397816, []int{8} } func (m *Solicit) XXX_Unmarshal(b []byte) error { @@ -351,17 +398,17 @@ type Neighbour struct { // network node Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` // neighbours - Neighbours []*Node `protobuf:"bytes,3,rep,name=neighbours,proto3" json:"neighbours,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Neighbours []*Neighbour `protobuf:"bytes,2,rep,name=neighbours,proto3" json:"neighbours,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Neighbour) Reset() { *m = Neighbour{} } func (m *Neighbour) String() string { return proto.CompactTextString(m) } func (*Neighbour) ProtoMessage() {} func (*Neighbour) Descriptor() ([]byte, []int) { - return fileDescriptor_8571034d60397816, []int{8} + return fileDescriptor_8571034d60397816, []int{9} } func (m *Neighbour) XXX_Unmarshal(b []byte) error { @@ -389,7 +436,7 @@ func (m *Neighbour) GetNode() *Node { return nil } -func (m *Neighbour) GetNeighbours() []*Node { +func (m *Neighbour) GetNeighbours() []*Neighbour { if m != nil { return m.Neighbours } @@ -401,6 +448,7 @@ func init() { proto.RegisterType((*ListResponse)(nil), "go.micro.network.ListResponse") proto.RegisterType((*NeighbourhoodRequest)(nil), "go.micro.network.NeighbourhoodRequest") proto.RegisterType((*NeighbourhoodResponse)(nil), "go.micro.network.NeighbourhoodResponse") + proto.RegisterType((*Neighbourhood)(nil), "go.micro.network.Neighbourhood") proto.RegisterType((*Node)(nil), "go.micro.network.Node") proto.RegisterType((*Connect)(nil), "go.micro.network.Connect") proto.RegisterType((*Close)(nil), "go.micro.network.Close") @@ -411,28 +459,29 @@ func init() { func init() { proto.RegisterFile("network.proto", fileDescriptor_8571034d60397816) } var fileDescriptor_8571034d60397816 = []byte{ - // 360 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0x41, 0x4f, 0xf2, 0x40, - 0x10, 0xfd, 0x28, 0xf0, 0x35, 0x0c, 0x1f, 0x5f, 0xcc, 0x46, 0x4d, 0x53, 0x83, 0x21, 0x7b, 0x40, - 0x62, 0xb4, 0x18, 0x08, 0x9e, 0xbc, 0x18, 0x0e, 0x5e, 0x08, 0x87, 0x7a, 0xf3, 0x66, 0xbb, 0x9b, - 0xb2, 0x11, 0x3a, 0xb8, 0xbb, 0x8d, 0x7f, 0xc0, 0x1f, 0x6e, 0xba, 0x5d, 0xb0, 0x80, 0x60, 0xb8, - 0x75, 0xe6, 0xbd, 0x37, 0x6f, 0xa7, 0xfb, 0x16, 0x5a, 0x29, 0xd7, 0x1f, 0x28, 0xdf, 0x82, 0xa5, - 0x44, 0x8d, 0xe4, 0x24, 0xc1, 0x60, 0x21, 0x62, 0x89, 0x81, 0xed, 0xfb, 0xc3, 0x44, 0xe8, 0x59, - 0x16, 0x05, 0x31, 0x2e, 0xfa, 0x06, 0xe9, 0x27, 0x78, 0x5b, 0x7c, 0x48, 0xcc, 0x34, 0x97, 0x7d, - 0xa3, 0xb4, 0x45, 0x31, 0x86, 0xb6, 0xa0, 0x39, 0x11, 0x4a, 0x87, 0xfc, 0x3d, 0xe3, 0x4a, 0xd3, - 0x07, 0xf8, 0x57, 0x94, 0x6a, 0x89, 0xa9, 0xe2, 0xe4, 0x06, 0xea, 0x29, 0x32, 0xae, 0xbc, 0x4a, - 0xa7, 0xda, 0x6b, 0x0e, 0xce, 0x83, 0x6d, 0xd7, 0x60, 0x8a, 0x8c, 0x87, 0x05, 0x89, 0x76, 0xe1, - 0x74, 0xca, 0x45, 0x32, 0x8b, 0x30, 0x93, 0x33, 0x44, 0x66, 0xa7, 0x92, 0xff, 0xe0, 0x08, 0xe6, - 0x55, 0x3a, 0x95, 0x5e, 0x23, 0x74, 0x04, 0xa3, 0x2f, 0x70, 0xb6, 0xc5, 0xb3, 0x76, 0x8f, 0xf9, - 0x96, 0x25, 0xc0, 0x68, 0x9a, 0x83, 0x8b, 0x1f, 0x6c, 0x57, 0xb4, 0x70, 0x53, 0x41, 0xef, 0xa0, - 0x96, 0x1f, 0x69, 0xdb, 0x93, 0x78, 0xe0, 0xbe, 0x32, 0x26, 0xb9, 0x52, 0x9e, 0x63, 0x9a, 0xab, - 0x92, 0x8e, 0xc0, 0x1d, 0x63, 0x9a, 0xf2, 0x58, 0x93, 0x6b, 0xa8, 0xe5, 0x9b, 0x58, 0xdb, 0x7d, - 0xdb, 0x1a, 0x0e, 0x1d, 0x42, 0x7d, 0x3c, 0x47, 0xc5, 0x8f, 0x12, 0x8d, 0xc0, 0x7d, 0xc6, 0xb9, - 0x88, 0xc5, 0x71, 0x5e, 0x08, 0x8d, 0xf5, 0xc2, 0xc7, 0x08, 0xc9, 0x3d, 0xc0, 0xfa, 0xf7, 0x28, - 0xaf, 0x7a, 0xf0, 0x12, 0x4b, 0xcc, 0xc1, 0xa7, 0x03, 0xee, 0xb4, 0x00, 0xc9, 0x13, 0x80, 0xc9, - 0x44, 0x1e, 0x1b, 0x45, 0xbc, 0x6f, 0xb5, 0x0d, 0x92, 0xbd, 0x65, 0xbf, 0xbd, 0x83, 0x94, 0xa3, - 0x44, 0xff, 0x90, 0x09, 0x34, 0xf2, 0x4e, 0x6e, 0xa6, 0x48, 0x7b, 0xf7, 0x14, 0xa5, 0x20, 0xfa, - 0x97, 0xfb, 0xe0, 0xf5, 0xb4, 0x08, 0x5a, 0x1b, 0x21, 0x22, 0xdd, 0x03, 0x29, 0x29, 0xa5, 0xd1, - 0xbf, 0xfa, 0x95, 0xb7, 0xf2, 0x88, 0xfe, 0x9a, 0x47, 0x32, 0xfc, 0x0a, 0x00, 0x00, 0xff, 0xff, - 0x59, 0xcf, 0xab, 0xb5, 0x7c, 0x03, 0x00, 0x00, + // 372 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0x5d, 0x4f, 0xea, 0x40, + 0x10, 0xbd, 0xf4, 0xc2, 0x6d, 0x18, 0x2e, 0xc4, 0x6c, 0xd4, 0x34, 0x18, 0x94, 0xec, 0x03, 0x12, + 0xa3, 0xc5, 0x40, 0xf0, 0x45, 0xdf, 0x78, 0xe0, 0x85, 0xf0, 0x80, 0x7f, 0x40, 0xdb, 0x6e, 0xca, + 0x46, 0xe8, 0xe0, 0xee, 0x36, 0xfe, 0x01, 0x7f, 0xb8, 0xd9, 0x76, 0xc1, 0x52, 0xbe, 0xd2, 0xb7, + 0xee, 0xcc, 0x99, 0x73, 0x66, 0xa6, 0x67, 0xa0, 0x1e, 0x31, 0xf5, 0x85, 0xe2, 0xc3, 0x5d, 0x09, + 0x54, 0x48, 0xce, 0x42, 0x74, 0x97, 0xdc, 0x17, 0xe8, 0x9a, 0x78, 0x73, 0x10, 0x72, 0x35, 0x8f, + 0x3d, 0xd7, 0xc7, 0x65, 0x2f, 0xc9, 0xf4, 0x42, 0x7c, 0x48, 0x3f, 0x04, 0xc6, 0x8a, 0x89, 0x5e, + 0x52, 0x69, 0x1e, 0x29, 0x0d, 0xad, 0x43, 0x6d, 0xc2, 0xa5, 0x9a, 0xb1, 0xcf, 0x98, 0x49, 0x45, + 0x5f, 0xe0, 0x7f, 0xfa, 0x94, 0x2b, 0x8c, 0x24, 0x23, 0xf7, 0x50, 0x89, 0x30, 0x60, 0xd2, 0x29, + 0xb5, 0xff, 0x76, 0x6b, 0xfd, 0x4b, 0x37, 0xaf, 0xea, 0x4e, 0x31, 0x60, 0xb3, 0x14, 0x44, 0x3b, + 0x70, 0x3e, 0x65, 0x3c, 0x9c, 0x7b, 0x18, 0x8b, 0x39, 0x62, 0x60, 0x58, 0x49, 0x03, 0x2c, 0x1e, + 0x38, 0xa5, 0x76, 0xa9, 0x5b, 0x9d, 0x59, 0x3c, 0xa0, 0x6f, 0x70, 0x91, 0xc3, 0x19, 0xb9, 0x31, + 0x34, 0xa2, 0x6c, 0x82, 0x27, 0x45, 0xb5, 0xfe, 0xcd, 0x1e, 0xdd, 0x2d, 0x82, 0x5c, 0x19, 0x95, + 0x50, 0xdf, 0x02, 0x90, 0x3b, 0x28, 0xeb, 0x1e, 0x0d, 0xdf, 0xa1, 0x39, 0x12, 0x0c, 0x79, 0x02, + 0xd8, 0xd0, 0x49, 0xc7, 0x3a, 0x3a, 0x79, 0x06, 0x49, 0x1f, 0xa1, 0xac, 0x63, 0xf9, 0x71, 0x89, + 0x03, 0xf6, 0x7b, 0x10, 0x08, 0x26, 0x35, 0x99, 0x0e, 0xae, 0x9f, 0x74, 0x08, 0xf6, 0x08, 0xa3, + 0x88, 0xf9, 0xaa, 0x48, 0x83, 0x74, 0x00, 0x95, 0xd1, 0x02, 0x25, 0x2b, 0x54, 0x34, 0x04, 0xfb, + 0x15, 0x17, 0xdc, 0xe7, 0xc5, 0xb4, 0x14, 0x54, 0x37, 0x9b, 0x2c, 0xb4, 0xc5, 0xe7, 0x3d, 0x5b, + 0xbc, 0x3a, 0xf2, 0x1f, 0xb3, 0xab, 0xec, 0x7f, 0x5b, 0x60, 0x4f, 0x53, 0x04, 0x99, 0x40, 0x55, + 0x7b, 0x52, 0x53, 0x4b, 0xd2, 0xda, 0x65, 0xc8, 0xf8, 0xb7, 0x79, 0x7d, 0x28, 0x9d, 0x1a, 0x8c, + 0xfe, 0x21, 0x5e, 0xde, 0x19, 0x9d, 0x53, 0xde, 0x32, 0xd4, 0xb7, 0x27, 0x71, 0x1b, 0x8d, 0x31, + 0x40, 0xa2, 0xaa, 0x0f, 0x4d, 0x12, 0xe7, 0xb7, 0xd0, 0x9c, 0xde, 0x9a, 0xb2, 0xb5, 0x93, 0xd9, + 0x6e, 0xd6, 0xfb, 0x97, 0x1c, 0xe9, 0xe0, 0x27, 0x00, 0x00, 0xff, 0xff, 0x63, 0xe7, 0xb4, 0xb0, + 0xfc, 0x03, 0x00, 0x00, } diff --git a/network/proto/network.proto b/network/proto/network.proto index 6025d90b..5f15c694 100644 --- a/network/proto/network.proto +++ b/network/proto/network.proto @@ -6,9 +6,9 @@ import "github.com/micro/go-micro/router/proto/router.proto"; // Network service is usesd to gain visibility into networks service Network { - rpc ListRoutes(go.micro.router.Request) returns (go.micro.router.ListResponse) {}; rpc ListNodes(ListRequest) returns (ListResponse) {}; rpc Neighbourhood(NeighbourhoodRequest) returns (NeighbourhoodResponse) {}; + rpc ListRoutes(go.micro.router.Request) returns (go.micro.router.ListResponse) {}; } // Empty request @@ -24,9 +24,14 @@ message NeighbourhoodRequest { string id = 1; } -// NeighbourhoodResponse contains node neighbourhood hierarchy +// NeighbourhoodResponse returns node neighbourhood message NeighbourhoodResponse { - Neighbour neighbourhood = 1; + Neighbourhood neighbourhoodi = 1; +} + +message Neighbourhood { + Node node = 1; + repeated Node neighbours = 2; } // Node is network node @@ -60,5 +65,5 @@ message Neighbour { // network node Node node = 1; // neighbours - repeated Node neighbours = 3; + repeated Neighbour neighbours = 2; } From eec780aaa71d899a8ba459cdf0ba3ba7f4b82516 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Mon, 9 Sep 2019 23:34:27 +0100 Subject: [PATCH 02/20] Update neighbours when neighbour message is received --- network/default.go | 96 +++++++++++++++++++++++++++------------------- 1 file changed, 57 insertions(+), 39 deletions(-) diff --git a/network/default.go b/network/default.go index e6dff7c5..ece93d82 100644 --- a/network/default.go +++ b/network/default.go @@ -131,21 +131,52 @@ func (n *node) getNeighbours(pbNeighbours *pbNet.Neighbour, depth int) error { return nil } -// updateNeighbour updates node neighbour up to given depth -func (n *node) updateNeighbour(neighbour *pbNet.Neighbour, depth int) error { - if neighbour == nil { - return errors.New("neighbour not initialized") +// unpackNeighbour unpacks pbNet.Neighbour into node of given depth +func unpackNeighbour(pbNeighbour *pbNet.Neighbour, depth int) (*node, error) { + if pbNeighbour == nil { + return nil, errors.New("neighbour not initialized") + } + + neighbourNode := &node{ + id: pbNeighbour.Node.Id, + address: pbNeighbour.Node.Address, + neighbours: make(map[string]*node), } // return if have either reached the depth or have no more neighbours - if depth == 0 { - return nil + if depth == 0 || len(pbNeighbour.Neighbours) == 0 { + return neighbourNode, nil } // decrement the depth depth-- - // TODO: implement this + neighbours := make(map[string]*node) + for _, pbNode := range pbNeighbour.Neighbours { + node, err := unpackNeighbour(pbNode, depth) + if err != nil { + return nil, err + } + neighbours[pbNode.Node.Id] = node + } + + neighbourNode.neighbours = neighbours + + return neighbourNode, nil +} + +// updateNeighbour updates node neighbour up to given depth +func (n *node) updateNeighbour(neighbour *pbNet.Neighbour, depth int) error { + // unpack neighbour into topology of size MaxDepth-1 + // NOTE: we need MaxDepth-1 because node n is the parent adding which + // gives us the max neighbour topology we maintain and propagate + node, err := unpackNeighbour(neighbour, MaxDepth-1) + if err != nil { + return err + } + + // update node neighbours with new topology + n.neighbours[neighbour.Node.Id] = node return nil } @@ -423,31 +454,24 @@ func (n *network) processNetChan(client transport.Client, listener tunnel.Listen neighbours: make(map[string]*node), lastSeen: now, } - } - // update lastSeen timestamp - if n.neighbours[pbNetNeighbour.Node.Id].lastSeen.Before(now) { - n.neighbours[pbNetNeighbour.Node.Id].lastSeen = now - } - // update/store the node neighbour neighbours up to TopologyDepth - // NOTE: * we do NOT update lastSeen time for the neighbours of the neighbour - // * even though we are NOT interested in neighbours over TopologyDepth - // we still allocate the map of neighbours for each of them - //for _, pbNeighbour := range pbNetNeighbour.Neighbours { - // neighbourNode := &node{ - // id: pbNeighbour.Node.Id, - // address: pbNeighbour.Node.Address, - // neighbours: make(map[string]*node), - // } - // n.neighbours[pbNetNeighbour.Node.Id].neighbours[pbNeighbour.Node.Id] = neighbourNode - //} - n.Unlock() - // send a solicit message when discovering a new node - // NOTE: we need to send the solicit message here after the Lock is released as sendMsg locks, too - if !exists { + n.Unlock() + // send a solicit message when discovering new neighbour + // NOTE: we need to release the Lock here as sendMsg locsk, too if err := n.sendMsg("solicit", ControlChannel); err != nil { log.Debugf("Network failed to send solicit message: %s", err) } + continue } + // update/store the node neighbour neighbours up to (MaxDepth-1) topology depth + // NOTE: we don't update max topology depth as we dont include this network node + if err := n.node.updateNeighbour(pbNetNeighbour, MaxDepth-1); err != nil { + log.Debugf("Network failed to update neighbours") + } + // update lastSeen timestamp if outdated + if n.neighbours[pbNetNeighbour.Node.Id].lastSeen.Before(now) { + n.neighbours[pbNetNeighbour.Node.Id].lastSeen = now + } + n.Unlock() case "close": pbNetClose := &pbNet.Close{} if err := proto.Unmarshal(m.Body, pbNetClose); err != nil { @@ -1031,32 +1055,26 @@ func (n *network) close() error { // Close closes network connection func (n *network) Close() error { - // lock this operation n.Lock() + defer n.Unlock() if !n.connected { - n.Unlock() return nil } select { case <-n.closed: - n.Unlock() return nil default: - // TODO: send close message to the network channel - close(n.closed) - // set connected to false - n.connected = false - - // unlock the lock otherwise we'll deadlock sending the close - n.Unlock() - // send close message only if we managed to connect to NetworkChannel log.Debugf("Sending close message from: %s", n.options.Id) if err := n.sendMsg("close", NetworkChannel); err != nil { log.Debugf("Network failed to send close message: %s", err) } + // TODO: send close message to the network channel + close(n.closed) + // set connected to false + n.connected = false } return n.close() From f91d0408ab44a96222c81a66321c2e58b0431b27 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Tue, 10 Sep 2019 00:01:41 +0100 Subject: [PATCH 03/20] Moved node implementation into dedicated source file --- network/default.go | 161 ++------------------------------------------- network/node.go | 154 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+), 157 deletions(-) create mode 100644 network/node.go diff --git a/network/default.go b/network/default.go index ece93d82..1029e636 100644 --- a/network/default.go +++ b/network/default.go @@ -27,8 +27,6 @@ var ( ControlChannel = "control" // DefaultLink is default network link DefaultLink = "network" - // MaxDepth defines max depth of neighbourhood topology - MaxDepth = 3 ) var ( @@ -38,149 +36,6 @@ var ( ErrClientNotFound = errors.New("client not found") ) -// node is network node -type node struct { - sync.RWMutex - // id is node id - id string - // address is node address - address string - // neighbours maps the node neighbourhood - neighbours map[string]*node - // network returns the node network - network Network - // lastSeen stores the time the node has been seen last time - lastSeen time.Time -} - -// Id is node ide -func (n *node) Id() string { - return n.id -} - -// Address returns node address -func (n *node) Address() string { - return n.address -} - -// Network returns node network -func (n *node) Network() Network { - return n.network -} - -// Neighbourhood returns node neighbourhood -func (n *node) Neighbourhood() []Node { - var nodes []Node - n.RLock() - for _, neighbourNode := range n.neighbours { - // make a copy of the node - n := &node{ - id: neighbourNode.id, - address: neighbourNode.address, - network: neighbourNode.network, - } - // NOTE: we do not care about neighbour's neighbours - nodes = append(nodes, n) - } - n.RUnlock() - - return nodes -} - -// getNeighbours collects node neighbours up to given depth into pbNeighbours -// NOTE: this method is not thread safe, so make sure you serialize access to it -// NOTE: we should be able to read-Lock this, even though it's recursive -// TODO: we should rework this so it returns pbNeighbours along with error -func (n *node) getNeighbours(pbNeighbours *pbNet.Neighbour, depth int) error { - if pbNeighbours == nil { - return errors.New("neighbours not initialized") - } - - // return if have either reached the depth or have no more neighbours - if depth == 0 || len(n.neighbours) == 0 { - return nil - } - - // decrement the depth - depth-- - - var neighbours []*pbNet.Neighbour - for _, neighbour := range n.neighbours { - // node - node := &pbNet.Node{ - Id: neighbour.id, - Address: neighbour.address, - } - // create new neighbour - pbNodeNeighbour := &pbNet.Neighbour{ - Node: node, - Neighbours: make([]*pbNet.Neighbour, 0), - } - // get neighbours of the neighbour - // NOTE: this is [not] a recursive call - if err := neighbour.getNeighbours(pbNodeNeighbour, depth); err != nil { - return err - } - // add current neighbour to explored neighbours - neighbours = append(neighbours, pbNodeNeighbour) - } - - // add neighbours to the parent topology - pbNeighbours.Neighbours = neighbours - - return nil -} - -// unpackNeighbour unpacks pbNet.Neighbour into node of given depth -func unpackNeighbour(pbNeighbour *pbNet.Neighbour, depth int) (*node, error) { - if pbNeighbour == nil { - return nil, errors.New("neighbour not initialized") - } - - neighbourNode := &node{ - id: pbNeighbour.Node.Id, - address: pbNeighbour.Node.Address, - neighbours: make(map[string]*node), - } - - // return if have either reached the depth or have no more neighbours - if depth == 0 || len(pbNeighbour.Neighbours) == 0 { - return neighbourNode, nil - } - - // decrement the depth - depth-- - - neighbours := make(map[string]*node) - for _, pbNode := range pbNeighbour.Neighbours { - node, err := unpackNeighbour(pbNode, depth) - if err != nil { - return nil, err - } - neighbours[pbNode.Node.Id] = node - } - - neighbourNode.neighbours = neighbours - - return neighbourNode, nil -} - -// updateNeighbour updates node neighbour up to given depth -func (n *node) updateNeighbour(neighbour *pbNet.Neighbour, depth int) error { - // unpack neighbour into topology of size MaxDepth-1 - // NOTE: we need MaxDepth-1 because node n is the parent adding which - // gives us the max neighbour topology we maintain and propagate - node, err := unpackNeighbour(neighbour, MaxDepth-1) - if err != nil { - return err - } - - // update node neighbours with new topology - n.neighbours[neighbour.Node.Id] = node - - return nil -} - // network implements Network interface type network struct { // node is network node @@ -520,21 +375,13 @@ func (n *network) sendMsg(msgType string, channel string) error { } case "neighbour": n.RLock() - node := &pbNet.Node{ - Id: n.node.id, - Address: n.node.address, - } - nodeNeighbour := &pbNet.Neighbour{ - Node: node, - Neighbours: make([]*pbNet.Neighbour, 0), - } - // get all the neighbours down to MaxNeighbourDepth - if err := n.node.getNeighbours(nodeNeighbour, MaxDepth); err != nil { + var err error + // get all the neighbours down to MaxDepth + protoMsg, err = n.node.getNeighbours(MaxDepth) + if err != nil { log.Debugf("Network unable to retrieve node neighbours: %s", err) return err } - // set protoMsg for serialization - protoMsg = nodeNeighbour n.RUnlock() default: return ErrMsgUnknown diff --git a/network/node.go b/network/node.go new file mode 100644 index 00000000..19976045 --- /dev/null +++ b/network/node.go @@ -0,0 +1,154 @@ +package network + +import ( + "errors" + "sync" + "time" + + pbNet "github.com/micro/go-micro/network/proto" +) + +var ( + // MaxDepth defines max depth of peer topology + MaxDepth = 3 +) + +// node is network node +type node struct { + sync.RWMutex + // id is node id + id string + // address is node address + address string + // neighbours maps the node neighbourhood + neighbours map[string]*node + // network returns the node network + network Network + // lastSeen stores the time the node has been seen last time + lastSeen time.Time +} + +// Id is node ide +func (n *node) Id() string { + return n.id +} + +// Address returns node address +func (n *node) Address() string { + return n.address +} + +// Network returns node network +func (n *node) Network() Network { + return n.network +} + +// Neighbourhood returns node neighbourhood +func (n *node) Neighbourhood() []Node { + var nodes []Node + n.RLock() + for _, neighbourNode := range n.neighbours { + // make a copy of the node + n := &node{ + id: neighbourNode.id, + address: neighbourNode.address, + network: neighbourNode.network, + } + // NOTE: we do not care about neighbour's neighbours + nodes = append(nodes, n) + } + n.RUnlock() + + return nodes +} + +// getNeighbours collects node neighbours up to given depth into pbNeighbours +// NOTE: this method is not thread safe, so make sure you serialize access to it +// NOTE: we should be able to read-Lock this, even though it's recursive +func (n *node) getNeighbours(depth int) (*pbNet.Neighbour, error) { + node := &pbNet.Node{ + Id: n.id, + Address: n.address, + } + pbNeighbours := &pbNet.Neighbour{ + Node: node, + Neighbours: make([]*pbNet.Neighbour, 0), + } + + // return if have either reached the depth or have no more neighbours + if depth == 0 || len(n.neighbours) == 0 { + return pbNeighbours, nil + } + + // decrement the depth + depth-- + + var neighbours []*pbNet.Neighbour + for _, neighbour := range n.neighbours { + // get neighbours of the neighbour + // NOTE: this is [not] a recursive call + pbNodeNeighbour, err := neighbour.getNeighbours(depth) + if err != nil { + return nil, err + } + // add current neighbour to explored neighbours + neighbours = append(neighbours, pbNodeNeighbour) + } + + // add neighbours to the parent topology + pbNeighbours.Neighbours = neighbours + + return pbNeighbours, nil +} + +// unpackNeighbour unpacks pbNet.Neighbour into node of given depth +// NOTE: this method is not thread safe, so make sure you serialize access to it +func unpackNeighbour(pbNeighbour *pbNet.Neighbour, depth int) (*node, error) { + if pbNeighbour == nil { + return nil, errors.New("neighbour not initialized") + } + + neighbourNode := &node{ + id: pbNeighbour.Node.Id, + address: pbNeighbour.Node.Address, + neighbours: make(map[string]*node), + } + + // return if have either reached the depth or have no more neighbours + if depth == 0 || len(pbNeighbour.Neighbours) == 0 { + return neighbourNode, nil + } + + // decrement the depth + depth-- + + neighbours := make(map[string]*node) + for _, pbNode := range pbNeighbour.Neighbours { + node, err := unpackNeighbour(pbNode, depth) + if err != nil { + return nil, err + } + neighbours[pbNode.Node.Id] = node + } + + neighbourNode.neighbours = neighbours + + return neighbourNode, nil +} + +// updateNeighbour updates node neighbour up to given depth +// NOTE: this method is not thread safe, so make sure you serialize access to it +func (n *node) updateNeighbour(neighbour *pbNet.Neighbour, depth int) error { + // unpack neighbour into topology of size MaxDepth-1 + // NOTE: we need MaxDepth-1 because node n is the parent adding which + // gives us the max neighbour topology we maintain and propagate + node, err := unpackNeighbour(neighbour, MaxDepth-1) + if err != nil { + return err + } + + // update node neighbours with new topology + n.neighbours[neighbour.Node.Id] = node + + return nil +} From 195c6a8c90efe440bd6385836a9d36d83c8b469d Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Tue, 10 Sep 2019 01:14:23 +0100 Subject: [PATCH 04/20] Neighbour is now peer. Neighbourhood is Peers. Small refactor. --- network/default.go | 168 ++++++++------------- network/handler/handler.go | 136 ++++++++--------- network/network.go | 4 +- network/node.go | 170 ++++++++++++--------- network/proto/network.micro.go | 16 +- network/proto/network.pb.go | 263 ++++++++++++++++----------------- network/proto/network.proto | 22 +-- 7 files changed, 385 insertions(+), 394 deletions(-) diff --git a/network/default.go b/network/default.go index 1029e636..e9821881 100644 --- a/network/default.go +++ b/network/default.go @@ -1,7 +1,6 @@ package network import ( - "container/list" "errors" "sync" "time" @@ -107,9 +106,9 @@ func newNetwork(opts ...Option) Network { network := &network{ node: &node{ - id: options.Id, - address: options.Address, - neighbours: make(map[string]*node), + id: options.Id, + address: options.Address, + peers: make(map[string]*node), }, options: options, Router: options.Router, @@ -261,70 +260,69 @@ func (n *network) processNetChan(client transport.Client, listener tunnel.Listen n.Lock() log.Debugf("Network received connect message from: %s", pbNetConnect.Node.Id) // if the entry already exists skip adding it - if neighbour, ok := n.neighbours[pbNetConnect.Node.Id]; ok { + if peer, ok := n.peers[pbNetConnect.Node.Id]; ok { // update lastSeen timestamp - if n.neighbours[pbNetConnect.Node.Id].lastSeen.Before(now) { - neighbour.lastSeen = now + if n.peers[pbNetConnect.Node.Id].lastSeen.Before(now) { + peer.lastSeen = now } n.Unlock() continue } - // add a new neighbour - // NOTE: new node does not have any neighbours - n.neighbours[pbNetConnect.Node.Id] = &node{ - id: pbNetConnect.Node.Id, - address: pbNetConnect.Node.Address, - neighbours: make(map[string]*node), - lastSeen: now, + // add a new peer to the node peers + // NOTE: new node does not have any peers, yet + n.peers[pbNetConnect.Node.Id] = &node{ + id: pbNetConnect.Node.Id, + address: pbNetConnect.Node.Address, + peers: make(map[string]*node), + lastSeen: now, } n.Unlock() // advertise yourself to the network - if err := n.sendMsg("neighbour", NetworkChannel); err != nil { - log.Debugf("Network failed to advertise neighbours: %v", err) + if err := n.sendMsg("peer", NetworkChannel); err != nil { + log.Debugf("Network failed to advertise peers: %v", err) } // advertise all the routes when a new node has connected if err := n.Router.Solicit(); err != nil { log.Debugf("Network failed to solicit routes: %s", err) } - case "neighbour": + case "peer": // mark the time the message has been received now := time.Now() - pbNetNeighbour := &pbNet.Neighbour{} - if err := proto.Unmarshal(m.Body, pbNetNeighbour); err != nil { - log.Debugf("Network tunnel [%s] neighbour unmarshal error: %v", NetworkChannel, err) + pbNetPeer := &pbNet.Peer{} + if err := proto.Unmarshal(m.Body, pbNetPeer); err != nil { + log.Debugf("Network tunnel [%s] peer unmarshal error: %v", NetworkChannel, err) continue } // don't process your own messages - if pbNetNeighbour.Node.Id == n.options.Id { + if pbNetPeer.Node.Id == n.options.Id { continue } n.Lock() - log.Debugf("Network received neighbour message from: %s", pbNetNeighbour.Node.Id) - // only add the neighbour if it is NOT already in node's list of neighbours - _, exists := n.neighbours[pbNetNeighbour.Node.Id] + log.Debugf("Network received peer message from: %s", pbNetPeer.Node.Id) + // only add the peer if it is NOT already in node's list of peers + _, exists := n.peers[pbNetPeer.Node.Id] if !exists { - n.neighbours[pbNetNeighbour.Node.Id] = &node{ - id: pbNetNeighbour.Node.Id, - address: pbNetNeighbour.Node.Address, - neighbours: make(map[string]*node), - lastSeen: now, + n.peers[pbNetPeer.Node.Id] = &node{ + id: pbNetPeer.Node.Id, + address: pbNetPeer.Node.Address, + peers: make(map[string]*node), + lastSeen: now, } n.Unlock() - // send a solicit message when discovering new neighbour + // send a solicit message when discovering new peer // NOTE: we need to release the Lock here as sendMsg locsk, too if err := n.sendMsg("solicit", ControlChannel); err != nil { log.Debugf("Network failed to send solicit message: %s", err) } continue } - // update/store the node neighbour neighbours up to (MaxDepth-1) topology depth // NOTE: we don't update max topology depth as we dont include this network node - if err := n.node.updateNeighbour(pbNetNeighbour, MaxDepth-1); err != nil { - log.Debugf("Network failed to update neighbours") + if err := n.node.updatePeerTopology(pbNetPeer, MaxDepth-1); err != nil { + log.Debugf("Network failed to update peers") } // update lastSeen timestamp if outdated - if n.neighbours[pbNetNeighbour.Node.Id].lastSeen.Before(now) { - n.neighbours[pbNetNeighbour.Node.Id].lastSeen = now + if n.peers[pbNetPeer.Node.Id].lastSeen.Before(now) { + n.peers[pbNetPeer.Node.Id].lastSeen = now } n.Unlock() case "close": @@ -373,13 +371,13 @@ func (n *network) sendMsg(msgType string, channel string) error { protoMsg = &pbNet.Solicit{ Node: node, } - case "neighbour": + case "peer": n.RLock() var err error - // get all the neighbours down to MaxDepth - protoMsg, err = n.node.getNeighbours(MaxDepth) + // get all the node peers down to MaxDepth + protoMsg, err = n.node.getProtoTopology(MaxDepth) if err != nil { - log.Debugf("Network unable to retrieve node neighbours: %s", err) + log.Debugf("Network unable to retrieve node peers: %s", err) return err } n.RUnlock() @@ -416,7 +414,7 @@ func (n *network) sendMsg(msgType string, channel string) error { return nil } -// announce announces node neighbourhood to the network +// announce announces node peers to the network func (n *network) announce(client transport.Client) { announce := time.NewTicker(AnnounceTime) defer announce.Stop() @@ -427,18 +425,18 @@ func (n *network) announce(client transport.Client) { return case <-announce.C: // advertise yourself to the network - if err := n.sendMsg("neighbour", NetworkChannel); err != nil { - log.Debugf("Network failed to advertise neighbours: %v", err) + if err := n.sendMsg("peer", NetworkChannel); err != nil { + log.Debugf("Network failed to advertise peers: %v", err) continue } } } } -// pruneNode removes a node with given id from the list of neighbours. It also removes all routes originted by this node. +// pruneNode removes a node with given id from the list of peers. It also removes all routes originted by this node. // NOTE: this method is not thread-safe; when calling it make sure you lock the particular code segment func (n *network) pruneNode(id string) error { - delete(n.neighbours, id) + delete(n.peers, id) // lookup all the routes originated at this node q := router.NewQuery( router.QueryRouter(id), @@ -470,7 +468,7 @@ func (n *network) prune() { return case <-prune.C: n.Lock() - for id, node := range n.neighbours { + for id, node := range n.peers { if id == n.options.Id { continue } @@ -528,8 +526,8 @@ func (n *network) acceptCtrlConn(l tunnel.Listener, recv chan *transport.Message // setRouteMetric calculates metric of the route and updates it in place // - Local route metric is 1 -// - Routes with ID of adjacent neighbour are 10 -// - Routes of neighbours of the advertiser are 100 +// - Routes with ID of adjacent nodes are 10 +// - Routes by peers of the advertiser are 100 // - Routes beyond your neighbourhood are 1000 func (n *network) setRouteMetric(route *router.Route) { // we are the origin of the route @@ -539,16 +537,16 @@ func (n *network) setRouteMetric(route *router.Route) { } n.RLock() - // check if the route origin is our neighbour - if _, ok := n.neighbours[route.Router]; ok { + // check if the route origin is our peer + if _, ok := n.peers[route.Router]; ok { route.Metric = 10 n.RUnlock() return } - // check if the route origin is the neighbour of our neighbour - for _, node := range n.neighbours { - for id := range node.neighbours { + // check if the route origin is the peer of our peer + for _, peer := range n.peers { + for id := range peer.peers { if route.Router == id { route.Metric = 100 n.RUnlock() @@ -586,19 +584,19 @@ func (n *network) processCtrlChan(client transport.Client, listener tunnel.Liste if pbRtrAdvert.Id == n.options.Id { continue } - // loookup advertising node in our neighbourhood + // loookup advertising node in our peers n.RLock() log.Debugf("Network received advert message from: %s", pbRtrAdvert.Id) - advertNode, ok := n.neighbours[pbRtrAdvert.Id] + advertNode, ok := n.peers[pbRtrAdvert.Id] if !ok { - // advertising node has not been registered as our neighbour, yet - // let's add it to the map of our neighbours + // advertising node has not been registered as our peer, yet + // let's add it to our peers advertNode = &node{ - id: pbRtrAdvert.Id, - neighbours: make(map[string]*node), - lastSeen: now, + id: pbRtrAdvert.Id, + peers: make(map[string]*node), + lastSeen: now, } - n.neighbours[pbRtrAdvert.Id] = advertNode + n.peers[pbRtrAdvert.Id] = advertNode // send a solicit message when discovering a new node if err := n.sendMsg("solicit", NetworkChannel); err != nil { log.Debugf("Network failed to send solicit message: %s", err) @@ -611,16 +609,16 @@ func (n *network) processCtrlChan(client transport.Client, listener tunnel.Liste // set the address of the advertising node // we know Route.Gateway is the address of advertNode // NOTE: this is true only when advertNode had not been registered - // as our neighbour when we received the advert from it + // as our peer when we received the advert from it if advertNode.address == "" { advertNode.address = event.Route.Gateway } // if advertising node id is not the same as Route.Router // we know the advertising node is not the origin of the route if advertNode.id != event.Route.Router { - // if the origin router is not in the advertising node neighbourhood + // if the origin router is not the advertising node peer // we can't rule out potential routing loops so we bail here - if _, ok := advertNode.neighbours[event.Route.Router]; !ok { + if _, ok := advertNode.peers[event.Route.Router]; !ok { continue } } @@ -821,7 +819,7 @@ func (n *network) Connect() error { // go resolving network nodes go n.resolve() - // broadcast neighbourhood + // broadcast peers go n.announce(netClient) // prune stale nodes go n.prune() @@ -839,48 +837,6 @@ func (n *network) Connect() error { return nil } -// Nodes returns a list of all network nodes -func (n *network) Nodes() []Node { - //track the visited nodes - visited := make(map[string]*node) - // queue of the nodes to visit - queue := list.New() - - // we need to freeze the network graph here - // otherwise we might get invalid results - n.RLock() - defer n.RUnlock() - - // push network node to the back of queue - queue.PushBack(n.node) - // mark the node as visited - visited[n.node.id] = n.node - - // keep iterating over the queue until its empty - for queue.Len() > 0 { - // pop the node from the front of the queue - qnode := queue.Front() - // iterate through all of its neighbours - // mark the visited nodes; enqueue the non-visted - for id, node := range qnode.Value.(*node).neighbours { - if _, ok := visited[id]; !ok { - visited[id] = node - queue.PushBack(node) - } - } - // remove the node from the queue - queue.Remove(qnode) - } - - var nodes []Node - // collect all the nodes and return them - for _, node := range visited { - nodes = append(nodes, node) - } - - return nodes -} - func (n *network) close() error { // stop the server if err := n.server.Stop(); err != nil { diff --git a/network/handler/handler.go b/network/handler/handler.go index d85a8446..89c63cef 100644 --- a/network/handler/handler.go +++ b/network/handler/handler.go @@ -16,6 +16,74 @@ type Network struct { Network network.Network } +// ListNodes returns a list of all accessible nodes in the network +func (n *Network) ListNodes(ctx context.Context, req *pbNet.ListRequest, resp *pbNet.ListResponse) error { + nodes := n.Network.Nodes() + + var respNodes []*pbNet.Node + for _, node := range nodes { + respNode := &pbNet.Node{ + Id: node.Id(), + Address: node.Address(), + } + respNodes = append(respNodes, respNode) + } + + resp.Nodes = respNodes + + return nil +} + +// ListPeers returns a list of all the nodes the node has a direct link with +func (n *Network) ListPeers(ctx context.Context, req *pbNet.PeerRequest, resp *pbNet.PeerResponse) error { + // extract the id of the node to query + id := req.Id + // if no id is passed, we assume local node + if id == "" { + id = n.Network.Id() + } + + // get all the nodes in the network + nodes := n.Network.Nodes() + + // sort the slice of nodes + sort.Slice(nodes, func(i, j int) bool { return nodes[i].Id() <= nodes[j].Id() }) + // find a node with a given id + i := sort.Search(len(nodes), func(j int) bool { return nodes[j].Id() >= id }) + + var nodePeers []*pbNet.Node + // collect all the node peers into slice + if i < len(nodes) && nodes[i].Id() == id { + for _, peer := range nodes[i].Peers() { + // don't return yourself in response + if peer.Id() == n.Network.Id() { + continue + } + pbPeer := &pbNet.Node{ + Id: peer.Id(), + Address: peer.Address(), + } + nodePeers = append(nodePeers, pbPeer) + } + } + + // requested node + node := &pbNet.Node{ + Id: nodes[i].Id(), + Address: nodes[i].Address(), + } + + // creaate peers answer + peers := &pbNet.Peers{ + Node: node, + Peers: nodePeers, + } + + resp.Peers = peers + + return nil +} + // ListRoutes returns a list of routing table routes func (n *Network) ListRoutes(ctx context.Context, req *pbRtr.Request, resp *pbRtr.ListResponse) error { routes, err := n.Network.Options().Router.Table().List() @@ -41,71 +109,3 @@ func (n *Network) ListRoutes(ctx context.Context, req *pbRtr.Request, resp *pbRt return nil } - -// ListNodes returns a list of all accessible nodes in the network -func (n *Network) ListNodes(ctx context.Context, req *pbNet.ListRequest, resp *pbNet.ListResponse) error { - nodes := n.Network.Nodes() - - var respNodes []*pbNet.Node - for _, node := range nodes { - respNode := &pbNet.Node{ - Id: node.Id(), - Address: node.Address(), - } - respNodes = append(respNodes, respNode) - } - - resp.Nodes = respNodes - - return nil -} - -// Neighbourhood returns a list of immediate neighbours -func (n *Network) Neighbourhood(ctx context.Context, req *pbNet.NeighbourhoodRequest, resp *pbNet.NeighbourhoodResponse) error { - // extract the id of the node to query - id := req.Id - // if no id is passed, we assume local node - if id == "" { - id = n.Network.Id() - } - - // get all the nodes in the network - nodes := n.Network.Nodes() - - // sort the slice of nodes - sort.Slice(nodes, func(i, j int) bool { return nodes[i].Id() <= nodes[j].Id() }) - // find a node with a given id - i := sort.Search(len(nodes), func(j int) bool { return nodes[j].Id() >= id }) - - var neighbours []*pbNet.Node - // collect all the nodes in the neighbourhood of the found node - if i < len(nodes) && nodes[i].Id() == id { - for _, neighbour := range nodes[i].Neighbourhood() { - // don't return yourself in response - if neighbour.Id() == n.Network.Id() { - continue - } - pbNeighbour := &pbNet.Node{ - Id: neighbour.Id(), - Address: neighbour.Address(), - } - neighbours = append(neighbours, pbNeighbour) - } - } - - // requested neighbourhood node - node := &pbNet.Node{ - Id: nodes[i].Id(), - Address: nodes[i].Address(), - } - - // creaate neighbourhood answer - neighbourhood := &pbNet.Neighbourhood{ - Node: node, - Neighbours: neighbours, - } - - resp.Neighbourhood = neighbourhood - - return nil -} diff --git a/network/network.go b/network/network.go index 5a9b7f6a..b500e2bc 100644 --- a/network/network.go +++ b/network/network.go @@ -28,8 +28,8 @@ type Node interface { Id() string // Address is node bind address Address() string - // Neighbourhood is node neighbourhood - Neighbourhood() []Node + // Peers returns node peers + Peers() []Node // Network is the network node is in Network() Network } diff --git a/network/node.go b/network/node.go index 19976045..263b60c8 100644 --- a/network/node.go +++ b/network/node.go @@ -1,6 +1,7 @@ package network import ( + "container/list" "errors" "sync" "time" @@ -20,11 +21,11 @@ type node struct { id string // address is node address address string - // neighbours maps the node neighbourhood - neighbours map[string]*node + // peers are nodes with direct link to this node + peers map[string]*node // network returns the node network network Network - // lastSeen stores the time the node has been seen last time + // lastSeen keeps track of node lifetime and updates lastSeen time.Time } @@ -43,112 +44,147 @@ func (n *node) Network() Network { return n.network } -// Neighbourhood returns node neighbourhood -func (n *node) Neighbourhood() []Node { - var nodes []Node +// Nodes returns a slice if all nodes in node topology +func (n *node) Nodes() []Node { + //track the visited nodes + visited := make(map[string]*node) + // queue of the nodes to visit + queue := list.New() + + // we need to freeze the network graph here + // otherwise we might get invalid results n.RLock() - for _, neighbourNode := range n.neighbours { - // make a copy of the node - n := &node{ - id: neighbourNode.id, - address: neighbourNode.address, - network: neighbourNode.network, + defer n.RUnlock() + + // push node to the back of queue + queue.PushBack(n) + // mark the node as visited + visited[n.id] = n + + // keep iterating over the queue until its empty + for queue.Len() > 0 { + // pop the node from the front of the queue + qnode := queue.Front() + // iterate through all of the node peers + // mark the visited nodes; enqueue the non-visted + for id, node := range qnode.Value.(*node).peers { + if _, ok := visited[id]; !ok { + visited[id] = node + queue.PushBack(node) + } } - // NOTE: we do not care about neighbour's neighbours - nodes = append(nodes, n) + // remove the node from the queue + queue.Remove(qnode) + } + + var nodes []Node + // collect all the nodes and return them + for _, node := range visited { + nodes = append(nodes, node) } - n.RUnlock() return nodes } -// getNeighbours collects node neighbours up to given depth into pbNeighbours -// NOTE: this method is not thread safe, so make sure you serialize access to it -// NOTE: we should be able to read-Lock this, even though it's recursive -func (n *node) getNeighbours(depth int) (*pbNet.Neighbour, error) { +// Peers returns node peers +func (n *node) Peers() []Node { + var peers []Node + n.RLock() + for _, peer := range n.peers { + // make a copy of the node + p := &node{ + id: peer.id, + address: peer.address, + network: peer.network, + } + // NOTE: we do not care about peer's peers + peers = append(peers, p) + } + n.RUnlock() + + return peers +} + +// getProtoTopology returns node peers up to given depth encoded in protobufs +// NOTE: this method is NOT thread-safe, so make sure you serialize access to it +func (n *node) getProtoTopology(depth int) (*pbNet.Peer, error) { node := &pbNet.Node{ Id: n.id, Address: n.address, } - pbNeighbours := &pbNet.Neighbour{ - Node: node, - Neighbours: make([]*pbNet.Neighbour, 0), + + pbPeers := &pbNet.Peer{ + Node: node, + Peers: make([]*pbNet.Peer, 0), } - // return if have either reached the depth or have no more neighbours - if depth == 0 || len(n.neighbours) == 0 { - return pbNeighbours, nil + // return if have either reached the depth or have no more peers + if depth == 0 || len(n.peers) == 0 { + return pbPeers, nil } // decrement the depth depth-- - var neighbours []*pbNet.Neighbour - for _, neighbour := range n.neighbours { - // get neighbours of the neighbour + var peers []*pbNet.Peer + for _, peer := range n.peers { + // get peers of the node peers // NOTE: this is [not] a recursive call - pbNodeNeighbour, err := neighbour.getNeighbours(depth) + pbPeerPeer, err := peer.getProtoTopology(depth) if err != nil { return nil, err } - // add current neighbour to explored neighbours - neighbours = append(neighbours, pbNodeNeighbour) + // add current peer to explored peers + peers = append(peers, pbPeerPeer) } - // add neighbours to the parent topology - pbNeighbours.Neighbours = neighbours + // add peers to the parent topology + pbPeers.Peers = peers - return pbNeighbours, nil + return pbPeers, nil } -// unpackNeighbour unpacks pbNet.Neighbour into node of given depth -// NOTE: this method is not thread safe, so make sure you serialize access to it -func unpackNeighbour(pbNeighbour *pbNet.Neighbour, depth int) (*node, error) { - if pbNeighbour == nil { - return nil, errors.New("neighbour not initialized") +// unpackPeer unpacks pbNet.Peer into node topology of given depth +// NOTE: this method is NOT thread-safe, so make sure you serialize access to it +func unpackPeer(pbPeer *pbNet.Peer, depth int) *node { + peerNode := &node{ + id: pbPeer.Node.Id, + address: pbPeer.Node.Address, + peers: make(map[string]*node), } - neighbourNode := &node{ - id: pbNeighbour.Node.Id, - address: pbNeighbour.Node.Address, - neighbours: make(map[string]*node), - } - - // return if have either reached the depth or have no more neighbours - if depth == 0 || len(pbNeighbour.Neighbours) == 0 { - return neighbourNode, nil + // return if have either reached the depth or have no more peers + if depth == 0 || len(pbPeer.Peers) == 0 { + return peerNode } // decrement the depth depth-- - neighbours := make(map[string]*node) - for _, pbNode := range pbNeighbour.Neighbours { - node, err := unpackNeighbour(pbNode, depth) - if err != nil { - return nil, err - } - neighbours[pbNode.Node.Id] = node + peers := make(map[string]*node) + for _, pbPeer := range pbPeer.Peers { + peer := unpackPeer(pbPeer, depth) + peers[pbPeer.Node.Id] = peer } - neighbourNode.neighbours = neighbours + peerNode.peers = peers - return neighbourNode, nil + return peerNode } -// updateNeighbour updates node neighbour up to given depth +// updatePeer updates node peer up to given depth // NOTE: this method is not thread safe, so make sure you serialize access to it -func (n *node) updateNeighbour(neighbour *pbNet.Neighbour, depth int) error { - // unpack neighbour into topology of size MaxDepth-1 - // NOTE: we need MaxDepth-1 because node n is the parent adding which - // gives us the max neighbour topology we maintain and propagate - node, err := unpackNeighbour(neighbour, MaxDepth-1) - if err != nil { - return err +func (n *node) updatePeerTopology(pbPeer *pbNet.Peer, depth int) error { + if pbPeer == nil { + return errors.New("peer not initialized") } - // update node neighbours with new topology - n.neighbours[neighbour.Node.Id] = node + // NOTE: we need MaxDepth-1 because node n is the parent adding which + // gives us the max peer topology we maintain and propagate + peer := unpackPeer(pbPeer, MaxDepth-1) + + // update node peers with new topology + n.peers[pbPeer.Node.Id] = peer return nil } diff --git a/network/proto/network.micro.go b/network/proto/network.micro.go index 0e52b20c..4b5dde73 100644 --- a/network/proto/network.micro.go +++ b/network/proto/network.micro.go @@ -36,7 +36,7 @@ var _ server.Option type NetworkService interface { ListNodes(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*ListResponse, error) - Neighbourhood(ctx context.Context, in *NeighbourhoodRequest, opts ...client.CallOption) (*NeighbourhoodResponse, error) + ListPeers(ctx context.Context, in *PeerRequest, opts ...client.CallOption) (*PeerResponse, error) ListRoutes(ctx context.Context, in *proto1.Request, opts ...client.CallOption) (*proto1.ListResponse, error) } @@ -68,9 +68,9 @@ func (c *networkService) ListNodes(ctx context.Context, in *ListRequest, opts .. return out, nil } -func (c *networkService) Neighbourhood(ctx context.Context, in *NeighbourhoodRequest, opts ...client.CallOption) (*NeighbourhoodResponse, error) { - req := c.c.NewRequest(c.name, "Network.Neighbourhood", in) - out := new(NeighbourhoodResponse) +func (c *networkService) ListPeers(ctx context.Context, in *PeerRequest, opts ...client.CallOption) (*PeerResponse, error) { + req := c.c.NewRequest(c.name, "Network.ListPeers", in) + out := new(PeerResponse) err := c.c.Call(ctx, req, out, opts...) if err != nil { return nil, err @@ -92,14 +92,14 @@ func (c *networkService) ListRoutes(ctx context.Context, in *proto1.Request, opt type NetworkHandler interface { ListNodes(context.Context, *ListRequest, *ListResponse) error - Neighbourhood(context.Context, *NeighbourhoodRequest, *NeighbourhoodResponse) error + ListPeers(context.Context, *PeerRequest, *PeerResponse) error ListRoutes(context.Context, *proto1.Request, *proto1.ListResponse) error } func RegisterNetworkHandler(s server.Server, hdlr NetworkHandler, opts ...server.HandlerOption) error { type network interface { ListNodes(ctx context.Context, in *ListRequest, out *ListResponse) error - Neighbourhood(ctx context.Context, in *NeighbourhoodRequest, out *NeighbourhoodResponse) error + ListPeers(ctx context.Context, in *PeerRequest, out *PeerResponse) error ListRoutes(ctx context.Context, in *proto1.Request, out *proto1.ListResponse) error } type Network struct { @@ -117,8 +117,8 @@ func (h *networkHandler) ListNodes(ctx context.Context, in *ListRequest, out *Li return h.NetworkHandler.ListNodes(ctx, in, out) } -func (h *networkHandler) Neighbourhood(ctx context.Context, in *NeighbourhoodRequest, out *NeighbourhoodResponse) error { - return h.NetworkHandler.Neighbourhood(ctx, in, out) +func (h *networkHandler) ListPeers(ctx context.Context, in *PeerRequest, out *PeerResponse) error { + return h.NetworkHandler.ListPeers(ctx, in, out) } func (h *networkHandler) ListRoutes(ctx context.Context, in *proto1.Request, out *proto1.ListResponse) error { diff --git a/network/proto/network.pb.go b/network/proto/network.pb.go index d55c8839..bca98658 100644 --- a/network/proto/network.pb.go +++ b/network/proto/network.pb.go @@ -93,129 +93,129 @@ func (m *ListResponse) GetNodes() []*Node { return nil } -// NeighbourhoodRequest is sent to query node neighbourhood -type NeighbourhoodRequest struct { +// PeerRequest is sent to query node peers +type PeerRequest struct { Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } -func (m *NeighbourhoodRequest) Reset() { *m = NeighbourhoodRequest{} } -func (m *NeighbourhoodRequest) String() string { return proto.CompactTextString(m) } -func (*NeighbourhoodRequest) ProtoMessage() {} -func (*NeighbourhoodRequest) Descriptor() ([]byte, []int) { +func (m *PeerRequest) Reset() { *m = PeerRequest{} } +func (m *PeerRequest) String() string { return proto.CompactTextString(m) } +func (*PeerRequest) ProtoMessage() {} +func (*PeerRequest) Descriptor() ([]byte, []int) { return fileDescriptor_8571034d60397816, []int{2} } -func (m *NeighbourhoodRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_NeighbourhoodRequest.Unmarshal(m, b) +func (m *PeerRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_PeerRequest.Unmarshal(m, b) } -func (m *NeighbourhoodRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_NeighbourhoodRequest.Marshal(b, m, deterministic) +func (m *PeerRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_PeerRequest.Marshal(b, m, deterministic) } -func (m *NeighbourhoodRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_NeighbourhoodRequest.Merge(m, src) +func (m *PeerRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_PeerRequest.Merge(m, src) } -func (m *NeighbourhoodRequest) XXX_Size() int { - return xxx_messageInfo_NeighbourhoodRequest.Size(m) +func (m *PeerRequest) XXX_Size() int { + return xxx_messageInfo_PeerRequest.Size(m) } -func (m *NeighbourhoodRequest) XXX_DiscardUnknown() { - xxx_messageInfo_NeighbourhoodRequest.DiscardUnknown(m) +func (m *PeerRequest) XXX_DiscardUnknown() { + xxx_messageInfo_PeerRequest.DiscardUnknown(m) } -var xxx_messageInfo_NeighbourhoodRequest proto.InternalMessageInfo +var xxx_messageInfo_PeerRequest proto.InternalMessageInfo -func (m *NeighbourhoodRequest) GetId() string { +func (m *PeerRequest) GetId() string { if m != nil { return m.Id } return "" } -// NeighbourhoodResponse returns node neighbourhood -type NeighbourhoodResponse struct { - Neighbourhoodi *Neighbourhood `protobuf:"bytes,1,opt,name=neighbourhoodi,proto3" json:"neighbourhoodi,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *NeighbourhoodResponse) Reset() { *m = NeighbourhoodResponse{} } -func (m *NeighbourhoodResponse) String() string { return proto.CompactTextString(m) } -func (*NeighbourhoodResponse) ProtoMessage() {} -func (*NeighbourhoodResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_8571034d60397816, []int{3} -} - -func (m *NeighbourhoodResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_NeighbourhoodResponse.Unmarshal(m, b) -} -func (m *NeighbourhoodResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_NeighbourhoodResponse.Marshal(b, m, deterministic) -} -func (m *NeighbourhoodResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_NeighbourhoodResponse.Merge(m, src) -} -func (m *NeighbourhoodResponse) XXX_Size() int { - return xxx_messageInfo_NeighbourhoodResponse.Size(m) -} -func (m *NeighbourhoodResponse) XXX_DiscardUnknown() { - xxx_messageInfo_NeighbourhoodResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_NeighbourhoodResponse proto.InternalMessageInfo - -func (m *NeighbourhoodResponse) GetNeighbourhoodi() *Neighbourhood { - if m != nil { - return m.Neighbourhoodi - } - return nil -} - -type Neighbourhood struct { - Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` - Neighbours []*Node `protobuf:"bytes,2,rep,name=neighbours,proto3" json:"neighbours,omitempty"` +// PeerResponse returns node neighbourhood +type PeerResponse struct { + Peers *Peers `protobuf:"bytes,1,opt,name=peers,proto3" json:"peers,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } -func (m *Neighbourhood) Reset() { *m = Neighbourhood{} } -func (m *Neighbourhood) String() string { return proto.CompactTextString(m) } -func (*Neighbourhood) ProtoMessage() {} -func (*Neighbourhood) Descriptor() ([]byte, []int) { +func (m *PeerResponse) Reset() { *m = PeerResponse{} } +func (m *PeerResponse) String() string { return proto.CompactTextString(m) } +func (*PeerResponse) ProtoMessage() {} +func (*PeerResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_8571034d60397816, []int{3} +} + +func (m *PeerResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_PeerResponse.Unmarshal(m, b) +} +func (m *PeerResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_PeerResponse.Marshal(b, m, deterministic) +} +func (m *PeerResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_PeerResponse.Merge(m, src) +} +func (m *PeerResponse) XXX_Size() int { + return xxx_messageInfo_PeerResponse.Size(m) +} +func (m *PeerResponse) XXX_DiscardUnknown() { + xxx_messageInfo_PeerResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_PeerResponse proto.InternalMessageInfo + +func (m *PeerResponse) GetPeers() *Peers { + if m != nil { + return m.Peers + } + return nil +} + +type Peers struct { + Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` + Peers []*Node `protobuf:"bytes,2,rep,name=peers,proto3" json:"peers,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Peers) Reset() { *m = Peers{} } +func (m *Peers) String() string { return proto.CompactTextString(m) } +func (*Peers) ProtoMessage() {} +func (*Peers) Descriptor() ([]byte, []int) { return fileDescriptor_8571034d60397816, []int{4} } -func (m *Neighbourhood) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Neighbourhood.Unmarshal(m, b) +func (m *Peers) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Peers.Unmarshal(m, b) } -func (m *Neighbourhood) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Neighbourhood.Marshal(b, m, deterministic) +func (m *Peers) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Peers.Marshal(b, m, deterministic) } -func (m *Neighbourhood) XXX_Merge(src proto.Message) { - xxx_messageInfo_Neighbourhood.Merge(m, src) +func (m *Peers) XXX_Merge(src proto.Message) { + xxx_messageInfo_Peers.Merge(m, src) } -func (m *Neighbourhood) XXX_Size() int { - return xxx_messageInfo_Neighbourhood.Size(m) +func (m *Peers) XXX_Size() int { + return xxx_messageInfo_Peers.Size(m) } -func (m *Neighbourhood) XXX_DiscardUnknown() { - xxx_messageInfo_Neighbourhood.DiscardUnknown(m) +func (m *Peers) XXX_DiscardUnknown() { + xxx_messageInfo_Peers.DiscardUnknown(m) } -var xxx_messageInfo_Neighbourhood proto.InternalMessageInfo +var xxx_messageInfo_Peers proto.InternalMessageInfo -func (m *Neighbourhood) GetNode() *Node { +func (m *Peers) GetNode() *Node { if m != nil { return m.Node } return nil } -func (m *Neighbourhood) GetNeighbours() []*Node { +func (m *Peers) GetPeers() []*Node { if m != nil { - return m.Neighbours + return m.Peers } return nil } @@ -393,52 +393,52 @@ func (m *Solicit) GetNode() *Node { return nil } -// Neighbour is used to nnounce node neighbourhood -type Neighbour struct { +// Peer is used to announce node peers +type Peer struct { // network node Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` // neighbours - Neighbours []*Neighbour `protobuf:"bytes,2,rep,name=neighbours,proto3" json:"neighbours,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Peers []*Peer `protobuf:"bytes,2,rep,name=peers,proto3" json:"peers,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *Neighbour) Reset() { *m = Neighbour{} } -func (m *Neighbour) String() string { return proto.CompactTextString(m) } -func (*Neighbour) ProtoMessage() {} -func (*Neighbour) Descriptor() ([]byte, []int) { +func (m *Peer) Reset() { *m = Peer{} } +func (m *Peer) String() string { return proto.CompactTextString(m) } +func (*Peer) ProtoMessage() {} +func (*Peer) Descriptor() ([]byte, []int) { return fileDescriptor_8571034d60397816, []int{9} } -func (m *Neighbour) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Neighbour.Unmarshal(m, b) +func (m *Peer) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Peer.Unmarshal(m, b) } -func (m *Neighbour) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Neighbour.Marshal(b, m, deterministic) +func (m *Peer) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Peer.Marshal(b, m, deterministic) } -func (m *Neighbour) XXX_Merge(src proto.Message) { - xxx_messageInfo_Neighbour.Merge(m, src) +func (m *Peer) XXX_Merge(src proto.Message) { + xxx_messageInfo_Peer.Merge(m, src) } -func (m *Neighbour) XXX_Size() int { - return xxx_messageInfo_Neighbour.Size(m) +func (m *Peer) XXX_Size() int { + return xxx_messageInfo_Peer.Size(m) } -func (m *Neighbour) XXX_DiscardUnknown() { - xxx_messageInfo_Neighbour.DiscardUnknown(m) +func (m *Peer) XXX_DiscardUnknown() { + xxx_messageInfo_Peer.DiscardUnknown(m) } -var xxx_messageInfo_Neighbour proto.InternalMessageInfo +var xxx_messageInfo_Peer proto.InternalMessageInfo -func (m *Neighbour) GetNode() *Node { +func (m *Peer) GetNode() *Node { if m != nil { return m.Node } return nil } -func (m *Neighbour) GetNeighbours() []*Neighbour { +func (m *Peer) GetPeers() []*Peer { if m != nil { - return m.Neighbours + return m.Peers } return nil } @@ -446,42 +446,41 @@ func (m *Neighbour) GetNeighbours() []*Neighbour { func init() { proto.RegisterType((*ListRequest)(nil), "go.micro.network.ListRequest") proto.RegisterType((*ListResponse)(nil), "go.micro.network.ListResponse") - proto.RegisterType((*NeighbourhoodRequest)(nil), "go.micro.network.NeighbourhoodRequest") - proto.RegisterType((*NeighbourhoodResponse)(nil), "go.micro.network.NeighbourhoodResponse") - proto.RegisterType((*Neighbourhood)(nil), "go.micro.network.Neighbourhood") + proto.RegisterType((*PeerRequest)(nil), "go.micro.network.PeerRequest") + proto.RegisterType((*PeerResponse)(nil), "go.micro.network.PeerResponse") + proto.RegisterType((*Peers)(nil), "go.micro.network.Peers") proto.RegisterType((*Node)(nil), "go.micro.network.Node") proto.RegisterType((*Connect)(nil), "go.micro.network.Connect") proto.RegisterType((*Close)(nil), "go.micro.network.Close") proto.RegisterType((*Solicit)(nil), "go.micro.network.Solicit") - proto.RegisterType((*Neighbour)(nil), "go.micro.network.Neighbour") + proto.RegisterType((*Peer)(nil), "go.micro.network.Peer") } func init() { proto.RegisterFile("network.proto", fileDescriptor_8571034d60397816) } var fileDescriptor_8571034d60397816 = []byte{ - // 372 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0x5d, 0x4f, 0xea, 0x40, - 0x10, 0xbd, 0xf4, 0xc2, 0x6d, 0x18, 0x2e, 0xc4, 0x6c, 0xd4, 0x34, 0x18, 0x94, 0xec, 0x03, 0x12, - 0xa3, 0xc5, 0x40, 0xf0, 0x45, 0xdf, 0x78, 0xe0, 0x85, 0xf0, 0x80, 0x7f, 0x40, 0xdb, 0x6e, 0xca, - 0x46, 0xe8, 0xe0, 0xee, 0x36, 0xfe, 0x01, 0x7f, 0xb8, 0xd9, 0x76, 0xc1, 0x52, 0xbe, 0xd2, 0xb7, - 0xee, 0xcc, 0x99, 0x73, 0x66, 0xa6, 0x67, 0xa0, 0x1e, 0x31, 0xf5, 0x85, 0xe2, 0xc3, 0x5d, 0x09, - 0x54, 0x48, 0xce, 0x42, 0x74, 0x97, 0xdc, 0x17, 0xe8, 0x9a, 0x78, 0x73, 0x10, 0x72, 0x35, 0x8f, - 0x3d, 0xd7, 0xc7, 0x65, 0x2f, 0xc9, 0xf4, 0x42, 0x7c, 0x48, 0x3f, 0x04, 0xc6, 0x8a, 0x89, 0x5e, - 0x52, 0x69, 0x1e, 0x29, 0x0d, 0xad, 0x43, 0x6d, 0xc2, 0xa5, 0x9a, 0xb1, 0xcf, 0x98, 0x49, 0x45, - 0x5f, 0xe0, 0x7f, 0xfa, 0x94, 0x2b, 0x8c, 0x24, 0x23, 0xf7, 0x50, 0x89, 0x30, 0x60, 0xd2, 0x29, - 0xb5, 0xff, 0x76, 0x6b, 0xfd, 0x4b, 0x37, 0xaf, 0xea, 0x4e, 0x31, 0x60, 0xb3, 0x14, 0x44, 0x3b, - 0x70, 0x3e, 0x65, 0x3c, 0x9c, 0x7b, 0x18, 0x8b, 0x39, 0x62, 0x60, 0x58, 0x49, 0x03, 0x2c, 0x1e, - 0x38, 0xa5, 0x76, 0xa9, 0x5b, 0x9d, 0x59, 0x3c, 0xa0, 0x6f, 0x70, 0x91, 0xc3, 0x19, 0xb9, 0x31, - 0x34, 0xa2, 0x6c, 0x82, 0x27, 0x45, 0xb5, 0xfe, 0xcd, 0x1e, 0xdd, 0x2d, 0x82, 0x5c, 0x19, 0x95, - 0x50, 0xdf, 0x02, 0x90, 0x3b, 0x28, 0xeb, 0x1e, 0x0d, 0xdf, 0xa1, 0x39, 0x12, 0x0c, 0x79, 0x02, - 0xd8, 0xd0, 0x49, 0xc7, 0x3a, 0x3a, 0x79, 0x06, 0x49, 0x1f, 0xa1, 0xac, 0x63, 0xf9, 0x71, 0x89, - 0x03, 0xf6, 0x7b, 0x10, 0x08, 0x26, 0x35, 0x99, 0x0e, 0xae, 0x9f, 0x74, 0x08, 0xf6, 0x08, 0xa3, - 0x88, 0xf9, 0xaa, 0x48, 0x83, 0x74, 0x00, 0x95, 0xd1, 0x02, 0x25, 0x2b, 0x54, 0x34, 0x04, 0xfb, - 0x15, 0x17, 0xdc, 0xe7, 0xc5, 0xb4, 0x14, 0x54, 0x37, 0x9b, 0x2c, 0xb4, 0xc5, 0xe7, 0x3d, 0x5b, - 0xbc, 0x3a, 0xf2, 0x1f, 0xb3, 0xab, 0xec, 0x7f, 0x5b, 0x60, 0x4f, 0x53, 0x04, 0x99, 0x40, 0x55, - 0x7b, 0x52, 0x53, 0x4b, 0xd2, 0xda, 0x65, 0xc8, 0xf8, 0xb7, 0x79, 0x7d, 0x28, 0x9d, 0x1a, 0x8c, - 0xfe, 0x21, 0x5e, 0xde, 0x19, 0x9d, 0x53, 0xde, 0x32, 0xd4, 0xb7, 0x27, 0x71, 0x1b, 0x8d, 0x31, - 0x40, 0xa2, 0xaa, 0x0f, 0x4d, 0x12, 0xe7, 0xb7, 0xd0, 0x9c, 0xde, 0x9a, 0xb2, 0xb5, 0x93, 0xd9, - 0x6e, 0xd6, 0xfb, 0x97, 0x1c, 0xe9, 0xe0, 0x27, 0x00, 0x00, 0xff, 0xff, 0x63, 0xe7, 0xb4, 0xb0, - 0xfc, 0x03, 0x00, 0x00, + // 353 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x93, 0x51, 0x4f, 0xc2, 0x30, + 0x10, 0xc7, 0x19, 0x32, 0x17, 0x6e, 0x60, 0x4c, 0x1f, 0x74, 0x21, 0x99, 0x21, 0x7d, 0x22, 0x46, + 0x86, 0x81, 0xf0, 0xa6, 0x4f, 0x3c, 0xf8, 0x42, 0x88, 0x99, 0x5f, 0x40, 0xd8, 0x2e, 0xd8, 0x08, + 0x3b, 0x6c, 0x4b, 0xfc, 0xd6, 0x7e, 0x06, 0xd3, 0x76, 0x44, 0x84, 0xcc, 0x84, 0xc4, 0xb7, 0xde, + 0xdd, 0xff, 0x7e, 0x77, 0x6d, 0xef, 0xa0, 0x5d, 0xa0, 0xfe, 0x24, 0xf9, 0x9e, 0x6c, 0x24, 0x69, + 0x62, 0x97, 0x4b, 0x4a, 0xd6, 0x22, 0x93, 0x94, 0x94, 0xfe, 0xce, 0x68, 0x29, 0xf4, 0xdb, 0x76, + 0x91, 0x64, 0xb4, 0x1e, 0xd8, 0xc8, 0x60, 0x49, 0x7d, 0x77, 0x90, 0xb4, 0xd5, 0x28, 0x07, 0x36, + 0xb3, 0x34, 0x1c, 0x86, 0xb7, 0x21, 0x9c, 0x0a, 0xa5, 0x53, 0xfc, 0xd8, 0xa2, 0xd2, 0xfc, 0x01, + 0x5a, 0xce, 0x54, 0x1b, 0x2a, 0x14, 0xb2, 0x3b, 0xf0, 0x0b, 0xca, 0x51, 0x45, 0x5e, 0xf7, 0xac, + 0x17, 0x0e, 0xaf, 0x92, 0xc3, 0xaa, 0xc9, 0x8c, 0x72, 0x4c, 0x9d, 0x88, 0xc7, 0x10, 0x3e, 0x23, + 0xca, 0x12, 0xc6, 0x2e, 0xa0, 0x2e, 0xf2, 0xc8, 0xeb, 0x7a, 0xbd, 0x66, 0x5a, 0x17, 0x39, 0x7f, + 0x84, 0x96, 0x0b, 0x97, 0xf0, 0x3e, 0xf8, 0x1b, 0x44, 0xa9, 0xac, 0x24, 0x1c, 0x5e, 0x1f, 0xc3, + 0x8d, 0x5c, 0xa5, 0x4e, 0xc5, 0xe7, 0xe0, 0x5b, 0x9b, 0xdd, 0x42, 0xc3, 0xd4, 0x2b, 0xd3, 0xaa, + 0x7a, 0xb2, 0x1a, 0x73, 0x01, 0x57, 0xa3, 0xfe, 0xf7, 0x05, 0x5c, 0x89, 0x7b, 0x68, 0x18, 0xf3, + 0xb0, 0x73, 0x16, 0x41, 0x30, 0xcf, 0x73, 0x89, 0xca, 0x70, 0x8c, 0x73, 0x67, 0xf2, 0x31, 0x04, + 0x13, 0x2a, 0x0a, 0xcc, 0xf4, 0x29, 0x6d, 0xf1, 0x11, 0xf8, 0x93, 0x15, 0x29, 0x3c, 0x29, 0x69, + 0x0c, 0xc1, 0x0b, 0xad, 0x44, 0x26, 0x4e, 0xab, 0xf5, 0x0a, 0x0d, 0xf3, 0x6e, 0xff, 0xfc, 0x6c, + 0xf6, 0x27, 0x9d, 0x68, 0xf8, 0xe5, 0x41, 0x30, 0x73, 0x7e, 0x36, 0x85, 0xa6, 0x99, 0x20, 0xc3, + 0x52, 0x2c, 0x3e, 0xce, 0xdb, 0x9b, 0xb6, 0xce, 0x4d, 0x55, 0xd8, 0x0d, 0x08, 0xaf, 0xed, 0x68, + 0xee, 0xdf, 0xe3, 0x8a, 0x2e, 0xaa, 0x69, 0xfb, 0xe3, 0xc6, 0x6b, 0xec, 0x09, 0xc0, 0xf2, 0xcd, + 0x02, 0x28, 0x16, 0xfd, 0xe8, 0xcb, 0x95, 0xd8, 0x91, 0xe2, 0xa3, 0xc8, 0xef, 0xb6, 0x16, 0xe7, + 0x76, 0x79, 0x46, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xaf, 0xb8, 0x9b, 0x3f, 0x94, 0x03, 0x00, + 0x00, } diff --git a/network/proto/network.proto b/network/proto/network.proto index 5f15c694..34e97158 100644 --- a/network/proto/network.proto +++ b/network/proto/network.proto @@ -7,7 +7,7 @@ import "github.com/micro/go-micro/router/proto/router.proto"; // Network service is usesd to gain visibility into networks service Network { rpc ListNodes(ListRequest) returns (ListResponse) {}; - rpc Neighbourhood(NeighbourhoodRequest) returns (NeighbourhoodResponse) {}; + rpc ListPeers(PeerRequest) returns (PeerResponse) {}; rpc ListRoutes(go.micro.router.Request) returns (go.micro.router.ListResponse) {}; } @@ -19,19 +19,19 @@ message ListResponse { repeated Node nodes = 1; } -// NeighbourhoodRequest is sent to query node neighbourhood -message NeighbourhoodRequest { +// PeerRequest is sent to query node peers +message PeerRequest { string id = 1; } -// NeighbourhoodResponse returns node neighbourhood -message NeighbourhoodResponse { - Neighbourhood neighbourhoodi = 1; +// PeerResponse returns node neighbourhood +message PeerResponse { + Peers peers = 1; } -message Neighbourhood { +message Peers { Node node = 1; - repeated Node neighbours = 2; + repeated Node peers = 2; } // Node is network node @@ -60,10 +60,10 @@ message Solicit { Node node = 1; } -// Neighbour is used to nnounce node neighbourhood -message Neighbour { +// Peer is used to announce node peers +message Peer { // network node Node node = 1; // neighbours - repeated Neighbour neighbours = 2; + repeated Peer peers = 2; } From baf4c056638de9a887d902f87866d62f81fe7cf8 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Tue, 10 Sep 2019 12:11:59 +0100 Subject: [PATCH 05/20] Send solicit message to ControlChannel --- network/default.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/network/default.go b/network/default.go index e9821881..b84cc319 100644 --- a/network/default.go +++ b/network/default.go @@ -314,6 +314,7 @@ func (n *network) processNetChan(client transport.Client, listener tunnel.Listen if err := n.sendMsg("solicit", ControlChannel); err != nil { log.Debugf("Network failed to send solicit message: %s", err) } + // after adding new peer go to the next step continue } // NOTE: we don't update max topology depth as we dont include this network node @@ -598,7 +599,7 @@ func (n *network) processCtrlChan(client transport.Client, listener tunnel.Liste } n.peers[pbRtrAdvert.Id] = advertNode // send a solicit message when discovering a new node - if err := n.sendMsg("solicit", NetworkChannel); err != nil { + if err := n.sendMsg("solicit", ControlChannel); err != nil { log.Debugf("Network failed to send solicit message: %s", err) } } From 4c709f7ac1c219476ed30024e9a57aff65a16102 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Tue, 10 Sep 2019 12:51:09 +0100 Subject: [PATCH 06/20] Write Lock() advert update: we are writing into peers map here --- network/default.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/network/default.go b/network/default.go index b84cc319..f4865a93 100644 --- a/network/default.go +++ b/network/default.go @@ -586,7 +586,7 @@ func (n *network) processCtrlChan(client transport.Client, listener tunnel.Liste continue } // loookup advertising node in our peers - n.RLock() + n.Lock() log.Debugf("Network received advert message from: %s", pbRtrAdvert.Id) advertNode, ok := n.peers[pbRtrAdvert.Id] if !ok { @@ -603,7 +603,7 @@ func (n *network) processCtrlChan(client transport.Client, listener tunnel.Liste log.Debugf("Network failed to send solicit message: %s", err) } } - n.RUnlock() + n.Unlock() var events []*router.Event for _, event := range pbRtrAdvert.Events { From cbce5490d7205cef6154d965f95295d277767db5 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Tue, 10 Sep 2019 13:31:02 +0100 Subject: [PATCH 07/20] Lock the Nodes method properly when collecting them. --- network/node.go | 10 +++++----- network/proto/network.pb.go | 21 +++++++++++++-------- network/proto/network.proto | 19 ++++++++++++------- 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/network/node.go b/network/node.go index 263b60c8..a0381ba3 100644 --- a/network/node.go +++ b/network/node.go @@ -46,16 +46,16 @@ func (n *node) Network() Network { // Nodes returns a slice if all nodes in node topology func (n *node) Nodes() []Node { - //track the visited nodes - visited := make(map[string]*node) - // queue of the nodes to visit - queue := list.New() - // we need to freeze the network graph here // otherwise we might get invalid results n.RLock() defer n.RUnlock() + //track the visited nodes + visited := make(map[string]*node) + // queue of the nodes to visit + queue := list.New() + // push node to the back of queue queue.PushBack(n) // mark the node as visited diff --git a/network/proto/network.pb.go b/network/proto/network.pb.go index bca98658..363ef5e4 100644 --- a/network/proto/network.pb.go +++ b/network/proto/network.pb.go @@ -53,8 +53,9 @@ func (m *ListRequest) XXX_DiscardUnknown() { var xxx_messageInfo_ListRequest proto.InternalMessageInfo -// ListResponse is returned by ListNodes and ListNeighbours +// ListResponse is returned by ListNodes type ListResponse struct { + // network nodes Nodes []*Node `protobuf:"bytes,1,rep,name=nodes,proto3" json:"nodes,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -93,8 +94,9 @@ func (m *ListResponse) GetNodes() []*Node { return nil } -// PeerRequest is sent to query node peers +// PeerRequest requests list of peers type PeerRequest struct { + // node id Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -133,7 +135,7 @@ func (m *PeerRequest) GetId() string { return "" } -// PeerResponse returns node neighbourhood +// PeerResponse is returned by ListPeers type PeerResponse struct { Peers *Peers `protobuf:"bytes,1,opt,name=peers,proto3" json:"peers,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -173,8 +175,11 @@ func (m *PeerResponse) GetPeers() *Peers { return nil } +// Peers are node peers type Peers struct { - Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` + // network node + Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` + // node peers Peers []*Node `protobuf:"bytes,2,rep,name=peers,proto3" json:"peers,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -222,7 +227,7 @@ func (m *Peers) GetPeers() []*Node { // Node is network node type Node struct { - // node ide + // node id Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // node address Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` @@ -352,7 +357,7 @@ func (m *Close) GetNode() *Node { return nil } -// Solicit is sent when requesting route advertisement from the network nodes +// Solicit is sent when soliciting routes from the network nodes type Solicit struct { // network node Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` @@ -393,11 +398,11 @@ func (m *Solicit) GetNode() *Node { return nil } -// Peer is used to announce node peers +// Peer is used to advertise node peers type Peer struct { // network node Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` - // neighbours + // node peers Peers []*Peer `protobuf:"bytes,2,rep,name=peers,proto3" json:"peers,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` diff --git a/network/proto/network.proto b/network/proto/network.proto index 34e97158..00e526e6 100644 --- a/network/proto/network.proto +++ b/network/proto/network.proto @@ -14,29 +14,34 @@ service Network { // Empty request message ListRequest {} -// ListResponse is returned by ListNodes and ListNeighbours +// ListResponse is returned by ListNodes message ListResponse { + // network nodes repeated Node nodes = 1; } -// PeerRequest is sent to query node peers +// PeerRequest requests list of peers message PeerRequest { + // node id string id = 1; } -// PeerResponse returns node neighbourhood +// PeerResponse is returned by ListPeers message PeerResponse { Peers peers = 1; } +// Peers are node peers message Peers { + // network node Node node = 1; + // node peers repeated Node peers = 2; } // Node is network node message Node { - // node ide + // node id string id = 1; // node address string address = 2; @@ -54,16 +59,16 @@ message Close { Node node = 1; } -// Solicit is sent when requesting route advertisement from the network nodes +// Solicit is sent when soliciting routes from the network nodes message Solicit { // network node Node node = 1; } -// Peer is used to announce node peers +// Peer is used to advertise node peers message Peer { // network node Node node = 1; - // neighbours + // node peers repeated Peer peers = 2; } From 16fcf1fbda7632bd39644dbce7e0b5741a7ce262 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Tue, 10 Sep 2019 18:32:25 +0100 Subject: [PATCH 08/20] Nodes, Peers and Topology methods for node Topology accepts an argument to define the depth of the topology requested from the network. proto definitions have been modified accordingly, too. --- network/handler/handler.go | 100 ++++++++-------- network/network.go | 2 + network/node.go | 54 +++++++-- network/node_test.go | 174 +++++++++++++++++++++++++++ network/proto/network.micro.go | 17 +++ network/proto/network.pb.go | 211 ++++++++++++++++++++++++--------- network/proto/network.proto | 28 +++-- 7 files changed, 463 insertions(+), 123 deletions(-) create mode 100644 network/node_test.go diff --git a/network/handler/handler.go b/network/handler/handler.go index 89c63cef..e09802f3 100644 --- a/network/handler/handler.go +++ b/network/handler/handler.go @@ -3,7 +3,6 @@ package handler import ( "context" - "sort" "github.com/micro/go-micro/errors" "github.com/micro/go-micro/network" @@ -18,65 +17,33 @@ type Network struct { // ListNodes returns a list of all accessible nodes in the network func (n *Network) ListNodes(ctx context.Context, req *pbNet.ListRequest, resp *pbNet.ListResponse) error { - nodes := n.Network.Nodes() + networkNodes := n.Network.Nodes() - var respNodes []*pbNet.Node - for _, node := range nodes { - respNode := &pbNet.Node{ - Id: node.Id(), - Address: node.Address(), + var nodes []*pbNet.Node + for _, networkNode := range networkNodes { + node := &pbNet.Node{ + Id: networkNode.Id(), + Address: networkNode.Address(), } - respNodes = append(respNodes, respNode) + nodes = append(nodes, node) } - resp.Nodes = respNodes + resp.Nodes = nodes return nil } // ListPeers returns a list of all the nodes the node has a direct link with func (n *Network) ListPeers(ctx context.Context, req *pbNet.PeerRequest, resp *pbNet.PeerResponse) error { - // extract the id of the node to query - id := req.Id - // if no id is passed, we assume local node - if id == "" { - id = n.Network.Id() - } + nodePeers := n.Network.Peers() - // get all the nodes in the network - nodes := n.Network.Nodes() - - // sort the slice of nodes - sort.Slice(nodes, func(i, j int) bool { return nodes[i].Id() <= nodes[j].Id() }) - // find a node with a given id - i := sort.Search(len(nodes), func(j int) bool { return nodes[j].Id() >= id }) - - var nodePeers []*pbNet.Node - // collect all the node peers into slice - if i < len(nodes) && nodes[i].Id() == id { - for _, peer := range nodes[i].Peers() { - // don't return yourself in response - if peer.Id() == n.Network.Id() { - continue - } - pbPeer := &pbNet.Node{ - Id: peer.Id(), - Address: peer.Address(), - } - nodePeers = append(nodePeers, pbPeer) + var peers []*pbNet.Node + for _, nodePeer := range nodePeers { + peer := &pbNet.Node{ + Id: nodePeer.Id(), + Address: nodePeer.Address(), } - } - - // requested node - node := &pbNet.Node{ - Id: nodes[i].Id(), - Address: nodes[i].Address(), - } - - // creaate peers answer - peers := &pbNet.Peers{ - Node: node, - Peers: nodePeers, + peers = append(peers, peer) } resp.Peers = peers @@ -84,6 +51,43 @@ func (n *Network) ListPeers(ctx context.Context, req *pbNet.PeerRequest, resp *p return nil } +// Topology returns a list of nodes in node topology i.e. it returns all (in)directly reachable nodes from this node +func (n *Network) Topology(ctx context.Context, req *pbNet.TopologyRequest, resp *pbNet.TopologyResponse) error { + // NOTE: we are downcasting here + depth := uint(req.Depth) + if depth <= 0 { + depth = network.MaxDepth + } + + // get topology + topNodes := n.Network.Topology(depth) + + var nodes []*pbNet.Node + for _, topNode := range topNodes { + // creaate peers answer + pbNode := &pbNet.Node{ + Id: topNode.Id(), + Address: topNode.Address(), + } + nodes = append(nodes, pbNode) + } + + // network node + node := &pbNet.Node{ + Id: n.Network.Id(), + Address: n.Network.Address(), + } + + topology := &pbNet.Topology{ + Node: node, + Nodes: nodes, + } + + resp.Topology = topology + + return nil +} + // ListRoutes returns a list of routing table routes func (n *Network) ListRoutes(ctx context.Context, req *pbRtr.Request, resp *pbRtr.ListResponse) error { routes, err := n.Network.Options().Router.Table().List() diff --git a/network/network.go b/network/network.go index b500e2bc..add29576 100644 --- a/network/network.go +++ b/network/network.go @@ -46,6 +46,8 @@ type Network interface { Connect() error // Nodes returns list of network nodes Nodes() []Node + // Topology returns a list of all reachable nodes up to depth + Topology(depth uint) []Node // Close stops the tunnel and resolving Close() error // Client is micro client diff --git a/network/node.go b/network/node.go index a0381ba3..dfacdd13 100644 --- a/network/node.go +++ b/network/node.go @@ -3,15 +3,16 @@ package network import ( "container/list" "errors" + "sort" "sync" "time" - pbNet "github.com/micro/go-micro/network/proto" + pb "github.com/micro/go-micro/network/proto" ) var ( // MaxDepth defines max depth of peer topology - MaxDepth = 3 + MaxDepth uint = 3 ) // node is network node @@ -98,6 +99,7 @@ func (n *node) Peers() []Node { network: peer.network, } // NOTE: we do not care about peer's peers + // we only collect the node's peers i.e. its adjacent nodes peers = append(peers, p) } n.RUnlock() @@ -105,17 +107,49 @@ func (n *node) Peers() []Node { return peers } +// Topology returns a slice of all nodes in reachable by node up to given depth +func (n *node) Topology(depth uint) []Node { + // get all the nodes + nodes := n.Nodes() + + n.RLock() + // sort the slice of nodes + sort.Slice(nodes, func(i, j int) bool { return nodes[i].Id() <= nodes[j].Id() }) + // find the node with our id + i := sort.Search(len(nodes), func(j int) bool { return nodes[j].Id() >= n.id }) + + // TODO: finish implementing this + var topology []Node + // collect all the reachable nodes into slice + if i < len(nodes) && nodes[i].Id() == n.id { + for _, peer := range nodes[i].Peers() { + // don't return yourself + if peer.Id() == n.id { + continue + } + topNode := &node{ + id: peer.Id(), + address: peer.Address(), + } + topology = append(topology, topNode) + } + } + n.RUnlock() + + return topology +} + // getProtoTopology returns node peers up to given depth encoded in protobufs // NOTE: this method is NOT thread-safe, so make sure you serialize access to it -func (n *node) getProtoTopology(depth int) (*pbNet.Peer, error) { - node := &pbNet.Node{ +func (n *node) getProtoTopology(depth uint) (*pb.Peer, error) { + node := &pb.Node{ Id: n.id, Address: n.address, } - pbPeers := &pbNet.Peer{ + pbPeers := &pb.Peer{ Node: node, - Peers: make([]*pbNet.Peer, 0), + Peers: make([]*pb.Peer, 0), } // return if have either reached the depth or have no more peers @@ -126,7 +160,7 @@ func (n *node) getProtoTopology(depth int) (*pbNet.Peer, error) { // decrement the depth depth-- - var peers []*pbNet.Peer + var peers []*pb.Peer for _, peer := range n.peers { // get peers of the node peers // NOTE: this is [not] a recursive call @@ -144,9 +178,9 @@ func (n *node) getProtoTopology(depth int) (*pbNet.Peer, error) { return pbPeers, nil } -// unpackPeer unpacks pbNet.Peer into node topology of given depth +// unpackPeer unpacks pb.Peer into node topology of given depth // NOTE: this method is NOT thread-safe, so make sure you serialize access to it -func unpackPeer(pbPeer *pbNet.Peer, depth int) *node { +func unpackPeer(pbPeer *pb.Peer, depth uint) *node { peerNode := &node{ id: pbPeer.Node.Id, address: pbPeer.Node.Address, @@ -174,7 +208,7 @@ func unpackPeer(pbPeer *pbNet.Peer, depth int) *node { // updatePeer updates node peer up to given depth // NOTE: this method is not thread safe, so make sure you serialize access to it -func (n *node) updatePeerTopology(pbPeer *pbNet.Peer, depth int) error { +func (n *node) updatePeerTopology(pbPeer *pb.Peer, depth uint) error { if pbPeer == nil { return errors.New("peer not initialized") } diff --git a/network/node_test.go b/network/node_test.go new file mode 100644 index 00000000..dc0add63 --- /dev/null +++ b/network/node_test.go @@ -0,0 +1,174 @@ +package network + +import "testing" + +var ( + testNodeId = "testNode" + testNodeAddress = "testAddress" + testNodeNetName = "testNetwork" + testNodePeerIds = []string{"peer1", "peer2", "peer3"} + testPeerOfPeerIds = []string{"peer11", "peer12"} +) + +func testSetup() *node { + testNode := &node{ + id: testNodeId, + address: testNodeAddress, + peers: make(map[string]*node), + network: newNetwork(Name(testNodeNetName)), + } + + // add some peers to the node + for _, id := range testNodePeerIds { + testNode.peers[id] = &node{ + id: id, + address: testNode.address + "-" + id, + peers: make(map[string]*node), + network: testNode.network, + } + } + + // add peers to peer1 + // NOTE: these are peers of peers! + for _, id := range testPeerOfPeerIds { + testNode.peers["peer1"].peers[id] = &node{ + id: id, + address: testNode.address + "-" + id, + peers: make(map[string]*node), + network: testNode.network, + } + } + + // connect peer1 with peer2 + testNode.peers["peer1"].peers["peer2"] = testNode.peers["peer2"] + // connect peer2 with peer3 + testNode.peers["peer2"].peers["peer3"] = testNode.peers["peer3"] + + return testNode +} + +func TestNodeId(t *testing.T) { + node := testSetup() + if node.Id() != testNodeId { + t.Errorf("Expected id: %s, found: %s", testNodeId, node.Id()) + } +} + +func TestNodeAddress(t *testing.T) { + node := testSetup() + if node.Address() != testNodeAddress { + t.Errorf("Expected address: %s, found: %s", testNodeAddress, node.Address()) + } +} +func TestNodeNetwork(t *testing.T) { + node := testSetup() + if node.Network().Name() != testNodeNetName { + t.Errorf("Expected network: %s, found: %s", testNodeNetName, node.Network().Name()) + } +} + +func TestNodes(t *testing.T) { + // single node + single := &node{ + id: testNodeId, + address: testNodeAddress, + peers: make(map[string]*node), + network: newNetwork(Name(testNodeNetName)), + } + // get all the nodes including yourself + nodes := single.Nodes() + nodeCount := 1 + + if len(nodes) != nodeCount { + t.Errorf("Expected to find %d nodes, found: %d", nodeCount, len(nodes)) + } + + // complicated node graph + node := testSetup() + // get all the nodes including yourself + nodes = node.Nodes() + + // compile a list of ids of all nodes in the network into map for easy indexing + nodeIds := make(map[string]bool) + // add yourself + nodeIds[node.id] = true + // add peer Ids + for _, id := range testNodePeerIds { + nodeIds[id] = true + } + // add peer1 peers i.e. peers of peer + for _, id := range testPeerOfPeerIds { + nodeIds[id] = true + } + + // we should return the correct number of nodes + if len(nodes) != len(nodeIds) { + t.Errorf("Expected %d nodes, found: %d", len(nodeIds), len(nodes)) + } + + // iterate through the list of nodes and makes sure all have been returned + for _, node := range nodes { + if _, ok := nodeIds[node.Id()]; !ok { + t.Errorf("Expected to find %s node", node.Id()) + } + } +} + +func TestPeers(t *testing.T) { + // single node + single := &node{ + id: testNodeId, + address: testNodeAddress, + peers: make(map[string]*node), + network: newNetwork(Name(testNodeNetName)), + } + // get all the nodes including yourself + peers := single.Peers() + peerCount := 0 + + if len(peers) != peerCount { + t.Errorf("Expected to find %d peers, found: %d", peerCount, len(peers)) + } + + // complicated node graph + node := testSetup() + // get all the nodes including yourself + peers = node.Peers() + + // compile a list of ids of all nodes in the network into map for easy indexing + peerIds := make(map[string]bool) + // add peer Ids + for _, id := range testNodePeerIds { + peerIds[id] = true + } + + // we should return the correct number of peers + if len(peers) != len(peerIds) { + t.Errorf("Expected %d nodes, found: %d", len(peerIds), len(peers)) + } + + // iterate through the list of peers and makes sure all have been returned + for _, peer := range peers { + if _, ok := peerIds[peer.Id()]; !ok { + t.Errorf("Expected to find %s peer", node.Id()) + } + } +} + +func TestTopology(t *testing.T) { + // single node + single := &node{ + id: testNodeId, + address: testNodeAddress, + peers: make(map[string]*node), + network: newNetwork(Name(testNodeNetName)), + } + // get all the nodes including yourself + topology := single.Topology(MaxDepth) + // you should not be in your topology + topCount := 0 + + if len(topology) != topCount { + t.Errorf("Expected to find %d nodes, found: %d", topCount, len(topology)) + } +} diff --git a/network/proto/network.micro.go b/network/proto/network.micro.go index 4b5dde73..b0f1ae6b 100644 --- a/network/proto/network.micro.go +++ b/network/proto/network.micro.go @@ -37,6 +37,7 @@ var _ server.Option type NetworkService interface { ListNodes(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*ListResponse, error) ListPeers(ctx context.Context, in *PeerRequest, opts ...client.CallOption) (*PeerResponse, error) + Topology(ctx context.Context, in *TopologyRequest, opts ...client.CallOption) (*TopologyResponse, error) ListRoutes(ctx context.Context, in *proto1.Request, opts ...client.CallOption) (*proto1.ListResponse, error) } @@ -78,6 +79,16 @@ func (c *networkService) ListPeers(ctx context.Context, in *PeerRequest, opts .. return out, nil } +func (c *networkService) Topology(ctx context.Context, in *TopologyRequest, opts ...client.CallOption) (*TopologyResponse, error) { + req := c.c.NewRequest(c.name, "Network.Topology", in) + out := new(TopologyResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *networkService) ListRoutes(ctx context.Context, in *proto1.Request, opts ...client.CallOption) (*proto1.ListResponse, error) { req := c.c.NewRequest(c.name, "Network.ListRoutes", in) out := new(proto1.ListResponse) @@ -93,6 +104,7 @@ func (c *networkService) ListRoutes(ctx context.Context, in *proto1.Request, opt type NetworkHandler interface { ListNodes(context.Context, *ListRequest, *ListResponse) error ListPeers(context.Context, *PeerRequest, *PeerResponse) error + Topology(context.Context, *TopologyRequest, *TopologyResponse) error ListRoutes(context.Context, *proto1.Request, *proto1.ListResponse) error } @@ -100,6 +112,7 @@ func RegisterNetworkHandler(s server.Server, hdlr NetworkHandler, opts ...server type network interface { ListNodes(ctx context.Context, in *ListRequest, out *ListResponse) error ListPeers(ctx context.Context, in *PeerRequest, out *PeerResponse) error + Topology(ctx context.Context, in *TopologyRequest, out *TopologyResponse) error ListRoutes(ctx context.Context, in *proto1.Request, out *proto1.ListResponse) error } type Network struct { @@ -121,6 +134,10 @@ func (h *networkHandler) ListPeers(ctx context.Context, in *PeerRequest, out *Pe return h.NetworkHandler.ListPeers(ctx, in, out) } +func (h *networkHandler) Topology(ctx context.Context, in *TopologyRequest, out *TopologyResponse) error { + return h.NetworkHandler.Topology(ctx, in, out) +} + func (h *networkHandler) ListRoutes(ctx context.Context, in *proto1.Request, out *proto1.ListResponse) error { return h.NetworkHandler.ListRoutes(ctx, in, out) } diff --git a/network/proto/network.pb.go b/network/proto/network.pb.go index 363ef5e4..83f63659 100644 --- a/network/proto/network.pb.go +++ b/network/proto/network.pb.go @@ -137,7 +137,7 @@ func (m *PeerRequest) GetId() string { // PeerResponse is returned by ListPeers type PeerResponse struct { - Peers *Peers `protobuf:"bytes,1,opt,name=peers,proto3" json:"peers,omitempty"` + Peers []*Node `protobuf:"bytes,1,rep,name=peers,proto3" json:"peers,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -168,59 +168,99 @@ func (m *PeerResponse) XXX_DiscardUnknown() { var xxx_messageInfo_PeerResponse proto.InternalMessageInfo -func (m *PeerResponse) GetPeers() *Peers { +func (m *PeerResponse) GetPeers() []*Node { if m != nil { return m.Peers } return nil } -// Peers are node peers -type Peers struct { - // network node - Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` - // node peers - Peers []*Node `protobuf:"bytes,2,rep,name=peers,proto3" json:"peers,omitempty"` +// TopologyRequest list node topology +type TopologyRequest struct { + // node id + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // topology depth + Depth uint64 `protobuf:"varint,2,opt,name=depth,proto3" json:"depth,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } -func (m *Peers) Reset() { *m = Peers{} } -func (m *Peers) String() string { return proto.CompactTextString(m) } -func (*Peers) ProtoMessage() {} -func (*Peers) Descriptor() ([]byte, []int) { +func (m *TopologyRequest) Reset() { *m = TopologyRequest{} } +func (m *TopologyRequest) String() string { return proto.CompactTextString(m) } +func (*TopologyRequest) ProtoMessage() {} +func (*TopologyRequest) Descriptor() ([]byte, []int) { return fileDescriptor_8571034d60397816, []int{4} } -func (m *Peers) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Peers.Unmarshal(m, b) +func (m *TopologyRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TopologyRequest.Unmarshal(m, b) } -func (m *Peers) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Peers.Marshal(b, m, deterministic) +func (m *TopologyRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TopologyRequest.Marshal(b, m, deterministic) } -func (m *Peers) XXX_Merge(src proto.Message) { - xxx_messageInfo_Peers.Merge(m, src) +func (m *TopologyRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_TopologyRequest.Merge(m, src) } -func (m *Peers) XXX_Size() int { - return xxx_messageInfo_Peers.Size(m) +func (m *TopologyRequest) XXX_Size() int { + return xxx_messageInfo_TopologyRequest.Size(m) } -func (m *Peers) XXX_DiscardUnknown() { - xxx_messageInfo_Peers.DiscardUnknown(m) +func (m *TopologyRequest) XXX_DiscardUnknown() { + xxx_messageInfo_TopologyRequest.DiscardUnknown(m) } -var xxx_messageInfo_Peers proto.InternalMessageInfo +var xxx_messageInfo_TopologyRequest proto.InternalMessageInfo -func (m *Peers) GetNode() *Node { +func (m *TopologyRequest) GetId() string { if m != nil { - return m.Node + return m.Id } - return nil + return "" } -func (m *Peers) GetPeers() []*Node { +func (m *TopologyRequest) GetDepth() uint64 { if m != nil { - return m.Peers + return m.Depth + } + return 0 +} + +// TopologyResponse is returned by Topology +type TopologyResponse struct { + Topology *Topology `protobuf:"bytes,1,opt,name=topology,proto3" json:"topology,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TopologyResponse) Reset() { *m = TopologyResponse{} } +func (m *TopologyResponse) String() string { return proto.CompactTextString(m) } +func (*TopologyResponse) ProtoMessage() {} +func (*TopologyResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_8571034d60397816, []int{5} +} + +func (m *TopologyResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TopologyResponse.Unmarshal(m, b) +} +func (m *TopologyResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TopologyResponse.Marshal(b, m, deterministic) +} +func (m *TopologyResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_TopologyResponse.Merge(m, src) +} +func (m *TopologyResponse) XXX_Size() int { + return xxx_messageInfo_TopologyResponse.Size(m) +} +func (m *TopologyResponse) XXX_DiscardUnknown() { + xxx_messageInfo_TopologyResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_TopologyResponse proto.InternalMessageInfo + +func (m *TopologyResponse) GetTopology() *Topology { + if m != nil { + return m.Topology } return nil } @@ -240,7 +280,7 @@ 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_8571034d60397816, []int{5} + return fileDescriptor_8571034d60397816, []int{6} } func (m *Node) XXX_Unmarshal(b []byte) error { @@ -275,6 +315,56 @@ func (m *Node) GetAddress() string { return "" } +// Topology is used to nnounce node neighbourhood +type Topology struct { + // network node + Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` + // neighbours + Nodes []*Node `protobuf:"bytes,2,rep,name=nodes,proto3" json:"nodes,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Topology) Reset() { *m = Topology{} } +func (m *Topology) String() string { return proto.CompactTextString(m) } +func (*Topology) ProtoMessage() {} +func (*Topology) Descriptor() ([]byte, []int) { + return fileDescriptor_8571034d60397816, []int{7} +} + +func (m *Topology) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Topology.Unmarshal(m, b) +} +func (m *Topology) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Topology.Marshal(b, m, deterministic) +} +func (m *Topology) XXX_Merge(src proto.Message) { + xxx_messageInfo_Topology.Merge(m, src) +} +func (m *Topology) XXX_Size() int { + return xxx_messageInfo_Topology.Size(m) +} +func (m *Topology) XXX_DiscardUnknown() { + xxx_messageInfo_Topology.DiscardUnknown(m) +} + +var xxx_messageInfo_Topology proto.InternalMessageInfo + +func (m *Topology) GetNode() *Node { + if m != nil { + return m.Node + } + return nil +} + +func (m *Topology) GetNodes() []*Node { + if m != nil { + return m.Nodes + } + return nil +} + // Connect is sent when the node connects to the network type Connect struct { // network mode @@ -288,7 +378,7 @@ 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_8571034d60397816, []int{6} + return fileDescriptor_8571034d60397816, []int{8} } func (m *Connect) XXX_Unmarshal(b []byte) error { @@ -329,7 +419,7 @@ func (m *Close) Reset() { *m = Close{} } func (m *Close) String() string { return proto.CompactTextString(m) } func (*Close) ProtoMessage() {} func (*Close) Descriptor() ([]byte, []int) { - return fileDescriptor_8571034d60397816, []int{7} + return fileDescriptor_8571034d60397816, []int{9} } func (m *Close) XXX_Unmarshal(b []byte) error { @@ -370,7 +460,7 @@ func (m *Solicit) Reset() { *m = Solicit{} } func (m *Solicit) String() string { return proto.CompactTextString(m) } func (*Solicit) ProtoMessage() {} func (*Solicit) Descriptor() ([]byte, []int) { - return fileDescriptor_8571034d60397816, []int{8} + return fileDescriptor_8571034d60397816, []int{10} } func (m *Solicit) XXX_Unmarshal(b []byte) error { @@ -413,7 +503,7 @@ func (m *Peer) Reset() { *m = Peer{} } func (m *Peer) String() string { return proto.CompactTextString(m) } func (*Peer) ProtoMessage() {} func (*Peer) Descriptor() ([]byte, []int) { - return fileDescriptor_8571034d60397816, []int{9} + return fileDescriptor_8571034d60397816, []int{11} } func (m *Peer) XXX_Unmarshal(b []byte) error { @@ -453,8 +543,10 @@ func init() { proto.RegisterType((*ListResponse)(nil), "go.micro.network.ListResponse") proto.RegisterType((*PeerRequest)(nil), "go.micro.network.PeerRequest") proto.RegisterType((*PeerResponse)(nil), "go.micro.network.PeerResponse") - proto.RegisterType((*Peers)(nil), "go.micro.network.Peers") + proto.RegisterType((*TopologyRequest)(nil), "go.micro.network.TopologyRequest") + proto.RegisterType((*TopologyResponse)(nil), "go.micro.network.TopologyResponse") proto.RegisterType((*Node)(nil), "go.micro.network.Node") + proto.RegisterType((*Topology)(nil), "go.micro.network.Topology") proto.RegisterType((*Connect)(nil), "go.micro.network.Connect") proto.RegisterType((*Close)(nil), "go.micro.network.Close") proto.RegisterType((*Solicit)(nil), "go.micro.network.Solicit") @@ -464,28 +556,31 @@ func init() { func init() { proto.RegisterFile("network.proto", fileDescriptor_8571034d60397816) } var fileDescriptor_8571034d60397816 = []byte{ - // 353 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x93, 0x51, 0x4f, 0xc2, 0x30, - 0x10, 0xc7, 0x19, 0x32, 0x17, 0x6e, 0x60, 0x4c, 0x1f, 0x74, 0x21, 0x99, 0x21, 0x7d, 0x22, 0x46, - 0x86, 0x81, 0xf0, 0xa6, 0x4f, 0x3c, 0xf8, 0x42, 0x88, 0x99, 0x5f, 0x40, 0xd8, 0x2e, 0xd8, 0x08, - 0x3b, 0x6c, 0x4b, 0xfc, 0xd6, 0x7e, 0x06, 0xd3, 0x76, 0x44, 0x84, 0xcc, 0x84, 0xc4, 0xb7, 0xde, - 0xdd, 0xff, 0x7e, 0x77, 0x6d, 0xef, 0xa0, 0x5d, 0xa0, 0xfe, 0x24, 0xf9, 0x9e, 0x6c, 0x24, 0x69, - 0x62, 0x97, 0x4b, 0x4a, 0xd6, 0x22, 0x93, 0x94, 0x94, 0xfe, 0xce, 0x68, 0x29, 0xf4, 0xdb, 0x76, - 0x91, 0x64, 0xb4, 0x1e, 0xd8, 0xc8, 0x60, 0x49, 0x7d, 0x77, 0x90, 0xb4, 0xd5, 0x28, 0x07, 0x36, - 0xb3, 0x34, 0x1c, 0x86, 0xb7, 0x21, 0x9c, 0x0a, 0xa5, 0x53, 0xfc, 0xd8, 0xa2, 0xd2, 0xfc, 0x01, - 0x5a, 0xce, 0x54, 0x1b, 0x2a, 0x14, 0xb2, 0x3b, 0xf0, 0x0b, 0xca, 0x51, 0x45, 0x5e, 0xf7, 0xac, - 0x17, 0x0e, 0xaf, 0x92, 0xc3, 0xaa, 0xc9, 0x8c, 0x72, 0x4c, 0x9d, 0x88, 0xc7, 0x10, 0x3e, 0x23, - 0xca, 0x12, 0xc6, 0x2e, 0xa0, 0x2e, 0xf2, 0xc8, 0xeb, 0x7a, 0xbd, 0x66, 0x5a, 0x17, 0x39, 0x7f, - 0x84, 0x96, 0x0b, 0x97, 0xf0, 0x3e, 0xf8, 0x1b, 0x44, 0xa9, 0xac, 0x24, 0x1c, 0x5e, 0x1f, 0xc3, - 0x8d, 0x5c, 0xa5, 0x4e, 0xc5, 0xe7, 0xe0, 0x5b, 0x9b, 0xdd, 0x42, 0xc3, 0xd4, 0x2b, 0xd3, 0xaa, - 0x7a, 0xb2, 0x1a, 0x73, 0x01, 0x57, 0xa3, 0xfe, 0xf7, 0x05, 0x5c, 0x89, 0x7b, 0x68, 0x18, 0xf3, - 0xb0, 0x73, 0x16, 0x41, 0x30, 0xcf, 0x73, 0x89, 0xca, 0x70, 0x8c, 0x73, 0x67, 0xf2, 0x31, 0x04, - 0x13, 0x2a, 0x0a, 0xcc, 0xf4, 0x29, 0x6d, 0xf1, 0x11, 0xf8, 0x93, 0x15, 0x29, 0x3c, 0x29, 0x69, - 0x0c, 0xc1, 0x0b, 0xad, 0x44, 0x26, 0x4e, 0xab, 0xf5, 0x0a, 0x0d, 0xf3, 0x6e, 0xff, 0xfc, 0x6c, - 0xf6, 0x27, 0x9d, 0x68, 0xf8, 0xe5, 0x41, 0x30, 0x73, 0x7e, 0x36, 0x85, 0xa6, 0x99, 0x20, 0xc3, - 0x52, 0x2c, 0x3e, 0xce, 0xdb, 0x9b, 0xb6, 0xce, 0x4d, 0x55, 0xd8, 0x0d, 0x08, 0xaf, 0xed, 0x68, - 0xee, 0xdf, 0xe3, 0x8a, 0x2e, 0xaa, 0x69, 0xfb, 0xe3, 0xc6, 0x6b, 0xec, 0x09, 0xc0, 0xf2, 0xcd, - 0x02, 0x28, 0x16, 0xfd, 0xe8, 0xcb, 0x95, 0xd8, 0x91, 0xe2, 0xa3, 0xc8, 0xef, 0xb6, 0x16, 0xe7, - 0x76, 0x79, 0x46, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xaf, 0xb8, 0x9b, 0x3f, 0x94, 0x03, 0x00, - 0x00, + // 412 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0xdf, 0x8a, 0xd3, 0x40, + 0x14, 0xc6, 0x37, 0x31, 0x35, 0xdb, 0x13, 0x57, 0x97, 0x41, 0x24, 0x14, 0x2a, 0x75, 0xae, 0x8a, + 0x68, 0x2a, 0x2d, 0xab, 0x37, 0xde, 0xed, 0x85, 0x20, 0xcb, 0x22, 0xa9, 0x0f, 0xa0, 0xcd, 0x0c, + 0x69, 0xb0, 0xcd, 0x89, 0x33, 0x53, 0xc4, 0xe7, 0xf3, 0xc5, 0x64, 0xfe, 0xa4, 0x89, 0xa6, 0xa9, + 0xe6, 0xae, 0x67, 0xce, 0xf9, 0x7e, 0x5f, 0x72, 0xfa, 0x4d, 0xe0, 0xaa, 0xe4, 0xea, 0x07, 0x8a, + 0x6f, 0x49, 0x25, 0x50, 0x21, 0xb9, 0xce, 0x31, 0xd9, 0x17, 0x99, 0xc0, 0xc4, 0x9d, 0x4f, 0x56, + 0x79, 0xa1, 0xb6, 0x87, 0x4d, 0x92, 0xe1, 0x7e, 0x61, 0x3a, 0x8b, 0x1c, 0x5f, 0xdb, 0x1f, 0x02, + 0x0f, 0x8a, 0x8b, 0x85, 0x51, 0xba, 0xc2, 0x62, 0xe8, 0x15, 0x44, 0x77, 0x85, 0x54, 0x29, 0xff, + 0x7e, 0xe0, 0x52, 0xd1, 0xf7, 0xf0, 0xc8, 0x96, 0xb2, 0xc2, 0x52, 0x72, 0xf2, 0x0a, 0x46, 0x25, + 0x32, 0x2e, 0x63, 0x6f, 0xf6, 0x60, 0x1e, 0x2d, 0x9f, 0x25, 0x7f, 0xbb, 0x26, 0xf7, 0xc8, 0x78, + 0x6a, 0x87, 0xe8, 0x14, 0xa2, 0x4f, 0x9c, 0x0b, 0x07, 0x23, 0x8f, 0xc1, 0x2f, 0x58, 0xec, 0xcd, + 0xbc, 0xf9, 0x38, 0xf5, 0x0b, 0xa6, 0xe1, 0xb6, 0xdd, 0xc0, 0x2b, 0xce, 0xc5, 0x3f, 0xe1, 0x66, + 0x88, 0xbe, 0x83, 0x27, 0x9f, 0xb1, 0xc2, 0x1d, 0xe6, 0x3f, 0x7b, 0x0c, 0xc8, 0x53, 0x18, 0x31, + 0x5e, 0xa9, 0x6d, 0xec, 0xcf, 0xbc, 0x79, 0x90, 0xda, 0x82, 0x7e, 0x84, 0xeb, 0x46, 0xe8, 0xac, + 0xdf, 0xc2, 0xa5, 0x72, 0x67, 0x46, 0x1f, 0x2d, 0x27, 0x5d, 0xf7, 0xa3, 0xea, 0x38, 0x4b, 0xdf, + 0x40, 0xa0, 0x9f, 0xa9, 0xe3, 0x1c, 0x43, 0xf8, 0x95, 0x31, 0xc1, 0xa5, 0x34, 0xde, 0xe3, 0xb4, + 0x2e, 0x29, 0x83, 0xcb, 0x9a, 0x43, 0x5e, 0x42, 0xa0, 0x17, 0xe5, 0x1c, 0xfb, 0xde, 0xd7, 0xcc, + 0x34, 0x9b, 0xf7, 0xff, 0x67, 0xf3, 0x37, 0x10, 0xde, 0x62, 0x59, 0xf2, 0x4c, 0x0d, 0x31, 0xa1, + 0x2b, 0x18, 0xdd, 0xee, 0x50, 0xf2, 0x41, 0xa2, 0x1b, 0x08, 0xd7, 0xb8, 0x2b, 0xb2, 0x62, 0x98, + 0xd7, 0x17, 0x08, 0xf4, 0xbf, 0x3f, 0x74, 0x09, 0x36, 0x21, 0xbd, 0x4b, 0x30, 0x81, 0xb2, 0x43, + 0xcb, 0x5f, 0x3e, 0x84, 0xf7, 0xf6, 0x9c, 0xdc, 0xc1, 0x58, 0x07, 0x59, 0xb3, 0x24, 0x99, 0x76, + 0x75, 0xad, 0xd0, 0x4f, 0x9e, 0xf7, 0xb5, 0x6d, 0x58, 0xe8, 0x45, 0x4d, 0xd3, 0x66, 0x27, 0x69, + 0xad, 0xd4, 0x9f, 0xa2, 0xb5, 0x53, 0x4f, 0x2f, 0xc8, 0xba, 0x15, 0x89, 0x17, 0x67, 0x62, 0xe7, + 0x80, 0xf4, 0xdc, 0xc8, 0x11, 0xfa, 0x01, 0xc0, 0x3c, 0xb4, 0xbe, 0xdc, 0x92, 0xc4, 0x8d, 0xc6, + 0x5d, 0xf7, 0x9a, 0x36, 0xed, 0x74, 0xfe, 0x7c, 0xd7, 0xcd, 0x43, 0xf3, 0x61, 0x58, 0xfd, 0x0e, + 0x00, 0x00, 0xff, 0xff, 0xdc, 0xcf, 0x08, 0x89, 0x70, 0x04, 0x00, 0x00, } diff --git a/network/proto/network.proto b/network/proto/network.proto index 00e526e6..72f600cc 100644 --- a/network/proto/network.proto +++ b/network/proto/network.proto @@ -8,6 +8,7 @@ import "github.com/micro/go-micro/router/proto/router.proto"; service Network { rpc ListNodes(ListRequest) returns (ListResponse) {}; rpc ListPeers(PeerRequest) returns (PeerResponse) {}; + rpc Topology(TopologyRequest) returns (TopologyResponse) {}; rpc ListRoutes(go.micro.router.Request) returns (go.micro.router.ListResponse) {}; } @@ -28,15 +29,20 @@ message PeerRequest { // PeerResponse is returned by ListPeers message PeerResponse { - Peers peers = 1; + repeated Node peers = 1; } -// Peers are node peers -message Peers { - // network node - Node node = 1; - // node peers - repeated Node peers = 2; +// TopologyRequest list node topology +message TopologyRequest { + // node id + string id = 1; + // topology depth + uint64 depth = 2; +} + +// TopologyResponse is returned by Topology +message TopologyResponse { + Topology topology = 1; } // Node is network node @@ -47,6 +53,14 @@ message Node { string address = 2; } +// Topology is used to nnounce node neighbourhood +message Topology { + // network node + Node node = 1; + // neighbours + repeated Node nodes = 2; +} + // Connect is sent when the node connects to the network message Connect { // network mode From 2dfbe93d6523f2360a0b99f232518bffe0196f5e Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Wed, 11 Sep 2019 00:23:37 +0100 Subject: [PATCH 09/20] Added more node tests. Small refactoring of Netowkr and handler. --- network/default.go | 10 +++ network/handler/handler.go | 43 +++++++----- network/network.go | 4 +- network/node.go | 53 +++++++-------- network/node_test.go | 50 ++++++++++++-- network/proto/network.pb.go | 132 ++++++++++-------------------------- network/proto/network.proto | 12 +--- 7 files changed, 145 insertions(+), 159 deletions(-) diff --git a/network/default.go b/network/default.go index f4865a93..d7deb5c7 100644 --- a/network/default.go +++ b/network/default.go @@ -838,6 +838,16 @@ func (n *network) Connect() error { return nil } +// Nodes returns a list of all network nodes +func (n *network) Nodes() []Node { + return n.node.Nodes() +} + +// Topology returns network topology +func (n *network) Topology() Node { + return n.node.Topology(MaxDepth) +} + func (n *network) close() error { // stop the server if err := n.server.Stop(); err != nil { diff --git a/network/handler/handler.go b/network/handler/handler.go index e09802f3..3bc47c1b 100644 --- a/network/handler/handler.go +++ b/network/handler/handler.go @@ -51,37 +51,46 @@ func (n *Network) ListPeers(ctx context.Context, req *pbNet.PeerRequest, resp *p return nil } -// Topology returns a list of nodes in node topology i.e. it returns all (in)directly reachable nodes from this node -func (n *Network) Topology(ctx context.Context, req *pbNet.TopologyRequest, resp *pbNet.TopologyResponse) error { - // NOTE: we are downcasting here - depth := uint(req.Depth) - if depth <= 0 { - depth = network.MaxDepth +// toplogyToProto recursively traverses node topology and returns it +func toplogyToProto(node network.Node, pbPeer *pbNet.Peer) *pbNet.Peer { + // return if we reached the end of topology + if len(node.Peers()) == 0 { + return pbPeer } - // get topology - topNodes := n.Network.Topology(depth) - - var nodes []*pbNet.Node - for _, topNode := range topNodes { - // creaate peers answer + for _, topNode := range node.Peers() { pbNode := &pbNet.Node{ Id: topNode.Id(), Address: topNode.Address(), } - nodes = append(nodes, pbNode) + pbPeer := &pbNet.Peer{ + Node: pbNode, + Peers: make([]*pbNet.Peer, 0), + } + peer := toplogyToProto(topNode, pbPeer) + pbPeer.Peers = append(pbPeer.Peers, peer) } - // network node + return pbPeer +} + +// Topology returns a list of nodes in node topology i.e. it returns all (in)directly reachable nodes from this node +func (n *Network) Topology(ctx context.Context, req *pbNet.TopologyRequest, resp *pbNet.TopologyResponse) error { + // get node topology + topNode := n.Network.Topology() + + // network node aka root node node := &pbNet.Node{ Id: n.Network.Id(), Address: n.Network.Address(), } - - topology := &pbNet.Topology{ + // we will build proto topology into this + pbPeer := &pbNet.Peer{ Node: node, - Nodes: nodes, + Peers: make([]*pbNet.Peer, 0), } + // return topology encoded into protobuf + topology := toplogyToProto(topNode, pbPeer) resp.Topology = topology diff --git a/network/network.go b/network/network.go index add29576..a2b4b60e 100644 --- a/network/network.go +++ b/network/network.go @@ -46,8 +46,8 @@ type Network interface { Connect() error // Nodes returns list of network nodes Nodes() []Node - // Topology returns a list of all reachable nodes up to depth - Topology(depth uint) []Node + // Topology returns node topology up to MaxDepth hops + Topology() Node // Close stops the tunnel and resolving Close() error // Client is micro client diff --git a/network/node.go b/network/node.go index dfacdd13..67a59b02 100644 --- a/network/node.go +++ b/network/node.go @@ -3,7 +3,6 @@ package network import ( "container/list" "errors" - "sort" "sync" "time" @@ -96,10 +95,13 @@ func (n *node) Peers() []Node { p := &node{ id: peer.id, address: peer.address, + peers: make(map[string]*node), network: peer.network, } - // NOTE: we do not care about peer's peers - // we only collect the node's peers i.e. its adjacent nodes + // collect peer's peers aka pop (peer of peer) + for id, pop := range peer.peers { + p.peers[id] = pop + } peers = append(peers, p) } n.RUnlock() @@ -107,36 +109,31 @@ func (n *node) Peers() []Node { return peers } -// Topology returns a slice of all nodes in reachable by node up to given depth -func (n *node) Topology(depth uint) []Node { - // get all the nodes - nodes := n.Nodes() - +// topology returns network topology up to MaxDepth +func (n *node) Topology(depth uint) *node { n.RLock() - // sort the slice of nodes - sort.Slice(nodes, func(i, j int) bool { return nodes[i].Id() <= nodes[j].Id() }) - // find the node with our id - i := sort.Search(len(nodes), func(j int) bool { return nodes[j].Id() >= n.id }) + // make a copy of yourself + node := &node{ + id: n.id, + address: n.address, + peers: make(map[string]*node), + network: n.network, + } - // TODO: finish implementing this - var topology []Node - // collect all the reachable nodes into slice - if i < len(nodes) && nodes[i].Id() == n.id { - for _, peer := range nodes[i].Peers() { - // don't return yourself - if peer.Id() == n.id { - continue - } - topNode := &node{ - id: peer.Id(), - address: peer.Address(), - } - topology = append(topology, topNode) - } + // return if we reach requested depth or we have no more peers + if depth == 0 || len(n.peers) == 0 { + return node + } + + depth-- + + for _, peer := range n.peers { + nodePeer := peer.Topology(depth) + node.peers[nodePeer.id] = nodePeer } n.RUnlock() - return topology + return node } // getProtoTopology returns node peers up to given depth encoded in protobufs diff --git a/network/node_test.go b/network/node_test.go index dc0add63..b99a284c 100644 --- a/network/node_test.go +++ b/network/node_test.go @@ -1,6 +1,8 @@ package network -import "testing" +import ( + "testing" +) var ( testNodeId = "testNode" @@ -150,7 +152,7 @@ func TestPeers(t *testing.T) { // iterate through the list of peers and makes sure all have been returned for _, peer := range peers { if _, ok := peerIds[peer.Id()]; !ok { - t.Errorf("Expected to find %s peer", node.Id()) + t.Errorf("Expected to find %s peer", peer.Id()) } } } @@ -168,7 +170,47 @@ func TestTopology(t *testing.T) { // you should not be in your topology topCount := 0 - if len(topology) != topCount { - t.Errorf("Expected to find %d nodes, found: %d", topCount, len(topology)) + if len(topology.peers) != topCount { + t.Errorf("Expected to find %d nodes, found: %d", topCount, len(topology.peers)) + } + + // complicated node graph + node := testSetup() + // list of ids of nodes of depth 1 i.e. node peers + peerIds := make(map[string]bool) + // add peer Ids + for _, id := range testNodePeerIds { + peerIds[id] = true + } + topology = node.Topology(1) + + // depth 1 should return only immediate peers + if len(topology.peers) != len(peerIds) { + t.Errorf("Expected to find %d nodes, found: %d", len(peerIds), len(topology.peers)) + } + for id := range topology.peers { + if _, ok := peerIds[id]; !ok { + t.Errorf("Expected to find %s peer", id) + } + } + + // add peers of peers to peerIds + for _, id := range testPeerOfPeerIds { + peerIds[id] = true + } + topology = node.Topology(2) + + // iterate through the whole graph + // NOTE: this is a manual iteration as we know the size of the graph + for id, peer := range topology.peers { + if _, ok := peerIds[id]; !ok { + t.Errorf("Expected to find %s peer", peer.Id()) + } + // peers of peers + for id := range peer.peers { + if _, ok := peerIds[id]; !ok { + t.Errorf("Expected to find %s peer", peer.Id()) + } + } } } diff --git a/network/proto/network.pb.go b/network/proto/network.pb.go index 83f63659..d6db18b9 100644 --- a/network/proto/network.pb.go +++ b/network/proto/network.pb.go @@ -178,9 +178,7 @@ func (m *PeerResponse) GetPeers() []*Node { // TopologyRequest list node topology type TopologyRequest struct { // node id - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - // topology depth - Depth uint64 `protobuf:"varint,2,opt,name=depth,proto3" json:"depth,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -218,19 +216,12 @@ func (m *TopologyRequest) GetId() string { return "" } -func (m *TopologyRequest) GetDepth() uint64 { - if m != nil { - return m.Depth - } - return 0 -} - // TopologyResponse is returned by Topology type TopologyResponse struct { - Topology *Topology `protobuf:"bytes,1,opt,name=topology,proto3" json:"topology,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Topology *Peer `protobuf:"bytes,1,opt,name=topology,proto3" json:"topology,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *TopologyResponse) Reset() { *m = TopologyResponse{} } @@ -258,7 +249,7 @@ func (m *TopologyResponse) XXX_DiscardUnknown() { var xxx_messageInfo_TopologyResponse proto.InternalMessageInfo -func (m *TopologyResponse) GetTopology() *Topology { +func (m *TopologyResponse) GetTopology() *Peer { if m != nil { return m.Topology } @@ -315,56 +306,6 @@ func (m *Node) GetAddress() string { return "" } -// Topology is used to nnounce node neighbourhood -type Topology struct { - // network node - Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` - // neighbours - Nodes []*Node `protobuf:"bytes,2,rep,name=nodes,proto3" json:"nodes,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Topology) Reset() { *m = Topology{} } -func (m *Topology) String() string { return proto.CompactTextString(m) } -func (*Topology) ProtoMessage() {} -func (*Topology) Descriptor() ([]byte, []int) { - return fileDescriptor_8571034d60397816, []int{7} -} - -func (m *Topology) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Topology.Unmarshal(m, b) -} -func (m *Topology) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Topology.Marshal(b, m, deterministic) -} -func (m *Topology) XXX_Merge(src proto.Message) { - xxx_messageInfo_Topology.Merge(m, src) -} -func (m *Topology) XXX_Size() int { - return xxx_messageInfo_Topology.Size(m) -} -func (m *Topology) XXX_DiscardUnknown() { - xxx_messageInfo_Topology.DiscardUnknown(m) -} - -var xxx_messageInfo_Topology proto.InternalMessageInfo - -func (m *Topology) GetNode() *Node { - if m != nil { - return m.Node - } - return nil -} - -func (m *Topology) GetNodes() []*Node { - if m != nil { - return m.Nodes - } - return nil -} - // Connect is sent when the node connects to the network type Connect struct { // network mode @@ -378,7 +319,7 @@ 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_8571034d60397816, []int{8} + return fileDescriptor_8571034d60397816, []int{7} } func (m *Connect) XXX_Unmarshal(b []byte) error { @@ -419,7 +360,7 @@ func (m *Close) Reset() { *m = Close{} } func (m *Close) String() string { return proto.CompactTextString(m) } func (*Close) ProtoMessage() {} func (*Close) Descriptor() ([]byte, []int) { - return fileDescriptor_8571034d60397816, []int{9} + return fileDescriptor_8571034d60397816, []int{8} } func (m *Close) XXX_Unmarshal(b []byte) error { @@ -460,7 +401,7 @@ func (m *Solicit) Reset() { *m = Solicit{} } func (m *Solicit) String() string { return proto.CompactTextString(m) } func (*Solicit) ProtoMessage() {} func (*Solicit) Descriptor() ([]byte, []int) { - return fileDescriptor_8571034d60397816, []int{10} + return fileDescriptor_8571034d60397816, []int{9} } func (m *Solicit) XXX_Unmarshal(b []byte) error { @@ -503,7 +444,7 @@ func (m *Peer) Reset() { *m = Peer{} } func (m *Peer) String() string { return proto.CompactTextString(m) } func (*Peer) ProtoMessage() {} func (*Peer) Descriptor() ([]byte, []int) { - return fileDescriptor_8571034d60397816, []int{11} + return fileDescriptor_8571034d60397816, []int{10} } func (m *Peer) XXX_Unmarshal(b []byte) error { @@ -546,7 +487,6 @@ func init() { proto.RegisterType((*TopologyRequest)(nil), "go.micro.network.TopologyRequest") proto.RegisterType((*TopologyResponse)(nil), "go.micro.network.TopologyResponse") proto.RegisterType((*Node)(nil), "go.micro.network.Node") - proto.RegisterType((*Topology)(nil), "go.micro.network.Topology") proto.RegisterType((*Connect)(nil), "go.micro.network.Connect") proto.RegisterType((*Close)(nil), "go.micro.network.Close") proto.RegisterType((*Solicit)(nil), "go.micro.network.Solicit") @@ -556,31 +496,29 @@ func init() { func init() { proto.RegisterFile("network.proto", fileDescriptor_8571034d60397816) } var fileDescriptor_8571034d60397816 = []byte{ - // 412 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0xdf, 0x8a, 0xd3, 0x40, - 0x14, 0xc6, 0x37, 0x31, 0x35, 0xdb, 0x13, 0x57, 0x97, 0x41, 0x24, 0x14, 0x2a, 0x75, 0xae, 0x8a, - 0x68, 0x2a, 0x2d, 0xab, 0x37, 0xde, 0xed, 0x85, 0x20, 0xcb, 0x22, 0xa9, 0x0f, 0xa0, 0xcd, 0x0c, - 0x69, 0xb0, 0xcd, 0x89, 0x33, 0x53, 0xc4, 0xe7, 0xf3, 0xc5, 0x64, 0xfe, 0xa4, 0x89, 0xa6, 0xa9, - 0xe6, 0xae, 0x67, 0xce, 0xf9, 0x7e, 0x5f, 0x72, 0xfa, 0x4d, 0xe0, 0xaa, 0xe4, 0xea, 0x07, 0x8a, - 0x6f, 0x49, 0x25, 0x50, 0x21, 0xb9, 0xce, 0x31, 0xd9, 0x17, 0x99, 0xc0, 0xc4, 0x9d, 0x4f, 0x56, - 0x79, 0xa1, 0xb6, 0x87, 0x4d, 0x92, 0xe1, 0x7e, 0x61, 0x3a, 0x8b, 0x1c, 0x5f, 0xdb, 0x1f, 0x02, - 0x0f, 0x8a, 0x8b, 0x85, 0x51, 0xba, 0xc2, 0x62, 0xe8, 0x15, 0x44, 0x77, 0x85, 0x54, 0x29, 0xff, - 0x7e, 0xe0, 0x52, 0xd1, 0xf7, 0xf0, 0xc8, 0x96, 0xb2, 0xc2, 0x52, 0x72, 0xf2, 0x0a, 0x46, 0x25, - 0x32, 0x2e, 0x63, 0x6f, 0xf6, 0x60, 0x1e, 0x2d, 0x9f, 0x25, 0x7f, 0xbb, 0x26, 0xf7, 0xc8, 0x78, - 0x6a, 0x87, 0xe8, 0x14, 0xa2, 0x4f, 0x9c, 0x0b, 0x07, 0x23, 0x8f, 0xc1, 0x2f, 0x58, 0xec, 0xcd, - 0xbc, 0xf9, 0x38, 0xf5, 0x0b, 0xa6, 0xe1, 0xb6, 0xdd, 0xc0, 0x2b, 0xce, 0xc5, 0x3f, 0xe1, 0x66, - 0x88, 0xbe, 0x83, 0x27, 0x9f, 0xb1, 0xc2, 0x1d, 0xe6, 0x3f, 0x7b, 0x0c, 0xc8, 0x53, 0x18, 0x31, - 0x5e, 0xa9, 0x6d, 0xec, 0xcf, 0xbc, 0x79, 0x90, 0xda, 0x82, 0x7e, 0x84, 0xeb, 0x46, 0xe8, 0xac, - 0xdf, 0xc2, 0xa5, 0x72, 0x67, 0x46, 0x1f, 0x2d, 0x27, 0x5d, 0xf7, 0xa3, 0xea, 0x38, 0x4b, 0xdf, - 0x40, 0xa0, 0x9f, 0xa9, 0xe3, 0x1c, 0x43, 0xf8, 0x95, 0x31, 0xc1, 0xa5, 0x34, 0xde, 0xe3, 0xb4, - 0x2e, 0x29, 0x83, 0xcb, 0x9a, 0x43, 0x5e, 0x42, 0xa0, 0x17, 0xe5, 0x1c, 0xfb, 0xde, 0xd7, 0xcc, - 0x34, 0x9b, 0xf7, 0xff, 0x67, 0xf3, 0x37, 0x10, 0xde, 0x62, 0x59, 0xf2, 0x4c, 0x0d, 0x31, 0xa1, - 0x2b, 0x18, 0xdd, 0xee, 0x50, 0xf2, 0x41, 0xa2, 0x1b, 0x08, 0xd7, 0xb8, 0x2b, 0xb2, 0x62, 0x98, - 0xd7, 0x17, 0x08, 0xf4, 0xbf, 0x3f, 0x74, 0x09, 0x36, 0x21, 0xbd, 0x4b, 0x30, 0x81, 0xb2, 0x43, - 0xcb, 0x5f, 0x3e, 0x84, 0xf7, 0xf6, 0x9c, 0xdc, 0xc1, 0x58, 0x07, 0x59, 0xb3, 0x24, 0x99, 0x76, - 0x75, 0xad, 0xd0, 0x4f, 0x9e, 0xf7, 0xb5, 0x6d, 0x58, 0xe8, 0x45, 0x4d, 0xd3, 0x66, 0x27, 0x69, - 0xad, 0xd4, 0x9f, 0xa2, 0xb5, 0x53, 0x4f, 0x2f, 0xc8, 0xba, 0x15, 0x89, 0x17, 0x67, 0x62, 0xe7, - 0x80, 0xf4, 0xdc, 0xc8, 0x11, 0xfa, 0x01, 0xc0, 0x3c, 0xb4, 0xbe, 0xdc, 0x92, 0xc4, 0x8d, 0xc6, - 0x5d, 0xf7, 0x9a, 0x36, 0xed, 0x74, 0xfe, 0x7c, 0xd7, 0xcd, 0x43, 0xf3, 0x61, 0x58, 0xfd, 0x0e, - 0x00, 0x00, 0xff, 0xff, 0xdc, 0xcf, 0x08, 0x89, 0x70, 0x04, 0x00, 0x00, + // 382 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x93, 0x51, 0x4f, 0xea, 0x30, + 0x14, 0xc7, 0x61, 0x17, 0xee, 0xe0, 0x70, 0xb9, 0x92, 0x3e, 0x98, 0x85, 0x04, 0x03, 0x7d, 0x22, + 0x46, 0x87, 0x81, 0xf0, 0xe6, 0x1b, 0x89, 0xbe, 0x10, 0x62, 0xc0, 0x0f, 0xa0, 0x6c, 0xcd, 0x6c, + 0x84, 0x9d, 0xd9, 0x96, 0x18, 0x3f, 0x9f, 0x5f, 0xcc, 0xb4, 0xdd, 0x18, 0x02, 0xd3, 0xf0, 0xb6, + 0x9e, 0xf3, 0x3f, 0xbf, 0xff, 0xda, 0xfe, 0x0b, 0xcd, 0x98, 0xa9, 0x77, 0x14, 0xaf, 0x7e, 0x22, + 0x50, 0x21, 0x69, 0x45, 0xe8, 0xaf, 0x79, 0x20, 0xd0, 0x4f, 0xeb, 0xed, 0x51, 0xc4, 0xd5, 0xcb, + 0x66, 0xe9, 0x07, 0xb8, 0x1e, 0x98, 0xce, 0x20, 0xc2, 0x6b, 0xfb, 0x21, 0x70, 0xa3, 0x98, 0x18, + 0x98, 0xc9, 0x74, 0x61, 0x31, 0xb4, 0x09, 0x8d, 0x29, 0x97, 0x6a, 0xce, 0xde, 0x36, 0x4c, 0x2a, + 0x7a, 0x0b, 0xff, 0xec, 0x52, 0x26, 0x18, 0x4b, 0x46, 0xae, 0xa0, 0x1a, 0x63, 0xc8, 0xa4, 0x57, + 0xee, 0xfe, 0xe9, 0x37, 0x86, 0xe7, 0xfe, 0xbe, 0xab, 0x3f, 0xc3, 0x90, 0xcd, 0xad, 0x88, 0x76, + 0xa0, 0xf1, 0xc0, 0x98, 0x48, 0x61, 0xe4, 0x3f, 0x38, 0x3c, 0xf4, 0xca, 0xdd, 0x72, 0xbf, 0x3e, + 0x77, 0x78, 0xa8, 0xe1, 0xb6, 0x9d, 0xc3, 0x13, 0xc6, 0xc4, 0xaf, 0x70, 0x23, 0xa2, 0x3d, 0x38, + 0x7b, 0xc4, 0x04, 0x57, 0x18, 0x7d, 0x14, 0x19, 0xdc, 0x41, 0x2b, 0x97, 0xa4, 0x26, 0x43, 0xa8, + 0xa9, 0xb4, 0x66, 0x94, 0x47, 0x7d, 0xcc, 0x6f, 0x6d, 0x75, 0xf4, 0x06, 0x2a, 0xda, 0x79, 0x9f, + 0x4f, 0x3c, 0x70, 0x9f, 0xc3, 0x50, 0x30, 0x29, 0x3d, 0xc7, 0x14, 0xb3, 0x25, 0x1d, 0x83, 0x3b, + 0xc1, 0x38, 0x66, 0x81, 0x22, 0x97, 0x50, 0xd1, 0xa7, 0x51, 0x6c, 0x66, 0x36, 0x65, 0x34, 0x74, + 0x04, 0xd5, 0xc9, 0x0a, 0x25, 0x3b, 0x69, 0x68, 0x0c, 0xee, 0x02, 0x57, 0x3c, 0xe0, 0xa7, 0x79, + 0x3d, 0x41, 0x45, 0x6f, 0xf3, 0x94, 0x99, 0xfc, 0x86, 0x9c, 0xa2, 0x1b, 0x32, 0x27, 0x67, 0x45, + 0xc3, 0x4f, 0x07, 0xdc, 0x99, 0xad, 0x93, 0x29, 0xd4, 0x75, 0x90, 0x34, 0x4b, 0x92, 0xce, 0xe1, + 0xdc, 0x4e, 0xe8, 0xda, 0x17, 0x45, 0x6d, 0x7b, 0x85, 0xb4, 0x94, 0xd1, 0xb4, 0xd9, 0x51, 0xda, + 0x4e, 0xea, 0x8e, 0xd1, 0x76, 0x53, 0x47, 0x4b, 0x64, 0x01, 0xb5, 0x2c, 0x26, 0xa4, 0x77, 0xa8, + 0xde, 0x4b, 0x59, 0x9b, 0xfe, 0x24, 0xd9, 0x42, 0xef, 0x01, 0xcc, 0x4f, 0xeb, 0xc7, 0x25, 0x89, + 0x97, 0xcf, 0xa4, 0xcf, 0x2d, 0xa3, 0x75, 0x0e, 0x3a, 0xdf, 0xf7, 0xba, 0xfc, 0x6b, 0x1e, 0xe6, + 0xe8, 0x2b, 0x00, 0x00, 0xff, 0xff, 0x0d, 0xd5, 0xbf, 0xdc, 0xf0, 0x03, 0x00, 0x00, } diff --git a/network/proto/network.proto b/network/proto/network.proto index 72f600cc..2ac8acc7 100644 --- a/network/proto/network.proto +++ b/network/proto/network.proto @@ -36,13 +36,11 @@ message PeerResponse { message TopologyRequest { // node id string id = 1; - // topology depth - uint64 depth = 2; } // TopologyResponse is returned by Topology message TopologyResponse { - Topology topology = 1; + Peer topology = 1; } // Node is network node @@ -53,14 +51,6 @@ message Node { string address = 2; } -// Topology is used to nnounce node neighbourhood -message Topology { - // network node - Node node = 1; - // neighbours - repeated Node nodes = 2; -} - // Connect is sent when the node connects to the network message Connect { // network mode From 35cf2a5739579dddbecee13d933ab1dcc5440743 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Wed, 11 Sep 2019 01:22:40 +0100 Subject: [PATCH 10/20] Make topology test more generic --- network/node_test.go | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/network/node_test.go b/network/node_test.go index b99a284c..df5a5e4a 100644 --- a/network/node_test.go +++ b/network/node_test.go @@ -157,6 +157,22 @@ func TestPeers(t *testing.T) { } } +func collectTopologyIds(peers map[string]*node, ids map[string]bool) map[string]bool { + if len(peers) == 0 { + return ids + } + + // iterate through the whole graph + for id, peer := range peers { + ids = collectTopologyIds(peer.peers, ids) + if _, ok := ids[id]; !ok { + ids[id] = true + } + } + + return ids +} + func TestTopology(t *testing.T) { // single node single := &node{ @@ -200,17 +216,16 @@ func TestTopology(t *testing.T) { } topology = node.Topology(2) - // iterate through the whole graph - // NOTE: this is a manual iteration as we know the size of the graph - for id, peer := range topology.peers { - if _, ok := peerIds[id]; !ok { - t.Errorf("Expected to find %s peer", peer.Id()) - } - // peers of peers - for id := range peer.peers { - if _, ok := peerIds[id]; !ok { - t.Errorf("Expected to find %s peer", peer.Id()) - } + topIds := make(map[string]bool) + topIds = collectTopologyIds(topology.peers, topIds) + + if len(topIds) != len(peerIds) { + t.Errorf("Expected to find %d nodes, found: %d", len(peerIds), len(topIds)) + } + + for id := range topIds { + if _, ok := topIds[id]; !ok { + t.Errorf("Expected to find %s peer", id) } } } From d58eb519768e015ce026af1814c8b75d6da4323a Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Wed, 11 Sep 2019 15:55:32 +0100 Subject: [PATCH 11/20] Code change to make Solicit router.proto message --- network/default.go | 123 +++---- network/proto/network.pb.go | 94 ++--- network/proto/network.proto | 6 - router/proto/router.micro.go | 19 +- router/proto/router.pb.go | 673 ++++++++--------------------------- router/proto/router.proto | 6 + 6 files changed, 246 insertions(+), 675 deletions(-) diff --git a/network/default.go b/network/default.go index d7deb5c7..41119912 100644 --- a/network/default.go +++ b/network/default.go @@ -29,8 +29,6 @@ var ( ) var ( - // ErrMsgUnknown is returned when unknown message is attempted to send or receive - ErrMsgUnknown = errors.New("unknown message") // ErrClientNotFound is returned when client for tunnel channel could not be found ErrClientNotFound = errors.New("client not found") ) @@ -277,8 +275,13 @@ func (n *network) processNetChan(client transport.Client, listener tunnel.Listen lastSeen: now, } n.Unlock() + // get all the node peers down to MaxDepth encoded in protobuf message + msg, err := n.node.getProtoTopology(MaxDepth) + if err != nil { + log.Debugf("Network unable to retrieve node peers: %s", err) + } // advertise yourself to the network - if err := n.sendMsg("peer", NetworkChannel); err != nil { + if err := n.sendMsg("peer", msg, NetworkChannel); err != nil { log.Debugf("Network failed to advertise peers: %v", err) } // advertise all the routes when a new node has connected @@ -310,8 +313,10 @@ func (n *network) processNetChan(client transport.Client, listener tunnel.Listen } n.Unlock() // send a solicit message when discovering new peer - // NOTE: we need to release the Lock here as sendMsg locsk, too - if err := n.sendMsg("solicit", ControlChannel); err != nil { + msg := &pbRtr.Solicit{ + Id: n.options.Id, + } + if err := n.sendMsg("solicit", msg, ControlChannel); err != nil { log.Debugf("Network failed to send solicit message: %s", err) } // after adding new peer go to the next step @@ -351,49 +356,15 @@ func (n *network) processNetChan(client transport.Client, listener tunnel.Listen } // sendMsg sends a message to the tunnel channel -func (n *network) sendMsg(msgType string, channel string) error { - node := &pbNet.Node{ - Id: n.options.Id, - Address: n.options.Address, - } - - var protoMsg proto.Message - - switch msgType { - case "connect": - protoMsg = &pbNet.Connect{ - Node: node, - } - case "close": - protoMsg = &pbNet.Close{ - Node: node, - } - case "solicit": - protoMsg = &pbNet.Solicit{ - Node: node, - } - case "peer": - n.RLock() - var err error - // get all the node peers down to MaxDepth - protoMsg, err = n.node.getProtoTopology(MaxDepth) - if err != nil { - log.Debugf("Network unable to retrieve node peers: %s", err) - return err - } - n.RUnlock() - default: - return ErrMsgUnknown - } - - body, err := proto.Marshal(protoMsg) +func (n *network) sendMsg(method string, msg proto.Message, channel string) error { + body, err := proto.Marshal(msg) if err != nil { return err } // create transport message and chuck it down the pipe m := transport.Message{ Header: map[string]string{ - "Micro-Method": msgType, + "Micro-Method": method, }, Body: body, } @@ -407,7 +378,7 @@ func (n *network) sendMsg(msgType string, channel string) error { } n.RUnlock() - log.Debugf("Network sending %s message from: %s", msgType, node.Id) + log.Debugf("Network sending %s message from: %s", method, n.options.Id) if err := client.Send(&m); err != nil { return err } @@ -425,8 +396,16 @@ func (n *network) announce(client transport.Client) { case <-n.closed: return case <-announce.C: + n.RLock() + msg, err := n.node.getProtoTopology(MaxDepth) + if err != nil { + log.Debugf("Network unable to retrieve node peers: %s", err) + n.RUnlock() + continue + } + n.RUnlock() // advertise yourself to the network - if err := n.sendMsg("peer", NetworkChannel); err != nil { + if err := n.sendMsg("peer", msg, NetworkChannel); err != nil { log.Debugf("Network failed to advertise peers: %v", err) continue } @@ -598,12 +577,15 @@ func (n *network) processCtrlChan(client transport.Client, listener tunnel.Liste lastSeen: now, } n.peers[pbRtrAdvert.Id] = advertNode + n.Unlock() // send a solicit message when discovering a new node - if err := n.sendMsg("solicit", ControlChannel); err != nil { + msg := &pbRtr.Solicit{ + Id: n.options.Id, + } + if err := n.sendMsg("solicit", msg, ControlChannel); err != nil { log.Debugf("Network failed to send solicit message: %s", err) } } - n.Unlock() var events []*router.Event for _, event := range pbRtrAdvert.Events { @@ -660,14 +642,14 @@ func (n *network) processCtrlChan(client transport.Client, listener tunnel.Liste continue } case "solicit": - pbNetSolicit := &pbNet.Solicit{} - if err := proto.Unmarshal(m.Body, pbNetSolicit); err != nil { + pbRtrSolicit := &pbRtr.Solicit{} + if err := proto.Unmarshal(m.Body, pbRtrSolicit); err != nil { log.Debugf("Network fail to unmarshal solicit message: %v", err) continue } - log.Debugf("Network received solicit message from: %s", pbNetSolicit.Node.Id) - // don't process your own messages - if pbNetSolicit.Node.Id == n.options.Id { + log.Debugf("Network received solicit message from: %s", pbRtrSolicit.Id) + // ignore solicitation when requested by you + if pbRtrSolicit.Id == n.options.Id { continue } // advertise all the routes when a new node has connected @@ -707,29 +689,14 @@ func (n *network) advertise(client transport.Client, advertChan <-chan *router.A } events = append(events, e) } - pbRtrAdvert := &pbRtr.Advert{ + msg := &pbRtr.Advert{ Id: advert.Id, Type: pbRtr.AdvertType(advert.Type), Timestamp: advert.Timestamp.UnixNano(), Events: events, } - body, err := proto.Marshal(pbRtrAdvert) - if err != nil { - // TODO: should we bail here? - log.Debugf("Network failed to marshal advert message: %v", err) - continue - } - // create transport message and chuck it down the pipe - m := transport.Message{ - Header: map[string]string{ - "Micro-Method": "advert", - }, - Body: body, - } - - log.Debugf("Network sending advert message from: %s", pbRtrAdvert.Id) - if err := client.Send(&m); err != nil { - log.Debugf("Network failed to send advert %s: %v", pbRtrAdvert.Id, err) + if err := n.sendMsg("advert", msg, NetworkChannel); err != nil { + log.Debugf("Network failed to advertise routes: %v", err) continue } case <-n.closed: @@ -814,7 +781,13 @@ func (n *network) Connect() error { // NOTE: in theory we could do this as soon as // Dial to NetworkChannel succeeds, but instead // we initialize all other node resources first - if err := n.sendMsg("connect", NetworkChannel); err != nil { + msg := &pbNet.Connect{ + Node: &pbNet.Node{ + Id: n.options.Id, + Address: n.options.Address, + }, + } + if err := n.sendMsg("connect", msg, NetworkChannel); err != nil { log.Debugf("Network failed to send connect message: %s", err) } @@ -880,9 +853,13 @@ func (n *network) Close() error { case <-n.closed: return nil default: - // send close message only if we managed to connect to NetworkChannel - log.Debugf("Sending close message from: %s", n.options.Id) - if err := n.sendMsg("close", NetworkChannel); err != nil { + msg := &pbNet.Close{ + Node: &pbNet.Node{ + Id: n.options.Id, + Address: n.options.Address, + }, + } + if err := n.sendMsg("close", msg, NetworkChannel); err != nil { log.Debugf("Network failed to send close message: %s", err) } // TODO: send close message to the network channel diff --git a/network/proto/network.pb.go b/network/proto/network.pb.go index d6db18b9..76ab4bbc 100644 --- a/network/proto/network.pb.go +++ b/network/proto/network.pb.go @@ -388,47 +388,6 @@ func (m *Close) GetNode() *Node { return nil } -// Solicit is sent when soliciting routes from the network nodes -type Solicit struct { - // network node - Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Solicit) Reset() { *m = Solicit{} } -func (m *Solicit) String() string { return proto.CompactTextString(m) } -func (*Solicit) ProtoMessage() {} -func (*Solicit) Descriptor() ([]byte, []int) { - return fileDescriptor_8571034d60397816, []int{9} -} - -func (m *Solicit) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Solicit.Unmarshal(m, b) -} -func (m *Solicit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Solicit.Marshal(b, m, deterministic) -} -func (m *Solicit) XXX_Merge(src proto.Message) { - xxx_messageInfo_Solicit.Merge(m, src) -} -func (m *Solicit) XXX_Size() int { - return xxx_messageInfo_Solicit.Size(m) -} -func (m *Solicit) XXX_DiscardUnknown() { - xxx_messageInfo_Solicit.DiscardUnknown(m) -} - -var xxx_messageInfo_Solicit proto.InternalMessageInfo - -func (m *Solicit) GetNode() *Node { - if m != nil { - return m.Node - } - return nil -} - // Peer is used to advertise node peers type Peer struct { // network node @@ -444,7 +403,7 @@ func (m *Peer) Reset() { *m = Peer{} } func (m *Peer) String() string { return proto.CompactTextString(m) } func (*Peer) ProtoMessage() {} func (*Peer) Descriptor() ([]byte, []int) { - return fileDescriptor_8571034d60397816, []int{10} + return fileDescriptor_8571034d60397816, []int{9} } func (m *Peer) XXX_Unmarshal(b []byte) error { @@ -489,36 +448,35 @@ func init() { proto.RegisterType((*Node)(nil), "go.micro.network.Node") proto.RegisterType((*Connect)(nil), "go.micro.network.Connect") proto.RegisterType((*Close)(nil), "go.micro.network.Close") - proto.RegisterType((*Solicit)(nil), "go.micro.network.Solicit") proto.RegisterType((*Peer)(nil), "go.micro.network.Peer") } func init() { proto.RegisterFile("network.proto", fileDescriptor_8571034d60397816) } var fileDescriptor_8571034d60397816 = []byte{ - // 382 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x93, 0x51, 0x4f, 0xea, 0x30, - 0x14, 0xc7, 0x61, 0x17, 0xee, 0xe0, 0x70, 0xb9, 0x92, 0x3e, 0x98, 0x85, 0x04, 0x03, 0x7d, 0x22, - 0x46, 0x87, 0x81, 0xf0, 0xe6, 0x1b, 0x89, 0xbe, 0x10, 0x62, 0xc0, 0x0f, 0xa0, 0x6c, 0xcd, 0x6c, - 0x84, 0x9d, 0xd9, 0x96, 0x18, 0x3f, 0x9f, 0x5f, 0xcc, 0xb4, 0xdd, 0x18, 0x02, 0xd3, 0xf0, 0xb6, - 0x9e, 0xf3, 0x3f, 0xbf, 0xff, 0xda, 0xfe, 0x0b, 0xcd, 0x98, 0xa9, 0x77, 0x14, 0xaf, 0x7e, 0x22, - 0x50, 0x21, 0x69, 0x45, 0xe8, 0xaf, 0x79, 0x20, 0xd0, 0x4f, 0xeb, 0xed, 0x51, 0xc4, 0xd5, 0xcb, - 0x66, 0xe9, 0x07, 0xb8, 0x1e, 0x98, 0xce, 0x20, 0xc2, 0x6b, 0xfb, 0x21, 0x70, 0xa3, 0x98, 0x18, - 0x98, 0xc9, 0x74, 0x61, 0x31, 0xb4, 0x09, 0x8d, 0x29, 0x97, 0x6a, 0xce, 0xde, 0x36, 0x4c, 0x2a, - 0x7a, 0x0b, 0xff, 0xec, 0x52, 0x26, 0x18, 0x4b, 0x46, 0xae, 0xa0, 0x1a, 0x63, 0xc8, 0xa4, 0x57, - 0xee, 0xfe, 0xe9, 0x37, 0x86, 0xe7, 0xfe, 0xbe, 0xab, 0x3f, 0xc3, 0x90, 0xcd, 0xad, 0x88, 0x76, - 0xa0, 0xf1, 0xc0, 0x98, 0x48, 0x61, 0xe4, 0x3f, 0x38, 0x3c, 0xf4, 0xca, 0xdd, 0x72, 0xbf, 0x3e, - 0x77, 0x78, 0xa8, 0xe1, 0xb6, 0x9d, 0xc3, 0x13, 0xc6, 0xc4, 0xaf, 0x70, 0x23, 0xa2, 0x3d, 0x38, - 0x7b, 0xc4, 0x04, 0x57, 0x18, 0x7d, 0x14, 0x19, 0xdc, 0x41, 0x2b, 0x97, 0xa4, 0x26, 0x43, 0xa8, - 0xa9, 0xb4, 0x66, 0x94, 0x47, 0x7d, 0xcc, 0x6f, 0x6d, 0x75, 0xf4, 0x06, 0x2a, 0xda, 0x79, 0x9f, - 0x4f, 0x3c, 0x70, 0x9f, 0xc3, 0x50, 0x30, 0x29, 0x3d, 0xc7, 0x14, 0xb3, 0x25, 0x1d, 0x83, 0x3b, - 0xc1, 0x38, 0x66, 0x81, 0x22, 0x97, 0x50, 0xd1, 0xa7, 0x51, 0x6c, 0x66, 0x36, 0x65, 0x34, 0x74, - 0x04, 0xd5, 0xc9, 0x0a, 0x25, 0x3b, 0x69, 0x68, 0x0c, 0xee, 0x02, 0x57, 0x3c, 0xe0, 0xa7, 0x79, - 0x3d, 0x41, 0x45, 0x6f, 0xf3, 0x94, 0x99, 0xfc, 0x86, 0x9c, 0xa2, 0x1b, 0x32, 0x27, 0x67, 0x45, - 0xc3, 0x4f, 0x07, 0xdc, 0x99, 0xad, 0x93, 0x29, 0xd4, 0x75, 0x90, 0x34, 0x4b, 0x92, 0xce, 0xe1, - 0xdc, 0x4e, 0xe8, 0xda, 0x17, 0x45, 0x6d, 0x7b, 0x85, 0xb4, 0x94, 0xd1, 0xb4, 0xd9, 0x51, 0xda, - 0x4e, 0xea, 0x8e, 0xd1, 0x76, 0x53, 0x47, 0x4b, 0x64, 0x01, 0xb5, 0x2c, 0x26, 0xa4, 0x77, 0xa8, - 0xde, 0x4b, 0x59, 0x9b, 0xfe, 0x24, 0xd9, 0x42, 0xef, 0x01, 0xcc, 0x4f, 0xeb, 0xc7, 0x25, 0x89, - 0x97, 0xcf, 0xa4, 0xcf, 0x2d, 0xa3, 0x75, 0x0e, 0x3a, 0xdf, 0xf7, 0xba, 0xfc, 0x6b, 0x1e, 0xe6, - 0xe8, 0x2b, 0x00, 0x00, 0xff, 0xff, 0x0d, 0xd5, 0xbf, 0xdc, 0xf0, 0x03, 0x00, 0x00, + // 371 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x93, 0xc1, 0x4e, 0xc2, 0x40, + 0x10, 0x86, 0xa1, 0x82, 0xc0, 0x20, 0x4a, 0xf6, 0x60, 0x1a, 0x12, 0x0c, 0xec, 0x89, 0x18, 0x2d, + 0x06, 0xe2, 0xcd, 0x1b, 0x89, 0x5e, 0x08, 0x31, 0xe8, 0x03, 0x28, 0x74, 0x52, 0x1b, 0xa1, 0x53, + 0x77, 0x97, 0x18, 0x9f, 0xcf, 0x17, 0x33, 0xbb, 0xdb, 0x52, 0x04, 0xaa, 0xe1, 0xd6, 0x9d, 0xf9, + 0xe7, 0xfb, 0xb7, 0xb3, 0x33, 0xd0, 0x88, 0x50, 0x7d, 0x92, 0x78, 0xf7, 0x62, 0x41, 0x8a, 0x58, + 0x33, 0x20, 0x6f, 0x19, 0xce, 0x05, 0x79, 0x49, 0xbc, 0x35, 0x0c, 0x42, 0xf5, 0xb6, 0x9a, 0x79, + 0x73, 0x5a, 0xf6, 0x4d, 0xa6, 0x1f, 0xd0, 0xb5, 0xfd, 0x10, 0xb4, 0x52, 0x28, 0xfa, 0xa6, 0x32, + 0x39, 0x58, 0x0c, 0x6f, 0x40, 0x7d, 0x1c, 0x4a, 0x35, 0xc5, 0x8f, 0x15, 0x4a, 0xc5, 0xef, 0xe0, + 0xc4, 0x1e, 0x65, 0x4c, 0x91, 0x44, 0x76, 0x05, 0xe5, 0x88, 0x7c, 0x94, 0x6e, 0xb1, 0x73, 0xd4, + 0xab, 0x0f, 0xce, 0xbd, 0x6d, 0x57, 0x6f, 0x42, 0x3e, 0x4e, 0xad, 0x88, 0xb7, 0xa1, 0xfe, 0x88, + 0x28, 0x12, 0x18, 0x3b, 0x05, 0x27, 0xf4, 0xdd, 0x62, 0xa7, 0xd8, 0xab, 0x4d, 0x9d, 0xd0, 0xd7, + 0x70, 0x9b, 0xce, 0xe0, 0x31, 0xa2, 0xf8, 0x17, 0x6e, 0x44, 0xbc, 0x0b, 0x67, 0xcf, 0x14, 0xd3, + 0x82, 0x82, 0xaf, 0x3c, 0x83, 0x7b, 0x68, 0x66, 0x92, 0xc4, 0x64, 0x00, 0x55, 0x95, 0xc4, 0x8c, + 0x72, 0xaf, 0x8f, 0xb9, 0xd6, 0x5a, 0xc7, 0x6f, 0xa0, 0xa4, 0x9d, 0xb7, 0xf9, 0xcc, 0x85, 0xca, + 0xab, 0xef, 0x0b, 0x94, 0xd2, 0x75, 0x4c, 0x30, 0x3d, 0xf2, 0x5b, 0xa8, 0x8c, 0x28, 0x8a, 0x70, + 0xae, 0xd8, 0x25, 0x94, 0x74, 0x37, 0xf2, 0xcd, 0xcc, 0x4f, 0x19, 0x0d, 0x1f, 0x42, 0x79, 0xb4, + 0x20, 0x89, 0x07, 0x15, 0xbd, 0x40, 0x49, 0xdf, 0xf7, 0x90, 0x9a, 0xac, 0xd5, 0x4e, 0x5e, 0xab, + 0x4d, 0x0b, 0xac, 0x68, 0xf0, 0xed, 0x40, 0x65, 0x62, 0xe3, 0x6c, 0x0c, 0x35, 0x3d, 0x11, 0x9a, + 0x25, 0x59, 0x7b, 0xb7, 0x6e, 0x63, 0x7a, 0x5a, 0x17, 0x79, 0x69, 0xfb, 0x16, 0xbc, 0x90, 0xd2, + 0xb4, 0xd9, 0x5e, 0xda, 0xc6, 0xf8, 0xec, 0xa3, 0x6d, 0x8e, 0x0f, 0x2f, 0xb0, 0x27, 0xa8, 0xa6, + 0xef, 0xcd, 0xba, 0xbb, 0xea, 0xad, 0x71, 0x69, 0xf1, 0xbf, 0x24, 0x6b, 0xe8, 0x03, 0x80, 0xb9, + 0xb4, 0xde, 0x12, 0xc9, 0xdc, 0xac, 0x26, 0xd9, 0x9b, 0x94, 0xd6, 0xde, 0xc9, 0xfc, 0xfe, 0xd7, + 0xd9, 0xb1, 0xd9, 0xb0, 0xe1, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x41, 0x11, 0x04, 0x65, 0xb9, + 0x03, 0x00, 0x00, } diff --git a/network/proto/network.proto b/network/proto/network.proto index 2ac8acc7..722f9377 100644 --- a/network/proto/network.proto +++ b/network/proto/network.proto @@ -63,12 +63,6 @@ message Close { Node node = 1; } -// Solicit is sent when soliciting routes from the network nodes -message Solicit { - // network node - Node node = 1; -} - // Peer is used to advertise node peers message Peer { // network node diff --git a/router/proto/router.micro.go b/router/proto/router.micro.go index b55c3043..a27af9e6 100644 --- a/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: micro/go-micro/router/proto/router.proto +// source: router.proto package go_micro_router @@ -37,6 +37,7 @@ 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 *Request, opts ...client.CallOption) (Router_AdvertiseService, error) + Solicit(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) Process(ctx context.Context, in *Advert, opts ...client.CallOption) (*ProcessResponse, error) Status(ctx context.Context, in *Request, opts ...client.CallOption) (*StatusResponse, error) } @@ -157,6 +158,16 @@ func (x *routerServiceAdvertise) Recv() (*Advert, error) { return m, nil } +func (c *routerService) Solicit(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) { + req := c.c.NewRequest(c.name, "Router.Solicit", in) + out := new(Response) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, 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) @@ -183,6 +194,7 @@ type RouterHandler interface { Lookup(context.Context, *LookupRequest, *LookupResponse) error Watch(context.Context, *WatchRequest, Router_WatchStream) error Advertise(context.Context, *Request, Router_AdvertiseStream) error + Solicit(context.Context, *Request, *Response) error Process(context.Context, *Advert, *ProcessResponse) error Status(context.Context, *Request, *StatusResponse) error } @@ -192,6 +204,7 @@ func RegisterRouterHandler(s server.Server, hdlr RouterHandler, opts ...server.H 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 + Solicit(ctx context.Context, in *Request, out *Response) error Process(ctx context.Context, in *Advert, out *ProcessResponse) error Status(ctx context.Context, in *Request, out *StatusResponse) error } @@ -280,6 +293,10 @@ func (x *routerAdvertiseStream) Send(m *Advert) error { return x.stream.Send(m) } +func (h *routerHandler) Solicit(ctx context.Context, in *Request, out *Response) error { + return h.RouterHandler.Solicit(ctx, in, out) +} + func (h *routerHandler) Process(ctx context.Context, in *Advert, out *ProcessResponse) error { return h.RouterHandler.Process(ctx, in, out) } diff --git a/router/proto/router.pb.go b/router/proto/router.pb.go index 6dedf13d..19813a34 100644 --- a/router/proto/router.pb.go +++ b/router/proto/router.pb.go @@ -1,13 +1,11 @@ // Code generated by protoc-gen-go. DO NOT EDIT. -// source: micro/go-micro/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_6a36eee0b1adf739, []int{0} + return fileDescriptor_367072455c71aedc, []int{0} } // EventType defines the type of event @@ -74,7 +72,7 @@ func (x EventType) String() string { } func (EventType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_6a36eee0b1adf739, []int{1} + return fileDescriptor_367072455c71aedc, []int{1} } // Empty request @@ -88,7 +86,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_6a36eee0b1adf739, []int{0} + return fileDescriptor_367072455c71aedc, []int{0} } func (m *Request) XXX_Unmarshal(b []byte) error { @@ -109,6 +107,38 @@ func (m *Request) XXX_DiscardUnknown() { var xxx_messageInfo_Request proto.InternalMessageInfo +// Empty response +type Response struct { + 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_367072455c71aedc, []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 + // ListResponse is returned by List type ListResponse struct { Routes []*Route `protobuf:"bytes,1,rep,name=routes,proto3" json:"routes,omitempty"` @@ -121,7 +151,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_6a36eee0b1adf739, []int{1} + return fileDescriptor_367072455c71aedc, []int{2} } func (m *ListResponse) XXX_Unmarshal(b []byte) error { @@ -161,7 +191,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_6a36eee0b1adf739, []int{2} + return fileDescriptor_367072455c71aedc, []int{3} } func (m *LookupRequest) XXX_Unmarshal(b []byte) error { @@ -201,7 +231,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_6a36eee0b1adf739, []int{3} + return fileDescriptor_367072455c71aedc, []int{4} } func (m *LookupResponse) XXX_Unmarshal(b []byte) error { @@ -229,6 +259,7 @@ func (m *LookupResponse) GetRoutes() []*Route { return nil } +// QueryRequest queries Table for Routes type QueryRequest struct { Query *Query `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -240,7 +271,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_6a36eee0b1adf739, []int{4} + return fileDescriptor_367072455c71aedc, []int{5} } func (m *QueryRequest) XXX_Unmarshal(b []byte) error { @@ -268,6 +299,7 @@ func (m *QueryRequest) GetQuery() *Query { return nil } +// QueryResponse is returned by Query type QueryResponse struct { Routes []*Route `protobuf:"bytes,1,rep,name=routes,proto3" json:"routes,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -279,7 +311,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_6a36eee0b1adf739, []int{5} + return fileDescriptor_367072455c71aedc, []int{6} } func (m *QueryResponse) XXX_Unmarshal(b []byte) error { @@ -318,7 +350,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_6a36eee0b1adf739, []int{6} + return fileDescriptor_367072455c71aedc, []int{7} } func (m *WatchRequest) XXX_Unmarshal(b []byte) error { @@ -360,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_6a36eee0b1adf739, []int{7} + return fileDescriptor_367072455c71aedc, []int{8} } func (m *Advert) XXX_Unmarshal(b []byte) error { @@ -416,6 +448,47 @@ func (m *Advert) GetEvents() []*Event { return nil } +// Solicit solicits routes +type Solicit struct { + // id of the soliciting router + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Solicit) Reset() { *m = Solicit{} } +func (m *Solicit) String() string { return proto.CompactTextString(m) } +func (*Solicit) ProtoMessage() {} +func (*Solicit) Descriptor() ([]byte, []int) { + return fileDescriptor_367072455c71aedc, []int{9} +} + +func (m *Solicit) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Solicit.Unmarshal(m, b) +} +func (m *Solicit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Solicit.Marshal(b, m, deterministic) +} +func (m *Solicit) XXX_Merge(src proto.Message) { + xxx_messageInfo_Solicit.Merge(m, src) +} +func (m *Solicit) XXX_Size() int { + return xxx_messageInfo_Solicit.Size(m) +} +func (m *Solicit) XXX_DiscardUnknown() { + xxx_messageInfo_Solicit.DiscardUnknown(m) +} + +var xxx_messageInfo_Solicit proto.InternalMessageInfo + +func (m *Solicit) GetId() string { + if m != nil { + return m.Id + } + return "" +} + // ProcessResponse is returned by Process type ProcessResponse struct { XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -427,7 +500,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_6a36eee0b1adf739, []int{8} + return fileDescriptor_367072455c71aedc, []int{10} } func (m *ProcessResponse) XXX_Unmarshal(b []byte) error { @@ -459,7 +532,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_6a36eee0b1adf739, []int{9} + return fileDescriptor_367072455c71aedc, []int{11} } func (m *CreateResponse) XXX_Unmarshal(b []byte) error { @@ -491,7 +564,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_6a36eee0b1adf739, []int{10} + return fileDescriptor_367072455c71aedc, []int{12} } func (m *DeleteResponse) XXX_Unmarshal(b []byte) error { @@ -523,7 +596,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_6a36eee0b1adf739, []int{11} + return fileDescriptor_367072455c71aedc, []int{13} } func (m *UpdateResponse) XXX_Unmarshal(b []byte) error { @@ -561,7 +634,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_6a36eee0b1adf739, []int{12} + return fileDescriptor_367072455c71aedc, []int{14} } func (m *Event) XXX_Unmarshal(b []byte) error { @@ -620,7 +693,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_6a36eee0b1adf739, []int{13} + return fileDescriptor_367072455c71aedc, []int{15} } func (m *Query) XXX_Unmarshal(b []byte) error { @@ -687,7 +760,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_6a36eee0b1adf739, []int{14} + return fileDescriptor_367072455c71aedc, []int{16} } func (m *Route) XXX_Unmarshal(b []byte) error { @@ -769,7 +842,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_6a36eee0b1adf739, []int{15} + return fileDescriptor_367072455c71aedc, []int{17} } func (m *Status) XXX_Unmarshal(b []byte) error { @@ -815,7 +888,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_6a36eee0b1adf739, []int{16} + return fileDescriptor_367072455c71aedc, []int{18} } func (m *StatusResponse) XXX_Unmarshal(b []byte) error { @@ -847,6 +920,7 @@ func init() { proto.RegisterEnum("go.micro.router.AdvertType", AdvertType_name, AdvertType_value) proto.RegisterEnum("go.micro.router.EventType", EventType_name, EventType_value) proto.RegisterType((*Request)(nil), "go.micro.router.Request") + proto.RegisterType((*Response)(nil), "go.micro.router.Response") proto.RegisterType((*ListResponse)(nil), "go.micro.router.ListResponse") proto.RegisterType((*LookupRequest)(nil), "go.micro.router.LookupRequest") proto.RegisterType((*LookupResponse)(nil), "go.micro.router.LookupResponse") @@ -854,6 +928,7 @@ func init() { proto.RegisterType((*QueryResponse)(nil), "go.micro.router.QueryResponse") proto.RegisterType((*WatchRequest)(nil), "go.micro.router.WatchRequest") proto.RegisterType((*Advert)(nil), "go.micro.router.Advert") + proto.RegisterType((*Solicit)(nil), "go.micro.router.Solicit") proto.RegisterType((*ProcessResponse)(nil), "go.micro.router.ProcessResponse") proto.RegisterType((*CreateResponse)(nil), "go.micro.router.CreateResponse") proto.RegisterType((*DeleteResponse)(nil), "go.micro.router.DeleteResponse") @@ -865,509 +940,53 @@ func init() { proto.RegisterType((*StatusResponse)(nil), "go.micro.router.StatusResponse") } -func init() { - proto.RegisterFile("micro/go-micro/router/proto/router.proto", fileDescriptor_6a36eee0b1adf739) -} - -var fileDescriptor_6a36eee0b1adf739 = []byte{ - // 699 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0xcd, 0x4e, 0xdb, 0x40, - 0x10, 0xb6, 0x9d, 0xd8, 0x91, 0xa7, 0xc1, 0xb8, 0xa3, 0x0a, 0xac, 0xb4, 0x40, 0xe4, 0x53, 0x84, - 0xa8, 0x53, 0xa5, 0xd7, 0xfe, 0x05, 0x4a, 0x55, 0xa9, 0x1c, 0x5a, 0x17, 0xd4, 0xb3, 0xb1, 0x57, - 0xd4, 0x22, 0xb1, 0xcd, 0xee, 0x06, 0x94, 0x73, 0x9f, 0xa6, 0xe7, 0x3e, 0x52, 0xaf, 0x7d, 0x88, - 0xca, 0xbb, 0xeb, 0x10, 0x62, 0x8c, 0x44, 0x4e, 0xde, 0x99, 0xf9, 0xe6, 0x9b, 0x99, 0xdd, 0x99, - 0x31, 0x0c, 0xa6, 0x69, 0x4c, 0xf3, 0xe1, 0x45, 0xfe, 0x52, 0x1e, 0x68, 0x3e, 0xe3, 0x84, 0x0e, - 0x0b, 0x9a, 0xf3, 0x4a, 0x08, 0x84, 0x80, 0x9b, 0x17, 0x79, 0x20, 0x30, 0x81, 0x54, 0xfb, 0x36, - 0x74, 0x42, 0x72, 0x35, 0x23, 0x8c, 0xfb, 0xef, 0xa0, 0x7b, 0x92, 0x32, 0x1e, 0x12, 0x56, 0xe4, - 0x19, 0x23, 0x18, 0x80, 0x25, 0x40, 0xcc, 0xd3, 0xfb, 0xad, 0xc1, 0x93, 0xd1, 0x56, 0xb0, 0xe2, - 0x1c, 0x84, 0xe5, 0x27, 0x54, 0x28, 0xff, 0x2d, 0x6c, 0x9c, 0xe4, 0xf9, 0xe5, 0xac, 0x50, 0x84, - 0x78, 0x00, 0xe6, 0xd5, 0x8c, 0xd0, 0xb9, 0xa7, 0xf7, 0xf5, 0x7b, 0xfd, 0xbf, 0x95, 0xd6, 0x50, - 0x82, 0xfc, 0x0f, 0xe0, 0x54, 0xee, 0x6b, 0x26, 0xf0, 0x06, 0xba, 0x92, 0x71, 0xad, 0xf8, 0xef, - 0x61, 0x43, 0x79, 0xaf, 0x19, 0xde, 0x81, 0xee, 0x8f, 0x88, 0xc7, 0x3f, 0xab, 0xfb, 0xfc, 0xad, - 0x83, 0x35, 0x4e, 0xae, 0x09, 0xe5, 0xe8, 0x80, 0x91, 0x26, 0x22, 0x0d, 0x3b, 0x34, 0xd2, 0x04, - 0x87, 0xd0, 0xe6, 0xf3, 0x82, 0x78, 0x46, 0x5f, 0x1f, 0x38, 0xa3, 0xe7, 0x35, 0x62, 0xe9, 0x76, - 0x3a, 0x2f, 0x48, 0x28, 0x80, 0xf8, 0x02, 0x6c, 0x9e, 0x4e, 0x09, 0xe3, 0xd1, 0xb4, 0xf0, 0x5a, - 0x7d, 0x7d, 0xd0, 0x0a, 0x6f, 0x15, 0xe8, 0x42, 0x8b, 0xf3, 0x89, 0xd7, 0x16, 0xfa, 0xf2, 0x58, - 0xe6, 0x4e, 0xae, 0x49, 0xc6, 0x99, 0x67, 0x36, 0xe4, 0x7e, 0x5c, 0x9a, 0x43, 0x85, 0xf2, 0x9f, - 0xc2, 0xe6, 0x57, 0x9a, 0xc7, 0x84, 0xb1, 0xaa, 0x7c, 0xdf, 0x05, 0xe7, 0x88, 0x92, 0x88, 0x93, - 0x65, 0xcd, 0x47, 0x32, 0x21, 0x77, 0x35, 0x67, 0x45, 0xb2, 0x8c, 0xf9, 0xa5, 0x83, 0x29, 0xa8, - 0x31, 0x50, 0x35, 0xea, 0xa2, 0xc6, 0xde, 0xfd, 0x09, 0x34, 0x95, 0x68, 0xac, 0x96, 0x78, 0x00, - 0xa6, 0xf0, 0x13, 0xc5, 0x37, 0xbf, 0x85, 0x04, 0xf9, 0x67, 0x60, 0x8a, 0xb7, 0x44, 0x0f, 0x3a, - 0x8c, 0xd0, 0xeb, 0x34, 0x26, 0xea, 0xf6, 0x2b, 0xb1, 0xb4, 0x5c, 0x44, 0x9c, 0xdc, 0x44, 0x73, - 0x11, 0xcc, 0x0e, 0x2b, 0xb1, 0xb4, 0x64, 0x84, 0xdf, 0xe4, 0xf4, 0x52, 0x04, 0xb3, 0xc3, 0x4a, - 0xf4, 0xff, 0xe8, 0x60, 0x8a, 0x38, 0x0f, 0xf3, 0x46, 0x49, 0x42, 0x09, 0x63, 0x15, 0xaf, 0x12, - 0x97, 0x23, 0xb6, 0x1a, 0x23, 0xb6, 0xef, 0x44, 0xc4, 0x2d, 0xd5, 0x83, 0xd4, 0x33, 0x85, 0x41, - 0x49, 0x88, 0xd0, 0x9e, 0xa4, 0xd9, 0xa5, 0x67, 0x09, 0xad, 0x38, 0x97, 0xd8, 0x29, 0xe1, 0x34, - 0x8d, 0xbd, 0x8e, 0xb8, 0x3d, 0x25, 0xf9, 0x23, 0xb0, 0xbe, 0xf3, 0x88, 0xcf, 0x58, 0xe9, 0x15, - 0xe7, 0x49, 0x95, 0xb2, 0x38, 0xe3, 0x33, 0x30, 0x09, 0xa5, 0x39, 0x55, 0xd9, 0x4a, 0xc1, 0x1f, - 0x83, 0x23, 0x7d, 0x16, 0xd3, 0x30, 0x04, 0x8b, 0x09, 0x8d, 0x9a, 0xa6, 0xed, 0xda, 0x0b, 0x28, - 0x07, 0x05, 0xdb, 0x1f, 0x01, 0xdc, 0xb6, 0x31, 0x22, 0x38, 0x52, 0x1a, 0x67, 0x59, 0x3e, 0xcb, - 0x62, 0xe2, 0x6a, 0xe8, 0x42, 0x57, 0xea, 0x64, 0x0f, 0xb9, 0xfa, 0xfe, 0x10, 0xec, 0x45, 0x5b, - 0x20, 0x80, 0x25, 0x1b, 0xd0, 0xd5, 0xca, 0xb3, 0x6c, 0x3d, 0x57, 0x2f, 0xcf, 0xca, 0xc1, 0x18, - 0xfd, 0x33, 0xc0, 0x0a, 0xe5, 0x95, 0x7c, 0x01, 0x4b, 0xee, 0x0f, 0xdc, 0xad, 0xa5, 0x76, 0x67, - 0x2f, 0xf5, 0xf6, 0x1a, 0xed, 0xaa, 0x89, 0x35, 0x3c, 0x04, 0x53, 0xcc, 0x32, 0xee, 0xd4, 0xb0, - 0xcb, 0x33, 0xde, 0x6b, 0x98, 0x2b, 0x5f, 0x7b, 0xa5, 0xe3, 0x21, 0xd8, 0xb2, 0xbc, 0x94, 0x11, - 0xf4, 0xea, 0x0d, 0xab, 0x28, 0xb6, 0x1b, 0xa6, 0x5f, 0x70, 0x7c, 0x82, 0x8e, 0x9a, 0x4b, 0x6c, - 0xc2, 0xf5, 0xfa, 0x35, 0xc3, 0xea, 0x28, 0x6b, 0x78, 0xbc, 0xe8, 0x81, 0xe6, 0x44, 0xf6, 0x9a, - 0x5e, 0x74, 0x41, 0x33, 0xfa, 0x6b, 0x80, 0x79, 0x1a, 0x9d, 0x4f, 0x08, 0x1e, 0x55, 0x8f, 0x83, - 0x0d, 0xa3, 0x78, 0x0f, 0xdd, 0xca, 0x3a, 0xd1, 0x4a, 0x12, 0xf9, 0xaa, 0x8f, 0x20, 0x59, 0xd9, - 0x40, 0x82, 0x44, 0xb6, 0xc3, 0x23, 0x48, 0x56, 0x96, 0x96, 0x86, 0x63, 0x68, 0x97, 0xff, 0xbe, - 0x07, 0x6e, 0xa7, 0xde, 0x08, 0xcb, 0x3f, 0x4b, 0x5f, 0xc3, 0xcf, 0xd5, 0xce, 0xd9, 0x69, 0xf8, - 0xcf, 0x28, 0xa2, 0xdd, 0x26, 0x73, 0xc5, 0x74, 0x6e, 0x89, 0x7f, 0xf5, 0xeb, 0xff, 0x01, 0x00, - 0x00, 0xff, 0xff, 0xe2, 0xe9, 0xe2, 0x3b, 0xd7, 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 *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) -} - -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 *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 - } - 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(*Request, 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(Request) - 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: "micro/go-micro/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) - 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 { - 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) 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) 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 -} - -// 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) - List(context.Context, *Request) (*ListResponse, error) - Query(context.Context, *QueryRequest) (*QueryResponse, 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_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) -} - -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), - Methods: []grpc.MethodDesc{ - { - MethodName: "Create", - Handler: _Table_Create_Handler, - }, - { - MethodName: "Delete", - Handler: _Table_Delete_Handler, - }, - { - MethodName: "Update", - Handler: _Table_Update_Handler, - }, - { - MethodName: "List", - Handler: _Table_List_Handler, - }, - { - MethodName: "Query", - Handler: _Table_Query_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "micro/go-micro/router/proto/router.proto", +func init() { proto.RegisterFile("router.proto", fileDescriptor_367072455c71aedc) } + +var fileDescriptor_367072455c71aedc = []byte{ + // 714 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xcd, 0x4e, 0xdb, 0x40, + 0x10, 0xb6, 0x93, 0xd8, 0x69, 0xa6, 0x21, 0xa4, 0xa3, 0x0a, 0x4c, 0x5a, 0x20, 0xf2, 0x09, 0x21, + 0x64, 0xaa, 0xf4, 0xda, 0x1f, 0x02, 0xa5, 0xaa, 0x54, 0x0e, 0xad, 0x01, 0xf5, 0x6c, 0xec, 0x15, + 0xb5, 0x48, 0xbc, 0x66, 0x77, 0x03, 0xca, 0xb9, 0x4f, 0xd3, 0x4b, 0x2f, 0x7d, 0xa4, 0xbe, 0x48, + 0xe5, 0xdd, 0x75, 0x08, 0x71, 0x16, 0x09, 0x4e, 0xd9, 0xf9, 0xfb, 0x66, 0x66, 0xf7, 0x9b, 0x71, + 0xa0, 0xcd, 0xe8, 0x44, 0x10, 0x16, 0xe4, 0x8c, 0x0a, 0x8a, 0xab, 0x97, 0x34, 0x18, 0xa7, 0x31, + 0xa3, 0x81, 0x52, 0xfb, 0x2d, 0x68, 0x86, 0xe4, 0x7a, 0x42, 0xb8, 0xf0, 0x01, 0x9e, 0x85, 0x84, + 0xe7, 0x34, 0xe3, 0xc4, 0xff, 0x00, 0xed, 0x93, 0x94, 0x8b, 0x52, 0xc6, 0x00, 0x5c, 0x19, 0xc0, + 0x3d, 0xbb, 0x5f, 0xdf, 0x79, 0x3e, 0x58, 0x0b, 0x16, 0x80, 0x82, 0xb0, 0xf8, 0x09, 0xb5, 0x97, + 0xff, 0x1e, 0x56, 0x4e, 0x28, 0xbd, 0x9a, 0xe4, 0x1a, 0x1c, 0xf7, 0xc0, 0xb9, 0x9e, 0x10, 0x36, + 0xf5, 0xec, 0xbe, 0xbd, 0x34, 0xfe, 0x7b, 0x61, 0x0d, 0x95, 0x93, 0x7f, 0x00, 0x9d, 0x32, 0xfc, + 0x89, 0x05, 0xbc, 0x83, 0xb6, 0x42, 0x7c, 0x52, 0xfe, 0x8f, 0xb0, 0xa2, 0xa3, 0x9f, 0x98, 0xbe, + 0x03, 0xed, 0x1f, 0x91, 0x88, 0x7f, 0x96, 0x77, 0xfb, 0xdb, 0x06, 0x77, 0x98, 0xdc, 0x10, 0x26, + 0xb0, 0x03, 0xb5, 0x34, 0x91, 0x65, 0xb4, 0xc2, 0x5a, 0x9a, 0xe0, 0x3e, 0x34, 0xc4, 0x34, 0x27, + 0x5e, 0xad, 0x6f, 0xef, 0x74, 0x06, 0xaf, 0x2a, 0xc0, 0x2a, 0xec, 0x6c, 0x9a, 0x93, 0x50, 0x3a, + 0xe2, 0x6b, 0x68, 0x89, 0x74, 0x4c, 0xb8, 0x88, 0xc6, 0xb9, 0x57, 0xef, 0xdb, 0x3b, 0xf5, 0xf0, + 0x4e, 0x81, 0x5d, 0xa8, 0x0b, 0x31, 0xf2, 0x1a, 0x52, 0x5f, 0x1c, 0x8b, 0xda, 0xc9, 0x0d, 0xc9, + 0x04, 0xf7, 0x1c, 0x43, 0xed, 0xc7, 0x85, 0x39, 0xd4, 0x5e, 0xfe, 0x06, 0x34, 0x4f, 0xe9, 0x28, + 0x8d, 0xd3, 0x4a, 0xad, 0xfe, 0x0b, 0x58, 0xfd, 0xc6, 0x68, 0x4c, 0x38, 0x9f, 0x31, 0xa5, 0x0b, + 0x9d, 0x23, 0x46, 0x22, 0x41, 0xe6, 0x35, 0x9f, 0xc8, 0x88, 0xdc, 0xd7, 0x9c, 0xe7, 0xc9, 0xbc, + 0xcf, 0x2f, 0x1b, 0x1c, 0x99, 0x15, 0x03, 0xdd, 0xbe, 0x2d, 0xdb, 0xef, 0x2d, 0xaf, 0xcd, 0xd4, + 0x7d, 0x6d, 0xb1, 0xfb, 0x3d, 0x70, 0x64, 0x9c, 0xbc, 0x17, 0xf3, 0x33, 0x29, 0x27, 0xff, 0x1c, + 0x1c, 0xf9, 0xcc, 0xe8, 0x41, 0x93, 0x13, 0x76, 0x93, 0xc6, 0x44, 0x37, 0x5b, 0x8a, 0x85, 0xe5, + 0x32, 0x12, 0xe4, 0x36, 0x9a, 0xca, 0x64, 0xad, 0xb0, 0x14, 0x0b, 0x4b, 0x46, 0xc4, 0x2d, 0x65, + 0x57, 0x32, 0x59, 0x2b, 0x2c, 0x45, 0xff, 0xaf, 0x0d, 0x8e, 0xcc, 0xf3, 0x30, 0x6e, 0x94, 0x24, + 0x8c, 0x70, 0x5e, 0xe2, 0x6a, 0x71, 0x3e, 0x63, 0xdd, 0x98, 0xb1, 0x71, 0x2f, 0x23, 0xae, 0x69, + 0x7a, 0x32, 0xcf, 0x91, 0x06, 0x2d, 0x21, 0x42, 0x63, 0x94, 0x66, 0x57, 0x9e, 0x2b, 0xb5, 0xf2, + 0x5c, 0xf8, 0x8e, 0x89, 0x60, 0x69, 0xec, 0x35, 0xe5, 0xed, 0x69, 0xc9, 0x1f, 0x80, 0x7b, 0x2a, + 0x22, 0x31, 0xe1, 0x45, 0x54, 0x4c, 0x93, 0xb2, 0x64, 0x79, 0xc6, 0x97, 0xe0, 0x10, 0xc6, 0x28, + 0xd3, 0xd5, 0x2a, 0xc1, 0x1f, 0x42, 0x47, 0xc5, 0xcc, 0x06, 0x65, 0x1f, 0x5c, 0x2e, 0x35, 0x7a, + 0xd0, 0xd6, 0x2b, 0x2f, 0xa0, 0x03, 0xb4, 0xdb, 0xee, 0x00, 0xe0, 0x8e, 0xe1, 0x88, 0xd0, 0x51, + 0xd2, 0x30, 0xcb, 0xe8, 0x24, 0x8b, 0x49, 0xd7, 0xc2, 0x2e, 0xb4, 0x95, 0x4e, 0x71, 0xa8, 0x6b, + 0xef, 0xee, 0x43, 0x6b, 0x46, 0x0b, 0x04, 0x70, 0x15, 0x01, 0xbb, 0x56, 0x71, 0x56, 0xd4, 0xeb, + 0xda, 0xc5, 0x59, 0x07, 0xd4, 0x06, 0x7f, 0xea, 0xe0, 0x86, 0xea, 0x4a, 0xbe, 0x82, 0xab, 0x56, + 0x0b, 0x6e, 0x55, 0x4a, 0xbb, 0xb7, 0xb2, 0x7a, 0xdb, 0x46, 0xbb, 0x26, 0xb1, 0x85, 0x87, 0xe0, + 0xc8, 0x31, 0xc7, 0xcd, 0x8a, 0xef, 0xfc, 0xf8, 0xf7, 0x0c, 0x23, 0xe7, 0x5b, 0x6f, 0x6c, 0x3c, + 0x84, 0x96, 0x6a, 0x2f, 0xe5, 0x04, 0xbd, 0x2a, 0x61, 0x35, 0xc4, 0xba, 0x61, 0x31, 0x48, 0x8c, + 0x83, 0xbb, 0x91, 0x35, 0x23, 0x6c, 0x2c, 0xb1, 0xcc, 0x3a, 0xf9, 0x0c, 0x4d, 0x3d, 0xd9, 0x68, + 0xca, 0xd4, 0xeb, 0x57, 0x0c, 0x8b, 0xcb, 0xc0, 0xc2, 0xe3, 0x19, 0x8b, 0xcc, 0x85, 0x6c, 0x9b, + 0x38, 0x31, 0x83, 0x19, 0xfc, 0xab, 0x81, 0x73, 0x16, 0x5d, 0x8c, 0x08, 0x1e, 0x95, 0xcf, 0x8b, + 0x86, 0x61, 0x5e, 0x02, 0xb7, 0xb0, 0x90, 0xac, 0x02, 0x44, 0xf1, 0xe2, 0x11, 0x20, 0x0b, 0x3b, + 0x4c, 0x82, 0x28, 0x42, 0x3d, 0x02, 0x64, 0x61, 0xed, 0x59, 0x38, 0x84, 0x46, 0xf1, 0x61, 0x7d, + 0xe0, 0x76, 0xaa, 0x54, 0x9a, 0xff, 0x12, 0xfb, 0x16, 0x7e, 0x29, 0xb7, 0xd6, 0xa6, 0xe1, 0x23, + 0xa6, 0x81, 0xb6, 0x4c, 0xe6, 0x12, 0xe9, 0xc2, 0x95, 0x7f, 0x0a, 0xde, 0xfe, 0x0f, 0x00, 0x00, + 0xff, 0xff, 0xb7, 0x25, 0xac, 0xac, 0x24, 0x08, 0x00, 0x00, } diff --git a/router/proto/router.proto b/router/proto/router.proto index 9c2ebed4..0ae180c9 100644 --- a/router/proto/router.proto +++ b/router/proto/router.proto @@ -74,6 +74,12 @@ message Advert { repeated Event events = 5; } +// Solicit solicits routes +message Solicit { + // id of the soliciting router + string id = 1; +} + // ProcessResponse is returned by Process message ProcessResponse {} From 588484c3bf6b05e40246189065b16fd955b276c8 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Wed, 11 Sep 2019 18:56:28 +0100 Subject: [PATCH 12/20] Fixed some races. Added more tests. --- network/default.go | 12 ++--- network/node.go | 19 ++++---- network/node_test.go | 110 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 15 deletions(-) diff --git a/network/default.go b/network/default.go index 41119912..03cb8236 100644 --- a/network/default.go +++ b/network/default.go @@ -275,10 +275,10 @@ func (n *network) processNetChan(client transport.Client, listener tunnel.Listen lastSeen: now, } n.Unlock() - // get all the node peers down to MaxDepth encoded in protobuf message + // get all the node peers down to MaxDepth encoded in protobuf msg, err := n.node.getProtoTopology(MaxDepth) if err != nil { - log.Debugf("Network unable to retrieve node peers: %s", err) + log.Debugf("Network unable to retrieve node topology: %s", err) } // advertise yourself to the network if err := n.sendMsg("peer", msg, NetworkChannel); err != nil { @@ -322,7 +322,7 @@ func (n *network) processNetChan(client transport.Client, listener tunnel.Listen // after adding new peer go to the next step continue } - // NOTE: we don't update max topology depth as we dont include this network node + // NOTE: we don't update MaxDepth toplogy as we dont update this node only its peers if err := n.node.updatePeerTopology(pbNetPeer, MaxDepth-1); err != nil { log.Debugf("Network failed to update peers") } @@ -396,14 +396,12 @@ func (n *network) announce(client transport.Client) { case <-n.closed: return case <-announce.C: - n.RLock() msg, err := n.node.getProtoTopology(MaxDepth) if err != nil { - log.Debugf("Network unable to retrieve node peers: %s", err) - n.RUnlock() + log.Debugf("Network unable to retrieve node topology: %s", err) continue } - n.RUnlock() + n.node.RUnlock() // advertise yourself to the network if err := n.sendMsg("peer", msg, NetworkChannel); err != nil { log.Debugf("Network failed to advertise peers: %v", err) diff --git a/network/node.go b/network/node.go index 67a59b02..6c9d59a9 100644 --- a/network/node.go +++ b/network/node.go @@ -136,9 +136,11 @@ func (n *node) Topology(depth uint) *node { return node } -// getProtoTopology returns node peers up to given depth encoded in protobufs -// NOTE: this method is NOT thread-safe, so make sure you serialize access to it +// getProtoTopology returns node topology down to the given depth encoded in protobuf func (n *node) getProtoTopology(depth uint) (*pb.Peer, error) { + n.RLock() + defer n.RUnlock() + node := &pb.Node{ Id: n.id, Address: n.address, @@ -176,7 +178,7 @@ func (n *node) getProtoTopology(depth uint) (*pb.Peer, error) { } // unpackPeer unpacks pb.Peer into node topology of given depth -// NOTE: this method is NOT thread-safe, so make sure you serialize access to it +// NOTE: this function is not thread-safe func unpackPeer(pbPeer *pb.Peer, depth uint) *node { peerNode := &node{ id: pbPeer.Node.Id, @@ -203,16 +205,17 @@ func unpackPeer(pbPeer *pb.Peer, depth uint) *node { return peerNode } -// updatePeer updates node peer up to given depth -// NOTE: this method is not thread safe, so make sure you serialize access to it +// updateTopology updates node peer topology down to given depth func (n *node) updatePeerTopology(pbPeer *pb.Peer, depth uint) error { + n.Lock() + defer n.Unlock() + if pbPeer == nil { return errors.New("peer not initialized") } - // NOTE: we need MaxDepth-1 because node n is the parent adding which - // gives us the max peer topology we maintain and propagate - peer := unpackPeer(pbPeer, MaxDepth-1) + // unpack Peer topology into *node + peer := unpackPeer(pbPeer, depth) // update node peers with new topology n.peers[pbPeer.Node.Id] = peer diff --git a/network/node_test.go b/network/node_test.go index df5a5e4a..623958b3 100644 --- a/network/node_test.go +++ b/network/node_test.go @@ -2,6 +2,8 @@ package network import ( "testing" + + pb "github.com/micro/go-micro/network/proto" ) var ( @@ -229,3 +231,111 @@ func TestTopology(t *testing.T) { } } } + +func TestUpdatePeerTopology(t *testing.T) { + // single node + single := &node{ + id: testNodeId, + address: testNodeAddress, + peers: make(map[string]*node), + network: newNetwork(Name(testNodeNetName)), + } + // nil peer should return error + if err := single.updatePeerTopology(nil, 5); err == nil { + t.Errorf("Expected error, got %s", err) + } + + // update with peer that is not yet in the peer map + pbPeer := &pb.Peer{ + Node: &pb.Node{ + Id: "newPeer", + Address: "newPeerAddress", + }, + Peers: make([]*pb.Peer, 0), + } + // it should add pbPeer to the single node peers + if err := single.updatePeerTopology(pbPeer, 5); err != nil { + t.Errorf("Error updating topology: %s", err) + } + if _, ok := single.peers[pbPeer.Node.Id]; !ok { + t.Errorf("Expected %s to be added to %s peers", pbPeer.Node.Id, single.id) + } + + // complicated node graph + node := testSetup() + // build a simple topology to update node peer1 + peer1 := node.peers["peer1"] + pbPeer1Node := &pb.Node{ + Id: peer1.id, + Address: peer1.address, + } + + pbPeer111 := &pb.Peer{ + Node: &pb.Node{ + Id: "peer111", + Address: "peer111Address", + }, + Peers: make([]*pb.Peer, 0), + } + + pbPeer121 := &pb.Peer{ + Node: &pb.Node{ + Id: "peer121", + Address: "peer121Address", + }, + Peers: make([]*pb.Peer, 0), + } + // topology to update + pbPeer1 := &pb.Peer{ + Node: pbPeer1Node, + Peers: []*pb.Peer{pbPeer111, pbPeer121}, + } + // update peer1 topology + if err := node.updatePeerTopology(pbPeer1, 5); err != nil { + t.Errorf("Error updating topology: %s", err) + } + // make sure peer1 topology has been correctly updated + newPeerIds := []string{pbPeer111.Node.Id, pbPeer121.Node.Id} + for _, id := range newPeerIds { + if _, ok := node.peers["peer1"].peers[id]; !ok { + t.Errorf("Expected %s to be a peer of %s", id, "peer1") + } + } +} + +func TestGetProtoTopology(t *testing.T) { + // single node + single := &node{ + id: testNodeId, + address: testNodeAddress, + peers: make(map[string]*node), + network: newNetwork(Name(testNodeNetName)), + } + topCount := 0 + + protoTop, err := single.getProtoTopology(10) + if err != nil { + t.Errorf("Error getting proto topology: %s", err) + } + if len(protoTop.Peers) != topCount { + t.Errorf("Expected to find %d nodes, found: %d", topCount, len(protoTop.Peers)) + } + + // complicated node graph + node := testSetup() + topCount = 3 + // list of ids of nodes of depth 1 i.e. node peers + peerIds := make(map[string]bool) + // add peer Ids + for _, id := range testNodePeerIds { + peerIds[id] = true + } + // depth 1 should give us immmediate neighbours only + protoTop, err = node.getProtoTopology(1) + if err != nil { + t.Errorf("Error getting proto topology: %s", err) + } + if len(protoTop.Peers) != topCount { + t.Errorf("Expected to find %d nodes, found: %d", topCount, len(protoTop.Peers)) + } +} From d6be91e8afff6d84fcdb49d618df1a693a4bbf7b Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Wed, 11 Sep 2019 23:03:27 +0100 Subject: [PATCH 13/20] Changed RPC methods. Changed Network interface. * Nodes/Topology removed from public methods from Network interface * Peers() returns max depth 3 topology * handler.Topology rpc endpoint removed * handler.Peers rpc endpoint accept "depth" param to return max depth peers --- network/default.go | 10 -- network/handler/handler.go | 96 ++++++-------- network/network.go | 4 - network/node.go | 54 ++++---- network/node_test.go | 115 +++++------------ network/proto/network.micro.go | 34 ----- network/proto/network.pb.go | 230 +++++---------------------------- network/proto/network.proto | 29 +---- 8 files changed, 132 insertions(+), 440 deletions(-) diff --git a/network/default.go b/network/default.go index 03cb8236..36bcd628 100644 --- a/network/default.go +++ b/network/default.go @@ -809,16 +809,6 @@ func (n *network) Connect() error { return nil } -// Nodes returns a list of all network nodes -func (n *network) Nodes() []Node { - return n.node.Nodes() -} - -// Topology returns network topology -func (n *network) Topology() Node { - return n.node.Topology(MaxDepth) -} - func (n *network) close() error { // stop the server if err := n.server.Stop(); err != nil { diff --git a/network/handler/handler.go b/network/handler/handler.go index 3bc47c1b..486b3fa5 100644 --- a/network/handler/handler.go +++ b/network/handler/handler.go @@ -15,84 +15,62 @@ type Network struct { Network network.Network } -// ListNodes returns a list of all accessible nodes in the network -func (n *Network) ListNodes(ctx context.Context, req *pbNet.ListRequest, resp *pbNet.ListResponse) error { - networkNodes := n.Network.Nodes() - - var nodes []*pbNet.Node - for _, networkNode := range networkNodes { - node := &pbNet.Node{ - Id: networkNode.Id(), - Address: networkNode.Address(), - } - nodes = append(nodes, node) +// toplogyToProto recursively traverses node topology and returns it +func peerTopology(peer network.Node, depth uint) *pbNet.Peer { + node := &pbNet.Node{ + Id: peer.Id(), + Address: peer.Address(), } - resp.Nodes = nodes + pbPeers := &pbNet.Peer{ + Node: node, + Peers: make([]*pbNet.Peer, 0), + } - return nil + // return if we reached the end of topology or depth + if depth == 0 || len(peer.Peers()) == 0 { + return pbPeers + } + + // decrement the depth + depth-- + + // iterate through peers of peers aka pops + for _, pop := range peer.Peers() { + peer := peerTopology(pop, depth) + pbPeers.Peers = append(pbPeers.Peers, peer) + } + + return pbPeers } // ListPeers returns a list of all the nodes the node has a direct link with func (n *Network) ListPeers(ctx context.Context, req *pbNet.PeerRequest, resp *pbNet.PeerResponse) error { + depth := uint(req.Depth) + if depth <= 0 || depth > network.MaxDepth { + depth = network.MaxDepth + } + + // get node peers nodePeers := n.Network.Peers() - var peers []*pbNet.Node - for _, nodePeer := range nodePeers { - peer := &pbNet.Node{ - Id: nodePeer.Id(), - Address: nodePeer.Address(), - } - peers = append(peers, peer) - } - - resp.Peers = peers - - return nil -} - -// toplogyToProto recursively traverses node topology and returns it -func toplogyToProto(node network.Node, pbPeer *pbNet.Peer) *pbNet.Peer { - // return if we reached the end of topology - if len(node.Peers()) == 0 { - return pbPeer - } - - for _, topNode := range node.Peers() { - pbNode := &pbNet.Node{ - Id: topNode.Id(), - Address: topNode.Address(), - } - pbPeer := &pbNet.Peer{ - Node: pbNode, - Peers: make([]*pbNet.Peer, 0), - } - peer := toplogyToProto(topNode, pbPeer) - pbPeer.Peers = append(pbPeer.Peers, peer) - } - - return pbPeer -} - -// Topology returns a list of nodes in node topology i.e. it returns all (in)directly reachable nodes from this node -func (n *Network) Topology(ctx context.Context, req *pbNet.TopologyRequest, resp *pbNet.TopologyResponse) error { - // get node topology - topNode := n.Network.Topology() - // network node aka root node node := &pbNet.Node{ Id: n.Network.Id(), Address: n.Network.Address(), } // we will build proto topology into this - pbPeer := &pbNet.Peer{ + peers := &pbNet.Peer{ Node: node, Peers: make([]*pbNet.Peer, 0), } - // return topology encoded into protobuf - topology := toplogyToProto(topNode, pbPeer) - resp.Topology = topology + for _, nodePeer := range nodePeers { + peer := peerTopology(nodePeer, depth) + peers.Peers = append(peers.Peers, peer) + } + + resp.Peers = peers return nil } diff --git a/network/network.go b/network/network.go index a2b4b60e..ef303992 100644 --- a/network/network.go +++ b/network/network.go @@ -44,10 +44,6 @@ type Network interface { Name() string // Connect starts the resolver and tunnel server Connect() error - // Nodes returns list of network nodes - Nodes() []Node - // Topology returns node topology up to MaxDepth hops - Topology() Node // Close stops the tunnel and resolving Close() error // Client is micro client diff --git a/network/node.go b/network/node.go index 6c9d59a9..c4c49f1c 100644 --- a/network/node.go +++ b/network/node.go @@ -47,11 +47,11 @@ func (n *node) Network() Network { // Nodes returns a slice if all nodes in node topology func (n *node) Nodes() []Node { // we need to freeze the network graph here - // otherwise we might get invalid results + // otherwise we might get inconsisten results n.RLock() defer n.RUnlock() - //track the visited nodes + // track the visited nodes visited := make(map[string]*node) // queue of the nodes to visit queue := list.New() @@ -86,32 +86,8 @@ func (n *node) Nodes() []Node { return nodes } -// Peers returns node peers -func (n *node) Peers() []Node { - var peers []Node - n.RLock() - for _, peer := range n.peers { - // make a copy of the node - p := &node{ - id: peer.id, - address: peer.address, - peers: make(map[string]*node), - network: peer.network, - } - // collect peer's peers aka pop (peer of peer) - for id, pop := range peer.peers { - p.peers[id] = pop - } - peers = append(peers, p) - } - n.RUnlock() - - return peers -} - -// topology returns network topology up to MaxDepth -func (n *node) Topology(depth uint) *node { - n.RLock() +// topology returns node topology down to given depth +func (n *node) topology(depth uint) *node { // make a copy of yourself node := &node{ id: n.id, @@ -125,15 +101,31 @@ func (n *node) Topology(depth uint) *node { return node } + // decrement the depth depth-- + // iterate through our peers and update the node peers for _, peer := range n.peers { - nodePeer := peer.Topology(depth) - node.peers[nodePeer.id] = nodePeer + nodePeer := peer.topology(depth) + if _, ok := node.peers[nodePeer.id]; !ok { + node.peers[nodePeer.id] = nodePeer + } + } + + return node +} + +// Peers returns node peers +func (n *node) Peers() []Node { + n.RLock() + var peers []Node + for _, nodePeer := range n.peers { + peer := nodePeer.topology(MaxDepth) + peers = append(peers, peer) } n.RUnlock() - return node + return peers } // getProtoTopology returns node topology down to the given depth encoded in protobuf diff --git a/network/node_test.go b/network/node_test.go index 623958b3..774d78ec 100644 --- a/network/node_test.go +++ b/network/node_test.go @@ -118,6 +118,22 @@ func TestNodes(t *testing.T) { } } +func collectPeerIds(peer Node, ids map[string]bool) map[string]bool { + if len(peer.Peers()) == 0 { + return ids + } + + // iterate through the whole graph + for _, peer := range peer.Peers() { + ids = collectPeerIds(peer, ids) + if _, ok := ids[peer.Id()]; !ok { + ids[peer.Id()] = true + } + } + + return ids +} + func TestPeers(t *testing.T) { // single node single := &node{ @@ -126,107 +142,44 @@ func TestPeers(t *testing.T) { peers: make(map[string]*node), network: newNetwork(Name(testNodeNetName)), } - // get all the nodes including yourself + // get node peers peers := single.Peers() + // there should be no peers peerCount := 0 if len(peers) != peerCount { - t.Errorf("Expected to find %d peers, found: %d", peerCount, len(peers)) + t.Errorf("Expected to find %d nodes, found: %d", peerCount, len(peers)) } // complicated node graph node := testSetup() - // get all the nodes including yourself - peers = node.Peers() - - // compile a list of ids of all nodes in the network into map for easy indexing + // list of ids of nodes of MaxDepth peerIds := make(map[string]bool) // add peer Ids for _, id := range testNodePeerIds { peerIds[id] = true } - - // we should return the correct number of peers - if len(peers) != len(peerIds) { - t.Errorf("Expected %d nodes, found: %d", len(peerIds), len(peers)) - } - - // iterate through the list of peers and makes sure all have been returned - for _, peer := range peers { - if _, ok := peerIds[peer.Id()]; !ok { - t.Errorf("Expected to find %s peer", peer.Id()) - } - } -} - -func collectTopologyIds(peers map[string]*node, ids map[string]bool) map[string]bool { - if len(peers) == 0 { - return ids - } - - // iterate through the whole graph - for id, peer := range peers { - ids = collectTopologyIds(peer.peers, ids) - if _, ok := ids[id]; !ok { - ids[id] = true - } - } - - return ids -} - -func TestTopology(t *testing.T) { - // single node - single := &node{ - id: testNodeId, - address: testNodeAddress, - peers: make(map[string]*node), - network: newNetwork(Name(testNodeNetName)), - } - // get all the nodes including yourself - topology := single.Topology(MaxDepth) - // you should not be in your topology - topCount := 0 - - if len(topology.peers) != topCount { - t.Errorf("Expected to find %d nodes, found: %d", topCount, len(topology.peers)) - } - - // complicated node graph - node := testSetup() - // list of ids of nodes of depth 1 i.e. node peers - peerIds := make(map[string]bool) - // add peer Ids - for _, id := range testNodePeerIds { - peerIds[id] = true - } - topology = node.Topology(1) - - // depth 1 should return only immediate peers - if len(topology.peers) != len(peerIds) { - t.Errorf("Expected to find %d nodes, found: %d", len(peerIds), len(topology.peers)) - } - for id := range topology.peers { - if _, ok := peerIds[id]; !ok { - t.Errorf("Expected to find %s peer", id) - } - } - // add peers of peers to peerIds for _, id := range testPeerOfPeerIds { peerIds[id] = true } - topology = node.Topology(2) + // get node peers + peers = node.Peers() - topIds := make(map[string]bool) - topIds = collectTopologyIds(topology.peers, topIds) - - if len(topIds) != len(peerIds) { - t.Errorf("Expected to find %d nodes, found: %d", len(peerIds), len(topIds)) + // we will collect all returned Peer Ids into this map + resPeerIds := make(map[string]bool) + for _, peer := range peers { + resPeerIds[peer.Id()] = true + resPeerIds = collectPeerIds(peer, resPeerIds) } - for id := range topIds { - if _, ok := topIds[id]; !ok { + // if correct, we must collect all peerIds + if len(resPeerIds) != len(peerIds) { + t.Errorf("Expected to find %d peers, found: %d", len(peerIds), len(resPeerIds)) + } + + for id := range resPeerIds { + if _, ok := peerIds[id]; !ok { t.Errorf("Expected to find %s peer", id) } } diff --git a/network/proto/network.micro.go b/network/proto/network.micro.go index b0f1ae6b..e1499490 100644 --- a/network/proto/network.micro.go +++ b/network/proto/network.micro.go @@ -35,9 +35,7 @@ var _ server.Option // Client API for Network service type NetworkService interface { - ListNodes(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*ListResponse, error) ListPeers(ctx context.Context, in *PeerRequest, opts ...client.CallOption) (*PeerResponse, error) - Topology(ctx context.Context, in *TopologyRequest, opts ...client.CallOption) (*TopologyResponse, error) ListRoutes(ctx context.Context, in *proto1.Request, opts ...client.CallOption) (*proto1.ListResponse, error) } @@ -59,16 +57,6 @@ func NewNetworkService(name string, c client.Client) NetworkService { } } -func (c *networkService) ListNodes(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*ListResponse, error) { - req := c.c.NewRequest(c.name, "Network.ListNodes", in) - out := new(ListResponse) - err := c.c.Call(ctx, req, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *networkService) ListPeers(ctx context.Context, in *PeerRequest, opts ...client.CallOption) (*PeerResponse, error) { req := c.c.NewRequest(c.name, "Network.ListPeers", in) out := new(PeerResponse) @@ -79,16 +67,6 @@ func (c *networkService) ListPeers(ctx context.Context, in *PeerRequest, opts .. return out, nil } -func (c *networkService) Topology(ctx context.Context, in *TopologyRequest, opts ...client.CallOption) (*TopologyResponse, error) { - req := c.c.NewRequest(c.name, "Network.Topology", in) - out := new(TopologyResponse) - err := c.c.Call(ctx, req, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *networkService) ListRoutes(ctx context.Context, in *proto1.Request, opts ...client.CallOption) (*proto1.ListResponse, error) { req := c.c.NewRequest(c.name, "Network.ListRoutes", in) out := new(proto1.ListResponse) @@ -102,17 +80,13 @@ func (c *networkService) ListRoutes(ctx context.Context, in *proto1.Request, opt // Server API for Network service type NetworkHandler interface { - ListNodes(context.Context, *ListRequest, *ListResponse) error ListPeers(context.Context, *PeerRequest, *PeerResponse) error - Topology(context.Context, *TopologyRequest, *TopologyResponse) error ListRoutes(context.Context, *proto1.Request, *proto1.ListResponse) error } func RegisterNetworkHandler(s server.Server, hdlr NetworkHandler, opts ...server.HandlerOption) error { type network interface { - ListNodes(ctx context.Context, in *ListRequest, out *ListResponse) error ListPeers(ctx context.Context, in *PeerRequest, out *PeerResponse) error - Topology(ctx context.Context, in *TopologyRequest, out *TopologyResponse) error ListRoutes(ctx context.Context, in *proto1.Request, out *proto1.ListResponse) error } type Network struct { @@ -126,18 +100,10 @@ type networkHandler struct { NetworkHandler } -func (h *networkHandler) ListNodes(ctx context.Context, in *ListRequest, out *ListResponse) error { - return h.NetworkHandler.ListNodes(ctx, in, out) -} - func (h *networkHandler) ListPeers(ctx context.Context, in *PeerRequest, out *PeerResponse) error { return h.NetworkHandler.ListPeers(ctx, in, out) } -func (h *networkHandler) Topology(ctx context.Context, in *TopologyRequest, out *TopologyResponse) error { - return h.NetworkHandler.Topology(ctx, in, out) -} - func (h *networkHandler) ListRoutes(ctx context.Context, in *proto1.Request, out *proto1.ListResponse) error { return h.NetworkHandler.ListRoutes(ctx, in, out) } diff --git a/network/proto/network.pb.go b/network/proto/network.pb.go index 76ab4bbc..3cacfb00 100644 --- a/network/proto/network.pb.go +++ b/network/proto/network.pb.go @@ -21,83 +21,10 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package -// Empty request -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_8571034d60397816, []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 ListNodes -type ListResponse struct { - // network nodes - Nodes []*Node `protobuf:"bytes,1,rep,name=nodes,proto3" json:"nodes,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_8571034d60397816, []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) GetNodes() []*Node { - if m != nil { - return m.Nodes - } - return nil -} - // PeerRequest requests list of peers type PeerRequest struct { - // node id - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // node topology depth + Depth uint32 `protobuf:"varint,1,opt,name=depth,proto3" json:"depth,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -107,7 +34,7 @@ func (m *PeerRequest) Reset() { *m = PeerRequest{} } func (m *PeerRequest) String() string { return proto.CompactTextString(m) } func (*PeerRequest) ProtoMessage() {} func (*PeerRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8571034d60397816, []int{2} + return fileDescriptor_8571034d60397816, []int{0} } func (m *PeerRequest) XXX_Unmarshal(b []byte) error { @@ -128,16 +55,17 @@ func (m *PeerRequest) XXX_DiscardUnknown() { var xxx_messageInfo_PeerRequest proto.InternalMessageInfo -func (m *PeerRequest) GetId() string { +func (m *PeerRequest) GetDepth() uint32 { if m != nil { - return m.Id + return m.Depth } - return "" + return 0 } // PeerResponse is returned by ListPeers type PeerResponse struct { - Peers []*Node `protobuf:"bytes,1,rep,name=peers,proto3" json:"peers,omitempty"` + // return peer topology + Peers *Peer `protobuf:"bytes,1,opt,name=peers,proto3" json:"peers,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -147,7 +75,7 @@ func (m *PeerResponse) Reset() { *m = PeerResponse{} } func (m *PeerResponse) String() string { return proto.CompactTextString(m) } func (*PeerResponse) ProtoMessage() {} func (*PeerResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_8571034d60397816, []int{3} + return fileDescriptor_8571034d60397816, []int{1} } func (m *PeerResponse) XXX_Unmarshal(b []byte) error { @@ -168,94 +96,13 @@ func (m *PeerResponse) XXX_DiscardUnknown() { var xxx_messageInfo_PeerResponse proto.InternalMessageInfo -func (m *PeerResponse) GetPeers() []*Node { +func (m *PeerResponse) GetPeers() *Peer { if m != nil { return m.Peers } return nil } -// TopologyRequest list node topology -type TopologyRequest struct { - // node id - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *TopologyRequest) Reset() { *m = TopologyRequest{} } -func (m *TopologyRequest) String() string { return proto.CompactTextString(m) } -func (*TopologyRequest) ProtoMessage() {} -func (*TopologyRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8571034d60397816, []int{4} -} - -func (m *TopologyRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_TopologyRequest.Unmarshal(m, b) -} -func (m *TopologyRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_TopologyRequest.Marshal(b, m, deterministic) -} -func (m *TopologyRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_TopologyRequest.Merge(m, src) -} -func (m *TopologyRequest) XXX_Size() int { - return xxx_messageInfo_TopologyRequest.Size(m) -} -func (m *TopologyRequest) XXX_DiscardUnknown() { - xxx_messageInfo_TopologyRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_TopologyRequest proto.InternalMessageInfo - -func (m *TopologyRequest) GetId() string { - if m != nil { - return m.Id - } - return "" -} - -// TopologyResponse is returned by Topology -type TopologyResponse struct { - Topology *Peer `protobuf:"bytes,1,opt,name=topology,proto3" json:"topology,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *TopologyResponse) Reset() { *m = TopologyResponse{} } -func (m *TopologyResponse) String() string { return proto.CompactTextString(m) } -func (*TopologyResponse) ProtoMessage() {} -func (*TopologyResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_8571034d60397816, []int{5} -} - -func (m *TopologyResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_TopologyResponse.Unmarshal(m, b) -} -func (m *TopologyResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_TopologyResponse.Marshal(b, m, deterministic) -} -func (m *TopologyResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_TopologyResponse.Merge(m, src) -} -func (m *TopologyResponse) XXX_Size() int { - return xxx_messageInfo_TopologyResponse.Size(m) -} -func (m *TopologyResponse) XXX_DiscardUnknown() { - xxx_messageInfo_TopologyResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_TopologyResponse proto.InternalMessageInfo - -func (m *TopologyResponse) GetTopology() *Peer { - if m != nil { - return m.Topology - } - return nil -} - // Node is network node type Node struct { // node id @@ -271,7 +118,7 @@ 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_8571034d60397816, []int{6} + return fileDescriptor_8571034d60397816, []int{2} } func (m *Node) XXX_Unmarshal(b []byte) error { @@ -319,7 +166,7 @@ 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_8571034d60397816, []int{7} + return fileDescriptor_8571034d60397816, []int{3} } func (m *Connect) XXX_Unmarshal(b []byte) error { @@ -360,7 +207,7 @@ func (m *Close) Reset() { *m = Close{} } func (m *Close) String() string { return proto.CompactTextString(m) } func (*Close) ProtoMessage() {} func (*Close) Descriptor() ([]byte, []int) { - return fileDescriptor_8571034d60397816, []int{8} + return fileDescriptor_8571034d60397816, []int{4} } func (m *Close) XXX_Unmarshal(b []byte) error { @@ -403,7 +250,7 @@ func (m *Peer) Reset() { *m = Peer{} } func (m *Peer) String() string { return proto.CompactTextString(m) } func (*Peer) ProtoMessage() {} func (*Peer) Descriptor() ([]byte, []int) { - return fileDescriptor_8571034d60397816, []int{9} + return fileDescriptor_8571034d60397816, []int{5} } func (m *Peer) XXX_Unmarshal(b []byte) error { @@ -439,12 +286,8 @@ func (m *Peer) GetPeers() []*Peer { } func init() { - proto.RegisterType((*ListRequest)(nil), "go.micro.network.ListRequest") - proto.RegisterType((*ListResponse)(nil), "go.micro.network.ListResponse") proto.RegisterType((*PeerRequest)(nil), "go.micro.network.PeerRequest") proto.RegisterType((*PeerResponse)(nil), "go.micro.network.PeerResponse") - proto.RegisterType((*TopologyRequest)(nil), "go.micro.network.TopologyRequest") - proto.RegisterType((*TopologyResponse)(nil), "go.micro.network.TopologyResponse") proto.RegisterType((*Node)(nil), "go.micro.network.Node") proto.RegisterType((*Connect)(nil), "go.micro.network.Connect") proto.RegisterType((*Close)(nil), "go.micro.network.Close") @@ -454,29 +297,24 @@ func init() { func init() { proto.RegisterFile("network.proto", fileDescriptor_8571034d60397816) } var fileDescriptor_8571034d60397816 = []byte{ - // 371 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x93, 0xc1, 0x4e, 0xc2, 0x40, - 0x10, 0x86, 0xa1, 0x82, 0xc0, 0x20, 0x4a, 0xf6, 0x60, 0x1a, 0x12, 0x0c, 0xec, 0x89, 0x18, 0x2d, - 0x06, 0xe2, 0xcd, 0x1b, 0x89, 0x5e, 0x08, 0x31, 0xe8, 0x03, 0x28, 0x74, 0x52, 0x1b, 0xa1, 0x53, - 0x77, 0x97, 0x18, 0x9f, 0xcf, 0x17, 0x33, 0xbb, 0xdb, 0x52, 0x04, 0xaa, 0xe1, 0xd6, 0x9d, 0xf9, - 0xe7, 0xfb, 0xb7, 0xb3, 0x33, 0xd0, 0x88, 0x50, 0x7d, 0x92, 0x78, 0xf7, 0x62, 0x41, 0x8a, 0x58, - 0x33, 0x20, 0x6f, 0x19, 0xce, 0x05, 0x79, 0x49, 0xbc, 0x35, 0x0c, 0x42, 0xf5, 0xb6, 0x9a, 0x79, - 0x73, 0x5a, 0xf6, 0x4d, 0xa6, 0x1f, 0xd0, 0xb5, 0xfd, 0x10, 0xb4, 0x52, 0x28, 0xfa, 0xa6, 0x32, - 0x39, 0x58, 0x0c, 0x6f, 0x40, 0x7d, 0x1c, 0x4a, 0x35, 0xc5, 0x8f, 0x15, 0x4a, 0xc5, 0xef, 0xe0, - 0xc4, 0x1e, 0x65, 0x4c, 0x91, 0x44, 0x76, 0x05, 0xe5, 0x88, 0x7c, 0x94, 0x6e, 0xb1, 0x73, 0xd4, - 0xab, 0x0f, 0xce, 0xbd, 0x6d, 0x57, 0x6f, 0x42, 0x3e, 0x4e, 0xad, 0x88, 0xb7, 0xa1, 0xfe, 0x88, - 0x28, 0x12, 0x18, 0x3b, 0x05, 0x27, 0xf4, 0xdd, 0x62, 0xa7, 0xd8, 0xab, 0x4d, 0x9d, 0xd0, 0xd7, - 0x70, 0x9b, 0xce, 0xe0, 0x31, 0xa2, 0xf8, 0x17, 0x6e, 0x44, 0xbc, 0x0b, 0x67, 0xcf, 0x14, 0xd3, - 0x82, 0x82, 0xaf, 0x3c, 0x83, 0x7b, 0x68, 0x66, 0x92, 0xc4, 0x64, 0x00, 0x55, 0x95, 0xc4, 0x8c, - 0x72, 0xaf, 0x8f, 0xb9, 0xd6, 0x5a, 0xc7, 0x6f, 0xa0, 0xa4, 0x9d, 0xb7, 0xf9, 0xcc, 0x85, 0xca, - 0xab, 0xef, 0x0b, 0x94, 0xd2, 0x75, 0x4c, 0x30, 0x3d, 0xf2, 0x5b, 0xa8, 0x8c, 0x28, 0x8a, 0x70, - 0xae, 0xd8, 0x25, 0x94, 0x74, 0x37, 0xf2, 0xcd, 0xcc, 0x4f, 0x19, 0x0d, 0x1f, 0x42, 0x79, 0xb4, - 0x20, 0x89, 0x07, 0x15, 0xbd, 0x40, 0x49, 0xdf, 0xf7, 0x90, 0x9a, 0xac, 0xd5, 0x4e, 0x5e, 0xab, - 0x4d, 0x0b, 0xac, 0x68, 0xf0, 0xed, 0x40, 0x65, 0x62, 0xe3, 0x6c, 0x0c, 0x35, 0x3d, 0x11, 0x9a, - 0x25, 0x59, 0x7b, 0xb7, 0x6e, 0x63, 0x7a, 0x5a, 0x17, 0x79, 0x69, 0xfb, 0x16, 0xbc, 0x90, 0xd2, - 0xb4, 0xd9, 0x5e, 0xda, 0xc6, 0xf8, 0xec, 0xa3, 0x6d, 0x8e, 0x0f, 0x2f, 0xb0, 0x27, 0xa8, 0xa6, - 0xef, 0xcd, 0xba, 0xbb, 0xea, 0xad, 0x71, 0x69, 0xf1, 0xbf, 0x24, 0x6b, 0xe8, 0x03, 0x80, 0xb9, - 0xb4, 0xde, 0x12, 0xc9, 0xdc, 0xac, 0x26, 0xd9, 0x9b, 0x94, 0xd6, 0xde, 0xc9, 0xfc, 0xfe, 0xd7, - 0xd9, 0xb1, 0xd9, 0xb0, 0xe1, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x41, 0x11, 0x04, 0x65, 0xb9, - 0x03, 0x00, 0x00, + // 292 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x52, 0xcd, 0x4a, 0xc3, 0x40, + 0x10, 0x36, 0x31, 0x31, 0x74, 0x6a, 0x45, 0x16, 0x91, 0x50, 0xa8, 0x94, 0xf5, 0x22, 0xa2, 0x1b, + 0x69, 0xf0, 0xe6, 0xad, 0x07, 0x2f, 0xa5, 0x48, 0x9e, 0x40, 0x9b, 0x1d, 0xd2, 0xa0, 0xcd, 0xc4, + 0xdd, 0x0d, 0xbe, 0x8e, 0x8f, 0x2a, 0xd9, 0x4d, 0x2d, 0x28, 0xa1, 0xf4, 0x96, 0xf9, 0xfe, 0x32, + 0xc3, 0xb7, 0x30, 0xaa, 0xd0, 0x7c, 0x91, 0x7a, 0x17, 0xb5, 0x22, 0x43, 0xec, 0xbc, 0x20, 0xb1, + 0x29, 0x73, 0x45, 0xa2, 0xc3, 0xc7, 0x69, 0x51, 0x9a, 0x75, 0xb3, 0x12, 0x39, 0x6d, 0x12, 0xcb, + 0x24, 0x05, 0xdd, 0xbb, 0x0f, 0x45, 0x8d, 0x41, 0x95, 0x58, 0x67, 0x37, 0xb8, 0x18, 0x7e, 0x0d, + 0xc3, 0x17, 0x44, 0x95, 0xe1, 0x67, 0x83, 0xda, 0xb0, 0x0b, 0x08, 0x25, 0xd6, 0x66, 0x1d, 0x7b, + 0x53, 0xef, 0x66, 0x94, 0xb9, 0x81, 0x3f, 0xc1, 0xa9, 0x13, 0xe9, 0x9a, 0x2a, 0x8d, 0xec, 0x0e, + 0xc2, 0x1a, 0x51, 0x69, 0xab, 0x1a, 0xce, 0x2e, 0xc5, 0xdf, 0x5d, 0x84, 0x95, 0x3b, 0x11, 0x7f, + 0x80, 0x60, 0x49, 0x12, 0xd9, 0x19, 0xf8, 0xa5, 0xb4, 0x96, 0x41, 0xe6, 0x97, 0x92, 0xc5, 0x10, + 0xbd, 0x49, 0xa9, 0x50, 0xeb, 0xd8, 0xb7, 0xe0, 0x76, 0xe4, 0x8f, 0x10, 0xcd, 0xa9, 0xaa, 0x30, + 0x37, 0xec, 0x16, 0x82, 0x8a, 0x24, 0xf6, 0xff, 0xa9, 0x8d, 0xce, 0xac, 0x86, 0xa7, 0x10, 0xce, + 0x3f, 0x48, 0xe3, 0x41, 0xa6, 0x57, 0x08, 0xda, 0x65, 0x0f, 0xf1, 0xec, 0xee, 0xf7, 0xa7, 0xc7, + 0x7b, 0xef, 0x9f, 0x7d, 0x7b, 0x10, 0x2d, 0x1d, 0xce, 0x16, 0x30, 0x58, 0x94, 0xda, 0xb4, 0xb4, + 0x66, 0x93, 0x1e, 0x9f, 0xeb, 0x62, 0x7c, 0xd5, 0x47, 0xbb, 0x16, 0xf8, 0x11, 0x7b, 0x06, 0x68, + 0xd3, 0xb2, 0xb6, 0x50, 0xcd, 0xe2, 0x9d, 0xbe, 0xab, 0x78, 0x9b, 0x34, 0xf9, 0xc7, 0x58, 0xdb, + 0x6f, 0xd0, 0xea, 0xc4, 0x3e, 0x86, 0xf4, 0x27, 0x00, 0x00, 0xff, 0xff, 0x68, 0x11, 0x14, 0x79, + 0x64, 0x02, 0x00, 0x00, } diff --git a/network/proto/network.proto b/network/proto/network.proto index 722f9377..2d95a455 100644 --- a/network/proto/network.proto +++ b/network/proto/network.proto @@ -6,41 +6,20 @@ import "github.com/micro/go-micro/router/proto/router.proto"; // Network service is usesd to gain visibility into networks service Network { - rpc ListNodes(ListRequest) returns (ListResponse) {}; rpc ListPeers(PeerRequest) returns (PeerResponse) {}; - rpc Topology(TopologyRequest) returns (TopologyResponse) {}; rpc ListRoutes(go.micro.router.Request) returns (go.micro.router.ListResponse) {}; } -// Empty request -message ListRequest {} - -// ListResponse is returned by ListNodes -message ListResponse { - // network nodes - repeated Node nodes = 1; -} - // PeerRequest requests list of peers message PeerRequest { - // node id - string id = 1; + // node topology depth + uint32 depth = 1; } // PeerResponse is returned by ListPeers message PeerResponse { - repeated Node peers = 1; -} - -// TopologyRequest list node topology -message TopologyRequest { - // node id - string id = 1; -} - -// TopologyResponse is returned by Topology -message TopologyResponse { - Peer topology = 1; + // return peer topology + Peer peers = 1; } // Node is network node From fa4ff8921e44a6ca29bd4f6ed49a622a8892004e Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Wed, 11 Sep 2019 23:19:29 +0100 Subject: [PATCH 14/20] Removed redundant lock. Simplified proto topology --- network/default.go | 12 ++---------- network/node.go | 11 ++++------- network/node_test.go | 12 ++++-------- 3 files changed, 10 insertions(+), 25 deletions(-) diff --git a/network/default.go b/network/default.go index 36bcd628..ab8905c7 100644 --- a/network/default.go +++ b/network/default.go @@ -276,10 +276,7 @@ func (n *network) processNetChan(client transport.Client, listener tunnel.Listen } n.Unlock() // get all the node peers down to MaxDepth encoded in protobuf - msg, err := n.node.getProtoTopology(MaxDepth) - if err != nil { - log.Debugf("Network unable to retrieve node topology: %s", err) - } + msg := n.node.getProtoTopology(MaxDepth) // advertise yourself to the network if err := n.sendMsg("peer", msg, NetworkChannel); err != nil { log.Debugf("Network failed to advertise peers: %v", err) @@ -396,12 +393,7 @@ func (n *network) announce(client transport.Client) { case <-n.closed: return case <-announce.C: - msg, err := n.node.getProtoTopology(MaxDepth) - if err != nil { - log.Debugf("Network unable to retrieve node topology: %s", err) - continue - } - n.node.RUnlock() + msg := n.node.getProtoTopology(MaxDepth) // advertise yourself to the network if err := n.sendMsg("peer", msg, NetworkChannel); err != nil { log.Debugf("Network failed to advertise peers: %v", err) diff --git a/network/node.go b/network/node.go index c4c49f1c..dad609e5 100644 --- a/network/node.go +++ b/network/node.go @@ -129,7 +129,7 @@ func (n *node) Peers() []Node { } // getProtoTopology returns node topology down to the given depth encoded in protobuf -func (n *node) getProtoTopology(depth uint) (*pb.Peer, error) { +func (n *node) getProtoTopology(depth uint) *pb.Peer { n.RLock() defer n.RUnlock() @@ -145,7 +145,7 @@ func (n *node) getProtoTopology(depth uint) (*pb.Peer, error) { // return if have either reached the depth or have no more peers if depth == 0 || len(n.peers) == 0 { - return pbPeers, nil + return pbPeers } // decrement the depth @@ -155,10 +155,7 @@ func (n *node) getProtoTopology(depth uint) (*pb.Peer, error) { for _, peer := range n.peers { // get peers of the node peers // NOTE: this is [not] a recursive call - pbPeerPeer, err := peer.getProtoTopology(depth) - if err != nil { - return nil, err - } + pbPeerPeer := peer.getProtoTopology(depth) // add current peer to explored peers peers = append(peers, pbPeerPeer) } @@ -166,7 +163,7 @@ func (n *node) getProtoTopology(depth uint) (*pb.Peer, error) { // add peers to the parent topology pbPeers.Peers = peers - return pbPeers, nil + return pbPeers } // unpackPeer unpacks pb.Peer into node topology of given depth diff --git a/network/node_test.go b/network/node_test.go index 774d78ec..2a49be11 100644 --- a/network/node_test.go +++ b/network/node_test.go @@ -266,10 +266,8 @@ func TestGetProtoTopology(t *testing.T) { } topCount := 0 - protoTop, err := single.getProtoTopology(10) - if err != nil { - t.Errorf("Error getting proto topology: %s", err) - } + protoTop := single.getProtoTopology(10) + if len(protoTop.Peers) != topCount { t.Errorf("Expected to find %d nodes, found: %d", topCount, len(protoTop.Peers)) } @@ -284,10 +282,8 @@ func TestGetProtoTopology(t *testing.T) { peerIds[id] = true } // depth 1 should give us immmediate neighbours only - protoTop, err = node.getProtoTopology(1) - if err != nil { - t.Errorf("Error getting proto topology: %s", err) - } + protoTop = node.getProtoTopology(1) + if len(protoTop.Peers) != topCount { t.Errorf("Expected to find %d nodes, found: %d", topCount, len(protoTop.Peers)) } From 77c6c9781b5b1cfb7942a7f9c7e870c63ad30cd3 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Wed, 11 Sep 2019 23:56:57 +0100 Subject: [PATCH 15/20] getProtoTopology has been replaced by PeersToProto This helps us remove redundant code across node and handler --- network/default.go | 4 +- network/handler/handler.go | 46 +----------------- network/node.go | 97 +++++++++++++++++++++----------------- network/node_test.go | 14 +++--- 4 files changed, 65 insertions(+), 96 deletions(-) diff --git a/network/default.go b/network/default.go index ab8905c7..2da925eb 100644 --- a/network/default.go +++ b/network/default.go @@ -276,7 +276,7 @@ func (n *network) processNetChan(client transport.Client, listener tunnel.Listen } n.Unlock() // get all the node peers down to MaxDepth encoded in protobuf - msg := n.node.getProtoTopology(MaxDepth) + msg := PeersToProto(n.node, n.Peers(), MaxDepth) // advertise yourself to the network if err := n.sendMsg("peer", msg, NetworkChannel); err != nil { log.Debugf("Network failed to advertise peers: %v", err) @@ -393,7 +393,7 @@ func (n *network) announce(client transport.Client) { case <-n.closed: return case <-announce.C: - msg := n.node.getProtoTopology(MaxDepth) + msg := PeersToProto(n.node, n.Peers(), MaxDepth) // advertise yourself to the network if err := n.sendMsg("peer", msg, NetworkChannel); err != nil { log.Debugf("Network failed to advertise peers: %v", err) diff --git a/network/handler/handler.go b/network/handler/handler.go index 486b3fa5..759e21a4 100644 --- a/network/handler/handler.go +++ b/network/handler/handler.go @@ -15,35 +15,6 @@ type Network struct { Network network.Network } -// toplogyToProto recursively traverses node topology and returns it -func peerTopology(peer network.Node, depth uint) *pbNet.Peer { - node := &pbNet.Node{ - Id: peer.Id(), - Address: peer.Address(), - } - - pbPeers := &pbNet.Peer{ - Node: node, - Peers: make([]*pbNet.Peer, 0), - } - - // return if we reached the end of topology or depth - if depth == 0 || len(peer.Peers()) == 0 { - return pbPeers - } - - // decrement the depth - depth-- - - // iterate through peers of peers aka pops - for _, pop := range peer.Peers() { - peer := peerTopology(pop, depth) - pbPeers.Peers = append(pbPeers.Peers, peer) - } - - return pbPeers -} - // ListPeers returns a list of all the nodes the node has a direct link with func (n *Network) ListPeers(ctx context.Context, req *pbNet.PeerRequest, resp *pbNet.PeerResponse) error { depth := uint(req.Depth) @@ -54,21 +25,8 @@ func (n *Network) ListPeers(ctx context.Context, req *pbNet.PeerRequest, resp *p // get node peers nodePeers := n.Network.Peers() - // network node aka root node - node := &pbNet.Node{ - Id: n.Network.Id(), - Address: n.Network.Address(), - } - // we will build proto topology into this - peers := &pbNet.Peer{ - Node: node, - Peers: make([]*pbNet.Peer, 0), - } - - for _, nodePeer := range nodePeers { - peer := peerTopology(nodePeer, depth) - peers.Peers = append(peers.Peers, peer) - } + // get peers encoded into protobuf + peers := network.PeersToProto(n.Network, nodePeers, depth) resp.Peers = peers diff --git a/network/node.go b/network/node.go index dad609e5..b5a318ee 100644 --- a/network/node.go +++ b/network/node.go @@ -128,42 +128,22 @@ func (n *node) Peers() []Node { return peers } -// getProtoTopology returns node topology down to the given depth encoded in protobuf -func (n *node) getProtoTopology(depth uint) *pb.Peer { - n.RLock() - defer n.RUnlock() +// updateTopology updates node peer topology down to given depth +func (n *node) updatePeerTopology(pbPeer *pb.Peer, depth uint) error { + n.Lock() + defer n.Unlock() - node := &pb.Node{ - Id: n.id, - Address: n.address, + if pbPeer == nil { + return errors.New("peer not initialized") } - pbPeers := &pb.Peer{ - Node: node, - Peers: make([]*pb.Peer, 0), - } + // unpack Peer topology into *node + peer := unpackPeer(pbPeer, depth) - // return if have either reached the depth or have no more peers - if depth == 0 || len(n.peers) == 0 { - return pbPeers - } + // update node peers with new topology + n.peers[pbPeer.Node.Id] = peer - // decrement the depth - depth-- - - var peers []*pb.Peer - for _, peer := range n.peers { - // get peers of the node peers - // NOTE: this is [not] a recursive call - pbPeerPeer := peer.getProtoTopology(depth) - // add current peer to explored peers - peers = append(peers, pbPeerPeer) - } - - // add peers to the parent topology - pbPeers.Peers = peers - - return pbPeers + return nil } // unpackPeer unpacks pb.Peer into node topology of given depth @@ -194,20 +174,51 @@ func unpackPeer(pbPeer *pb.Peer, depth uint) *node { return peerNode } -// updateTopology updates node peer topology down to given depth -func (n *node) updatePeerTopology(pbPeer *pb.Peer, depth uint) error { - n.Lock() - defer n.Unlock() - - if pbPeer == nil { - return errors.New("peer not initialized") +func peerTopology(peer Node, depth uint) *pb.Peer { + node := &pb.Node{ + Id: peer.Id(), + Address: peer.Address(), } - // unpack Peer topology into *node - peer := unpackPeer(pbPeer, depth) + pbPeers := &pb.Peer{ + Node: node, + Peers: make([]*pb.Peer, 0), + } - // update node peers with new topology - n.peers[pbPeer.Node.Id] = peer + // return if we reached the end of topology or depth + if depth == 0 || len(peer.Peers()) == 0 { + return pbPeers + } - return nil + // decrement the depth + depth-- + + // iterate through peers of peers aka pops + for _, pop := range peer.Peers() { + peer := peerTopology(pop, depth) + pbPeers.Peers = append(pbPeers.Peers, peer) + } + + return pbPeers +} + +// PeersToProto returns node peers graph encoded into protobuf +func PeersToProto(root Node, peers []Node, depth uint) *pb.Peer { + // network node aka root node + node := &pb.Node{ + Id: root.Id(), + Address: root.Address(), + } + // we will build proto topology into this + pbPeers := &pb.Peer{ + Node: node, + Peers: make([]*pb.Peer, 0), + } + + for _, peer := range peers { + pbPeer := peerTopology(peer, depth) + pbPeers.Peers = append(pbPeers.Peers, pbPeer) + } + + return pbPeers } diff --git a/network/node_test.go b/network/node_test.go index 2a49be11..f5941c1a 100644 --- a/network/node_test.go +++ b/network/node_test.go @@ -256,7 +256,7 @@ func TestUpdatePeerTopology(t *testing.T) { } } -func TestGetProtoTopology(t *testing.T) { +func TestPeersToProto(t *testing.T) { // single node single := &node{ id: testNodeId, @@ -266,10 +266,10 @@ func TestGetProtoTopology(t *testing.T) { } topCount := 0 - protoTop := single.getProtoTopology(10) + protoPeers := PeersToProto(single, single.Peers(), 0) - if len(protoTop.Peers) != topCount { - t.Errorf("Expected to find %d nodes, found: %d", topCount, len(protoTop.Peers)) + if len(protoPeers.Peers) != topCount { + t.Errorf("Expected to find %d nodes, found: %d", topCount, len(protoPeers.Peers)) } // complicated node graph @@ -282,9 +282,9 @@ func TestGetProtoTopology(t *testing.T) { peerIds[id] = true } // depth 1 should give us immmediate neighbours only - protoTop = node.getProtoTopology(1) + protoPeers = PeersToProto(node, node.Peers(), 1) - if len(protoTop.Peers) != topCount { - t.Errorf("Expected to find %d nodes, found: %d", topCount, len(protoTop.Peers)) + if len(protoPeers.Peers) != topCount { + t.Errorf("Expected to find %d nodes, found: %d", topCount, len(protoPeers.Peers)) } } From ef91d836eb7961c40f23bd8fa98613c156e77edd Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Thu, 12 Sep 2019 12:18:43 +0100 Subject: [PATCH 16/20] Implement Solicit method for handler.Router --- router/handler/router.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/router/handler/router.go b/router/handler/router.go index ac05f012..5e4bceb7 100644 --- a/router/handler/router.go +++ b/router/handler/router.go @@ -45,6 +45,16 @@ func (r *Router) Lookup(ctx context.Context, req *pb.LookupRequest, resp *pb.Loo return nil } +// Solicit triggers full routing table advertisement +func (r *Router) Solicit(ctx context.Context, req *pb.Request, resp *pb.Response) error { + if err := r.Router.Solicit(); err != nil { + return err + } + + return nil +} + +// Advertise streams router advertisements func (r *Router) Advertise(ctx context.Context, req *pb.Request, stream pb.Router_AdvertiseStream) error { advertChan, err := r.Router.Advertise() if err != nil { @@ -91,6 +101,7 @@ func (r *Router) Advertise(ctx context.Context, req *pb.Request, stream pb.Route return nil } +// Process processes advertisements 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 { @@ -126,6 +137,7 @@ func (r *Router) Process(ctx context.Context, req *pb.Advert, rsp *pb.ProcessRes return nil } +// Status returns router status func (r *Router) Status(ctx context.Context, req *pb.Request, rsp *pb.StatusResponse) error { status := r.Router.Status() From b91c3147e70e88f242cdb6b58f34cfd32db2b067 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Fri, 13 Sep 2019 03:02:20 +0100 Subject: [PATCH 17/20] Node API allows us to drop all network locks Network locks are now needed only when accessing client map. node map access is serialied with the node mutex. --- network/default.go | 138 +++++++++++++++++-------------------- network/handler/handler.go | 5 +- network/node.go | 134 +++++++++++++++++++++++++---------- network/node_test.go | 37 +++------- 4 files changed, 171 insertions(+), 143 deletions(-) diff --git a/network/default.go b/network/default.go index 2da925eb..1a314cee 100644 --- a/network/default.go +++ b/network/default.go @@ -124,9 +124,10 @@ func newNetwork(opts ...Option) Network { // Options returns network options func (n *network) Options() Options { - n.Lock() + n.RLock() + defer n.RUnlock() + options := n.options - n.Unlock() return options } @@ -196,7 +197,6 @@ func (n *network) handleNetConn(sess tunnel.Session, msg chan *transport.Message for { m := new(transport.Message) if err := sess.Recv(m); err != nil { - // TODO: should we bail here? log.Debugf("Network tunnel [%s] receive error: %v", NetworkChannel, err) return } @@ -255,28 +255,23 @@ func (n *network) processNetChan(client transport.Client, listener tunnel.Listen if pbNetConnect.Node.Id == n.options.Id { continue } - n.Lock() log.Debugf("Network received connect message from: %s", pbNetConnect.Node.Id) - // if the entry already exists skip adding it - if peer, ok := n.peers[pbNetConnect.Node.Id]; ok { - // update lastSeen timestamp - if n.peers[pbNetConnect.Node.Id].lastSeen.Before(now) { - peer.lastSeen = now - } - n.Unlock() - continue - } - // add a new peer to the node peers - // NOTE: new node does not have any peers, yet - n.peers[pbNetConnect.Node.Id] = &node{ + peer := &node{ id: pbNetConnect.Node.Id, address: pbNetConnect.Node.Address, peers: make(map[string]*node), lastSeen: now, } - n.Unlock() - // get all the node peers down to MaxDepth encoded in protobuf - msg := PeersToProto(n.node, n.Peers(), MaxDepth) + if ok := n.node.AddPeer(peer); !ok { + log.Debugf("Network peer exists, refreshing: %s", peer.id) + // update lastSeen time for the peer + if ok := n.RefreshPeer(peer.id, now); !ok { + log.Debugf("Network failed refreshing peer: %s", peer.id) + } + continue + } + // get node peers down to MaxDepth encoded in protobuf + msg := PeersToProto(n.node, MaxDepth) // advertise yourself to the network if err := n.sendMsg("peer", msg, NetworkChannel); err != nil { log.Debugf("Network failed to advertise peers: %v", err) @@ -297,18 +292,14 @@ func (n *network) processNetChan(client transport.Client, listener tunnel.Listen if pbNetPeer.Node.Id == n.options.Id { continue } - n.Lock() log.Debugf("Network received peer message from: %s", pbNetPeer.Node.Id) - // only add the peer if it is NOT already in node's list of peers - _, exists := n.peers[pbNetPeer.Node.Id] - if !exists { - n.peers[pbNetPeer.Node.Id] = &node{ - id: pbNetPeer.Node.Id, - address: pbNetPeer.Node.Address, - peers: make(map[string]*node), - lastSeen: now, - } - n.Unlock() + peer := &node{ + id: pbNetPeer.Node.Id, + address: pbNetPeer.Node.Address, + peers: make(map[string]*node), + lastSeen: now, + } + if ok := n.node.AddPeer(peer); ok { // send a solicit message when discovering new peer msg := &pbRtr.Solicit{ Id: n.options.Id, @@ -316,18 +307,19 @@ func (n *network) processNetChan(client transport.Client, listener tunnel.Listen if err := n.sendMsg("solicit", msg, ControlChannel); err != nil { log.Debugf("Network failed to send solicit message: %s", err) } - // after adding new peer go to the next step continue } - // NOTE: we don't update MaxDepth toplogy as we dont update this node only its peers - if err := n.node.updatePeerTopology(pbNetPeer, MaxDepth-1); err != nil { + log.Debugf("Network peer exists, refreshing: %s", pbNetPeer.Node.Id) + // update lastSeen time for the peer + if ok := n.RefreshPeer(pbNetPeer.Node.Id, now); !ok { + log.Debugf("Network failed refreshing peer: %s", pbNetPeer.Node.Id) + } + // NOTE: we don't uunpack MaxDepth toplogy + peer = UnpackPeerTopology(pbNetPeer, now, MaxDepth-1) + log.Debugf("Network updating topology of node: %s", n.node.id) + if ok := n.node.UpdatePeer(peer); !ok { log.Debugf("Network failed to update peers") } - // update lastSeen timestamp if outdated - if n.peers[pbNetPeer.Node.Id].lastSeen.Before(now) { - n.peers[pbNetPeer.Node.Id].lastSeen = now - } - n.Unlock() case "close": pbNetClose := &pbNet.Close{} if err := proto.Unmarshal(m.Body, pbNetClose); err != nil { @@ -338,13 +330,11 @@ func (n *network) processNetChan(client transport.Client, listener tunnel.Listen if pbNetClose.Node.Id == n.options.Id { continue } - n.Lock() log.Debugf("Network received close message from: %s", pbNetClose.Node.Id) if err := n.pruneNode(pbNetClose.Node.Id); err != nil { log.Debugf("Network failed to prune the node %s: %v", pbNetClose.Node.Id, err) continue } - n.Unlock() } case <-n.closed: return @@ -393,7 +383,7 @@ func (n *network) announce(client transport.Client) { case <-n.closed: return case <-announce.C: - msg := PeersToProto(n.node, n.Peers(), MaxDepth) + msg := PeersToProto(n.node, MaxDepth) // advertise yourself to the network if err := n.sendMsg("peer", msg, NetworkChannel); err != nil { log.Debugf("Network failed to advertise peers: %v", err) @@ -404,9 +394,9 @@ func (n *network) announce(client transport.Client) { } // pruneNode removes a node with given id from the list of peers. It also removes all routes originted by this node. -// NOTE: this method is not thread-safe; when calling it make sure you lock the particular code segment func (n *network) pruneNode(id string) error { - delete(n.peers, id) + // DeletePeer serializes access + n.node.DeletePeer(id) // lookup all the routes originated at this node q := router.NewQuery( router.QueryRouter(id), @@ -506,11 +496,9 @@ func (n *network) setRouteMetric(route *router.Route) { return } - n.RLock() // check if the route origin is our peer if _, ok := n.peers[route.Router]; ok { route.Metric = 10 - n.RUnlock() return } @@ -519,12 +507,10 @@ func (n *network) setRouteMetric(route *router.Route) { for id := range peer.peers { if route.Router == id { route.Metric = 100 - n.RUnlock() return } } } - n.RUnlock() // the origin of the route is beyond our neighbourhood route.Metric = 1000 @@ -544,7 +530,6 @@ func (n *network) processCtrlChan(client transport.Client, listener tunnel.Liste // switch on type of message and take action switch m.Header["Micro-Method"] { case "advert": - now := time.Now() pbRtrAdvert := &pbRtr.Advert{} if err := proto.Unmarshal(m.Body, pbRtrAdvert); err != nil { log.Debugf("Network fail to unmarshal advert message: %v", err) @@ -554,27 +539,13 @@ func (n *network) processCtrlChan(client transport.Client, listener tunnel.Liste if pbRtrAdvert.Id == n.options.Id { continue } - // loookup advertising node in our peers - n.Lock() log.Debugf("Network received advert message from: %s", pbRtrAdvert.Id) - advertNode, ok := n.peers[pbRtrAdvert.Id] - if !ok { - // advertising node has not been registered as our peer, yet - // let's add it to our peers - advertNode = &node{ - id: pbRtrAdvert.Id, - peers: make(map[string]*node), - lastSeen: now, - } - n.peers[pbRtrAdvert.Id] = advertNode - n.Unlock() - // send a solicit message when discovering a new node - msg := &pbRtr.Solicit{ - Id: n.options.Id, - } - if err := n.sendMsg("solicit", msg, ControlChannel); err != nil { - log.Debugf("Network failed to send solicit message: %s", err) - } + // loookup advertising node in our peers + advertNode := n.node.GetPeer(pbRtrAdvert.Id) + // if we dont recognize the node as our peer we skip processing its adverts + if advertNode == nil { + log.Debugf("Network skipping advert message from unknown peer: %s", pbRtrAdvert.Id) + continue } var events []*router.Event @@ -585,13 +556,17 @@ func (n *network) processCtrlChan(client transport.Client, listener tunnel.Liste // as our peer when we received the advert from it if advertNode.address == "" { advertNode.address = event.Route.Gateway + if ok := n.node.UpdatePeer(advertNode); !ok { + log.Debugf("Network failed to update peer: %s", advertNode.id) + continue + } } // if advertising node id is not the same as Route.Router // we know the advertising node is not the origin of the route if advertNode.id != event.Route.Router { // if the origin router is not the advertising node peer // we can't rule out potential routing loops so we bail here - if _, ok := advertNode.peers[event.Route.Router]; !ok { + if peer := advertNode.GetPeer(event.Route.Router); peer == nil { continue } } @@ -605,7 +580,9 @@ func (n *network) processCtrlChan(client transport.Client, listener tunnel.Liste Metric: int(event.Route.Metric), } // set the route metric + n.node.RLock() n.setRouteMetric(&route) + n.node.RUnlock() // throw away metric bigger than 1000 if route.Metric > 1000 { log.Debugf("Network route metric %d dropping node: %s", route.Metric, route.Router) @@ -619,6 +596,7 @@ func (n *network) processCtrlChan(client transport.Client, listener tunnel.Liste } events = append(events, e) } + // create an advert and process it advert := &router.Advert{ Id: pbRtrAdvert.Id, Type: router.AdvertType(pbRtrAdvert.Type), @@ -627,9 +605,9 @@ func (n *network) processCtrlChan(client transport.Client, listener tunnel.Liste Events: events, } + log.Debugf("Network router processing advert: %s", advert.Id) if err := n.Router.Process(advert); err != nil { log.Debugf("Network failed to process advert %s: %v", advert.Id, err) - continue } case "solicit": pbRtrSolicit := &pbRtr.Solicit{} @@ -642,6 +620,7 @@ func (n *network) processCtrlChan(client transport.Client, listener tunnel.Liste if pbRtrSolicit.Id == n.options.Id { continue } + log.Debugf("Network router flushing routes for: %s", pbRtrSolicit.Id) // advertise all the routes when a new node has connected if err := n.Router.Solicit(); err != nil { log.Debugf("Network failed to solicit routes: %s", err) @@ -685,7 +664,7 @@ func (n *network) advertise(client transport.Client, advertChan <-chan *router.A Timestamp: advert.Timestamp.UnixNano(), Events: events, } - if err := n.sendMsg("advert", msg, NetworkChannel); err != nil { + if err := n.sendMsg("advert", msg, ControlChannel); err != nil { log.Debugf("Network failed to advertise routes: %v", err) continue } @@ -823,16 +802,27 @@ func (n *network) close() error { // Close closes network connection func (n *network) Close() error { n.Lock() - defer n.Unlock() if !n.connected { + n.Unlock() return nil } select { case <-n.closed: + n.Unlock() return nil default: + // TODO: send close message to the network channel + close(n.closed) + // set connected to false + n.connected = false + + // unlock the lock otherwise we'll deadlock sending the close + n.Unlock() + + // send close message only if we managed to connect to NetworkChannel + log.Debugf("Sending close message from: %s", n.options.Id) msg := &pbNet.Close{ Node: &pbNet.Node{ Id: n.options.Id, @@ -842,10 +832,6 @@ func (n *network) Close() error { if err := n.sendMsg("close", msg, NetworkChannel); err != nil { log.Debugf("Network failed to send close message: %s", err) } - // TODO: send close message to the network channel - close(n.closed) - // set connected to false - n.connected = false } return n.close() diff --git a/network/handler/handler.go b/network/handler/handler.go index 759e21a4..a0905936 100644 --- a/network/handler/handler.go +++ b/network/handler/handler.go @@ -22,11 +22,8 @@ func (n *Network) ListPeers(ctx context.Context, req *pbNet.PeerRequest, resp *p depth = network.MaxDepth } - // get node peers - nodePeers := n.Network.Peers() - // get peers encoded into protobuf - peers := network.PeersToProto(n.Network, nodePeers, depth) + peers := network.PeersToProto(n.Network, depth) resp.Peers = peers diff --git a/network/node.go b/network/node.go index b5a318ee..cbd19d10 100644 --- a/network/node.go +++ b/network/node.go @@ -2,7 +2,6 @@ package network import ( "container/list" - "errors" "sync" "time" @@ -44,6 +43,86 @@ func (n *node) Network() Network { return n.network } +// AddPeer adds a new peer to node +// It returns false if the peer already exists +func (n *node) AddPeer(peer *node) bool { + n.Lock() + defer n.Unlock() + + if _, ok := n.peers[peer.id]; !ok { + n.peers[peer.id] = peer + return true + } + + return false +} + +// GetPeer returns a peer if it exists +// It returns nil if the peer was not found +func (n *node) GetPeer(id string) *node { + n.RLock() + defer n.RUnlock() + + p, ok := n.peers[id] + if !ok { + return nil + } + + peer := &node{ + id: p.id, + address: p.address, + peers: make(map[string]*node), + network: p.network, + lastSeen: p.lastSeen, + } + + // TODO: recursively retrieve all of its peers + for id, pop := range p.peers { + peer.peers[id] = pop + } + + return peer +} + +// UpdatePeer updates a peer if it exists +// It returns false if the peer does not exist +func (n *node) UpdatePeer(peer *node) bool { + n.Lock() + defer n.Unlock() + + if _, ok := n.peers[peer.id]; ok { + n.peers[peer.id] = peer + return true + } + + return false +} + +// DeletePeer deletes a peer if it exists +func (n *node) DeletePeer(id string) { + n.Lock() + defer n.Unlock() + + delete(n.peers, id) +} + +// Refresh updates node timestamp +func (n *node) RefreshPeer(id string, now time.Time) bool { + n.Lock() + defer n.Unlock() + + peer, ok := n.peers[id] + if !ok { + return false + } + + if peer.lastSeen.Before(now) { + peer.lastSeen = now + } + + return true +} + // Nodes returns a slice if all nodes in node topology func (n *node) Nodes() []Node { // we need to freeze the network graph here @@ -90,10 +169,11 @@ func (n *node) Nodes() []Node { func (n *node) topology(depth uint) *node { // make a copy of yourself node := &node{ - id: n.id, - address: n.address, - peers: make(map[string]*node), - network: n.network, + id: n.id, + address: n.address, + peers: make(map[string]*node), + network: n.network, + lastSeen: n.lastSeen, } // return if we reach requested depth or we have no more peers @@ -128,31 +208,13 @@ func (n *node) Peers() []Node { return peers } -// updateTopology updates node peer topology down to given depth -func (n *node) updatePeerTopology(pbPeer *pb.Peer, depth uint) error { - n.Lock() - defer n.Unlock() - - if pbPeer == nil { - return errors.New("peer not initialized") - } - - // unpack Peer topology into *node - peer := unpackPeer(pbPeer, depth) - - // update node peers with new topology - n.peers[pbPeer.Node.Id] = peer - - return nil -} - -// unpackPeer unpacks pb.Peer into node topology of given depth -// NOTE: this function is not thread-safe -func unpackPeer(pbPeer *pb.Peer, depth uint) *node { +// UnpackPeerTopology unpacks pb.Peer into node topology of given depth +func UnpackPeerTopology(pbPeer *pb.Peer, lastSeen time.Time, depth uint) *node { peerNode := &node{ - id: pbPeer.Node.Id, - address: pbPeer.Node.Address, - peers: make(map[string]*node), + id: pbPeer.Node.Id, + address: pbPeer.Node.Address, + peers: make(map[string]*node), + lastSeen: lastSeen, } // return if have either reached the depth or have no more peers @@ -165,7 +227,7 @@ func unpackPeer(pbPeer *pb.Peer, depth uint) *node { peers := make(map[string]*node) for _, pbPeer := range pbPeer.Peers { - peer := unpackPeer(pbPeer, depth) + peer := UnpackPeerTopology(pbPeer, lastSeen, depth) peers[pbPeer.Node.Id] = peer } @@ -203,19 +265,19 @@ func peerTopology(peer Node, depth uint) *pb.Peer { } // PeersToProto returns node peers graph encoded into protobuf -func PeersToProto(root Node, peers []Node, depth uint) *pb.Peer { +func PeersToProto(node Node, depth uint) *pb.Peer { // network node aka root node - node := &pb.Node{ - Id: root.Id(), - Address: root.Address(), + pbNode := &pb.Node{ + Id: node.Id(), + Address: node.Address(), } // we will build proto topology into this pbPeers := &pb.Peer{ - Node: node, + Node: pbNode, Peers: make([]*pb.Peer, 0), } - for _, peer := range peers { + for _, peer := range node.Peers() { pbPeer := peerTopology(peer, depth) pbPeers.Peers = append(pbPeers.Peers, pbPeer) } diff --git a/network/node_test.go b/network/node_test.go index f5941c1a..82959693 100644 --- a/network/node_test.go +++ b/network/node_test.go @@ -2,6 +2,7 @@ package network import ( "testing" + "time" pb "github.com/micro/go-micro/network/proto" ) @@ -185,20 +186,7 @@ func TestPeers(t *testing.T) { } } -func TestUpdatePeerTopology(t *testing.T) { - // single node - single := &node{ - id: testNodeId, - address: testNodeAddress, - peers: make(map[string]*node), - network: newNetwork(Name(testNodeNetName)), - } - // nil peer should return error - if err := single.updatePeerTopology(nil, 5); err == nil { - t.Errorf("Expected error, got %s", err) - } - - // update with peer that is not yet in the peer map +func TestUnpackPeerTopology(t *testing.T) { pbPeer := &pb.Peer{ Node: &pb.Node{ Id: "newPeer", @@ -207,14 +195,11 @@ func TestUpdatePeerTopology(t *testing.T) { Peers: make([]*pb.Peer, 0), } // it should add pbPeer to the single node peers - if err := single.updatePeerTopology(pbPeer, 5); err != nil { - t.Errorf("Error updating topology: %s", err) - } - if _, ok := single.peers[pbPeer.Node.Id]; !ok { - t.Errorf("Expected %s to be added to %s peers", pbPeer.Node.Id, single.id) + peer := UnpackPeerTopology(pbPeer, time.Now(), 5) + if peer.id != pbPeer.Node.Id { + t.Errorf("Expected peer id %s, found: %s", pbPeer.Node.Id, peer.id) } - // complicated node graph node := testSetup() // build a simple topology to update node peer1 peer1 := node.peers["peer1"] @@ -243,14 +228,12 @@ func TestUpdatePeerTopology(t *testing.T) { Node: pbPeer1Node, Peers: []*pb.Peer{pbPeer111, pbPeer121}, } - // update peer1 topology - if err := node.updatePeerTopology(pbPeer1, 5); err != nil { - t.Errorf("Error updating topology: %s", err) - } + // unpack peer1 topology + peer = UnpackPeerTopology(pbPeer1, time.Now(), 5) // make sure peer1 topology has been correctly updated newPeerIds := []string{pbPeer111.Node.Id, pbPeer121.Node.Id} for _, id := range newPeerIds { - if _, ok := node.peers["peer1"].peers[id]; !ok { + if _, ok := peer.peers[id]; !ok { t.Errorf("Expected %s to be a peer of %s", id, "peer1") } } @@ -266,7 +249,7 @@ func TestPeersToProto(t *testing.T) { } topCount := 0 - protoPeers := PeersToProto(single, single.Peers(), 0) + protoPeers := PeersToProto(single, 0) if len(protoPeers.Peers) != topCount { t.Errorf("Expected to find %d nodes, found: %d", topCount, len(protoPeers.Peers)) @@ -282,7 +265,7 @@ func TestPeersToProto(t *testing.T) { peerIds[id] = true } // depth 1 should give us immmediate neighbours only - protoPeers = PeersToProto(node, node.Peers(), 1) + protoPeers = PeersToProto(node, 1) if len(protoPeers.Peers) != topCount { t.Errorf("Expected to find %d nodes, found: %d", topCount, len(protoPeers.Peers)) From d72e91fb3839fc17ea5b3899770317a2987c7556 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Fri, 13 Sep 2019 03:31:58 +0100 Subject: [PATCH 18/20] Unlock on return from network.Connect --- network/default.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/network/default.go b/network/default.go index 1a314cee..1f62392b 100644 --- a/network/default.go +++ b/network/default.go @@ -676,12 +676,14 @@ func (n *network) advertise(client transport.Client, advertChan <-chan *router.A // Connect connects the network func (n *network) Connect() error { - n.Lock() + n.RLock() // return if already connected if n.connected { + n.RUnlock() return nil } + n.Lock() // try to resolve network nodes nodes, err := n.resolveNodes() if err != nil { @@ -690,6 +692,7 @@ func (n *network) Connect() error { // connect network tunnel if err := n.Tunnel.Connect(); err != nil { + n.Unlock() return err } @@ -701,6 +704,7 @@ func (n *network) Connect() error { // dial into ControlChannel to send route adverts ctrlClient, err := n.Tunnel.Dial(ControlChannel, tunnel.DialMulticast()) if err != nil { + n.Unlock() return err } @@ -709,12 +713,14 @@ func (n *network) Connect() error { // listen on ControlChannel ctrlListener, err := n.Tunnel.Listen(ControlChannel) if err != nil { + n.Unlock() return err } // dial into NetworkChannel to send network messages netClient, err := n.Tunnel.Dial(NetworkChannel, tunnel.DialMulticast()) if err != nil { + n.Unlock() return err } @@ -723,6 +729,7 @@ func (n *network) Connect() error { // listen on NetworkChannel netListener, err := n.Tunnel.Listen(NetworkChannel) if err != nil { + n.Unlock() return err } @@ -731,17 +738,20 @@ func (n *network) Connect() error { // start the router if err := n.options.Router.Start(); err != nil { + n.Unlock() return err } // start advertising routes advertChan, err := n.options.Router.Advertise() if err != nil { + n.Unlock() return err } // start the server if err := n.server.Start(); err != nil { + n.Unlock() return err } n.Unlock() From 323a72be3498f9f3382ee7667a51da73cc1b18c2 Mon Sep 17 00:00:00 2001 From: Milos Gajdos Date: Fri, 13 Sep 2019 18:46:24 +0100 Subject: [PATCH 19/20] Small refactoring; Split horizon loop break. --- network/default.go | 36 +++++--------- network/node.go | 114 ++++++++++++++++++++++++++----------------- network/node_test.go | 6 +++ router/default.go | 3 ++ router/table.go | 4 ++ 5 files changed, 93 insertions(+), 70 deletions(-) diff --git a/network/default.go b/network/default.go index 1f62392b..c981f1d4 100644 --- a/network/default.go +++ b/network/default.go @@ -264,7 +264,7 @@ func (n *network) processNetChan(client transport.Client, listener tunnel.Listen } if ok := n.node.AddPeer(peer); !ok { log.Debugf("Network peer exists, refreshing: %s", peer.id) - // update lastSeen time for the peer + // update lastSeen time for the existing node if ok := n.RefreshPeer(peer.id, now); !ok { log.Debugf("Network failed refreshing peer: %s", peer.id) } @@ -314,7 +314,7 @@ func (n *network) processNetChan(client transport.Client, listener tunnel.Listen if ok := n.RefreshPeer(pbNetPeer.Node.Id, now); !ok { log.Debugf("Network failed refreshing peer: %s", pbNetPeer.Node.Id) } - // NOTE: we don't uunpack MaxDepth toplogy + // NOTE: we don't unpack MaxDepth toplogy peer = UnpackPeerTopology(pbNetPeer, now, MaxDepth-1) log.Debugf("Network updating topology of node: %s", n.node.id) if ok := n.node.UpdatePeer(peer); !ok { @@ -539,34 +539,23 @@ func (n *network) processCtrlChan(client transport.Client, listener tunnel.Liste if pbRtrAdvert.Id == n.options.Id { continue } - log.Debugf("Network received advert message from: %s", pbRtrAdvert.Id) - // loookup advertising node in our peers - advertNode := n.node.GetPeer(pbRtrAdvert.Id) - // if we dont recognize the node as our peer we skip processing its adverts + log.Debugf("Network received advert message with %d events from: %s", len(pbRtrAdvert.Events), pbRtrAdvert.Id) + // loookup advertising node in our peer topology + advertNode := n.node.GetPeerNode(pbRtrAdvert.Id) if advertNode == nil { + // if we can't find the node in our topology (MaxDepth) we skipp prcessing adverts log.Debugf("Network skipping advert message from unknown peer: %s", pbRtrAdvert.Id) continue } var events []*router.Event for _, event := range pbRtrAdvert.Events { - // set the address of the advertising node - // we know Route.Gateway is the address of advertNode - // NOTE: this is true only when advertNode had not been registered - // as our peer when we received the advert from it - if advertNode.address == "" { - advertNode.address = event.Route.Gateway - if ok := n.node.UpdatePeer(advertNode); !ok { - log.Debugf("Network failed to update peer: %s", advertNode.id) - continue - } - } - // if advertising node id is not the same as Route.Router // we know the advertising node is not the origin of the route - if advertNode.id != event.Route.Router { + if pbRtrAdvert.Id != event.Route.Router { // if the origin router is not the advertising node peer // we can't rule out potential routing loops so we bail here - if peer := advertNode.GetPeer(event.Route.Router); peer == nil { + if !advertNode.HasPeer(event.Route.Router) { + log.Debugf("Network skipping advert message from peer: %s", pbRtrAdvert.Id) continue } } @@ -676,14 +665,13 @@ func (n *network) advertise(client transport.Client, advertChan <-chan *router.A // Connect connects the network func (n *network) Connect() error { - n.RLock() + n.Lock() // return if already connected if n.connected { - n.RUnlock() + n.Unlock() return nil } - n.Lock() // try to resolve network nodes nodes, err := n.resolveNodes() if err != nil { @@ -831,8 +819,6 @@ func (n *network) Close() error { // unlock the lock otherwise we'll deadlock sending the close n.Unlock() - // send close message only if we managed to connect to NetworkChannel - log.Debugf("Sending close message from: %s", n.options.Id) msg := &pbNet.Close{ Node: &pbNet.Node{ Id: n.options.Id, diff --git a/network/node.go b/network/node.go index cbd19d10..b9c362bb 100644 --- a/network/node.go +++ b/network/node.go @@ -43,7 +43,7 @@ func (n *node) Network() Network { return n.network } -// AddPeer adds a new peer to node +// AddPeer adds a new peer to node topology // It returns false if the peer already exists func (n *node) AddPeer(peer *node) bool { n.Lock() @@ -57,33 +57,6 @@ func (n *node) AddPeer(peer *node) bool { return false } -// GetPeer returns a peer if it exists -// It returns nil if the peer was not found -func (n *node) GetPeer(id string) *node { - n.RLock() - defer n.RUnlock() - - p, ok := n.peers[id] - if !ok { - return nil - } - - peer := &node{ - id: p.id, - address: p.address, - peers: make(map[string]*node), - network: p.network, - lastSeen: p.lastSeen, - } - - // TODO: recursively retrieve all of its peers - for id, pop := range p.peers { - peer.peers[id] = pop - } - - return peer -} - // UpdatePeer updates a peer if it exists // It returns false if the peer does not exist func (n *node) UpdatePeer(peer *node) bool { @@ -106,7 +79,17 @@ func (n *node) DeletePeer(id string) { delete(n.peers, id) } -// Refresh updates node timestamp +// HasPeer returns true if node has peer with given id +func (n *node) HasPeer(id string) bool { + n.RLock() + defer n.RUnlock() + + _, ok := n.peers[id] + return ok +} + +// RefreshPeer updates node timestamp +// It returns false if the peer has not been found. func (n *node) RefreshPeer(id string, now time.Time) bool { n.Lock() defer n.Unlock() @@ -123,13 +106,7 @@ func (n *node) RefreshPeer(id string, now time.Time) bool { return true } -// Nodes returns a slice if all nodes in node topology -func (n *node) Nodes() []Node { - // we need to freeze the network graph here - // otherwise we might get inconsisten results - n.RLock() - defer n.RUnlock() - +func (n *node) walk(until func(peer *node) bool) map[string]*node { // track the visited nodes visited := make(map[string]*node) // queue of the nodes to visit @@ -151,11 +128,31 @@ func (n *node) Nodes() []Node { visited[id] = node queue.PushBack(node) } + if until(node) { + return visited + } } // remove the node from the queue queue.Remove(qnode) } + return visited +} + +// Nodes returns a slice if all nodes in node topology +func (n *node) Nodes() []Node { + // we need to freeze the network graph here + // otherwise we might get inconsisten results + n.RLock() + defer n.RUnlock() + + // NOTE: this should never be true + untilNoMorePeers := func(n *node) bool { + return n == nil + } + + visited := n.walk(untilNoMorePeers) + var nodes []Node // collect all the nodes and return them for _, node := range visited { @@ -165,8 +162,34 @@ func (n *node) Nodes() []Node { return nodes } -// topology returns node topology down to given depth -func (n *node) topology(depth uint) *node { +// GetPeerNode returns a peer from node topology i.e. up to MaxDepth +// It returns nil if the peer was not found in the node topology +func (n *node) GetPeerNode(id string) *node { + n.RLock() + defer n.RUnlock() + + // get node topology up to MaxDepth + top := n.Topology(MaxDepth) + + untilFoundPeer := func(n *node) bool { + return n.id == id + } + + visited := top.walk(untilFoundPeer) + + peerNode, ok := visited[id] + if !ok { + return nil + } + + return peerNode +} + +// Topology returns a copy of th node topology down to given depth +func (n *node) Topology(depth uint) *node { + n.RLock() + defer n.RUnlock() + // make a copy of yourself node := &node{ id: n.id, @@ -186,7 +209,7 @@ func (n *node) topology(depth uint) *node { // iterate through our peers and update the node peers for _, peer := range n.peers { - nodePeer := peer.topology(depth) + nodePeer := peer.Topology(depth) if _, ok := node.peers[nodePeer.id]; !ok { node.peers[nodePeer.id] = nodePeer } @@ -195,15 +218,16 @@ func (n *node) topology(depth uint) *node { return node } -// Peers returns node peers +// Peers returns node peers up to MaxDepth func (n *node) Peers() []Node { n.RLock() + defer n.RUnlock() + var peers []Node for _, nodePeer := range n.peers { - peer := nodePeer.topology(MaxDepth) + peer := nodePeer.Topology(MaxDepth) peers = append(peers, peer) } - n.RUnlock() return peers } @@ -236,7 +260,7 @@ func UnpackPeerTopology(pbPeer *pb.Peer, lastSeen time.Time, depth uint) *node { return peerNode } -func peerTopology(peer Node, depth uint) *pb.Peer { +func peerProtoTopology(peer Node, depth uint) *pb.Peer { node := &pb.Node{ Id: peer.Id(), Address: peer.Address(), @@ -257,7 +281,7 @@ func peerTopology(peer Node, depth uint) *pb.Peer { // iterate through peers of peers aka pops for _, pop := range peer.Peers() { - peer := peerTopology(pop, depth) + peer := peerProtoTopology(pop, depth) pbPeers.Peers = append(pbPeers.Peers, peer) } @@ -278,7 +302,7 @@ func PeersToProto(node Node, depth uint) *pb.Peer { } for _, peer := range node.Peers() { - pbPeer := peerTopology(peer, depth) + pbPeer := peerProtoTopology(peer, depth) pbPeers.Peers = append(pbPeers.Peers, pbPeer) } diff --git a/network/node_test.go b/network/node_test.go index 82959693..10bc17bc 100644 --- a/network/node_test.go +++ b/network/node_test.go @@ -117,6 +117,12 @@ func TestNodes(t *testing.T) { t.Errorf("Expected to find %s node", node.Id()) } } + + // this is a leaf node + id := "peer11" + if nodePeer := node.GetPeerNode(id); nodePeer == nil { + t.Errorf("Expected to find %s node", id) + } } func collectPeerIds(peer Node, ids map[string]bool) map[string]bool { diff --git a/router/default.go b/router/default.go index cfc30548..0006df29 100644 --- a/router/default.go +++ b/router/default.go @@ -337,6 +337,7 @@ func (r *router) advertiseTable() error { // advertise all routes as Update events to subscribers if len(events) > 0 { + log.Debugf("Network router flushing table with %d events: %s", len(events), r.options.Id) r.advertWg.Add(1) go r.publishAdvert(RouteUpdate, events) } @@ -668,11 +669,13 @@ func (r *router) Process(a *Advert) error { for _, event := range events { // skip if the router is the origin of this route if event.Route.Router == r.options.Id { + log.Debugf("Network router skipping processing its own route: %s", r.options.Id) continue } // create a copy of the route route := event.Route action := event.Type + log.Debugf("Network router processing route action %s: %s", action, r.options.Id) 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/router/table.go b/router/table.go index c61b560c..1db4c265 100644 --- a/router/table.go +++ b/router/table.go @@ -110,8 +110,12 @@ func (t *table) Update(r Route) error { if _, ok := t.routes[service][sum]; !ok { t.routes[service][sum] = r go t.sendEvent(&Event{Type: Update, Timestamp: time.Now(), Route: r}) + return nil } + t.routes[service][sum] = r + go t.sendEvent(&Event{Type: Update, Timestamp: time.Now(), Route: r}) + return nil } From b23ee588654a3e4b47ba3e4be4b2edc65dc3dba9 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 13 Sep 2019 11:55:53 -0700 Subject: [PATCH 20/20] Update default.go --- network/default.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network/default.go b/network/default.go index c981f1d4..605fa017 100644 --- a/network/default.go +++ b/network/default.go @@ -554,7 +554,7 @@ func (n *network) processCtrlChan(client transport.Client, listener tunnel.Liste if pbRtrAdvert.Id != event.Route.Router { // if the origin router is not the advertising node peer // we can't rule out potential routing loops so we bail here - if !advertNode.HasPeer(event.Route.Router) { + if peer := advertNode.GetPeerNode(event.Route.Router); peer == nil { log.Debugf("Network skipping advert message from peer: %s", pbRtrAdvert.Id) continue }