You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

218 lines
5.4 KiB

package config
import (
"context"
"fmt"
bhost "github.com/libp2p/go-libp2p/p2p/host/basic"
relay "github.com/libp2p/go-libp2p/p2p/host/relay"
routed "github.com/libp2p/go-libp2p/p2p/host/routed"
logging "github.com/ipfs/go-log"
circuit "github.com/libp2p/go-libp2p-circuit"
crypto "github.com/libp2p/go-libp2p-crypto"
discovery "github.com/libp2p/go-libp2p-discovery"
host "github.com/libp2p/go-libp2p-host"
ifconnmgr "github.com/libp2p/go-libp2p-interface-connmgr"
pnet "github.com/libp2p/go-libp2p-interface-pnet"
metrics "github.com/libp2p/go-libp2p-metrics"
inet "github.com/libp2p/go-libp2p-net"
peer "github.com/libp2p/go-libp2p-peer"
pstore "github.com/libp2p/go-libp2p-peerstore"
routing "github.com/libp2p/go-libp2p-routing"
swarm "github.com/libp2p/go-libp2p-swarm"
tptu "github.com/libp2p/go-libp2p-transport-upgrader"
filter "github.com/libp2p/go-maddr-filter"
ma "github.com/multiformats/go-multiaddr"
)
var log = logging.Logger("p2p-config")
// AddrsFactory is a function that takes a set of multiaddrs we're listening on and
// returns the set of multiaddrs we should advertise to the network.
type AddrsFactory = bhost.AddrsFactory
// NATManagerC is a NATManager constructor.
type NATManagerC func(inet.Network) bhost.NATManager
type RoutingC func(host.Host) (routing.PeerRouting, error)
// Config describes a set of settings for a libp2p node
//
// This is *not* a stable interface. Use the options defined in the root
// package.
type Config struct {
PeerKey crypto.PrivKey
Transports []TptC
Muxers []MsMuxC
SecurityTransports []MsSecC
Insecure bool
Protector pnet.Protector
RelayCustom bool
Relay bool
RelayOpts []circuit.RelayOpt
ListenAddrs []ma.Multiaddr
AddrsFactory bhost.AddrsFactory
Filters *filter.Filters
ConnManager ifconnmgr.ConnManager
NATManager NATManagerC
Peerstore pstore.Peerstore
Reporter metrics.Reporter
DisablePing bool
Routing RoutingC
}
// NewNode constructs a new libp2p Host from the Config.
//
// This function consumes the config. Do not reuse it (really!).
func (cfg *Config) NewNode(ctx context.Context) (host.Host, error) {
// Check this early. Prevents us from even *starting* without verifying this.
if pnet.ForcePrivateNetwork && cfg.Protector == nil {
log.Error("tried to create a libp2p node with no Private" +
" Network Protector but usage of Private Networks" +
" is forced by the enviroment")
// Note: This is *also* checked the upgrader itself so it'll be
// enforced even *if* you don't use the libp2p constructor.
return nil, pnet.ErrNotInPrivateNetwork
}
if cfg.PeerKey == nil {
return nil, fmt.Errorf("no peer key specified")
}
// Obtain Peer ID from public key
pid, err := peer.IDFromPublicKey(cfg.PeerKey.GetPublic())
if err != nil {
return nil, err
}
if cfg.Peerstore == nil {
return nil, fmt.Errorf("no peerstore specified")
}
if !cfg.Insecure {
cfg.Peerstore.AddPrivKey(pid, cfg.PeerKey)
cfg.Peerstore.AddPubKey(pid, cfg.PeerKey.GetPublic())
}
// TODO: Make the swarm implementation configurable.
swrm := swarm.NewSwarm(ctx, pid, cfg.Peerstore, cfg.Reporter)
if cfg.Filters != nil {
swrm.Filters = cfg.Filters
}
var h host.Host
h, err = bhost.NewHost(ctx, swrm, &bhost.HostOpts{
ConnManager: cfg.ConnManager,
AddrsFactory: cfg.AddrsFactory,
NATManager: cfg.NATManager,
EnablePing: !cfg.DisablePing,
})
if err != nil {
swrm.Close()
return nil, err
}
upgrader := new(tptu.Upgrader)
upgrader.Protector = cfg.Protector
upgrader.Filters = swrm.Filters
if cfg.Insecure {
upgrader.Secure = makeInsecureTransport(pid)
} else {
upgrader.Secure, err = makeSecurityTransport(h, cfg.SecurityTransports)
if err != nil {
h.Close()
return nil, err
}
}
upgrader.Muxer, err = makeMuxer(h, cfg.Muxers)
if err != nil {
h.Close()
return nil, err
}
tpts, err := makeTransports(h, upgrader, cfg.Transports)
if err != nil {
h.Close()
return nil, err
}
for _, t := range tpts {
err = swrm.AddTransport(t)
if err != nil {
h.Close()
return nil, err
}
}
if cfg.Relay {
err := circuit.AddRelayTransport(swrm.Context(), h, upgrader, cfg.RelayOpts...)
if err != nil {
h.Close()
return nil, err
}
}
// TODO: This method succeeds if listening on one address succeeds. We
// should probably fail if listening on *any* addr fails.
if err := h.Network().Listen(cfg.ListenAddrs...); err != nil {
h.Close()
return nil, err
}
if cfg.Routing != nil {
router, err := cfg.Routing(h)
if err != nil {
h.Close()
return nil, err
}
crouter, ok := router.(routing.ContentRouting)
if ok {
if cfg.Relay {
discovery := discovery.NewRoutingDiscovery(crouter)
hop := false
for _, opt := range cfg.RelayOpts {
if opt == circuit.OptHop {
hop = true
break
}
}
if hop {
h = relay.NewRelayHost(swrm.Context(), h.(*bhost.BasicHost), discovery)
} else {
h = relay.NewAutoRelayHost(swrm.Context(), h.(*bhost.BasicHost), discovery)
}
}
}
h = routed.Wrap(h, router)
}
// TODO: Bootstrapping.
return h, nil
}
// Option is a libp2p config option that can be given to the libp2p constructor
// (`libp2p.New`).
type Option func(cfg *Config) error
// Apply applies the given options to the config, returning the first error
// encountered (if any).
func (cfg *Config) Apply(opts ...Option) error {
for _, opt := range opts {
if err := opt(cfg); err != nil {
return err
}
}
return nil
}