v3 refactor (#1868)

* Move to v3

Co-authored-by: Ben Toogood <bentoogood@gmail.com>
This commit is contained in:
Asim Aslam
2020-07-27 13:22:00 +01:00
committed by GitHub
parent 9dfeb98111
commit 563768b58a
424 changed files with 6383 additions and 22490 deletions

View File

@@ -1,4 +1,4 @@
package network
package mucp
import (
"errors"
@@ -12,25 +12,41 @@ import (
"time"
"github.com/golang/protobuf/proto"
"github.com/micro/go-micro/v2/client"
cmucp "github.com/micro/go-micro/v2/client/mucp"
"github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/network/resolver/dns"
pbNet "github.com/micro/go-micro/v2/network/service/proto"
"github.com/micro/go-micro/v2/proxy"
"github.com/micro/go-micro/v2/router"
pbRtr "github.com/micro/go-micro/v2/router/service/proto"
"github.com/micro/go-micro/v2/server"
smucp "github.com/micro/go-micro/v2/server/mucp"
"github.com/micro/go-micro/v2/transport"
"github.com/micro/go-micro/v2/tunnel"
bun "github.com/micro/go-micro/v2/tunnel/broker"
tun "github.com/micro/go-micro/v2/tunnel/transport"
"github.com/micro/go-micro/v2/util/backoff"
pbUtil "github.com/micro/go-micro/v2/util/proto"
"github.com/micro/go-micro/v3/client"
cmucp "github.com/micro/go-micro/v3/client/mucp"
"github.com/micro/go-micro/v3/logger"
"github.com/micro/go-micro/v3/network"
pb "github.com/micro/go-micro/v3/network/mucp/proto"
"github.com/micro/go-micro/v3/network/resolver/dns"
"github.com/micro/go-micro/v3/proxy"
"github.com/micro/go-micro/v3/router"
"github.com/micro/go-micro/v3/server"
smucp "github.com/micro/go-micro/v3/server/mucp"
"github.com/micro/go-micro/v3/transport"
"github.com/micro/go-micro/v3/tunnel"
bun "github.com/micro/go-micro/v3/tunnel/broker"
tun "github.com/micro/go-micro/v3/tunnel/transport"
"github.com/micro/go-micro/v3/util/backoff"
)
var (
// DefaultName is default network name
DefaultName = "go.micro"
// DefaultAddress is default network address
DefaultAddress = ":0"
// ResolveTime defines time interval to periodically resolve network nodes
ResolveTime = 1 * time.Minute
// AnnounceTime defines time interval to periodically announce node neighbours
AnnounceTime = 1 * time.Second
// KeepAliveTime is the time in which we want to have sent a message to a peer
KeepAliveTime = 30 * time.Second
// SyncTime is the time a network node requests full sync from the network
SyncTime = 1 * time.Minute
// PruneTime defines time interval to periodically check nodes that need to be pruned
// due to their not announcing their presence within this time interval
PruneTime = 90 * time.Second
// MaxDepth defines max depth of peer topology
MaxDepth uint = 3
// NetworkChannel is the name of the tunnel channel for passing network messages
NetworkChannel = "network"
// ControlChannel is the name of the tunnel channel for passing control message
@@ -41,9 +57,10 @@ var (
MaxConnections = 3
// MaxPeerErrors is the max number of peer errors before we remove it from network graph
MaxPeerErrors = 3
)
var (
// ErrPeerExists is returned when adding a peer which already exists
ErrPeerExists = errors.New("peer already exists")
// ErrPeerNotFound is returned when a peer could not be found in node topology
ErrPeerNotFound = errors.New("peer not found")
// ErrClientNotFound is returned when client for tunnel channel could not be found
ErrClientNotFound = errors.New("client not found")
// ErrPeerLinkNotFound is returned when peer link could not be found in tunnel Links
@@ -53,11 +70,11 @@ var (
)
// network implements Network interface
type network struct {
type mucpNetwork struct {
// node is network node
*node
// options configure the network
options Options
options network.Options
// rtr is network router
router router.Router
// proxy is network proxy
@@ -91,10 +108,10 @@ type message struct {
session tunnel.Session
}
// newNetwork returns a new network node
func newNetwork(opts ...Option) Network {
// NewNetwork returns a new network node
func NewNetwork(opts ...network.Option) network.Network {
// create default options
options := DefaultOptions()
options := network.DefaultOptions()
// initialize network options
for _, o := range opts {
o(&options)
@@ -155,7 +172,7 @@ func newNetwork(opts ...Option) Network {
client.Router(options.Router),
)
network := &network{
network := &mucpNetwork{
node: &node{
id: options.Id,
address: peerAddress,
@@ -178,7 +195,7 @@ func newNetwork(opts ...Option) Network {
return network
}
func (n *network) Init(opts ...Option) error {
func (n *mucpNetwork) Init(opts ...network.Option) error {
n.Lock()
defer n.Unlock()
@@ -191,7 +208,7 @@ func (n *network) Init(opts ...Option) error {
}
// Options returns network options
func (n *network) Options() Options {
func (n *mucpNetwork) Options() network.Options {
n.RLock()
defer n.RUnlock()
@@ -201,7 +218,7 @@ func (n *network) Options() Options {
}
// Name returns network name
func (n *network) Name() string {
func (n *mucpNetwork) Name() string {
n.RLock()
defer n.RUnlock()
@@ -211,7 +228,7 @@ func (n *network) Name() string {
}
// acceptNetConn accepts connections from NetworkChannel
func (n *network) acceptNetConn(l tunnel.Listener, recv chan *message) {
func (n *mucpNetwork) acceptNetConn(l tunnel.Listener, recv chan *message) {
var i int
for {
// accept a connection
@@ -238,7 +255,7 @@ func (n *network) acceptNetConn(l tunnel.Listener, recv chan *message) {
}
// acceptCtrlConn accepts connections from ControlChannel
func (n *network) acceptCtrlConn(l tunnel.Listener, recv chan *message) {
func (n *mucpNetwork) acceptCtrlConn(l tunnel.Listener, recv chan *message) {
var i int
for {
// accept a connection
@@ -269,7 +286,7 @@ func (n *network) acceptCtrlConn(l tunnel.Listener, recv chan *message) {
}
// maskRoute will mask the route so that we apply the right values
func (n *network) maskRoute(r *pbRtr.Route) {
func (n *mucpNetwork) maskRoute(r *pb.Route) {
hasher := fnv.New64()
// the routes service address
address := r.Address
@@ -297,18 +314,18 @@ func (n *network) maskRoute(r *pbRtr.Route) {
}
// advertise advertises routes to the network
func (n *network) advertise(advertChan <-chan *router.Advert) {
func (n *mucpNetwork) advertise(advertChan <-chan *router.Advert) {
rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
for {
select {
// process local adverts and randomly fire them at other nodes
case advert := <-advertChan:
// create a proto advert
var events []*pbRtr.Event
var events []*pb.Event
for _, event := range advert.Events {
// make a copy of the route
route := &pbRtr.Route{
route := &pb.Route{
Service: event.Route.Service,
Address: event.Route.Address,
Gateway: event.Route.Gateway,
@@ -321,8 +338,8 @@ func (n *network) advertise(advertChan <-chan *router.Advert) {
// override the various values
n.maskRoute(route)
e := &pbRtr.Event{
Type: pbRtr.EventType(event.Type),
e := &pb.Event{
Type: pb.EventType(event.Type),
Timestamp: event.Timestamp.UnixNano(),
Route: route,
}
@@ -330,9 +347,9 @@ func (n *network) advertise(advertChan <-chan *router.Advert) {
events = append(events, e)
}
msg := &pbRtr.Advert{
msg := &pb.Advert{
Id: advert.Id,
Type: pbRtr.AdvertType(advert.Type),
Type: pb.AdvertType(advert.Type),
Timestamp: advert.Timestamp.UnixNano(),
Events: events,
}
@@ -367,7 +384,7 @@ func (n *network) advertise(advertChan <-chan *router.Advert) {
}
// initNodes initializes tunnel with a list of resolved nodes
func (n *network) initNodes(startup bool) {
func (n *mucpNetwork) initNodes(startup bool) {
nodes, err := n.resolveNodes()
// NOTE: this condition never fires
// as resolveNodes() never returns error
@@ -404,7 +421,7 @@ func (n *network) initNodes(startup bool) {
}
// resolveNodes resolves network nodes to addresses
func (n *network) resolveNodes() ([]string, error) {
func (n *mucpNetwork) resolveNodes() ([]string, error) {
// resolve the network address to network nodes
records, err := n.options.Resolver.Resolve(n.options.Name)
if err != nil {
@@ -469,7 +486,7 @@ func (n *network) resolveNodes() ([]string, error) {
}
// handleNetConn handles network announcement messages
func (n *network) handleNetConn(s tunnel.Session, msg chan *message) {
func (n *mucpNetwork) handleNetConn(s tunnel.Session, msg chan *message) {
for {
m := new(transport.Message)
if err := s.Recv(m); err != nil {
@@ -504,7 +521,7 @@ func (n *network) handleNetConn(s tunnel.Session, msg chan *message) {
}
// handleCtrlConn handles ControlChannel connections
func (n *network) handleCtrlConn(s tunnel.Session, msg chan *message) {
func (n *mucpNetwork) handleCtrlConn(s tunnel.Session, msg chan *message) {
for {
m := new(transport.Message)
if err := s.Recv(m); err != nil {
@@ -544,7 +561,7 @@ func (n *network) handleCtrlConn(s tunnel.Session, msg chan *message) {
// - Routes with ID of adjacent nodes have hop count 10
// - Routes by peers of the advertiser have hop count 100
// - Routes beyond node neighbourhood have hop count 1000
func (n *network) getHopCount(rtr string) int {
func (n *mucpNetwork) getHopCount(rtr string) int {
// make sure node.peers are not modified
n.node.RLock()
defer n.node.RUnlock()
@@ -573,7 +590,7 @@ func (n *network) getHopCount(rtr string) int {
// getRouteMetric calculates router metric and returns it
// Route metric is calculated based on link status and route hopd count
func (n *network) getRouteMetric(router string, gateway string, link string) int64 {
func (n *mucpNetwork) getRouteMetric(router string, gateway string, link string) int64 {
// set the route metric
n.RLock()
defer n.RUnlock()
@@ -628,7 +645,7 @@ func (n *network) getRouteMetric(router string, gateway string, link string) int
}
// processCtrlChan processes messages received on ControlChannel
func (n *network) processCtrlChan(listener tunnel.Listener) {
func (n *mucpNetwork) processCtrlChan(listener tunnel.Listener) {
defer listener.Close()
// receive control message queue
@@ -643,9 +660,9 @@ func (n *network) processCtrlChan(listener tunnel.Listener) {
// switch on type of message and take action
switch m.msg.Header["Micro-Method"] {
case "advert":
pbRtrAdvert := &pbRtr.Advert{}
pbAdvert := &pb.Advert{}
if err := proto.Unmarshal(m.msg.Body, pbRtrAdvert); err != nil {
if err := proto.Unmarshal(m.msg.Body, pbAdvert); err != nil {
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Network fail to unmarshal advert message: %v", err)
}
@@ -653,38 +670,38 @@ func (n *network) processCtrlChan(listener tunnel.Listener) {
}
// don't process your own messages
if pbRtrAdvert.Id == n.options.Id {
if pbAdvert.Id == n.options.Id {
continue
}
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Network received advert message from: %s", pbRtrAdvert.Id)
logger.Debugf("Network received advert message from: %s", pbAdvert.Id)
}
// lookup advertising node in our peer topology
advertNode := n.node.GetPeerNode(pbRtrAdvert.Id)
advertNode := n.node.GetPeerNode(pbAdvert.Id)
if advertNode == nil {
// if we can't find the node in our topology (MaxDepth) we skipp prcessing adverts
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Network skipping advert message from unknown peer: %s", pbRtrAdvert.Id)
logger.Debugf("Network skipping advert message from unknown peer: %s", pbAdvert.Id)
}
continue
}
var events []*router.Event
for _, event := range pbRtrAdvert.Events {
for _, event := range pbAdvert.Events {
// for backwards compatibility reasons
if event == nil || event.Route == nil {
continue
}
// we know the advertising node is not the origin of the route
if pbRtrAdvert.Id != event.Route.Router {
if pbAdvert.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.GetPeerNode(event.Route.Router); peer == nil {
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Network skipping advert message from peer: %s", pbRtrAdvert.Id)
logger.Debugf("Network skipping advert message from peer: %s", pbAdvert.Id)
}
continue
}
@@ -719,7 +736,7 @@ func (n *network) processCtrlChan(listener tunnel.Listener) {
// create router event
e := &router.Event{
Type: router.EventType(event.Type),
Timestamp: time.Unix(0, pbRtrAdvert.Timestamp),
Timestamp: time.Unix(0, pbAdvert.Timestamp),
Route: route,
}
events = append(events, e)
@@ -735,10 +752,10 @@ func (n *network) processCtrlChan(listener tunnel.Listener) {
// create an advert and process it
advert := &router.Advert{
Id: pbRtrAdvert.Id,
Type: router.AdvertType(pbRtrAdvert.Type),
Timestamp: time.Unix(0, pbRtrAdvert.Timestamp),
TTL: time.Duration(pbRtrAdvert.Ttl),
Id: pbAdvert.Id,
Type: router.AdvertType(pbAdvert.Type),
Timestamp: time.Unix(0, pbAdvert.Timestamp),
TTL: time.Duration(pbAdvert.Ttl),
Events: events,
}
@@ -758,7 +775,7 @@ func (n *network) processCtrlChan(listener tunnel.Listener) {
}
// processNetChan processes messages received on NetworkChannel
func (n *network) processNetChan(listener tunnel.Listener) {
func (n *mucpNetwork) processNetChan(listener tunnel.Listener) {
defer listener.Close()
// receive network message queue
@@ -776,22 +793,22 @@ func (n *network) processNetChan(listener tunnel.Listener) {
// mark the time the message has been received
now := time.Now()
pbNetConnect := &pbNet.Connect{}
if err := proto.Unmarshal(m.msg.Body, pbNetConnect); err != nil {
pbConnect := &pb.Connect{}
if err := proto.Unmarshal(m.msg.Body, pbConnect); err != nil {
logger.Debugf("Network tunnel [%s] connect unmarshal error: %v", NetworkChannel, err)
continue
}
// don't process your own messages
if pbNetConnect.Node.Id == n.options.Id {
if pbConnect.Node.Id == n.options.Id {
continue
}
logger.Debugf("Network received connect message from: %s", pbNetConnect.Node.Id)
logger.Debugf("Network received connect message from: %s", pbConnect.Node.Id)
peer := &node{
id: pbNetConnect.Node.Id,
address: pbNetConnect.Node.Address,
id: pbConnect.Node.Id,
address: pbConnect.Node.Address,
link: m.msg.Header["Micro-Link"],
peers: make(map[string]*node),
status: newStatus(),
@@ -824,7 +841,7 @@ func (n *network) processNetChan(listener tunnel.Listener) {
// get node peer graph to send back to the connecting node
node := PeersToProto(n.node, MaxDepth)
msg := &pbNet.Sync{
msg := &pb.Sync{
Peer: node,
}
@@ -844,26 +861,26 @@ func (n *network) processNetChan(listener tunnel.Listener) {
case "peer":
// mark the time the message has been received
now := time.Now()
pbNetPeer := &pbNet.Peer{}
pbPeer := &pb.Peer{}
if err := proto.Unmarshal(m.msg.Body, pbNetPeer); err != nil {
if err := proto.Unmarshal(m.msg.Body, pbPeer); err != nil {
logger.Debugf("Network tunnel [%s] peer unmarshal error: %v", NetworkChannel, err)
continue
}
// don't process your own messages
if pbNetPeer.Node.Id == n.options.Id {
if pbPeer.Node.Id == n.options.Id {
continue
}
logger.Debugf("Network received peer message from: %s %s", pbNetPeer.Node.Id, pbNetPeer.Node.Address)
logger.Debugf("Network received peer message from: %s %s", pbPeer.Node.Id, pbPeer.Node.Address)
peer := &node{
id: pbNetPeer.Node.Id,
address: pbNetPeer.Node.Address,
id: pbPeer.Node.Id,
address: pbPeer.Node.Address,
link: m.msg.Header["Micro-Link"],
peers: make(map[string]*node),
status: newPeerStatus(pbNetPeer),
status: newPeerStatus(pbPeer),
lastSeen: now,
}
@@ -881,7 +898,7 @@ func (n *network) processNetChan(listener tunnel.Listener) {
// marshal node graph into protobuf
node := PeersToProto(n.node, MaxDepth)
msg := &pbNet.Sync{
msg := &pb.Sync{
Peer: node,
}
@@ -906,15 +923,15 @@ func (n *network) processNetChan(listener tunnel.Listener) {
continue
}
logger.Tracef("Network peer exists, refreshing: %s", pbNetPeer.Node.Id)
logger.Tracef("Network peer exists, refreshing: %s", pbPeer.Node.Id)
// update lastSeen time for the peer
if err := n.RefreshPeer(peer.id, peer.link, now); err != nil {
logger.Debugf("Network failed refreshing peer %s: %v", pbNetPeer.Node.Id, err)
logger.Debugf("Network failed refreshing peer %s: %v", pbPeer.Node.Id, err)
}
// NOTE: we don't unpack MaxDepth topology
peer = UnpackPeerTopology(pbNetPeer, now, MaxDepth-1)
peer = UnpackPeerTopology(pbPeer, now, MaxDepth-1)
// update the link
peer.link = m.msg.Header["Micro-Link"]
@@ -934,25 +951,25 @@ func (n *network) processNetChan(listener tunnel.Listener) {
// record the timestamp of the message receipt
now := time.Now()
pbNetSync := &pbNet.Sync{}
if err := proto.Unmarshal(m.msg.Body, pbNetSync); err != nil {
pbSync := &pb.Sync{}
if err := proto.Unmarshal(m.msg.Body, pbSync); err != nil {
logger.Debugf("Network tunnel [%s] sync unmarshal error: %v", NetworkChannel, err)
continue
}
// don't process your own messages
if pbNetSync.Peer.Node.Id == n.options.Id {
if pbSync.Peer.Node.Id == n.options.Id {
continue
}
logger.Debugf("Network received sync message from: %s", pbNetSync.Peer.Node.Id)
logger.Debugf("Network received sync message from: %s", pbSync.Peer.Node.Id)
peer := &node{
id: pbNetSync.Peer.Node.Id,
address: pbNetSync.Peer.Node.Address,
id: pbSync.Peer.Node.Id,
address: pbSync.Peer.Node.Address,
link: m.msg.Header["Micro-Link"],
peers: make(map[string]*node),
status: newPeerStatus(pbNetSync.Peer),
status: newPeerStatus(pbSync.Peer),
lastSeen: now,
}
@@ -983,9 +1000,9 @@ func (n *network) processNetChan(listener tunnel.Listener) {
// and send a peer message back to the network to announce our presence
// add all the routes we have received in the sync message
for _, pbRoute := range pbNetSync.Routes {
for _, pbRoute := range pbSync.Routes {
// unmarshal the routes received from remote peer
route := pbUtil.ProtoToRoute(pbRoute)
route := ProtoToRoute(pbRoute)
// continue if we are the originator of the route
if route.Router == n.router.Options().Id {
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
@@ -1079,8 +1096,8 @@ func (n *network) processNetChan(listener tunnel.Listener) {
}
}()
case "close":
pbNetClose := &pbNet.Close{}
if err := proto.Unmarshal(m.msg.Body, pbNetClose); err != nil {
pbClose := &pb.Close{}
if err := proto.Unmarshal(m.msg.Body, pbClose); err != nil {
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Network tunnel [%s] close unmarshal error: %v", NetworkChannel, err)
}
@@ -1088,17 +1105,17 @@ func (n *network) processNetChan(listener tunnel.Listener) {
}
// don't process your own messages
if pbNetClose.Node.Id == n.options.Id {
if pbClose.Node.Id == n.options.Id {
continue
}
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Network received close message from: %s", pbNetClose.Node.Id)
logger.Debugf("Network received close message from: %s", pbClose.Node.Id)
}
peer := &node{
id: pbNetClose.Node.Id,
address: pbNetClose.Node.Address,
id: pbClose.Node.Id,
address: pbClose.Node.Address,
}
if err := n.DeletePeerNode(peer.id); err != nil {
@@ -1118,7 +1135,7 @@ func (n *network) processNetChan(listener tunnel.Listener) {
// delete peer from the peerLinks
n.Lock()
delete(n.peerLinks, pbNetClose.Node.Address)
delete(n.peerLinks, pbClose.Node.Address)
n.Unlock()
}
case <-n.closed:
@@ -1128,7 +1145,7 @@ func (n *network) processNetChan(listener tunnel.Listener) {
}
// pruneRoutes prunes routes return by given query
func (n *network) pruneRoutes(q ...router.QueryOption) error {
func (n *mucpNetwork) pruneRoutes(q ...router.QueryOption) error {
routes, err := n.router.Table().Query(q...)
if err != nil && err != router.ErrRouteNotFound {
return err
@@ -1144,7 +1161,7 @@ func (n *network) pruneRoutes(q ...router.QueryOption) error {
}
// pruneNodeRoutes prunes routes that were either originated by or routable via given node
func (n *network) prunePeerRoutes(peer *node) error {
func (n *mucpNetwork) prunePeerRoutes(peer *node) error {
// lookup all routes originated by router
q := []router.QueryOption{
router.QueryRouter(peer.id),
@@ -1167,7 +1184,7 @@ func (n *network) prunePeerRoutes(peer *node) error {
// manage the process of announcing to peers and prune any peer nodes that have not been
// seen for a period of time. Also removes all the routes either originated by or routable
// by the stale nodes. it also resolves nodes periodically and adds them to the tunnel
func (n *network) manage() {
func (n *mucpNetwork) manage() {
rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
announce := time.NewTicker(AnnounceTime)
defer announce.Stop()
@@ -1360,7 +1377,7 @@ func (n *network) manage() {
// get node peer graph to send back to the connecting node
node := PeersToProto(n.node, MaxDepth)
msg := &pbNet.Sync{
msg := &pb.Sync{
Peer: node,
}
@@ -1390,7 +1407,7 @@ func (n *network) manage() {
// getAdvertProtoRoutes returns a list of routes to advertise to remote peer
// based on the advertisement strategy encoded in protobuf
// It returns error if the routes failed to be retrieved from the routing table
func (n *network) getProtoRoutes() ([]*pbRtr.Route, error) {
func (n *mucpNetwork) getProtoRoutes() ([]*pb.Route, error) {
// get a list of the best routes for each service in our routing table
q := []router.QueryOption{
router.QueryStrategy(n.router.Options().Advertise),
@@ -1402,10 +1419,10 @@ func (n *network) getProtoRoutes() ([]*pbRtr.Route, error) {
}
// encode the routes to protobuf
pbRoutes := make([]*pbRtr.Route, 0, len(routes))
pbRoutes := make([]*pb.Route, 0, len(routes))
for _, route := range routes {
// generate new route proto
pbRoute := pbUtil.RouteToProto(route)
pbRoute := RouteToProto(route)
// mask the route before outbounding
n.maskRoute(pbRoute)
// add to list of routes
@@ -1415,13 +1432,13 @@ func (n *network) getProtoRoutes() ([]*pbRtr.Route, error) {
return pbRoutes, nil
}
func (n *network) sendConnect() {
func (n *mucpNetwork) sendConnect() {
// send connect message to NetworkChannel
// NOTE: in theory we could do this as soon as
// Dial to NetworkChannel succeeds, but instead
// we initialize all other node resources first
msg := &pbNet.Connect{
Node: &pbNet.Node{
msg := &pb.Connect{
Node: &pb.Node{
Id: n.node.id,
Address: n.node.address,
},
@@ -1437,7 +1454,7 @@ func (n *network) sendConnect() {
// sendTo sends a message to a specific node as a one off.
// we need this because when links die, we have no discovery info,
// and sending to an existing multicast link doesn't immediately work
func (n *network) sendTo(method, channel string, peer *node, msg proto.Message) error {
func (n *mucpNetwork) sendTo(method, channel string, peer *node, msg proto.Message) error {
body, err := proto.Marshal(msg)
if err != nil {
return err
@@ -1509,7 +1526,7 @@ func (n *network) sendTo(method, channel string, peer *node, msg proto.Message)
}
// sendMsg sends a message to the tunnel channel
func (n *network) sendMsg(method, channel string, msg proto.Message) error {
func (n *mucpNetwork) sendMsg(method, channel string, msg proto.Message) error {
body, err := proto.Marshal(msg)
if err != nil {
return err
@@ -1537,7 +1554,7 @@ func (n *network) sendMsg(method, channel string, msg proto.Message) error {
}
// updatePeerLinks updates link for a given peer
func (n *network) updatePeerLinks(peer *node) error {
func (n *mucpNetwork) updatePeerLinks(peer *node) error {
n.Lock()
defer n.Unlock()
@@ -1582,7 +1599,7 @@ func (n *network) updatePeerLinks(peer *node) error {
}
// isLoopback checks if a link is a loopback to ourselves
func (n *network) isLoopback(link tunnel.Link) bool {
func (n *mucpNetwork) isLoopback(link tunnel.Link) bool {
// skip loopback
if link.Loopback() {
return true
@@ -1606,7 +1623,7 @@ func (n *network) isLoopback(link tunnel.Link) bool {
// message. We're trying to ensure convergence pretty quickly. So we want
// to hear back. In the case we become completely disconnected we'll
// connect again once a new link is established
func (n *network) connect() {
func (n *mucpNetwork) connect() {
// discovered lets us know what we received a peer message back
var discovered bool
var attempts int
@@ -1671,7 +1688,7 @@ func (n *network) connect() {
}
// Connect connects the network
func (n *network) Connect() error {
func (n *mucpNetwork) Connect() error {
n.Lock()
defer n.Unlock()
@@ -1769,7 +1786,7 @@ func (n *network) Connect() error {
return nil
}
func (n *network) close() error {
func (n *mucpNetwork) close() error {
// stop the server
if err := n.server.Stop(); err != nil {
return err
@@ -1789,7 +1806,7 @@ func (n *network) close() error {
}
// createClients is used to create new clients in the event we lose all the tunnels
func (n *network) createClients() error {
func (n *mucpNetwork) createClients() error {
// dial into ControlChannel to send route adverts
ctrlClient, err := n.tunnel.Dial(ControlChannel, tunnel.DialMode(tunnel.Multicast))
if err != nil {
@@ -1823,7 +1840,7 @@ func (n *network) createClients() error {
}
// Close closes network connection
func (n *network) Close() error {
func (n *mucpNetwork) Close() error {
n.Lock()
if !n.connected {
@@ -1844,8 +1861,8 @@ func (n *network) Close() error {
// unlock the lock otherwise we'll deadlock sending the close
n.Unlock()
msg := &pbNet.Close{
Node: &pbNet.Node{
msg := &pb.Close{
Node: &pb.Node{
Id: n.node.id,
Address: n.node.address,
},
@@ -1863,11 +1880,37 @@ func (n *network) Close() error {
}
// Client returns network client
func (n *network) Client() client.Client {
func (n *mucpNetwork) Client() client.Client {
return n.client
}
// Server returns network server
func (n *network) Server() server.Server {
func (n *mucpNetwork) Server() server.Server {
return n.server
}
// RouteToProto encodes route into protobuf and returns it
func RouteToProto(route router.Route) *pb.Route {
return &pb.Route{
Service: route.Service,
Address: route.Address,
Gateway: route.Gateway,
Network: route.Network,
Router: route.Router,
Link: route.Link,
Metric: int64(route.Metric),
}
}
// ProtoToRoute decodes protobuf route into router route and returns it
func ProtoToRoute(route *pb.Route) router.Route {
return router.Route{
Service: route.Service,
Address: route.Address,
Gateway: route.Gateway,
Network: route.Network,
Router: route.Router,
Link: route.Link,
Metric: route.Metric,
}
}

View File

@@ -1,4 +1,4 @@
package network
package mucp
import (
"container/list"
@@ -6,19 +6,8 @@ import (
"sync"
"time"
pb "github.com/micro/go-micro/v2/network/service/proto"
)
var (
// MaxDepth defines max depth of peer topology
MaxDepth uint = 3
)
var (
// ErrPeerExists is returned when adding a peer which already exists
ErrPeerExists = errors.New("peer already exists")
// ErrPeerNotFound is returned when a peer could not be found in node topology
ErrPeerNotFound = errors.New("peer not found")
"github.com/micro/go-micro/v3/network"
pb "github.com/micro/go-micro/v3/network/mucp/proto"
)
// nodeError tracks node errors
@@ -88,7 +77,7 @@ func newPeerStatus(peer *pb.Peer) *status {
return status
}
func (s *status) Error() Error {
func (s *status) Error() network.Error {
s.RLock()
defer s.RUnlock()
@@ -110,7 +99,7 @@ type node struct {
// peers are nodes with direct link to this node
peers map[string]*node
// network returns the node network
network Network
network network.Network
// lastSeen keeps track of node lifetime and updates
lastSeen time.Time
// lastSync keeps track of node last sync request
@@ -130,12 +119,12 @@ func (n *node) Address() string {
}
// Network returns node network
func (n *node) Network() Network {
func (n *node) Network() network.Network {
return n.network
}
// Status returns node status
func (n *node) Status() Status {
func (n *node) Status() network.Status {
n.RLock()
defer n.RUnlock()
@@ -272,7 +261,7 @@ func (n *node) RefreshSync(now time.Time) error {
}
// Nodes returns a slice of all nodes in the whole node topology
func (n *node) Nodes() []Node {
func (n *node) Nodes() []network.Node {
// we need to freeze the network graph here
// otherwise we might get inconsistent results
n.RLock()
@@ -286,7 +275,7 @@ func (n *node) Nodes() []Node {
visited := n.walk(untilNoMorePeers, justWalk)
nodes := make([]Node, 0, len(visited))
nodes := make([]network.Node, 0, len(visited))
// collect all the nodes and return them
for _, node := range visited {
nodes = append(nodes, node)
@@ -425,11 +414,11 @@ func (n *node) Topology(depth uint) *node {
}
// Peers returns node peers up to MaxDepth
func (n *node) Peers() []Node {
func (n *node) Peers() []network.Node {
n.RLock()
defer n.RUnlock()
peers := make([]Node, 0, len(n.peers))
peers := make([]network.Node, 0, len(n.peers))
for _, nodePeer := range n.peers {
peer := nodePeer.getTopology(MaxDepth)
peers = append(peers, peer)
@@ -467,7 +456,7 @@ func UnpackPeerTopology(pbPeer *pb.Peer, lastSeen time.Time, depth uint) *node {
return peerNode
}
func peerProtoTopology(peer Node, depth uint) *pb.Peer {
func peerProtoTopology(peer network.Node, depth uint) *pb.Peer {
node := &pb.Node{
Id: peer.Id(),
Address: peer.Address(),
@@ -507,7 +496,7 @@ func peerProtoTopology(peer Node, depth uint) *pb.Peer {
}
// PeersToProto returns node peers graph encoded into protobuf
func PeersToProto(node Node, depth uint) *pb.Peer {
func PeersToProto(node network.Node, depth uint) *pb.Peer {
// network node aka root node
pbNode := &pb.Node{
Id: node.Id(),

View File

@@ -1,10 +1,11 @@
package network
package mucp
import (
"testing"
"time"
pb "github.com/micro/go-micro/v2/network/service/proto"
"github.com/micro/go-micro/v3/network"
pb "github.com/micro/go-micro/v3/network/mucp/proto"
)
var (
@@ -20,7 +21,7 @@ func testSetup() *node {
id: testNodeId,
address: testNodeAddress,
peers: make(map[string]*node),
network: newNetwork(Name(testNodeNetName)),
network: NewNetwork(network.Name(testNodeNetName)),
status: newStatus(),
}
@@ -81,7 +82,7 @@ func TestNodes(t *testing.T) {
id: testNodeId,
address: testNodeAddress,
peers: make(map[string]*node),
network: newNetwork(Name(testNodeNetName)),
network: NewNetwork(network.Name(testNodeNetName)),
}
// get all the nodes including yourself
nodes := single.Nodes()
@@ -128,7 +129,7 @@ func TestNodes(t *testing.T) {
}
}
func collectPeerIds(peer Node, ids map[string]bool) map[string]bool {
func collectPeerIds(peer network.Node, ids map[string]bool) map[string]bool {
if len(peer.Peers()) == 0 {
return ids
}
@@ -150,7 +151,7 @@ func TestPeers(t *testing.T) {
id: testNodeId,
address: testNodeAddress,
peers: make(map[string]*node),
network: newNetwork(Name(testNodeNetName)),
network: NewNetwork(network.Name(testNodeNetName)),
}
// get node peers
peers := single.Peers()
@@ -338,7 +339,7 @@ func TestPeersToProto(t *testing.T) {
id: testNodeId,
address: testNodeAddress,
peers: make(map[string]*node),
network: newNetwork(Name(testNodeNetName)),
network: NewNetwork(network.Name(testNodeNetName)),
status: newStatus(),
}
topCount := 0

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,21 @@
// Code generated by protoc-gen-micro. DO NOT EDIT.
// source: github.com/micro/go-micro/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

View File

@@ -0,0 +1,115 @@
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;
}

View File

@@ -2,28 +2,8 @@
package network
import (
"time"
"github.com/micro/go-micro/v2/client"
"github.com/micro/go-micro/v2/server"
)
var (
// DefaultName is default network name
DefaultName = "go.micro"
// DefaultAddress is default network address
DefaultAddress = ":0"
// ResolveTime defines time interval to periodically resolve network nodes
ResolveTime = 1 * time.Minute
// AnnounceTime defines time interval to periodically announce node neighbours
AnnounceTime = 1 * time.Second
// KeepAliveTime is the time in which we want to have sent a message to a peer
KeepAliveTime = 30 * time.Second
// SyncTime is the time a network node requests full sync from the network
SyncTime = 1 * time.Minute
// PruneTime defines time interval to periodically check nodes that need to be pruned
// due to their not announcing their presence within this time interval
PruneTime = 90 * time.Second
"github.com/micro/go-micro/v3/client"
"github.com/micro/go-micro/v3/server"
)
// Error is network node errors
@@ -73,8 +53,3 @@ type Network interface {
// Server is micro server
Server() server.Server
}
// NewNetwork returns a new network interface
func NewNetwork(opts ...Option) Network {
return newNetwork(opts...)
}

View File

@@ -2,12 +2,13 @@ package network
import (
"github.com/google/uuid"
"github.com/micro/go-micro/v2/network/resolver"
"github.com/micro/go-micro/v2/network/resolver/registry"
"github.com/micro/go-micro/v2/proxy"
"github.com/micro/go-micro/v2/proxy/mucp"
"github.com/micro/go-micro/v2/router"
"github.com/micro/go-micro/v2/tunnel"
"github.com/micro/go-micro/v3/network/resolver"
"github.com/micro/go-micro/v3/network/resolver/registry"
"github.com/micro/go-micro/v3/proxy"
"github.com/micro/go-micro/v3/proxy/mucp"
"github.com/micro/go-micro/v3/router"
regRouter "github.com/micro/go-micro/v3/router/registry"
"github.com/micro/go-micro/v3/tunnel"
)
type Option func(*Options)
@@ -101,10 +102,10 @@ func Resolver(r resolver.Resolver) Option {
func DefaultOptions() Options {
return Options{
Id: uuid.New().String(),
Name: DefaultName,
Address: DefaultAddress,
Name: "go.micro",
Address: ":0",
Tunnel: tunnel.NewTunnel(),
Router: router.DefaultRouter,
Router: regRouter.NewRouter(),
Proxy: mucp.NewProxy(),
Resolver: &registry.Resolver{},
}

View File

@@ -5,7 +5,7 @@ import (
"context"
"net"
"github.com/micro/go-micro/v2/network/resolver"
"github.com/micro/go-micro/v3/network/resolver"
"github.com/miekg/dns"
)

View File

@@ -5,7 +5,7 @@ import (
"fmt"
"net"
"github.com/micro/go-micro/v2/network/resolver"
"github.com/micro/go-micro/v3/network/resolver"
)
// Resolver is a DNS network resolve

View File

@@ -8,7 +8,7 @@ import (
"net/http"
"net/url"
"github.com/micro/go-micro/v2/network/resolver"
"github.com/micro/go-micro/v3/network/resolver"
)
// Resolver is a HTTP network resolver

View File

@@ -2,8 +2,9 @@
package registry
import (
"github.com/micro/go-micro/v2/network/resolver"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v3/network/resolver"
"github.com/micro/go-micro/v3/registry"
"github.com/micro/go-micro/v3/registry/mdns"
)
// Resolver is a registry network resolver
@@ -16,7 +17,7 @@ type Resolver struct {
func (r *Resolver) Resolve(name string) ([]*resolver.Record, error) {
reg := r.Registry
if reg == nil {
reg = registry.DefaultRegistry
reg = mdns.NewRegistry()
}
services, err := reg.GetService(name)

View File

@@ -2,7 +2,7 @@
package registry
import (
"github.com/micro/go-micro/v2/network/resolver"
"github.com/micro/go-micro/v3/network/resolver"
)
// Resolver returns a static list of nodes. In the event the node list

File diff suppressed because it is too large Load Diff

View File

@@ -1,191 +0,0 @@
// Code generated by protoc-gen-micro. DO NOT EDIT.
// source: network/service/proto/network.proto
package go_micro_network
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
_ "github.com/micro/go-micro/v2/router/service/proto"
math "math"
)
import (
context "context"
api "github.com/micro/go-micro/v2/api"
client "github.com/micro/go-micro/v2/client"
server "github.com/micro/go-micro/v2/server"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
// Reference imports to suppress errors if they are not otherwise used.
var _ api.Endpoint
var _ context.Context
var _ client.Option
var _ server.Option
// Api Endpoints for Network service
func NewNetworkEndpoints() []*api.Endpoint {
return []*api.Endpoint{}
}
// Client API for Network service
type NetworkService interface {
// Connect to the network
Connect(ctx context.Context, in *ConnectRequest, opts ...client.CallOption) (*ConnectResponse, error)
// Returns the entire network graph
Graph(ctx context.Context, in *GraphRequest, opts ...client.CallOption) (*GraphResponse, error)
// Returns a list of known nodes in the network
Nodes(ctx context.Context, in *NodesRequest, opts ...client.CallOption) (*NodesResponse, error)
// Returns a list of known routes in the network
Routes(ctx context.Context, in *RoutesRequest, opts ...client.CallOption) (*RoutesResponse, error)
// Returns a list of known services based on routes
Services(ctx context.Context, in *ServicesRequest, opts ...client.CallOption) (*ServicesResponse, error)
// Status returns network status
Status(ctx context.Context, in *StatusRequest, opts ...client.CallOption) (*StatusResponse, error)
}
type networkService struct {
c client.Client
name string
}
func NewNetworkService(name string, c client.Client) NetworkService {
return &networkService{
c: c,
name: name,
}
}
func (c *networkService) Connect(ctx context.Context, in *ConnectRequest, opts ...client.CallOption) (*ConnectResponse, error) {
req := c.c.NewRequest(c.name, "Network.Connect", in)
out := new(ConnectResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *networkService) Graph(ctx context.Context, in *GraphRequest, opts ...client.CallOption) (*GraphResponse, error) {
req := c.c.NewRequest(c.name, "Network.Graph", in)
out := new(GraphResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *networkService) Nodes(ctx context.Context, in *NodesRequest, opts ...client.CallOption) (*NodesResponse, error) {
req := c.c.NewRequest(c.name, "Network.Nodes", in)
out := new(NodesResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *networkService) Routes(ctx context.Context, in *RoutesRequest, opts ...client.CallOption) (*RoutesResponse, error) {
req := c.c.NewRequest(c.name, "Network.Routes", in)
out := new(RoutesResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *networkService) Services(ctx context.Context, in *ServicesRequest, opts ...client.CallOption) (*ServicesResponse, error) {
req := c.c.NewRequest(c.name, "Network.Services", in)
out := new(ServicesResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *networkService) Status(ctx context.Context, in *StatusRequest, opts ...client.CallOption) (*StatusResponse, error) {
req := c.c.NewRequest(c.name, "Network.Status", in)
out := new(StatusResponse)
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 {
// Connect to the network
Connect(context.Context, *ConnectRequest, *ConnectResponse) error
// Returns the entire network graph
Graph(context.Context, *GraphRequest, *GraphResponse) error
// Returns a list of known nodes in the network
Nodes(context.Context, *NodesRequest, *NodesResponse) error
// Returns a list of known routes in the network
Routes(context.Context, *RoutesRequest, *RoutesResponse) error
// Returns a list of known services based on routes
Services(context.Context, *ServicesRequest, *ServicesResponse) error
// Status returns network status
Status(context.Context, *StatusRequest, *StatusResponse) error
}
func RegisterNetworkHandler(s server.Server, hdlr NetworkHandler, opts ...server.HandlerOption) error {
type network interface {
Connect(ctx context.Context, in *ConnectRequest, out *ConnectResponse) error
Graph(ctx context.Context, in *GraphRequest, out *GraphResponse) error
Nodes(ctx context.Context, in *NodesRequest, out *NodesResponse) error
Routes(ctx context.Context, in *RoutesRequest, out *RoutesResponse) error
Services(ctx context.Context, in *ServicesRequest, out *ServicesResponse) error
Status(ctx context.Context, in *StatusRequest, out *StatusResponse) error
}
type Network struct {
network
}
h := &networkHandler{hdlr}
return s.Handle(s.NewHandler(&Network{h}, opts...))
}
type networkHandler struct {
NetworkHandler
}
func (h *networkHandler) Connect(ctx context.Context, in *ConnectRequest, out *ConnectResponse) error {
return h.NetworkHandler.Connect(ctx, in, out)
}
func (h *networkHandler) Graph(ctx context.Context, in *GraphRequest, out *GraphResponse) error {
return h.NetworkHandler.Graph(ctx, in, out)
}
func (h *networkHandler) Nodes(ctx context.Context, in *NodesRequest, out *NodesResponse) error {
return h.NetworkHandler.Nodes(ctx, in, out)
}
func (h *networkHandler) Routes(ctx context.Context, in *RoutesRequest, out *RoutesResponse) error {
return h.NetworkHandler.Routes(ctx, in, out)
}
func (h *networkHandler) Services(ctx context.Context, in *ServicesRequest, out *ServicesResponse) error {
return h.NetworkHandler.Services(ctx, in, out)
}
func (h *networkHandler) Status(ctx context.Context, in *StatusRequest, out *StatusResponse) error {
return h.NetworkHandler.Status(ctx, in, out)
}

View File

@@ -1,131 +0,0 @@
syntax = "proto3";
package go.micro.network;
import "router/service/proto/router.proto";
// Network service is usesd to gain visibility into networks
service Network {
// Connect to the network
rpc Connect(ConnectRequest) returns (ConnectResponse) {};
// Returns the entire network graph
rpc Graph(GraphRequest) returns (GraphResponse) {};
// Returns a list of known nodes in the network
rpc Nodes(NodesRequest) returns (NodesResponse) {};
// Returns a list of known routes in the network
rpc Routes(RoutesRequest) returns (RoutesResponse) {};
// Returns a list of known services based on routes
rpc Services(ServicesRequest) returns (ServicesResponse) {};
// Status returns network status
rpc Status(StatusRequest) returns (StatusResponse) {};
}
// Query is passed in a LookupRequest
message Query {
string service = 1;
string address = 2;
string gateway = 3;
string router = 4;
string network = 5;
}
message ConnectRequest {
repeated Node nodes = 1;
}
message ConnectResponse {}
// PeerRequest requests list of peers
message NodesRequest {
// node topology depth
uint32 depth = 1;
}
// PeerResponse is returned by ListPeers
message NodesResponse {
// return peer topology
repeated Node nodes = 1;
}
message GraphRequest {
// node topology depth
uint32 depth = 1;
}
message GraphResponse {
Peer root = 1;
}
message RoutesRequest {
// filter based on
Query query = 1;
}
message RoutesResponse {
repeated go.micro.router.Route routes = 1;
}
message ServicesRequest {}
message ServicesResponse {
repeated string services = 1;
}
message StatusRequest {}
message StatusResponse {
Status status = 1;
}
// 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 go.micro.router.Route routes = 2;
}