storj/internal/testplanet/node.go
2018-12-27 11:56:25 +02:00

191 lines
5.0 KiB
Go

// Copyright (C) 2018 Storj Labs, Inc.
// See LICENSE for copying information
package testplanet
import (
"context"
"io"
"net"
"go.uber.org/zap"
"google.golang.org/grpc"
"storj.io/storj/pkg/auth/grpcauth"
"storj.io/storj/pkg/discovery"
"storj.io/storj/pkg/kademlia"
"storj.io/storj/pkg/node"
"storj.io/storj/pkg/overlay"
"storj.io/storj/pkg/pb"
"storj.io/storj/pkg/pointerdb/pdbclient"
"storj.io/storj/pkg/provider"
"storj.io/storj/pkg/statdb"
"storj.io/storj/pkg/storj"
"storj.io/storj/pkg/transport"
"storj.io/storj/pkg/utils"
"storj.io/storj/satellite"
"storj.io/storj/satellite/satellitedb"
"storj.io/storj/storage/teststore"
)
// Node is a general purpose
type Node struct {
Log *zap.Logger
Info pb.Node
Identity *provider.FullIdentity
Transport transport.Client
Listener net.Listener
Provider *provider.Provider
Kademlia *kademlia.Kademlia
Discovery *discovery.Discovery
StatDB statdb.DB
Overlay *overlay.Cache
Database satellite.DB
Dependencies []io.Closer
}
// newNode creates a new node.
func (planet *Planet) newNode(name string, nodeType pb.NodeType) (*Node, error) {
identity, err := planet.newIdentity()
if err != nil {
return nil, err
}
listener, err := planet.newListener()
if err != nil {
return nil, err
}
node := &Node{
Log: planet.log.Named(name),
Identity: identity,
Listener: listener,
}
node.Log.Debug("id=" + identity.ID.String())
node.Transport = transport.NewClient(identity)
serverConfig := provider.ServerConfig{Address: node.Listener.Addr().String()}
opts, err := provider.NewServerOptions(node.Identity, serverConfig)
if err != nil {
return nil, err
}
node.Provider, err = provider.NewProvider(opts, node.Listener, grpcauth.NewAPIKeyInterceptor())
if err != nil {
return nil, utils.CombineErrors(err, listener.Close())
}
node.Info = pb.Node{
Id: node.Identity.ID,
Type: nodeType,
Address: &pb.NodeAddress{
Transport: pb.NodeTransport_TCP_TLS_GRPC,
Address: node.Listener.Addr().String(),
},
}
planet.nodes = append(planet.nodes, node)
planet.nodeInfos = append(planet.nodeInfos, node.Info)
planet.nodeLinks = append(planet.nodeLinks, node.Info.Id.String()+":"+node.Listener.Addr().String())
return node, nil
}
// ID returns node id
func (node *Node) ID() storj.NodeID { return node.Info.Id }
// Addr retursn node address
func (node *Node) Addr() string { return node.Info.Address.Address }
// Shutdown shuts down all node dependencies
func (node *Node) Shutdown() error {
var errs []error
if node.Kademlia != nil {
errs = append(errs, node.Kademlia.Disconnect())
}
if node.Provider != nil {
errs = append(errs, node.Provider.Close())
}
// Provider automatically closes listener
// if node.Listener != nil {
// errs = append(errs, node.Listener.Close())
// }
for _, dep := range node.Dependencies {
err := dep.Close()
if err != nil {
errs = append(errs, err)
}
}
return utils.CombineErrors(errs...)
}
// NewNodeClient creates a node client for this node
func (n *Node) NewNodeClient() (node.Client, error) { //nolint renaming to node would conflict with package name; rename Node to Peer to resolve
// TODO: handle disconnect verification
return node.NewNodeClient(n.Identity, n.Info, n.Kademlia)
}
// DialPointerDB dials destination with apikey and returns pointerdb Client
func (node *Node) DialPointerDB(destination *Node, apikey string) (pdbclient.Client, error) {
// TODO: use node.Transport instead of pdbclient.NewClient
/*
conn, err := node.Transport.DialNode(context.Background(), &destination.Info)
if err != nil {
return nil, err
}
return piececlient.NewPSClient
*/
// TODO: handle disconnect
return pdbclient.NewClient(node.Identity, destination.Addr(), apikey)
}
// DialOverlay dials destination and returns an overlay.Client
func (node *Node) DialOverlay(destination *Node) (overlay.Client, error) {
conn, err := node.Transport.DialNode(context.Background(), &destination.Info, grpc.WithBlock())
if err != nil {
return nil, err
}
// TODO: handle disconnect
return overlay.NewClientFrom(pb.NewOverlayClient(conn)), nil
}
// initOverlay creates overlay for a given planet
func (node *Node) initOverlay(planet *Planet) error {
var err error
node.Database, err = satellitedb.NewInMemory()
if err != nil {
return err
}
err = node.Database.CreateTables()
if err != nil {
return err
}
routing, err := kademlia.NewRoutingTable(node.Log.Named("routing"), node.Info, teststore.New(), teststore.New())
if err != nil {
return err
}
kad, err := kademlia.NewKademliaWithRoutingTable(node.Log.Named("kademlia"), node.Info, planet.nodeInfos, node.Identity, 5, routing)
if err != nil {
return utils.CombineErrors(err, routing.Close())
}
node.Kademlia = kad
node.StatDB = node.Database.StatDB()
node.Overlay = overlay.NewCache(teststore.New(), node.StatDB)
node.Discovery = discovery.NewDiscovery(node.Log.Named("discovery"), node.Overlay, node.Kademlia, node.StatDB)
return nil
}
type closerFunc func() error
func (fn closerFunc) Close() error { return fn() }