From 0899282277c6f7f6ee45c7c0d3225ac81dfea44f Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Mon, 1 Jul 2019 11:55:15 +0100 Subject: [PATCH] Checkpoint networking code --- network/default.go | 608 ++++++++++++++++++++++++++++++++- network/network.go | 65 +++- network/proto/network.micro.go | 21 ++ network/proto/network.pb.go | 197 +++++++++++ network/proto/network.proto | 27 ++ 5 files changed, 895 insertions(+), 23 deletions(-) create mode 100644 network/proto/network.micro.go create mode 100644 network/proto/network.pb.go create mode 100644 network/proto/network.proto diff --git a/network/default.go b/network/default.go index 8ee82b04..4262da8d 100644 --- a/network/default.go +++ b/network/default.go @@ -1,26 +1,47 @@ package network import ( + "crypto/sha256" + "fmt" + "io" + "runtime/debug" "sync" + "time" + gproto "github.com/golang/protobuf/proto" + "github.com/google/uuid" + "github.com/micro/go-micro/codec" + "github.com/micro/go-micro/codec/proto" "github.com/micro/go-micro/config/options" "github.com/micro/go-micro/network/proxy" + "github.com/micro/go-micro/network/resolver" "github.com/micro/go-micro/network/router" + "github.com/micro/go-micro/registry" + "github.com/micro/go-micro/transport" + "github.com/micro/go-micro/util/log" + + pb "github.com/micro/go-micro/network/proto" + nreg "github.com/micro/go-micro/network/resolver/registry" ) type network struct { options.Options - // router - r router.Router + // resolver use to connect to the network + resolver resolver.Resolver - // proxy - p proxy.Proxy + // router used to find routes in the network + router router.Router + + // proxy used to route through the network + proxy proxy.Proxy // id of this network id string // links maintained for this network + // based on peers not nodes. maybe maintain + // node separately or note that links have nodes mtx sync.RWMutex links []Link } @@ -28,31 +49,233 @@ type network struct { type node struct { *network + // closed channel + closed chan bool + + mtx sync.RWMutex + + // the node id + id string + // address of this node address string + + // the node registry + registry registry.Registry + + // the base level transport + transport transport.Transport + + // the listener + listener transport.Listener + + // leases for connections to us + // link id:link + links map[string]*link } type link struct { // the embedded node *node + // the link id + id string + + // queue buffer for this link + queue chan *Message + + // the socket for this link + socket *socket + + // the lease for this link + lease *pb.Lease + // length and weight of the link - mtx sync.RWMutex + mtx sync.RWMutex + + // determines the cost of the link + // based on queue length and roundtrip length int weight int } +type socket struct { + node *node + codec codec.Marshaler + socket transport.Socket +} + // network methods +// lease generates a new lease with a node id/address +// TODO: use a consensus mechanism, pool or some deterministic +// unique prefixing method. +func (n *network) lease() *pb.Lease { + // create the id + id := uuid.New().String() + // create a timestamp + now := time.Now().UnixNano() + // create the address + h := sha256.New() + h.Write([]byte(fmt.Sprintf("%s-%d\n", id, now))) + address := fmt.Sprintf("%x", h.Sum(nil)) + + // return the node + return &pb.Lease{ + Id: id, + Timestamp: now, + Node: &pb.Node{ + Id: id, + Address: address, + }, + } +} + +// lookup returns a list of network records in priority order of local +func (n *network) lookup(r registry.Registry) []*resolver.Record { + // create a registry resolver to find local nodes + rr := nreg.Resolver{Registry: r} + + // get all the nodes for the network that are local + localRecords, err := rr.Resolve("network:" + n.Id()) + if err != nil { + // we're not in a good place here + } + + // if its a local network we never try lookup anything else + if n.Id() == "local" { + return localRecords + } + + // now resolve incrementally based on resolvers specified + networkRecords, err := n.resolver.Resolve(n.Id()) + if err != nil { + // still not in a good place + } + + // return aggregate records + return append(localRecords, networkRecords...) +} + func (n *network) Id() string { return n.id } +// Connect connects to the network and returns a new node. +// The node is the callers connection to the network. They +// should advertise this address to people. Anyone else +// on the network should be able to route to it. func (n *network) Connect() (Node, error) { - return nil, nil + // create a new node + node := new(node) + // closed channel + node.closed = make(chan bool) + // set the nodes network + node.network = n + + // initially we have no id + // create an id and address + // TODO: create a real unique id and address + // lease := n.lease() + // set the node id + // node.id = lease.Node.Id + + // get the transport we're going to use for our tunnels + t, ok := n.Options.Values().Get("network.transport") + if ok { + node.transport = t.(transport.Transport) + } else { + // TODO: set to quic + node.transport = transport.DefaultTransport + } + + // start the node + + // we listen on a random address, this is not advertised + // TODO: use util/addr to get something anyone in the same private network can talk to + l, err := node.transport.Listen(":0") + if err != nil { + return nil, err + } + // set the listener + node.listener = l + + // TODO: this should be an overlay address + // ideally received via some dhcp style broadcast + node.address = l.Addr() + + // TODO: start the router and broadcast advertisements + // receive updates and push them to the network in accept(l) below + // chan, err := n.router.Advertise() + // u <- chan + // socket.send("route", u) + // u := socket.recv() => r.router.Update(u) + + // process any incoming messages on the listener + // this is our inbound network connection + node.accept(l) + + // register the node with the registry for the network + // TODO: use a registrar or something else for local things + r, ok := n.Options.Values().Get("network.registry") + if ok { + node.registry = r.(registry.Registry) + } else { + node.registry = registry.DefaultRegistry + } + + // lookup the network to see if there's any nodes + records := n.lookup(node.registry) + + // should we actually do this? + if len(records) == 0 { + // set your own node id + lease := n.lease() + node.id = lease.Node.Id + } + + // register self with the network registry + // this is a local registry of nodes separate to the resolver + // maybe consolidate registry/resolver + // TODO: find a way to do this via gossip or something else + if err := node.registry.Register(®istry.Service{ + // register with the network id + Name: "network:" + n.Id(), + Nodes: []*registry.Node{ + {Id: node.id, Address: node.address}, + }, + }); err != nil { + node.Close() + return nil, err + } + + // create a channel to get links + linkChan := make(chan *link, 1) + + // we're going to wait for the first connection + go node.connect(linkChan) + + // wait forever to connect + // TODO: do something with the links we receive + <-linkChan + + return node, nil } +// TODO: establish links for peering networks func (n *network) Peer(Network) (Link, error) { + // New network was created using NewNetwork after receiving routes from a different node + + // Connect to the new network and be assigned a node + + // Transfer data between the networks + + // take other resolver + // order: registry (local), ...resolver + // resolve the network + + // periodically connect to nodes resolved in the network + // and add to the network links return nil, nil } @@ -64,24 +287,235 @@ func (n *network) Links() ([]Link, error) { // node methods +// Accept processes the incoming messages on its listener. +// This listener was created with the first call to network.Connect. +// Any inbound new socket here is essentially something else attempting +// to connect to the network. So we turn it into a socket, then process it. +func (n *node) accept(l transport.Listener) error { + return l.Accept(func(sock transport.Socket) { + defer func() { + // close socket + sock.Close() + + if r := recover(); r != nil { + log.Log("panic recovered: ", r) + log.Log(string(debug.Stack())) + } + }() + + // create a new link + // generate a new link + link := &link{ + node: n, + id: uuid.New().String(), + } + // create a new network socket + sk := new(socket) + sk.node = n + sk.codec = proto.Marshaler{} + sk.socket = sock + + // set link socket + link.socket = sk + + // accept messages on the socket + // blocks forever or until error + if err := link.up(); err != nil { + // TODO: delete link + } + }) +} + +// connect attempts to periodically connect to new nodes in the network. +// It will only do this if it has less than 3 connections. this method +// is called by network.Connect and fired in a go routine after establishing +// the first connection and creating a node. The node attempts to maintain +// its connection to the network via multiple links. +func (n *node) connect(linkChan chan *link) { + // TODO: adjustable ticker + t := time.NewTicker(time.Second) + var lease *pb.Lease + + for { + select { + // on every tick check the number of links and then attempt + // to connect to new nodes if we don't have sufficient links + case <-t.C: + n.mtx.RLock() + + // only start processing if we have less than 3 links + if len(n.links) > 2 { + n.mtx.RUnlock() + continue + } + + // get a list of link addresses so we don't reconnect + // to the ones we're already connected to + nodes := map[string]bool{} + for _, l := range n.links { + nodes[l.lease.Node.Address] = true + } + + n.mtx.RUnlock() + + records := n.network.lookup(n.registry) + + // for each record check we haven't already got a connection + // attempt to dial it, create a new socket and call + // connect with our existing network lease. + // if its the first call we don't actually have a lease + + // TODO: determine how to prioritise local records + // while still connecting to the global network + for _, record := range records { + // skip existing connections + if nodes[record.Address] { + continue + } + + // attempt to connect and create a link + + // connect to the node + s, err := n.transport.Dial(record.Address) + if err != nil { + continue + } + + // create a new socket + sk := &socket{ + node: n, + codec: &proto.Marshaler{}, + socket: s, + } + + // broadcast a "connect" request and get back "lease" + // this is your tunnel to the outside world and to the network + // then push updates and messages over this link + // first connect will not have a lease so we get one with node id/address + l, err := sk.connect(lease) + if err != nil { + s.Close() + continue + } + + // set lease for next time + lease = l + + // create a new link with the lease and socket + link := &link{ + id: uuid.New().String(), + lease: lease, + node: n, + queue: make(chan *Message, 128), + socket: sk, + } + + // bring up the link + go link.up() + + // save the new link + n.mtx.Lock() + n.links[link.id] = link + n.mtx.Unlock() + + // drop this down the link channel to the network + // so it can manage the links + select { + case linkChan <- link: + // we don't wait for anyone + default: + } + } + case <-n.closed: + return + } + } +} + func (n *node) Address() string { return n.address } +// Close shutdowns all the links and closes the listener func (n *node) Close() error { + select { + case <-n.closed: + return nil + default: + close(n.closed) + // shutdown all the links + n.mtx.Lock() + for id, link := range n.links { + link.down() + delete(n.links, id) + } + n.mtx.Unlock() + // deregister self + n.registry.Deregister(®istry.Service{ + Name: "network:" + n.network.Id(), + Nodes: []*registry.Node{ + {Id: n.id, Address: n.address}, + }, + }) + return n.listener.Close() + } return nil } func (n *node) Accept() (*Message, error) { + // process the inbound cruft + return nil, nil } -func (n *node) Send(*Message) error { - return nil +func (n *node) Links() ([]Link, error) { + n.mtx.RLock() + defer n.mtx.RUnlock() + + var links []Link + for _, l := range n.links { + links = append(links, l) + } + return links, nil +} + +func (n *node) Network() Network { + return n.network +} + +func (n *node) Send(m *Message) error { + n.mtx.RLock() + defer n.mtx.RUnlock() + + var gerr error + + // send to all links + // TODO: be smarter + for _, link := range n.links { + // TODO: process the error, do some link flap detection + // blackhold the connection, etc + if err := link.socket.send(m, nil); err != nil { + gerr = err + continue + } + } + + return gerr } // link methods +// bring up the link +func (l *link) up() error { + // TODO: manage the length/weight of the link + return l.socket.accept() +} + +// kill the link +func (l *link) down() error { + return l.socket.close() +} + func (l *link) Length() int { l.mtx.RLock() defer l.mtx.RUnlock() @@ -93,3 +527,161 @@ func (l *link) Weight() int { defer l.mtx.RUnlock() return l.weight } + +// accept is the state machine that processes messages on the socket +func (s *socket) accept() error { + for { + m := new(transport.Message) + err := s.socket.Recv(m) + if err == io.EOF { + return nil + } + if err != nil { + return err + } + + // TODO: pick a reliable header + event := m.Header["Micro-Method"] + + switch event { + // connect event + case "connect": + // process connect events from network.Connect() + // these are new connections to join the network + + // decode the connection event + conn := new(pb.Connect) + if err := s.codec.Unmarshal(m.Body, conn); err != nil { + // skip error + continue + } + + // get the existing lease if it exists + lease := conn.Lease + if lease == nil { + // create a new lease/node + lease = s.node.network.lease() + } + + // send back a lease offer for the node + if err := s.send(&Message{ + Header: map[string]string{ + "Micro-Method": "lease", + }, + }, lease); err != nil { + return err + } + + // record this mapping of socket to node/lease + s.node.mtx.Lock() + id := uuid.New().String() + s.node.links[id] = &link{ + node: s.node, + id: id, + lease: lease, + queue: make(chan *Message, 128), + socket: s, + } + s.node.mtx.Unlock() + // a route update + case "route": + // process router events + + // received a lease + case "lease": + // no op as we don't process lease events on existing connections + // these are in response to a connect message + default: + // process all other messages + } + } +} + +func (s *socket) close() error { + return s.socket.Close() +} + +// connect sends a connect request and waits on a lease. +// this is for a new connection. in the event we send +// an existing lease, the same lease should be returned. +// if it differs then we assume our address for this link +// is different... +func (s *socket) connect(l *pb.Lease) (*pb.Lease, error) { + // send a lease request + if err := s.send(&Message{ + Header: map[string]string{ + "Micro-Method": "connect", + }, + }, &pb.Connect{Lease: l}); err != nil { + return nil, err + } + + // create the new things + tm := new(Message) + lease := new(pb.Lease) + + // wait for a lease response + if err := s.recv(tm, lease); err != nil { + return nil, err + } + + return lease, nil +} + +func (s *socket) send(m *Message, v interface{}) error { + tm := new(transport.Message) + tm.Header = m.Header + tm.Body = m.Body + + // set the body if not nil + // we're assuming this is network message + if v != nil { + // encode the data + b, err := s.codec.Marshal(v) + if err != nil { + return err + } + + // set the content type + tm.Header["Content-Type"] = "application/protobuf" + // set the marshalled body + tm.Body = b + } + + // send via the transport socket + return s.socket.Send(&transport.Message{ + Header: m.Header, + Body: m.Body, + }) +} + +func (s *socket) recv(m *Message, v interface{}) error { + if m.Header == nil { + m.Header = make(map[string]string) + } + + tm := new(transport.Message) + + // receive the transport message + if err := s.socket.Recv(tm); err != nil { + return err + } + + // set the message + m.Header = tm.Header + m.Body = tm.Body + + // bail early + if v == nil { + return nil + } + + // try unmarshal the body + // skip if there's no content-type + if tm.Header["Content-Type"] != "application/protobuf" { + return nil + } + + // return unmarshalled + return s.codec.Unmarshal(m.Body, v.(gproto.Message)) +} diff --git a/network/network.go b/network/network.go index 098c0807..dfa0116b 100644 --- a/network/network.go +++ b/network/network.go @@ -3,9 +3,14 @@ package network import ( "github.com/micro/go-micro/config/options" + "github.com/micro/go-micro/network/proxy" + "github.com/micro/go-micro/network/proxy/mucp" + "github.com/micro/go-micro/network/resolver" + "github.com/micro/go-micro/network/resolver/registry" + "github.com/micro/go-micro/network/router" ) -// Network is an interface defining a network +// Network defines a network interface type Network interface { options.Options // Id of this node @@ -14,16 +19,20 @@ type Network interface { Connect() (Node, error) // Peer with a neighboring network Peer(Network) (Link, error) - // Retrieve list of connections + // Retrieve list of peers Links() ([]Link, error) } // Node represents a single node on a network type Node interface { - // Node is a network. Network is a node. - Network + // Id of the node + Id() string // Address of the node Address() string + // The network of the node + Network() Network + // Links to other nodes + Links() ([]Link, error) // Close the network connection Close() error // Accept messages on the network @@ -36,9 +45,9 @@ type Node interface { type Link interface { // remote node the link is to Node - // length of link which dictates speed + // length defines the speed or distance of the link Length() int - // weight of link which dictates curvature + // weight defines the saturation or usage of the link Weight() int } @@ -47,29 +56,55 @@ type Message struct { // Headers which provide local/remote info Header map[string]string // The opaque data being sent - Data []byte + Body []byte } var ( // The default network ID is local - DefaultNetworkId = "local" + DefaultId = "local" // just the standard network element DefaultNetwork = NewNetwork() ) -// NewNetwork returns a new network +// NewNetwork returns a new network interface func NewNetwork(opts ...options.Option) Network { options := options.NewOptions(opts...) + // new network instance + net := &network{ + id: DefaultId, + } + + // get network id + id, ok := options.Values().Get("network.id") + if ok { + net.id = id.(string) + } + // get router + r, ok := options.Values().Get("network.router") + if ok { + net.router = r.(router.Router) + } else { + net.router = router.DefaultRouter + } // get proxy - - return &network{ - Options: options, - // fill the blanks - // router: r, - // proxy: p, + p, ok := options.Values().Get("network.proxy") + if ok { + net.proxy = p.(proxy.Proxy) + } else { + net.proxy = new(mucp.Proxy) } + + // get resolver + res, ok := options.Values().Get("network.resolver") + if ok { + net.resolver = res.(resolver.Resolver) + } else { + net.resolver = new(registry.Resolver) + } + + return net } diff --git a/network/proto/network.micro.go b/network/proto/network.micro.go new file mode 100644 index 00000000..96883952 --- /dev/null +++ b/network/proto/network.micro.go @@ -0,0 +1,21 @@ +// Code generated by protoc-gen-micro. DO NOT EDIT. +// source: micro/go-micro/network/proto/network.proto + +package go_micro_network + +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package diff --git a/network/proto/network.pb.go b/network/proto/network.pb.go new file mode 100644 index 00000000..d8368e42 --- /dev/null +++ b/network/proto/network.pb.go @@ -0,0 +1,197 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: micro/go-micro/network/proto/network.proto + +package go_micro_network + +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +// A connect message is for connecting to the network +type Connect struct { + // Lease specifies an existing lease to indicate + // we don't need a new address, we just want to + // establish a link. + Lease *Lease `protobuf:"bytes,1,opt,name=lease,proto3" json:"lease,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Connect) Reset() { *m = Connect{} } +func (m *Connect) String() string { return proto.CompactTextString(m) } +func (*Connect) ProtoMessage() {} +func (*Connect) Descriptor() ([]byte, []int) { + return fileDescriptor_4daa91d05ddc28b6, []int{0} +} + +func (m *Connect) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Connect.Unmarshal(m, b) +} +func (m *Connect) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Connect.Marshal(b, m, deterministic) +} +func (m *Connect) XXX_Merge(src proto.Message) { + xxx_messageInfo_Connect.Merge(m, src) +} +func (m *Connect) XXX_Size() int { + return xxx_messageInfo_Connect.Size(m) +} +func (m *Connect) XXX_DiscardUnknown() { + xxx_messageInfo_Connect.DiscardUnknown(m) +} + +var xxx_messageInfo_Connect proto.InternalMessageInfo + +func (m *Connect) GetLease() *Lease { + if m != nil { + return m.Lease + } + return nil +} + +// A lease is returned to anyone attempting to connect. +type Lease struct { + // unique lease id + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // timestamp of lease + Timestamp int64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + // the node + Node *Node `protobuf:"bytes,3,opt,name=node,proto3" json:"node,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Lease) Reset() { *m = Lease{} } +func (m *Lease) String() string { return proto.CompactTextString(m) } +func (*Lease) ProtoMessage() {} +func (*Lease) Descriptor() ([]byte, []int) { + return fileDescriptor_4daa91d05ddc28b6, []int{1} +} + +func (m *Lease) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Lease.Unmarshal(m, b) +} +func (m *Lease) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Lease.Marshal(b, m, deterministic) +} +func (m *Lease) XXX_Merge(src proto.Message) { + xxx_messageInfo_Lease.Merge(m, src) +} +func (m *Lease) XXX_Size() int { + return xxx_messageInfo_Lease.Size(m) +} +func (m *Lease) XXX_DiscardUnknown() { + xxx_messageInfo_Lease.DiscardUnknown(m) +} + +var xxx_messageInfo_Lease proto.InternalMessageInfo + +func (m *Lease) GetId() string { + if m != nil { + return m.Id + } + return "" +} + +func (m *Lease) GetTimestamp() int64 { + if m != nil { + return m.Timestamp + } + return 0 +} + +func (m *Lease) GetNode() *Node { + if m != nil { + return m.Node + } + return nil +} + +// A node is the network node +type Node struct { + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Node) Reset() { *m = Node{} } +func (m *Node) String() string { return proto.CompactTextString(m) } +func (*Node) ProtoMessage() {} +func (*Node) Descriptor() ([]byte, []int) { + return fileDescriptor_4daa91d05ddc28b6, []int{2} +} + +func (m *Node) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Node.Unmarshal(m, b) +} +func (m *Node) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Node.Marshal(b, m, deterministic) +} +func (m *Node) XXX_Merge(src proto.Message) { + xxx_messageInfo_Node.Merge(m, src) +} +func (m *Node) XXX_Size() int { + return xxx_messageInfo_Node.Size(m) +} +func (m *Node) XXX_DiscardUnknown() { + xxx_messageInfo_Node.DiscardUnknown(m) +} + +var xxx_messageInfo_Node proto.InternalMessageInfo + +func (m *Node) GetId() string { + if m != nil { + return m.Id + } + return "" +} + +func (m *Node) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func init() { + proto.RegisterType((*Connect)(nil), "go.micro.network.Connect") + proto.RegisterType((*Lease)(nil), "go.micro.network.Lease") + proto.RegisterType((*Node)(nil), "go.micro.network.Node") +} + +func init() { + proto.RegisterFile("micro/go-micro/network/proto/network.proto", fileDescriptor_4daa91d05ddc28b6) +} + +var fileDescriptor_4daa91d05ddc28b6 = []byte{ + // 192 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x8f, 0x3d, 0x4b, 0xc0, 0x30, + 0x10, 0x86, 0xe9, 0x97, 0xa5, 0x27, 0x88, 0x64, 0xd0, 0x0c, 0x0e, 0xa5, 0x53, 0x29, 0x34, 0x15, + 0x5d, 0xdc, 0x5d, 0xc5, 0x21, 0xff, 0x20, 0x36, 0x47, 0x09, 0xda, 0x5c, 0x49, 0x02, 0xfe, 0x7d, + 0xe9, 0xd5, 0x0f, 0xb0, 0x5b, 0x9e, 0x37, 0xcf, 0xdd, 0xcb, 0xc1, 0xb0, 0xba, 0x39, 0xd0, 0xb4, + 0xd0, 0x78, 0x3c, 0x3c, 0xa6, 0x4f, 0x0a, 0xef, 0xd3, 0x16, 0x28, 0xfd, 0x92, 0x62, 0x12, 0xd7, + 0x0b, 0x29, 0xb6, 0xd4, 0x77, 0xde, 0x3d, 0x41, 0xfd, 0x4c, 0xde, 0xe3, 0x9c, 0xc4, 0x08, 0xd5, + 0x07, 0x9a, 0x88, 0x32, 0x6b, 0xb3, 0xfe, 0xf2, 0xe1, 0x56, 0xfd, 0x97, 0xd5, 0xcb, 0xfe, 0xad, + 0x0f, 0xab, 0x33, 0x50, 0x31, 0x8b, 0x2b, 0xc8, 0x9d, 0xe5, 0xa1, 0x46, 0xe7, 0xce, 0x8a, 0x3b, + 0x68, 0x92, 0x5b, 0x31, 0x26, 0xb3, 0x6e, 0x32, 0x6f, 0xb3, 0xbe, 0xd0, 0x7f, 0x81, 0x18, 0xa0, + 0xf4, 0x64, 0x51, 0x16, 0x5c, 0x72, 0x73, 0x2e, 0x79, 0x25, 0x8b, 0x9a, 0x9d, 0xee, 0x1e, 0xca, + 0x9d, 0x4e, 0x0d, 0x12, 0x6a, 0x63, 0x6d, 0xc0, 0x18, 0x79, 0x7f, 0xa3, 0x7f, 0xf0, 0xed, 0x82, + 0xef, 0x7c, 0xfc, 0x0a, 0x00, 0x00, 0xff, 0xff, 0x48, 0x8c, 0x11, 0x91, 0x15, 0x01, 0x00, 0x00, +} diff --git a/network/proto/network.proto b/network/proto/network.proto new file mode 100644 index 00000000..26cf2cbc --- /dev/null +++ b/network/proto/network.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; + +package go.micro.network; + +// A connect message is for connecting to the network +message Connect { + // Lease specifies an existing lease to indicate + // we don't need a new address, we just want to + // establish a link. + Lease lease = 1; +} + +// A lease is returned to anyone attempting to connect. +message Lease { + // unique lease id + string id = 1; + // timestamp of lease + int64 timestamp = 2; + // the node + Node node = 3; +} + +// A node is the network node +message Node { + string id = 1; + string address = 2; +}