rewrite network interface

This commit is contained in:
Asim Aslam
2019-07-08 16:24:57 +01:00
parent d3edad474e
commit 4a02e1ff2f
8 changed files with 244 additions and 896 deletions

View File

@@ -1,144 +1,136 @@
package network
import (
"crypto/sha256"
"fmt"
"io"
"sync"
"time"
"github.com/google/uuid"
"github.com/micro/go-micro/config/options"
"github.com/micro/go-micro/network/proxy"
"github.com/micro/go-micro/network/proxy/mucp"
"github.com/micro/go-micro/network/resolver"
"github.com/micro/go-micro/network/router"
"github.com/micro/go-micro/registry"
pb "github.com/micro/go-micro/network/proto"
nreg "github.com/micro/go-micro/network/resolver/registry"
"github.com/micro/go-micro/network/transport"
"github.com/micro/go-micro/util/addr"
)
// default network implementation
type network struct {
options.Options
// resolver use to connect to the network
resolver resolver.Resolver
// router used to find routes in the network
router router.Router
// proxy used to route through the network
proxy proxy.Proxy
// name of this network
// name of the network
name string
// links maintained for this network
// based on peers not nodes. maybe maintain
// node separately or note that links have nodes
mtx sync.RWMutex
links []Link
// transport
transport transport.Transport
}
// network methods
type listener struct {
// start accepting once
once sync.Once
// close channel to close the connection
closed chan bool
// the listener
listener transport.Listener
// the connection queue
conns chan Conn
}
// lease generates a new lease with a node id/address
// TODO: use a consensus mechanism, pool or some deterministic
// unique addressing method.
func (n *network) lease(muid string) *pb.Lease {
// create the id
id := uuid.New().String()
// create a timestamp
now := time.Now().UnixNano()
// create the address by hashing the id and timestamp
h := sha256.New()
h.Write([]byte(fmt.Sprintf("%s-%d\n", id, now)))
// magic new address
address := fmt.Sprintf("%x", h.Sum(nil))
// return the node
return &pb.Lease{
Id: id,
Timestamp: now,
Node: &pb.Node{
Muid: muid,
Id: id,
Address: address,
Network: n.name,
func (n *network) Create() (*Node, error) {
ip, err := addr.Extract("")
if err != nil {
return nil, err
}
return &Node{
Id: fmt.Sprintf("%s-%s", n.name, uuid.New().String()),
Address: ip,
Metadata: map[string]string{
"network": n.Name(),
},
}
}
// lookup returns a list of network records in priority order of local
func (n *network) lookup(r registry.Registry) []*resolver.Record {
// create a registry resolver to find local nodes
rr := nreg.Resolver{Registry: r}
// get all the nodes for the network that are local
localRecords, err := rr.Resolve(n.Name())
if err != nil {
// we're not in a good place here
}
// if its a local network we never try lookup anything else
if n.Name() == "local" {
return localRecords
}
// now resolve incrementally based on resolvers specified
networkRecords, err := n.resolver.Resolve(n.Name())
if err != nil {
// still not in a good place
}
// return aggregate records
return append(localRecords, networkRecords...)
}, nil
}
func (n *network) Name() string {
return n.name
}
// Connect connects to the network and returns a new node.
// The node is the callers connection to the network. They
// should advertise this address to people. Anyone else
// on the network should be able to route to it.
func (n *network) Connect() (Node, error) {
return newNode(n)
func (n *network) Connect(node *Node) (Conn, error) {
c, err := n.transport.Dial(node.Address)
if err != nil {
return nil, err
}
return newLink(c.(transport.Socket)), nil
}
// Peer is used to establish a link between two networks.
// e.g micro.mu connects to example.com and share routes
// This is done by creating a new node on both networks
// and creating a link between them.
func (n *network) Peer(Network) (Link, error) {
// New network was created using NewNetwork after receiving routes from a different node
// Connect to the new network and be assigned a node
// Transfer data between the networks
// take other resolver
// order: registry (local), ...resolver
// resolve the network
// periodically connect to nodes resolved in the network
// and add to the network links
return nil, nil
func (n *network) Listen(node *Node) (Listener, error) {
l, err := n.transport.Listen(node.Address)
if err != nil {
return nil, err
}
return newListener(l), nil
}
func (l *listener) process() {
if err := l.listener.Accept(l.accept); err != nil {
// close the listener
l.Close()
}
}
func (l *listener) accept(sock transport.Socket) {
// create a new link and pass it through
link := newLink(sock)
// send it
l.conns <- link
// wait for it to be closed
select {
case <-l.closed:
return
case <-link.closed:
return
}
}
func (l *listener) Address() string {
return l.listener.Addr()
}
func (l *listener) Close() error {
select {
case <-l.closed:
return nil
default:
close(l.closed)
}
return nil
}
func (l *listener) Accept() (Conn, error) {
l.once.Do(func() {
// TODO: catch the error
go l.process()
})
select {
case c := <-l.conns:
return c, nil
case <-l.closed:
return nil, io.EOF
}
}
func newListener(l transport.Listener) *listener {
return &listener{
closed: make(chan bool),
conns: make(chan Conn),
listener: l,
}
}
// newNetwork returns a new network interface
func newNetwork(opts ...options.Option) *network {
options := options.NewOptions(opts...)
// new network instance with defaults
net := &network{
Options: options,
name: DefaultName,
router: router.DefaultRouter,
proxy: new(mucp.Proxy),
resolver: new(nreg.Resolver),
name: DefaultName,
transport: transport.DefaultTransport,
}
// get network name
@@ -147,22 +139,10 @@ func newNetwork(opts ...options.Option) *network {
net.name = name.(string)
}
// get router
r, ok := options.Values().Get("network.router")
// get network transport
t, ok := options.Values().Get("network.transport")
if ok {
net.router = r.(router.Router)
}
// get proxy
p, ok := options.Values().Get("network.proxy")
if ok {
net.proxy = p.(proxy.Proxy)
}
// get resolver
res, ok := options.Values().Get("network.resolver")
if ok {
net.resolver = res.(resolver.Resolver)
net.transport = t.(transport.Transport)
}
return net