rewrite network interface
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user