move implementations to external repos (#17)
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
1854
network/mucp/mucp.go
1854
network/mucp/mucp.go
File diff suppressed because it is too large
Load Diff
@@ -1,529 +0,0 @@
|
||||
package mucp
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/unistack-org/micro/v3/network"
|
||||
pb "github.com/unistack-org/micro/v3/network/mucp/proto"
|
||||
)
|
||||
|
||||
// nodeError tracks node errors
|
||||
type nodeError struct {
|
||||
sync.RWMutex
|
||||
count int
|
||||
msg error
|
||||
}
|
||||
|
||||
// Increment increments node error count
|
||||
func (e *nodeError) Update(err error) {
|
||||
e.Lock()
|
||||
defer e.Unlock()
|
||||
|
||||
e.count++
|
||||
e.msg = err
|
||||
}
|
||||
|
||||
// Count returns node error count
|
||||
func (e *nodeError) Count() int {
|
||||
e.RLock()
|
||||
defer e.RUnlock()
|
||||
|
||||
return e.count
|
||||
}
|
||||
|
||||
func (e *nodeError) Msg() string {
|
||||
e.RLock()
|
||||
defer e.RUnlock()
|
||||
|
||||
if e.msg != nil {
|
||||
return e.msg.Error()
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// status returns node status
|
||||
type status struct {
|
||||
sync.RWMutex
|
||||
err *nodeError
|
||||
}
|
||||
|
||||
// newStatus creates
|
||||
func newStatus() *status {
|
||||
return &status{
|
||||
err: new(nodeError),
|
||||
}
|
||||
}
|
||||
|
||||
func newPeerStatus(peer *pb.Peer) *status {
|
||||
status := &status{
|
||||
err: new(nodeError),
|
||||
}
|
||||
|
||||
// if Node.Status is nil, return empty status
|
||||
if peer.Node.Status == nil {
|
||||
return status
|
||||
}
|
||||
|
||||
// if peer.Node.Status.Error is NOT nil, update status fields
|
||||
if err := peer.Node.Status.GetError(); err != nil {
|
||||
status.err.count = int(peer.Node.Status.Error.Count)
|
||||
status.err.msg = errors.New(peer.Node.Status.Error.Msg)
|
||||
}
|
||||
|
||||
return status
|
||||
}
|
||||
|
||||
func (s *status) Error() network.Error {
|
||||
s.RLock()
|
||||
defer s.RUnlock()
|
||||
|
||||
return &nodeError{
|
||||
count: s.err.count,
|
||||
msg: s.err.msg,
|
||||
}
|
||||
}
|
||||
|
||||
// node is network node
|
||||
type node struct {
|
||||
sync.RWMutex
|
||||
// id is node id
|
||||
id string
|
||||
// address is node address
|
||||
address string
|
||||
// link on which we communicate with the peer
|
||||
link string
|
||||
// peers are nodes with direct link to this node
|
||||
peers map[string]*node
|
||||
// network returns the node network
|
||||
network network.Network
|
||||
// lastSeen keeps track of node lifetime and updates
|
||||
lastSeen time.Time
|
||||
// lastSync keeps track of node last sync request
|
||||
lastSync time.Time
|
||||
// err tracks node status
|
||||
status *status
|
||||
}
|
||||
|
||||
// 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.Network {
|
||||
return n.network
|
||||
}
|
||||
|
||||
// Status returns node status
|
||||
func (n *node) Status() network.Status {
|
||||
n.RLock()
|
||||
defer n.RUnlock()
|
||||
|
||||
return &status{
|
||||
err: &nodeError{
|
||||
count: n.status.err.count,
|
||||
msg: n.status.err.msg,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// walk walks the node graph until some condition is met
|
||||
func (n *node) walk(until func(peer *node) bool, action func(parent, peer *node)) map[string]*node {
|
||||
// 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
|
||||
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()
|
||||
if until(qnode.Value.(*node)) {
|
||||
return visited
|
||||
}
|
||||
// iterate through all of the node peers
|
||||
// mark the visited nodes; enqueue the non-visited
|
||||
for id, peer := range qnode.Value.(*node).peers {
|
||||
action(qnode.Value.(*node), peer)
|
||||
if _, ok := visited[id]; !ok {
|
||||
visited[id] = peer
|
||||
queue.PushBack(peer)
|
||||
}
|
||||
}
|
||||
// remove the node from the queue
|
||||
queue.Remove(qnode)
|
||||
}
|
||||
|
||||
return visited
|
||||
}
|
||||
|
||||
// AddPeer adds a new peer to node topology
|
||||
// It returns false if the peer already exists
|
||||
func (n *node) AddPeer(peer *node) error {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
// get node topology: we need to check if the peer
|
||||
// we are trying to add is already in our graph
|
||||
top := n.getTopology(MaxDepth)
|
||||
|
||||
untilFoundPeer := func(n *node) bool {
|
||||
return n.id == peer.id
|
||||
}
|
||||
|
||||
justWalk := func(paent, node *node) {}
|
||||
|
||||
visited := top.walk(untilFoundPeer, justWalk)
|
||||
|
||||
peerNode, inTop := visited[peer.id]
|
||||
|
||||
if _, ok := n.peers[peer.id]; !ok {
|
||||
if inTop {
|
||||
// just create a new edge to the existing peer
|
||||
// but make sure you update the peer link
|
||||
peerNode.link = peer.link
|
||||
n.peers[peer.id] = peerNode
|
||||
return nil
|
||||
}
|
||||
n.peers[peer.id] = peer
|
||||
return nil
|
||||
}
|
||||
|
||||
return ErrPeerExists
|
||||
}
|
||||
|
||||
// DeletePeer deletes a peer from node peers
|
||||
// It returns true if the peer has been deleted
|
||||
func (n *node) DeletePeer(id string) bool {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
delete(n.peers, id)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// UpdatePeer updates a peer if it already exists
|
||||
// It returns error if the peer does not exist
|
||||
func (n *node) UpdatePeer(peer *node) error {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
if _, ok := n.peers[peer.id]; ok {
|
||||
n.peers[peer.id] = peer
|
||||
return nil
|
||||
}
|
||||
|
||||
return ErrPeerNotFound
|
||||
}
|
||||
|
||||
// RefreshPeer updates node last seen timestamp
|
||||
// It returns false if the peer has not been found.
|
||||
func (n *node) RefreshPeer(id, link string, now time.Time) error {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
peer, ok := n.peers[id]
|
||||
if !ok {
|
||||
return ErrPeerNotFound
|
||||
}
|
||||
|
||||
// set peer link
|
||||
peer.link = link
|
||||
// set last seen
|
||||
peer.lastSeen = now
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RefreshSync refreshes nodes sync time
|
||||
func (n *node) RefreshSync(now time.Time) error {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
n.lastSync = now
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Nodes returns a slice of all nodes in the whole node topology
|
||||
func (n *node) Nodes() []network.Node {
|
||||
// we need to freeze the network graph here
|
||||
// otherwise we might get inconsistent results
|
||||
n.RLock()
|
||||
defer n.RUnlock()
|
||||
|
||||
// NOTE: this should never be true
|
||||
untilNoMorePeers := func(node *node) bool {
|
||||
return node == nil
|
||||
}
|
||||
justWalk := func(parent, node *node) {}
|
||||
|
||||
visited := n.walk(untilNoMorePeers, justWalk)
|
||||
|
||||
nodes := make([]network.Node, 0, len(visited))
|
||||
// collect all the nodes and return them
|
||||
for _, node := range visited {
|
||||
nodes = append(nodes, node)
|
||||
}
|
||||
|
||||
return nodes
|
||||
}
|
||||
|
||||
// GetPeerNode returns a node from node MaxDepth topology
|
||||
// It returns nil if the peer was not found
|
||||
func (n *node) GetPeerNode(id string) *node {
|
||||
// get node topology up to MaxDepth
|
||||
top := n.Topology(MaxDepth)
|
||||
|
||||
untilFoundPeer := func(n *node) bool {
|
||||
return n.id == id
|
||||
}
|
||||
justWalk := func(paent, node *node) {}
|
||||
|
||||
visited := top.walk(untilFoundPeer, justWalk)
|
||||
|
||||
peerNode, ok := visited[id]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return peerNode
|
||||
}
|
||||
|
||||
// DeletePeerNode removes peer node from node topology
|
||||
func (n *node) DeletePeerNode(id string) error {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
untilNoMorePeers := func(node *node) bool {
|
||||
return node == nil
|
||||
}
|
||||
|
||||
deleted := make(map[string]*node)
|
||||
deletePeer := func(parent, node *node) {
|
||||
if node.id != n.id && node.id == id {
|
||||
delete(parent.peers, node.id)
|
||||
deleted[node.id] = node
|
||||
}
|
||||
}
|
||||
|
||||
n.walk(untilNoMorePeers, deletePeer)
|
||||
|
||||
if _, ok := deleted[id]; !ok {
|
||||
return ErrPeerNotFound
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PrunePeer prunes the peers with the given id
|
||||
func (n *node) PrunePeer(id string) {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
untilNoMorePeers := func(node *node) bool {
|
||||
return node == nil
|
||||
}
|
||||
|
||||
prunePeer := func(parent, node *node) {
|
||||
if node.id != n.id && node.id == id {
|
||||
delete(parent.peers, node.id)
|
||||
}
|
||||
}
|
||||
|
||||
n.walk(untilNoMorePeers, prunePeer)
|
||||
}
|
||||
|
||||
// PruneStalePeerNodes prunes the peers that have not been seen for longer than pruneTime
|
||||
// It returns a map of the the nodes that got pruned
|
||||
func (n *node) PruneStalePeers(pruneTime time.Duration) map[string]*node {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
untilNoMorePeers := func(node *node) bool {
|
||||
return node == nil
|
||||
}
|
||||
|
||||
pruned := make(map[string]*node)
|
||||
pruneStalePeer := func(parent, node *node) {
|
||||
if node.id != n.id && time.Since(node.lastSeen) > PruneTime {
|
||||
delete(parent.peers, node.id)
|
||||
pruned[node.id] = node
|
||||
}
|
||||
}
|
||||
|
||||
n.walk(untilNoMorePeers, pruneStalePeer)
|
||||
|
||||
return pruned
|
||||
}
|
||||
|
||||
// getTopology traverses node graph and builds node topology
|
||||
// NOTE: this function is not thread safe
|
||||
func (n *node) getTopology(depth uint) *node {
|
||||
// make a copy of yourself
|
||||
node := &node{
|
||||
id: n.id,
|
||||
address: n.address,
|
||||
peers: make(map[string]*node),
|
||||
network: n.network,
|
||||
status: n.status,
|
||||
lastSeen: n.lastSeen,
|
||||
}
|
||||
|
||||
// return if we reach requested depth or we have no more peers
|
||||
if depth == 0 || len(n.peers) == 0 {
|
||||
return node
|
||||
}
|
||||
|
||||
// decrement the depth
|
||||
depth--
|
||||
|
||||
// iterate through our peers and update the node peers
|
||||
for _, peer := range n.peers {
|
||||
nodePeer := peer.getTopology(depth)
|
||||
if _, ok := node.peers[nodePeer.id]; !ok {
|
||||
node.peers[nodePeer.id] = nodePeer
|
||||
}
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
// Topology returns a copy of the node topology down to given depth
|
||||
// NOTE: the returned node is a node graph - not a single node
|
||||
func (n *node) Topology(depth uint) *node {
|
||||
n.RLock()
|
||||
defer n.RUnlock()
|
||||
|
||||
return n.getTopology(depth)
|
||||
}
|
||||
|
||||
// Peers returns node peers up to MaxDepth
|
||||
func (n *node) Peers() []network.Node {
|
||||
n.RLock()
|
||||
defer n.RUnlock()
|
||||
|
||||
peers := make([]network.Node, 0, len(n.peers))
|
||||
for _, nodePeer := range n.peers {
|
||||
peer := nodePeer.getTopology(MaxDepth)
|
||||
peers = append(peers, peer)
|
||||
}
|
||||
|
||||
return peers
|
||||
}
|
||||
|
||||
// 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),
|
||||
status: newPeerStatus(pbPeer),
|
||||
lastSeen: lastSeen,
|
||||
}
|
||||
|
||||
// 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--
|
||||
|
||||
peers := make(map[string]*node)
|
||||
for _, pbPeer := range pbPeer.Peers {
|
||||
peer := UnpackPeerTopology(pbPeer, lastSeen, depth)
|
||||
peers[pbPeer.Node.Id] = peer
|
||||
}
|
||||
|
||||
peerNode.peers = peers
|
||||
|
||||
return peerNode
|
||||
}
|
||||
|
||||
func peerProtoTopology(peer network.Node, depth uint) *pb.Peer {
|
||||
node := &pb.Node{
|
||||
Id: peer.Id(),
|
||||
Address: peer.Address(),
|
||||
Status: &pb.Status{
|
||||
Error: &pb.Error{
|
||||
Count: uint32(peer.Status().Error().Count()),
|
||||
Msg: peer.Status().Error().Msg(),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// set the network name if network is not nil
|
||||
if peer.Network() != nil {
|
||||
node.Network = peer.Network().Name()
|
||||
}
|
||||
|
||||
pbPeers := &pb.Peer{
|
||||
Node: node,
|
||||
Peers: make([]*pb.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 := peerProtoTopology(pop, depth)
|
||||
pbPeers.Peers = append(pbPeers.Peers, peer)
|
||||
}
|
||||
|
||||
return pbPeers
|
||||
}
|
||||
|
||||
// PeersToProto returns node peers graph encoded into protobuf
|
||||
func PeersToProto(node network.Node, depth uint) *pb.Peer {
|
||||
// network node aka root node
|
||||
pbNode := &pb.Node{
|
||||
Id: node.Id(),
|
||||
Address: node.Address(),
|
||||
Status: &pb.Status{
|
||||
Error: &pb.Error{
|
||||
Count: uint32(node.Status().Error().Count()),
|
||||
Msg: node.Status().Error().Msg(),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// set the network name if network is not nil
|
||||
if node.Network() != nil {
|
||||
pbNode.Network = node.Network().Name()
|
||||
}
|
||||
|
||||
// we will build proto topology into this
|
||||
pbPeers := &pb.Peer{
|
||||
Node: pbNode,
|
||||
Peers: make([]*pb.Peer, 0),
|
||||
}
|
||||
|
||||
for _, peer := range node.Peers() {
|
||||
pbPeer := peerProtoTopology(peer, depth)
|
||||
pbPeers.Peers = append(pbPeers.Peers, pbPeer)
|
||||
}
|
||||
|
||||
return pbPeers
|
||||
}
|
||||
@@ -1,368 +0,0 @@
|
||||
package mucp
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/unistack-org/micro/v3/network"
|
||||
pb "github.com/unistack-org/micro/v3/network/mucp/proto"
|
||||
)
|
||||
|
||||
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(network.Name(testNodeNetName)),
|
||||
status: newStatus(),
|
||||
}
|
||||
|
||||
// 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,
|
||||
status: newStatus(),
|
||||
}
|
||||
}
|
||||
|
||||
// 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,
|
||||
status: newStatus(),
|
||||
}
|
||||
}
|
||||
|
||||
// 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(network.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())
|
||||
}
|
||||
}
|
||||
|
||||
// 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 network.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{
|
||||
id: testNodeId,
|
||||
address: testNodeAddress,
|
||||
peers: make(map[string]*node),
|
||||
network: NewNetwork(network.Name(testNodeNetName)),
|
||||
}
|
||||
// get node peers
|
||||
peers := single.Peers()
|
||||
// there should be no peers
|
||||
peerCount := 0
|
||||
|
||||
if len(peers) != peerCount {
|
||||
t.Errorf("Expected to find %d nodes, found: %d", peerCount, len(peers))
|
||||
}
|
||||
|
||||
// complicated node graph
|
||||
node := testSetup()
|
||||
// list of ids of nodes of MaxDepth
|
||||
peerIds := make(map[string]bool)
|
||||
// add peer Ids
|
||||
for _, id := range testNodePeerIds {
|
||||
peerIds[id] = true
|
||||
}
|
||||
// add peers of peers to peerIds
|
||||
for _, id := range testPeerOfPeerIds {
|
||||
peerIds[id] = true
|
||||
}
|
||||
// get node peers
|
||||
peers = node.Peers()
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeletePeerNode(t *testing.T) {
|
||||
// complicated node graph
|
||||
node := testSetup()
|
||||
|
||||
nodeCount := len(node.Nodes())
|
||||
|
||||
// should not find non-existent peer node
|
||||
if err := node.DeletePeerNode("foobar"); err != ErrPeerNotFound {
|
||||
t.Errorf("Expected: %v, got: %v", ErrPeerNotFound, err)
|
||||
}
|
||||
|
||||
// lets pick one of the peer1 peers
|
||||
if err := node.DeletePeerNode(testPeerOfPeerIds[0]); err != nil {
|
||||
t.Errorf("Error deleting peer node: %v", err)
|
||||
}
|
||||
|
||||
nodeDelCount := len(node.Nodes())
|
||||
|
||||
if nodeDelCount != nodeCount-1 {
|
||||
t.Errorf("Expected node count: %d, got: %d", nodeCount-1, nodeDelCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrunePeer(t *testing.T) {
|
||||
// complicated node graph
|
||||
node := testSetup()
|
||||
|
||||
before := node.Nodes()
|
||||
|
||||
node.PrunePeer("peer3")
|
||||
|
||||
now := node.Nodes()
|
||||
|
||||
if len(now) != len(before)-1 {
|
||||
t.Errorf("Expected pruned node count: %d, got: %d", len(before)-1, len(now))
|
||||
}
|
||||
}
|
||||
|
||||
func TestPruneStalePeers(t *testing.T) {
|
||||
// complicated node graph
|
||||
node := testSetup()
|
||||
nodes := node.Nodes()
|
||||
// this will delete all nodes besides the root node
|
||||
pruneTime := 10 * time.Millisecond
|
||||
time.Sleep(pruneTime)
|
||||
|
||||
// should delete all nodes besides (root) node
|
||||
pruned := node.PruneStalePeers(pruneTime)
|
||||
|
||||
if len(pruned) != len(nodes)-1 {
|
||||
t.Errorf("Expected pruned node count: %d, got: %d", len(nodes)-1, len(pruned))
|
||||
}
|
||||
|
||||
// complicated node graph
|
||||
node = testSetup()
|
||||
nodes = node.Nodes()
|
||||
|
||||
// set prune time to 100ms and wait for half of it
|
||||
pruneTime = 100 * time.Millisecond
|
||||
time.Sleep(pruneTime)
|
||||
|
||||
// update the time of peer1
|
||||
node.peers["peer1"].lastSeen = time.Now()
|
||||
|
||||
// should prune all but the root nodes and peer1
|
||||
pruned = node.PruneStalePeers(pruneTime)
|
||||
|
||||
if len(pruned) != len(nodes)-2 {
|
||||
t.Errorf("Expected pruned node count: %d, got: %d", len(nodes)-2, len(pruned))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnpackPeerTopology(t *testing.T) {
|
||||
pbPeer := &pb.Peer{
|
||||
Node: &pb.Node{
|
||||
Id: "newPeer",
|
||||
Address: "newPeerAddress",
|
||||
Status: &pb.Status{
|
||||
Error: &pb.Error{},
|
||||
},
|
||||
},
|
||||
Peers: make([]*pb.Peer, 0),
|
||||
}
|
||||
// it should add pbPeer to the single node peers
|
||||
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)
|
||||
}
|
||||
|
||||
node := testSetup()
|
||||
// build a simple topology to update node peer1
|
||||
peer1 := node.peers["peer1"]
|
||||
pbPeer1Node := &pb.Node{
|
||||
Id: peer1.id,
|
||||
Address: peer1.address,
|
||||
Status: &pb.Status{
|
||||
Error: &pb.Error{},
|
||||
},
|
||||
}
|
||||
|
||||
pbPeer111 := &pb.Peer{
|
||||
Node: &pb.Node{
|
||||
Id: "peer111",
|
||||
Address: "peer111Address",
|
||||
Status: &pb.Status{
|
||||
Error: &pb.Error{},
|
||||
},
|
||||
},
|
||||
Peers: make([]*pb.Peer, 0),
|
||||
}
|
||||
|
||||
pbPeer121 := &pb.Peer{
|
||||
Node: &pb.Node{
|
||||
Id: "peer121",
|
||||
Address: "peer121Address",
|
||||
Status: &pb.Status{
|
||||
Error: &pb.Error{},
|
||||
},
|
||||
},
|
||||
Peers: make([]*pb.Peer, 0),
|
||||
}
|
||||
// topology to update
|
||||
pbPeer1 := &pb.Peer{
|
||||
Node: pbPeer1Node,
|
||||
Peers: []*pb.Peer{pbPeer111, pbPeer121},
|
||||
}
|
||||
// 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 := peer.peers[id]; !ok {
|
||||
t.Errorf("Expected %s to be a peer of %s", id, "peer1")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPeersToProto(t *testing.T) {
|
||||
// single node
|
||||
single := &node{
|
||||
id: testNodeId,
|
||||
address: testNodeAddress,
|
||||
peers: make(map[string]*node),
|
||||
network: NewNetwork(network.Name(testNodeNetName)),
|
||||
status: newStatus(),
|
||||
}
|
||||
topCount := 0
|
||||
|
||||
protoPeers := PeersToProto(single, 0)
|
||||
|
||||
if len(protoPeers.Peers) != topCount {
|
||||
t.Errorf("Expected to find %d nodes, found: %d", topCount, len(protoPeers.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
|
||||
protoPeers = PeersToProto(node, 1)
|
||||
|
||||
if len(protoPeers.Peers) != topCount {
|
||||
t.Errorf("Expected to find %d nodes, found: %d", topCount, len(protoPeers.Peers))
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,21 +0,0 @@
|
||||
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
||||
// source: network/mucp/proto/network.proto
|
||||
|
||||
package go_micro_network_mucp
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
@@ -1,115 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package go.micro.network.mucp;
|
||||
|
||||
// AdvertType defines the type of advert
|
||||
enum AdvertType {
|
||||
AdvertAnnounce = 0;
|
||||
AdvertUpdate = 1;
|
||||
}
|
||||
|
||||
// Advert is router advertsement streamed by Watch
|
||||
message Advert {
|
||||
// id of the advertising router
|
||||
string id = 1;
|
||||
// type of advertisement
|
||||
AdvertType type = 2;
|
||||
// unix timestamp of the advertisement
|
||||
int64 timestamp = 3;
|
||||
// TTL of the Advert
|
||||
int64 ttl = 4;
|
||||
// events is a list of advertised events
|
||||
repeated Event events = 5;
|
||||
}
|
||||
|
||||
// EventType defines the type of event
|
||||
enum EventType {
|
||||
Create = 0;
|
||||
Delete = 1;
|
||||
Update = 2;
|
||||
}
|
||||
|
||||
// Event is routing table event
|
||||
message Event {
|
||||
// the unique event id
|
||||
string id = 1;
|
||||
// type of event
|
||||
EventType type = 2;
|
||||
// unix timestamp of event
|
||||
int64 timestamp = 3;
|
||||
// service route
|
||||
Route route = 4;
|
||||
}
|
||||
|
||||
// Route is a service route
|
||||
message Route {
|
||||
// service for the route
|
||||
string service = 1;
|
||||
// the address that advertise this route
|
||||
string address = 2;
|
||||
// gateway as the next hop
|
||||
string gateway = 3;
|
||||
// the network for this destination
|
||||
string network = 4;
|
||||
// router if the router id
|
||||
string router = 5;
|
||||
// the network link
|
||||
string link = 6;
|
||||
// the metric / score of this route
|
||||
int64 metric = 7;
|
||||
// metadata for the route
|
||||
map<string,string> metadata = 8;
|
||||
}
|
||||
|
||||
// Error tracks network errors
|
||||
message Error {
|
||||
uint32 count = 1;
|
||||
string msg = 2;
|
||||
}
|
||||
|
||||
// Status is node status
|
||||
message Status {
|
||||
Error error = 1;
|
||||
}
|
||||
|
||||
// Node is network node
|
||||
message Node {
|
||||
// node id
|
||||
string id = 1;
|
||||
// node address
|
||||
string address = 2;
|
||||
// the network
|
||||
string network = 3;
|
||||
// associated metadata
|
||||
map<string,string> metadata = 4;
|
||||
// node status
|
||||
Status status = 5;
|
||||
}
|
||||
|
||||
// Connect is sent when the node connects to the network
|
||||
message Connect {
|
||||
// network mode
|
||||
Node node = 1;
|
||||
}
|
||||
|
||||
// Close is sent when the node disconnects from the network
|
||||
message Close {
|
||||
// network node
|
||||
Node node = 1;
|
||||
}
|
||||
|
||||
// Peer is used to advertise node peers
|
||||
message Peer {
|
||||
// network node
|
||||
Node node = 1;
|
||||
// node peers
|
||||
repeated Peer peers = 2;
|
||||
}
|
||||
|
||||
// Sync is network sync message
|
||||
message Sync {
|
||||
// peer origin
|
||||
Peer peer = 1;
|
||||
// node routes
|
||||
repeated Route routes = 2;
|
||||
}
|
||||
@@ -3,11 +3,8 @@ package network
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
"github.com/unistack-org/micro/v3/proxy"
|
||||
"github.com/unistack-org/micro/v3/proxy/mucp"
|
||||
"github.com/unistack-org/micro/v3/router"
|
||||
regRouter "github.com/unistack-org/micro/v3/router/registry"
|
||||
"github.com/unistack-org/micro/v3/tunnel"
|
||||
tmucp "github.com/unistack-org/micro/v3/tunnel/mucp"
|
||||
)
|
||||
|
||||
type Option func(*Options)
|
||||
@@ -94,8 +91,5 @@ func DefaultOptions() Options {
|
||||
Id: uuid.New().String(),
|
||||
Name: "go.micro",
|
||||
Address: ":0",
|
||||
Tunnel: tmucp.NewTunnel(),
|
||||
Router: regRouter.NewRouter(),
|
||||
Proxy: mucp.NewProxy(),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user