Unverified Commit 8bdf9d0d authored by Steven Allen's avatar Steven Allen Committed by GitHub
Browse files

Merge pull request #299 from libp2p/feat/refactor

refactor for transport changes
parents 4b33a800 a612c7dd
5.0.21: QmY6iAoG9DVgZwh5ZRcQEpa2uErAe1Hbei8qXPCjpDS9Ge 6.0.0: QmRvoAami8AAf5Yy6jcPq5KqQT1ZCaoi9dF1vdKAghmq9X
package config
import (
"context"
"fmt"
bhost "github.com/libp2p/go-libp2p/p2p/host/basic"
logging "github.com/ipfs/go-log"
circuit "github.com/libp2p/go-libp2p-circuit"
crypto "github.com/libp2p/go-libp2p-crypto"
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"
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
// 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
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
}
// 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
}
// TODO: make host implementation configurable.
h, err := bhost.NewHost(ctx, swrm, &bhost.HostOpts{
ConnManager: cfg.ConnManager,
AddrsFactory: cfg.AddrsFactory,
NATManager: cfg.NATManager,
})
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
}
// TODO: Configure routing (it's a pain to setup).
// 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
}
package config
import (
"fmt"
"reflect"
security "github.com/libp2p/go-conn-security"
crypto "github.com/libp2p/go-libp2p-crypto"
host "github.com/libp2p/go-libp2p-host"
pnet "github.com/libp2p/go-libp2p-interface-pnet"
inet "github.com/libp2p/go-libp2p-net"
peer "github.com/libp2p/go-libp2p-peer"
pstore "github.com/libp2p/go-libp2p-peerstore"
transport "github.com/libp2p/go-libp2p-transport"
tptu "github.com/libp2p/go-libp2p-transport-upgrader"
filter "github.com/libp2p/go-maddr-filter"
mux "github.com/libp2p/go-stream-muxer"
)
var (
// interfaces
hostType = reflect.TypeOf((*host.Host)(nil)).Elem()
networkType = reflect.TypeOf((*inet.Network)(nil)).Elem()
transportType = reflect.TypeOf((*transport.Transport)(nil)).Elem()
muxType = reflect.TypeOf((*mux.Transport)(nil)).Elem()
securityType = reflect.TypeOf((*security.Transport)(nil)).Elem()
protectorType = reflect.TypeOf((*pnet.Protector)(nil)).Elem()
privKeyType = reflect.TypeOf((*crypto.PrivKey)(nil)).Elem()
pubKeyType = reflect.TypeOf((*crypto.PubKey)(nil)).Elem()
pstoreType = reflect.TypeOf((*pstore.Peerstore)(nil)).Elem()
// concrete types
peerIDType = reflect.TypeOf((peer.ID)(""))
filtersType = reflect.TypeOf((*filter.Filters)(nil))
upgraderType = reflect.TypeOf((*tptu.Upgrader)(nil))
)
var argTypes = map[reflect.Type]constructor{
upgraderType: func(h host.Host, u *tptu.Upgrader) interface{} { return u },
hostType: func(h host.Host, u *tptu.Upgrader) interface{} { return h },
networkType: func(h host.Host, u *tptu.Upgrader) interface{} { return h.Network() },
muxType: func(h host.Host, u *tptu.Upgrader) interface{} { return u.Muxer },
securityType: func(h host.Host, u *tptu.Upgrader) interface{} { return u.Secure },
protectorType: func(h host.Host, u *tptu.Upgrader) interface{} { return u.Protector },
filtersType: func(h host.Host, u *tptu.Upgrader) interface{} { return u.Filters },
peerIDType: func(h host.Host, u *tptu.Upgrader) interface{} { return h.ID() },
privKeyType: func(h host.Host, u *tptu.Upgrader) interface{} { return h.Peerstore().PrivKey(h.ID()) },
pubKeyType: func(h host.Host, u *tptu.Upgrader) interface{} { return h.Peerstore().PubKey(h.ID()) },
pstoreType: func(h host.Host, u *tptu.Upgrader) interface{} { return h.Peerstore() },
}
func newArgTypeSet(types ...reflect.Type) map[reflect.Type]constructor {
result := make(map[reflect.Type]constructor, len(types))
for _, ty := range types {
c, ok := argTypes[ty]
if !ok {
panic(fmt.Sprintf("missing constructor for type %s", ty))
}
result[ty] = c
}
return result
}
package config
import (
"fmt"
host "github.com/libp2p/go-libp2p-host"
mux "github.com/libp2p/go-stream-muxer"
msmux "github.com/whyrusleeping/go-smux-multistream"
)
// MuxC is a stream multiplex transport constructor
type MuxC func(h host.Host) (mux.Transport, error)
// MsMuxC is a tuple containing a multiplex transport constructor and a protocol
// ID.
type MsMuxC struct {
MuxC
ID string
}
var muxArgTypes = newArgTypeSet(hostType, networkType, peerIDType, pstoreType)
// MuxerConstructor creates a multiplex constructor from the passed parameter
// using reflection.
func MuxerConstructor(m interface{}) (MuxC, error) {
// Already constructed?
if t, ok := m.(mux.Transport); ok {
return func(_ host.Host) (mux.Transport, error) {
return t, nil
}, nil
}
ctor, err := makeConstructor(m, muxType, muxArgTypes)
if err != nil {
return nil, err
}
return func(h host.Host) (mux.Transport, error) {
t, err := ctor(h, nil)
if err != nil {
return nil, err
}
return t.(mux.Transport), nil
}, nil
}
func makeMuxer(h host.Host, tpts []MsMuxC) (mux.Transport, error) {
muxMuxer := msmux.NewBlankTransport()
transportSet := make(map[string]struct{}, len(tpts))
for _, tptC := range tpts {
if _, ok := transportSet[tptC.ID]; ok {
return nil, fmt.Errorf("duplicate muxer transport: %s", tptC.ID)
}
}
for _, tptC := range tpts {
tpt, err := tptC.MuxC(h)
if err != nil {
return nil, err
}
muxMuxer.AddTransport(tptC.ID, tpt)
}
return muxMuxer, nil
}
package config
import (
"testing"
peer "github.com/libp2p/go-libp2p-peer"
mux "github.com/libp2p/go-stream-muxer"
yamux "github.com/whyrusleeping/go-smux-yamux"
)
func TestMuxerSimple(t *testing.T) {
// single
_, err := MuxerConstructor(func(_ peer.ID) mux.Transport { return nil })
if err != nil {
t.Fatal(err)
}
}
func TestMuxerByValue(t *testing.T) {
_, err := MuxerConstructor(yamux.DefaultTransport)
if err != nil {
t.Fatal(err)
}
}
func TestMuxerDuplicate(t *testing.T) {
_, err := MuxerConstructor(func(_ peer.ID, _ peer.ID) mux.Transport { return nil })
if err != nil {
t.Fatal(err)
}
}
func TestMuxerError(t *testing.T) {
_, err := MuxerConstructor(func() (mux.Transport, error) { return nil, nil })
if err != nil {
t.Fatal(err)
}
}
func TestMuxerBadTypes(t *testing.T) {
for i, f := range []interface{}{
func() error { return nil },
func() string { return "" },
func() {},
func(string) mux.Transport { return nil },
func(string) (mux.Transport, error) { return nil, nil },
nil,
"testing",
} {
if _, err := MuxerConstructor(f); err == nil {
t.Fatalf("constructor %d with type %T should have failed", i, f)
}
}
}
package config
import (
"fmt"
"reflect"
"runtime"
host "github.com/libp2p/go-libp2p-host"
tptu "github.com/libp2p/go-libp2p-transport-upgrader"
)
var errorType = reflect.TypeOf((*error)(nil)).Elem()
// checks if a function returns either the specified type or the specified type
// and an error.
func checkReturnType(fnType, tptType reflect.Type) error {
switch fnType.NumOut() {
case 2:
if fnType.Out(1) != errorType {
return fmt.Errorf("expected (optional) second return value from transport constructor to be an error")
}
fallthrough
case 1:
if !fnType.Out(0).Implements(tptType) {
return fmt.Errorf("expected first return value from transport constructor to be a transport")
}
default:
return fmt.Errorf("expected transport constructor to return a transport and, optionally, an error")
}
return nil
}
// Handles return values with optional errors. That is, return values of the
// form `(something, error)` or just `something`.
//
// Panics if the return value isn't of the correct form.
func handleReturnValue(out []reflect.Value) (interface{}, error) {
switch len(out) {
case 2:
err := out[1]
if err != (reflect.Value{}) && !err.IsNil() {
return nil, err.Interface().(error)
}
fallthrough
case 1:
tpt := out[0]
// Check for nil value and nil error.
if tpt == (reflect.Value{}) {
return nil, fmt.Errorf("unspecified error")
}
switch tpt.Kind() {
case reflect.Ptr, reflect.Interface, reflect.Func:
if tpt.IsNil() {
return nil, fmt.Errorf("unspecified error")
}
}
return tpt.Interface(), nil
default:
panic("expected 1 or 2 return values from transport constructor")
}
}
// calls the transport constructor and annotates the error with the name of the constructor.
func callConstructor(c reflect.Value, args []reflect.Value) (interface{}, error) {
val, err := handleReturnValue(c.Call(args))
if err != nil {
name := runtime.FuncForPC(c.Pointer()).Name()
if name != "" {
// makes debugging easier
return nil, fmt.Errorf("transport constructor %s failed: %s", name, err)
}
}
return val, err
}
type constructor func(h host.Host, u *tptu.Upgrader) interface{}
func makeArgumentConstructors(fnType reflect.Type, argTypes map[reflect.Type]constructor) ([]constructor, error) {
out := make([]constructor, fnType.NumIn())
for i := range out {
argType := fnType.In(i)
c, ok := argTypes[argType]
if !ok {
return nil, fmt.Errorf("argument %d has an unexpected type %s", i, argType.Name())
}
out[i] = c
}
return out, nil
}
// makes a transport constructor.
func makeConstructor(
tpt interface{},
tptType reflect.Type,
argTypes map[reflect.Type]constructor,
) (func(host.Host, *tptu.Upgrader) (interface{}, error), error) {
v := reflect.ValueOf(tpt)
// avoid panicing on nil/zero value.
if v == (reflect.Value{}) {
return nil, fmt.Errorf("expected a transport or transport constructor, got a %T", tpt)
}
t := v.Type()
if t.Kind() != reflect.Func {
return nil, fmt.Errorf("expected a transport or transport constructor, got a %T", tpt)
}
if err := checkReturnType(t, tptType); err != nil {
return nil, err
}
argConstructors, err := makeArgumentConstructors(t, argTypes)
if err != nil {
return nil, err
}
return func(h host.Host, u *tptu.Upgrader) (interface{}, error) {
arguments := make([]reflect.Value, len(argConstructors))
for i, makeArg := range argConstructors {
arguments[i] = reflect.ValueOf(makeArg(h, u))
}
return callConstructor(v, arguments)
}, nil
}
package config
import (
"errors"
"reflect"
"strings"
"testing"
)
func TestHandleReturnValue(t *testing.T) {
// one value
v, err := handleReturnValue([]reflect.Value{reflect.ValueOf(1)})
if v.(int) != 1 {
t.Fatal("expected value")
}
if err != nil {
t.Fatal(err)
}
// Nil value
v, err = handleReturnValue([]reflect.Value{reflect.ValueOf(nil)})
if v != nil {
t.Fatal("expected no value")
}
if err == nil {
t.Fatal("expected an error")
}
// Nil value, nil err
v, err = handleReturnValue([]reflect.Value{reflect.ValueOf(nil), reflect.ValueOf(nil)})
if v != nil {
t.Fatal("expected no value")
}
if err == nil {
t.Fatal("expected an error")
}
// two values
v, err = handleReturnValue([]reflect.Value{reflect.ValueOf(1), reflect.ValueOf(nil)})
if v, ok := v.(int); !ok || v != 1 {
t.Fatalf("expected value of 1, got %v", v)
}
if err != nil {
t.Fatal("expected no error")
}
// an error
myError := errors.New("my error")
_, err = handleReturnValue([]reflect.Value{reflect.ValueOf(1), reflect.ValueOf(myError)})
if err != myError {
t.Fatal(err)
}
for _, vals := range [][]reflect.Value{
{reflect.ValueOf(1), reflect.ValueOf("not an error")},
{},
{reflect.ValueOf(1), reflect.ValueOf(myError), reflect.ValueOf(myError)},
} {
func() {
defer func() { recover() }()
handleReturnValue(vals)
t.Fatal("expected a panic")
}()
}
}
type foo interface {
foo() foo
}
var fooType = reflect.TypeOf((*foo)(nil)).Elem()
func TestCheckReturnType(t *testing.T) {
for i, fn := range []interface{}{
func() { panic("") },
func() error { panic("") },
func() (error, error) { panic("") },
func() (foo, error, error) { panic("") },
func() (foo, foo) { panic("") },
} {
if checkReturnType(reflect.TypeOf(fn), fooType) == nil {
t.Errorf("expected falure for case %d (type %T)", i, fn)
}
}
for i, fn := range []interface{}{
func() foo { panic("") },
func() (foo, error) { panic("") },
} {
if err := checkReturnType(reflect.TypeOf(fn), fooType); err != nil {
t.Errorf("expected success for case %d (type %T), got: %s", i, fn, err)
}
}
}
func constructFoo() foo {
return nil
}
type fooImpl struct{}
func (f *fooImpl) foo() foo { return nil }
func TestCallConstructor(t *testing.T) {
_, err := callConstructor(reflect.ValueOf(constructFoo), nil)
if err == nil {
t.Fatal("expected constructor to fail")
}
if !strings.Contains(err.Error(), "constructFoo") {
t.Errorf("expected error to contain the constructor name: %s", err)
}
v, err := callConstructor(reflect.ValueOf(func() foo { return &fooImpl{} }), nil)
if err != nil {
t.Fatal(err)
}
if _, ok := v.(*fooImpl); !ok {
t.Fatal("expected a fooImpl")
}
v, err = callConstructor(reflect.ValueOf(func() *fooImpl { return new(fooImpl) }), nil)
if err != nil {
t.Fatal(err)
}
if _, ok := v.(*fooImpl); !ok {
t.Fatal("expected a fooImpl")
}
_, err = callConstructor(reflect.ValueOf(func() (*fooImpl, error) { return nil, nil }), nil)
if err == nil {
t.Fatal("expected error")
}
v, err = callConstructor(reflect.ValueOf(func() (*fooImpl, error) { return new(fooImpl), nil }), nil)
if err != nil {
t.Fatal(err)
}
if _, ok := v.(*fooImpl); !ok {
t.Fatal("expected a fooImpl")
}
}
package config
import (
"fmt"
security "github.com/libp2p/go-conn-security"
csms "github.com/libp2p/go-conn-security-multistream"
insecure "github.com/libp2p/go-conn-security/insecure"
host "github.com/libp2p/go-libp2p-host"
peer "github.com/libp2p/go-libp2p-peer"
)
// SecC is a security transport constructor
type SecC func(h host.Host) (security.Transport, error)
// MsSecC is a tuple containing a security transport constructor and a protocol
// ID.
type MsSecC struct {
SecC
ID string
}
var securityArgTypes = newArgTypeSet(
hostType, networkType, peerIDType,
privKeyType, pubKeyType, pstoreType,
)
// SecurityConstructor creates a security constructor from the passed parameter
// using reflection.
func SecurityConstructor(sec interface{}) (SecC, error) {
// Already constructed?
if t, ok := sec.(security.Transport); ok {
return func(_ host.Host) (security.Transport, error) {
return t, nil
}, nil
}
ctor, err := makeConstructor(sec, securityType, securityArgTypes)
if err != nil {
return nil, err
}
return func(h host.Host) (security.Transport, error) {
t, err := ctor(h, nil)
if err != nil {
return nil, err
}
return t.(security.Transport), nil
}, nil
}
func makeInsecureTransport(id peer.ID) security.Transport {
secMuxer := new(csms.SSMuxer)
secMuxer.AddTransport(insecure.ID, insecure.New(id))
return secMuxer
}
func makeSecurityTransport(h host.Host, tpts []MsSecC) (security.Transport, error) {
secMuxer := new(csms.SSMuxer)
transportSet := make(map[string]struct{}, len(tpts))
for _, tptC := range tpts {
if _, ok := transportSet[tptC.ID]; ok {
return nil, fmt.Errorf("duplicate security transport: %s", tptC.ID)
}
}
for _, tptC := range tpts {
tpt, err := tptC.SecC(h)
if err != nil {
return nil, err
}
if _, ok := tpt.(*insecure.Transport); ok {
return nil, fmt.Errorf("cannot construct libp2p with an insecure transport, set the Insecure config option instead")
}
secMuxer.AddTransport(tptC.ID, tpt)
}
return secMuxer, nil
}
package config
import (
host "github.com/libp2p/go-libp2p-host"
transport "github.com/libp2p/go-libp2p-transport"
tptu "github.com/libp2p/go-libp2p-transport-upgrader"
)
// TptC is the type for libp2p transport constructors. You probably won't ever
// implement this function interface directly. Instead, pass your transport
// constructor to TransportConstructor.
type TptC func(h host.Host, u *tptu.Upgrader) (transport.Transport, error)
var transportArgTypes = argTypes
// TransportConstructor uses reflection to turn a function that constructs a
// transport into a TptC.
//
// You can pass either a constructed transport (something that implements
// `transport.Transport`) or a function that takes any of:
//
// * The local peer ID.
// * A transport connection upgrader.
// * A private key.
// * A public key.
// * A Host.
// * A Network.
// * A Peerstore.
// * An address filter.
// * A security transport.
// * A stream multiplexer transport.
// * A private network protector.
//
// And returns a type implementing transport.Transport and, optionally, an error
// (as the second argument).
func TransportConstructor(tpt interface{}) (TptC, error) {
// Already constructed?
if t, ok := tpt.(transport.Transport); ok {
return func(_ host.Host, _ *tptu.Upgrader) (transport.Transport, error) {
return t, nil
}, nil
}
ctor, err := makeConstructor(tpt, transportType, transportArgTypes)
if err != nil {
return nil, err
}
return func(h host.Host, u *tptu.Upgrader) (transport.Transport, error) {
t, err := ctor(h, u)
if err != nil {
return nil, err
}
return t.(transport.Transport), nil
}, nil
}
func makeTransports(h host.Host, u *tptu.Upgrader, tpts []TptC) ([]transport.Transport, error) {
transports := make([]transport.Transport, len(tpts))
for i, tC := range tpts {
t, err := tC(h, u)
if err != nil {
return nil, err
}
transports[i] = t
}
return transports, nil
}
package libp2p
// This file contains all the default configuration options.
import (
"crypto/rand"
crypto "github.com/libp2p/go-libp2p-crypto"
pstore "github.com/libp2p/go-libp2p-peerstore"
secio "github.com/libp2p/go-libp2p-secio"
tcp "github.com/libp2p/go-tcp-transport"
ws "github.com/libp2p/go-ws-transport"
mplex "github.com/whyrusleeping/go-smux-multiplex"
yamux "github.com/whyrusleeping/go-smux-yamux"
)
// DefaultSecurity is the default security option.
//
// Useful when you want to extend, but not replace, the supported transport
// security protocols.
var DefaultSecurity = Security(secio.ID, secio.New)
// DefaultMuxer configures libp2p to use the stream connection multiplexers.
//
// Use this option when you want to *extend* the set of multiplexers used by
// libp2p instead of replacing them.
var DefaultMuxers = ChainOptions(
Muxer("/yamux/1.0.0", yamux.DefaultTransport),
Muxer("/mplex/6.3.0", mplex.DefaultTransport),
)
// DefaultTransports are the default libp2p transports.
//
// Use this option when you want to *extend* the set of multiplexers used by
// libp2p instead of replacing them.
var DefaultTransports = ChainOptions(
Transport(tcp.NewTCPTransport),
Transport(ws.New),
)
// DefaultPeerstore configures libp2p to use the default peerstore.
var DefaultPeerstore Option = func(cfg *Config) error {
return cfg.Apply(Peerstore(pstore.NewPeerstore()))
}
// RandomIdentity generates a random identity (default behaviour)
var RandomIdentity = func(cfg *Config) error {
priv, _, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, rand.Reader)
if err != nil {
return err
}
return cfg.Apply(Identity(priv))
}
// Complete list of default options and when to fallback on them.
//
// Please *DON'T* specify default options any other way. Putting this all here
// makes tracking defaults *much* easier.
var defaults = []struct {
fallback func(cfg *Config) bool
opt Option
}{
{
fallback: func(cfg *Config) bool { return cfg.Transports == nil },
opt: DefaultTransports,
},
{
fallback: func(cfg *Config) bool { return cfg.Muxers == nil },
opt: DefaultMuxers,
},
{
fallback: func(cfg *Config) bool { return !cfg.Insecure && cfg.SecurityTransports == nil },
opt: DefaultSecurity,
},
{
fallback: func(cfg *Config) bool { return cfg.PeerKey == nil },
opt: RandomIdentity,
},
{
fallback: func(cfg *Config) bool { return cfg.Peerstore == nil },
opt: DefaultPeerstore,
},
}
// Defaults configures libp2p to use the default options. Can be combined with
// other options to *extend* the default options.
var Defaults Option = func(cfg *Config) error {
for _, def := range defaults {
if err := cfg.Apply(def.opt); err != nil {
return err
}
}
return nil
}
// FallbackDefaults applies default options to the libp2p node if and only if no
// other relevent options have been applied. will be appended to the options
// passed into New.
var FallbackDefaults Option = func(cfg *Config) error {
for _, def := range defaults {
if !def.fallback(cfg) {
continue
}
if err := cfg.Apply(def.opt); err != nil {
return err
}
}
return nil
}
package libp2p
import (
"fmt"
"runtime"
)
func traceError(err error, skip int) error {
if err == nil {
return nil
}
_, file, line, ok := runtime.Caller(skip + 1)
if !ok {
return err
}
return fmt.Errorf("%s:%d: %s", file, line, err)
}
...@@ -39,13 +39,13 @@ import ( ...@@ -39,13 +39,13 @@ import (
mrand "math/rand" mrand "math/rand"
"os" "os"
"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p-crypto" "github.com/libp2p/go-libp2p-crypto"
"github.com/libp2p/go-libp2p-host" "github.com/libp2p/go-libp2p-host"
"github.com/libp2p/go-libp2p-net" "github.com/libp2p/go-libp2p-net"
"github.com/libp2p/go-libp2p-peer" "github.com/libp2p/go-libp2p-peer"
"github.com/libp2p/go-libp2p-peerstore" "github.com/libp2p/go-libp2p-peerstore"
"github.com/libp2p/go-libp2p-swarm"
"github.com/libp2p/go-libp2p/p2p/host/basic"
"github.com/multiformats/go-multiaddr" "github.com/multiformats/go-multiaddr"
) )
...@@ -155,37 +155,27 @@ func main() { ...@@ -155,37 +155,27 @@ func main() {
} }
// Creates a new RSA key pair for this host // Creates a new RSA key pair for this host
prvKey, pubKey, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, r) prvKey, _, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, r)
if err != nil { if err != nil {
panic(err) panic(err)
} }
// Getting host ID from public key.
// host ID is the hash of public key
nodeID, _ := peer.IDFromPublicKey(pubKey)
// 0.0.0.0 will listen on any interface device // 0.0.0.0 will listen on any interface device
sourceMultiAddr, _ := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", *sourcePort)) sourceMultiAddr, _ := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", *sourcePort))
// Adding self to the peerstore. // libp2p.New constructs a new libp2p Host.
ps := peerstore.NewPeerstore() // Other options can be added here.
ps.AddPrivKey(nodeID, prvKey) host, err := libp2p.New(
ps.AddPubKey(nodeID, pubKey) context.Background(),
libp2p.ListenAddrs(sourceMultiAddr),
// Creating a new Swarm network. libp2p.Identity(prvKey),
network, err := swarm.NewNetwork(context.Background(), []multiaddr.Multiaddr{sourceMultiAddr}, nodeID, ps, nil) )
if err != nil { if err != nil {
panic(err) panic(err)
} }
// NewHost constructs a new *BasicHost and activates it by attaching its
// stream and connection handlers to the given inet.Network (network).
// Other options like NATManager can also be added here.
// See docs: https://godoc.org/github.com/libp2p/go-libp2p/p2p/host/basic#HostOpts
host := basichost.New(network)
if *dest == "" { if *dest == "" {
// Set a function as stream handler. // Set a function as stream handler.
// This function is called when a peer initiate a connection and starts a stream with this peer. // This function is called when a peer initiate a connection and starts a stream with this peer.
......
...@@ -49,7 +49,7 @@ func makeBasicHost(listenPort int, secio bool, randseed int64) (host.Host, error ...@@ -49,7 +49,7 @@ func makeBasicHost(listenPort int, secio bool, randseed int64) (host.Host, error
} }
if !secio { if !secio {
opts = append(opts, libp2p.NoEncryption()) opts = append(opts, libp2p.NoSecurity)
} }
basicHost, err := libp2p.New(context.Background(), opts...) basicHost, err := libp2p.New(context.Background(), opts...)
......
...@@ -12,16 +12,14 @@ import ( ...@@ -12,16 +12,14 @@ import (
// We need to import libp2p's libraries that we use in this project. // We need to import libp2p's libraries that we use in this project.
// In order to work, these libraries need to be rewritten by gx-go. // In order to work, these libraries need to be rewritten by gx-go.
crypto "github.com/libp2p/go-libp2p-crypto"
host "github.com/libp2p/go-libp2p-host" host "github.com/libp2p/go-libp2p-host"
inet "github.com/libp2p/go-libp2p-net" inet "github.com/libp2p/go-libp2p-net"
peer "github.com/libp2p/go-libp2p-peer" peer "github.com/libp2p/go-libp2p-peer"
ps "github.com/libp2p/go-libp2p-peerstore" ps "github.com/libp2p/go-libp2p-peerstore"
swarm "github.com/libp2p/go-libp2p-swarm"
ma "github.com/multiformats/go-multiaddr" ma "github.com/multiformats/go-multiaddr"
manet "github.com/multiformats/go-multiaddr-net" manet "github.com/multiformats/go-multiaddr-net"
bhost "github.com/libp2p/go-libp2p/p2p/host/basic" libp2p "github.com/libp2p/go-libp2p"
) )
// Protocol defines the libp2p protocol that we will use for the libp2p proxy // Protocol defines the libp2p protocol that we will use for the libp2p proxy
...@@ -33,27 +31,11 @@ const Protocol = "/proxy-example/0.0.1" ...@@ -33,27 +31,11 @@ const Protocol = "/proxy-example/0.0.1"
// makeRandomHost creates a libp2p host with a randomly generated identity. // makeRandomHost creates a libp2p host with a randomly generated identity.
// This step is described in depth in other tutorials. // This step is described in depth in other tutorials.
func makeRandomHost(port int) host.Host { func makeRandomHost(port int) host.Host {
priv, pub, err := crypto.GenerateKeyPair(crypto.RSA, 2048) host, err := libp2p.New(context.Background(), libp2p.ListenAddrStrings(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", port)))
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
pid, err := peer.IDFromPublicKey(pub) return host
if err != nil {
log.Fatalln(err)
}
listen, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", port))
if err != nil {
log.Fatalln(err)
}
ps := ps.NewPeerstore()
ps.AddPrivKey(pid, priv)
ps.AddPubKey(pid, pub)
n, err := swarm.NewNetwork(context.Background(),
[]ma.Multiaddr{listen}, pid, ps, nil)
if err != nil {
log.Fatalln(err)
}
return bhost.New(n)
} }
// ProxyService provides HTTP proxying on top of libp2p by launching an // ProxyService provides HTTP proxying on top of libp2p by launching an
......
...@@ -6,11 +6,9 @@ import ( ...@@ -6,11 +6,9 @@ import (
"log" "log"
"math/rand" "math/rand"
libp2p "github.com/libp2p/go-libp2p"
crypto "github.com/libp2p/go-libp2p-crypto" crypto "github.com/libp2p/go-libp2p-crypto"
peer "github.com/libp2p/go-libp2p-peer"
ps "github.com/libp2p/go-libp2p-peerstore" ps "github.com/libp2p/go-libp2p-peerstore"
swarm "github.com/libp2p/go-libp2p-swarm"
bhost "github.com/libp2p/go-libp2p/p2p/host/basic"
ma "github.com/multiformats/go-multiaddr" ma "github.com/multiformats/go-multiaddr"
) )
...@@ -18,14 +16,13 @@ import ( ...@@ -18,14 +16,13 @@ import (
func makeRandomNode(port int, done chan bool) *Node { func makeRandomNode(port int, done chan bool) *Node {
// Ignoring most errors for brevity // Ignoring most errors for brevity
// See echo example for more details and better implementation // See echo example for more details and better implementation
priv, pub, _ := crypto.GenerateKeyPair(crypto.Secp256k1, 256) priv, _, _ := crypto.GenerateKeyPair(crypto.Secp256k1, 256)
pid, _ := peer.IDFromPublicKey(pub)
listen, _ := ma.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", port)) listen, _ := ma.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", port))
peerStore := ps.NewPeerstore() host, _ := libp2p.New(
peerStore.AddPrivKey(pid, priv) context.Background(),
peerStore.AddPubKey(pid, pub) libp2p.ListenAddrs(listen),
n, _ := swarm.NewNetwork(context.Background(), []ma.Multiaddr{listen}, pid, peerStore, nil) libp2p.Identity(priv),
host := bhost.New(n) )
return NewNode(host, done) return NewNode(host, done)
} }
......
...@@ -8,15 +8,11 @@ import ( ...@@ -8,15 +8,11 @@ import (
"math/rand" "math/rand"
"time" "time"
crypto "github.com/libp2p/go-libp2p-crypto"
host "github.com/libp2p/go-libp2p-host" host "github.com/libp2p/go-libp2p-host"
inet "github.com/libp2p/go-libp2p-net" inet "github.com/libp2p/go-libp2p-net"
peer "github.com/libp2p/go-libp2p-peer"
ps "github.com/libp2p/go-libp2p-peerstore" ps "github.com/libp2p/go-libp2p-peerstore"
swarm "github.com/libp2p/go-libp2p-swarm"
ma "github.com/multiformats/go-multiaddr"
bhost "github.com/libp2p/go-libp2p/p2p/host/basic" libp2p "github.com/libp2p/go-libp2p"
multicodec "github.com/multiformats/go-multicodec" multicodec "github.com/multiformats/go-multicodec"
json "github.com/multiformats/go-multicodec/json" json "github.com/multiformats/go-multicodec/json"
) )
...@@ -80,17 +76,11 @@ var conversationMsgs = []string{ ...@@ -80,17 +76,11 @@ var conversationMsgs = []string{
} }
func makeRandomHost(port int) host.Host { func makeRandomHost(port int) host.Host {
// Ignoring most errors for brevity h, err := libp2p.New(context.Background(), libp2p.ListenAddrStrings(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", port)))
// See echo example for more details and better implementation if err != nil {
priv, pub, _ := crypto.GenerateKeyPair(crypto.RSA, 2048) panic(err)
pid, _ := peer.IDFromPublicKey(pub) }
listen, _ := ma.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", port)) return h
ps := ps.NewPeerstore()
ps.AddPrivKey(pid, priv)
ps.AddPubKey(pid, pub)
n, _ := swarm.NewNetwork(context.Background(),
[]ma.Multiaddr{listen}, pid, ps, nil)
return bhost.New(n)
} }
func main() { func main() {
......
...@@ -2,240 +2,49 @@ package libp2p ...@@ -2,240 +2,49 @@ package libp2p
import ( import (
"context" "context"
"crypto/rand"
"fmt"
crypto "github.com/libp2p/go-libp2p-crypto" config "github.com/libp2p/go-libp2p/config"
host "github.com/libp2p/go-libp2p-host" host "github.com/libp2p/go-libp2p-host"
pnet "github.com/libp2p/go-libp2p-interface-pnet"
metrics "github.com/libp2p/go-libp2p-metrics"
peer "github.com/libp2p/go-libp2p-peer"
pstore "github.com/libp2p/go-libp2p-peerstore"
swarm "github.com/libp2p/go-libp2p-swarm"
transport "github.com/libp2p/go-libp2p-transport"
bhost "github.com/libp2p/go-libp2p/p2p/host/basic"
mux "github.com/libp2p/go-stream-muxer"
ma "github.com/multiformats/go-multiaddr"
mplex "github.com/whyrusleeping/go-smux-multiplex"
msmux "github.com/whyrusleeping/go-smux-multistream"
yamux "github.com/whyrusleeping/go-smux-yamux"
) )
// Config describes a set of settings for a libp2p node // Config describes a set of settings for a libp2p node
type Config struct { type Config = config.Config
Transports []transport.Transport
Muxer mux.Transport
ListenAddrs []ma.Multiaddr
PeerKey crypto.PrivKey
Peerstore pstore.Peerstore
Protector pnet.Protector
Reporter metrics.Reporter
DisableSecio bool
EnableNAT bool
}
type Option func(cfg *Config) error
func Transports(tpts ...transport.Transport) Option { // Option is a libp2p config option that can be given to the libp2p constructor
return func(cfg *Config) error { // (`libp2p.New`).
cfg.Transports = append(cfg.Transports, tpts...) type Option = config.Option
return nil
}
}
func ListenAddrStrings(s ...string) Option { // ChainOptions chains multiple options into a single option.
func ChainOptions(opts ...Option) Option {
return func(cfg *Config) error { return func(cfg *Config) error {
for _, addrstr := range s { for _, opt := range opts {
a, err := ma.NewMultiaddr(addrstr) if err := opt(cfg); err != nil {
if err != nil {
return err return err
} }
cfg.ListenAddrs = append(cfg.ListenAddrs, a)
}
return nil
}
}
func ListenAddrs(addrs ...ma.Multiaddr) Option {
return func(cfg *Config) error {
cfg.ListenAddrs = append(cfg.ListenAddrs, addrs...)
return nil
}
}
type transportEncOpt int
const (
EncPlaintext = transportEncOpt(0)
EncSecio = transportEncOpt(1)
)
func TransportEncryption(tenc ...transportEncOpt) Option {
return func(cfg *Config) error {
if len(tenc) != 1 {
return fmt.Errorf("can only specify a single transport encryption option right now")
}
// TODO: actually make this pluggable, otherwise tls will get tricky
switch tenc[0] {
case EncPlaintext:
cfg.DisableSecio = true
case EncSecio:
// noop
default:
return fmt.Errorf("unrecognized transport encryption option: %d", tenc[0])
}
return nil
}
}
func NoEncryption() Option {
return TransportEncryption(EncPlaintext)
}
func NATPortMap() Option {
return func(cfg *Config) error {
cfg.EnableNAT = true
return nil
}
}
func Muxer(m mux.Transport) Option {
return func(cfg *Config) error {
if cfg.Muxer != nil {
return fmt.Errorf("cannot specify multiple muxer options")
} }
cfg.Muxer = m
return nil
}
}
func Peerstore(ps pstore.Peerstore) Option {
return func(cfg *Config) error {
if cfg.Peerstore != nil {
return fmt.Errorf("cannot specify multiple peerstore options")
}
cfg.Peerstore = ps
return nil
}
}
func PrivateNetwork(prot pnet.Protector) Option {
return func(cfg *Config) error {
if cfg.Protector != nil {
return fmt.Errorf("cannot specify multiple private network options")
}
cfg.Protector = prot
return nil
}
}
func BandwidthReporter(rep metrics.Reporter) Option {
return func(cfg *Config) error {
if cfg.Reporter != nil {
return fmt.Errorf("cannot specify multiple bandwidth reporter options")
}
cfg.Reporter = rep
return nil
}
}
func Identity(sk crypto.PrivKey) Option {
return func(cfg *Config) error {
if cfg.PeerKey != nil {
return fmt.Errorf("cannot specify multiple identities")
}
cfg.PeerKey = sk
return nil return nil
} }
} }
// New constructs a new libp2p node with the given options (falling back on
// reasonable defaults).
//
// Canceling the passed context will stop the returned libp2p node.
func New(ctx context.Context, opts ...Option) (host.Host, error) { func New(ctx context.Context, opts ...Option) (host.Host, error) {
var cfg Config return NewWithoutDefaults(ctx, append(opts, FallbackDefaults)...)
for _, opt := range opts {
if err := opt(&cfg); err != nil {
return nil, err
}
}
return newWithCfg(ctx, &cfg)
} }
func newWithCfg(ctx context.Context, cfg *Config) (host.Host, error) { // NewWithoutDefaults constructs a new libp2p node with the given options but
// If no key was given, generate a random 2048 bit RSA key // *without* falling back on reasonable defaults.
if cfg.PeerKey == nil { //
priv, _, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, rand.Reader) // Warning: This function should not be considered a stable interface. We may
if err != nil { // choose to add required services at any time and, by using this function, you
return nil, err // opt-out of any defaults we may provide.
} func NewWithoutDefaults(ctx context.Context, opts ...Option) (host.Host, error) {
cfg.PeerKey = priv var cfg Config
} if err := cfg.Apply(opts...); err != nil {
// Obtain Peer ID from public key
pid, err := peer.IDFromPublicKey(cfg.PeerKey.GetPublic())
if err != nil {
return nil, err
}
// Create a new blank peerstore if none was passed in
ps := cfg.Peerstore
if ps == nil {
ps = pstore.NewPeerstore()
}
// Set default muxer if none was passed in
muxer := cfg.Muxer
if muxer == nil {
muxer = DefaultMuxer()
}
// If secio is disabled, don't add our private key to the peerstore
if !cfg.DisableSecio {
ps.AddPrivKey(pid, cfg.PeerKey)
ps.AddPubKey(pid, cfg.PeerKey.GetPublic())
}
swrm, err := swarm.NewSwarmWithProtector(ctx, cfg.ListenAddrs, pid, ps, cfg.Protector, muxer, cfg.Reporter)
if err != nil {
return nil, err return nil, err
} }
return cfg.NewNode(ctx)
netw := (*swarm.Network)(swrm)
hostOpts := &bhost.HostOpts{}
if cfg.EnableNAT {
hostOpts.NATManager = bhost.NewNATManager(netw)
}
return bhost.NewHost(ctx, netw, hostOpts)
}
func DefaultMuxer() mux.Transport {
// Set up stream multiplexer
tpt := msmux.NewBlankTransport()
// By default, support yamux and multiplex
tpt.AddTransport("/yamux/1.0.0", yamux.DefaultTransport)
tpt.AddTransport("/mplex/6.3.0", mplex.DefaultTransport)
return tpt
}
func Defaults(cfg *Config) error {
// Create a multiaddress that listens on a random port on all interfaces
addr, err := ma.NewMultiaddr("/ip4/0.0.0.0/tcp/0")
if err != nil {
return err
}
cfg.ListenAddrs = []ma.Multiaddr{addr}
cfg.Peerstore = pstore.NewPeerstore()
cfg.Muxer = DefaultMuxer()
return nil
} }
...@@ -3,6 +3,7 @@ package libp2p ...@@ -3,6 +3,7 @@ package libp2p
import ( import (
"context" "context"
"fmt" "fmt"
"strings"
"testing" "testing"
crypto "github.com/libp2p/go-libp2p-crypto" crypto "github.com/libp2p/go-libp2p-crypto"
...@@ -10,10 +11,32 @@ import ( ...@@ -10,10 +11,32 @@ import (
) )
func TestNewHost(t *testing.T) { func TestNewHost(t *testing.T) {
_, err := makeRandomHost(t, 9000) h, err := makeRandomHost(t, 9000)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
h.Close()
}
func TestBadTransportConstructor(t *testing.T) {
ctx := context.Background()
h, err := New(ctx, Transport(func() {}))
if err == nil {
h.Close()
t.Fatal("expected an error")
}
if !strings.Contains(err.Error(), "libp2p_test.go") {
t.Error("expected error to contain debugging info")
}
}
func TestInsecure(t *testing.T) {
ctx := context.Background()
h, err := New(ctx, NoSecurity)
if err != nil {
t.Fatal(err)
}
h.Close()
} }
func makeRandomHost(t *testing.T, port int) (host.Host, error) { func makeRandomHost(t *testing.T, port int) (host.Host, error) {
...@@ -26,7 +49,9 @@ func makeRandomHost(t *testing.T, port int) (host.Host, error) { ...@@ -26,7 +49,9 @@ func makeRandomHost(t *testing.T, port int) (host.Host, error) {
opts := []Option{ opts := []Option{
ListenAddrStrings(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", port)), ListenAddrStrings(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", port)),
Identity(priv), Identity(priv),
Muxer(DefaultMuxer()), DefaultTransports,
DefaultMuxers,
DefaultSecurity,
NATPortMap(), NATPortMap(),
} }
......
package libp2p
// This file contains all libp2p configuration options (except the defaults,
// those are in defaults.go)
import (
"fmt"
"net"
config "github.com/libp2p/go-libp2p/config"
bhost "github.com/libp2p/go-libp2p/p2p/host/basic"
circuit "github.com/libp2p/go-libp2p-circuit"
crypto "github.com/libp2p/go-libp2p-crypto"
ifconnmgr "github.com/libp2p/go-libp2p-interface-connmgr"
pnet "github.com/libp2p/go-libp2p-interface-pnet"
metrics "github.com/libp2p/go-libp2p-metrics"
pstore "github.com/libp2p/go-libp2p-peerstore"
filter "github.com/libp2p/go-maddr-filter"
ma "github.com/multiformats/go-multiaddr"
)
// ListenAddrStrings configures libp2p to listen on the given (unparsed)
// addresses.
func ListenAddrStrings(s ...string) Option {
return func(cfg *Config) error {
for _, addrstr := range s {
a, err := ma.NewMultiaddr(addrstr)
if err != nil {
return err
}
cfg.ListenAddrs = append(cfg.ListenAddrs, a)
}
return nil
}
}
// ListenAddrs configures libp2p to listen on the given addresses.
func ListenAddrs(addrs ...ma.Multiaddr) Option {
return func(cfg *Config) error {
cfg.ListenAddrs = append(cfg.ListenAddrs, addrs...)
return nil
}
}
// Security configures libp2p to use the given security transport (or transport
// constructor).
//
// Name is the protocol name.
//
// The transport can be a constructed security.Transport or a function taking
// any subset of this libp2p node's:
// * Public key
// * Private key
// * Peer ID
// * Host
// * Network
// * Peerstore
func Security(name string, tpt interface{}) Option {
stpt, err := config.SecurityConstructor(tpt)
err = traceError(err, 1)
return func(cfg *Config) error {
if err != nil {
return err
}
if cfg.Insecure {
return fmt.Errorf("cannot use security transports with an insecure libp2p configuration")
}
cfg.SecurityTransports = append(cfg.SecurityTransports, config.MsSecC{SecC: stpt, ID: name})
return nil
}
}
// NoSecurity is an option that completely disables all transport security.
// It's incompatible with all other transport security protocols.
var NoSecurity Option = func(cfg *Config) error {
if len(cfg.SecurityTransports) > 0 {
return fmt.Errorf("cannot use security transports with an insecure libp2p configuration")
}
cfg.Insecure = true
return nil
}
// Muxer configures libp2p to use the given stream multiplexer (or stream
// multiplexer constructor).
//
// Name is the protocol name.
//
// The transport can be a constructed mux.Transport or a function taking any
// subset of this libp2p node's:
// * Peer ID
// * Host
// * Network
// * Peerstore
func Muxer(name string, tpt interface{}) Option {
mtpt, err := config.MuxerConstructor(tpt)
err = traceError(err, 1)
return func(cfg *Config) error {
if err != nil {
return err
}
cfg.Muxers = append(cfg.Muxers, config.MsMuxC{MuxC: mtpt, ID: name})
return nil
}
}
// Transport configures libp2p to use the given transport (or transport
// constructor).
//
// The transport can be a constructed transport.Transport or a function taking
// any subset of this libp2p node's:
// * Transport Upgrader (*tptu.Upgrader)
// * Host
// * Stream muxer (muxer.Transport)
// * Security transport (security.Transport)
// * Private network protector (pnet.Protector)
// * Peer ID
// * Private Key
// * Public Key
// * Address filter (filter.Filter)
// * Peerstore
func Transport(tpt interface{}) Option {
tptc, err := config.TransportConstructor(tpt)
err = traceError(err, 1)
return func(cfg *Config) error {
if err != nil {
return err
}
cfg.Transports = append(cfg.Transports, tptc)
return nil
}
}
// Peerstore configures libp2p to use the given peerstore.
func Peerstore(ps pstore.Peerstore) Option {
return func(cfg *Config) error {
if cfg.Peerstore != nil {
return fmt.Errorf("cannot specify multiple peerstore options")
}
cfg.Peerstore = ps
return nil
}
}
// PrivateNetwork configures libp2p to use the given private network protector.
func PrivateNetwork(prot pnet.Protector) Option {
return func(cfg *Config) error {
if cfg.Protector != nil {
return fmt.Errorf("cannot specify multiple private network options")
}
cfg.Protector = prot
return nil
}
}
// BandwidthReporter configures libp2p to use the given bandwidth reporter.
func BandwidthReporter(rep metrics.Reporter) Option {
return func(cfg *Config) error {
if cfg.Reporter != nil {
return fmt.Errorf("cannot specify multiple bandwidth reporter options")
}
cfg.Reporter = rep
return nil
}
}
// Identity configures libp2p to use the given private key to identify itself.
func Identity(sk crypto.PrivKey) Option {
return func(cfg *Config) error {
if cfg.PeerKey != nil {
return fmt.Errorf("cannot specify multiple identities")
}
cfg.PeerKey = sk
return nil
}
}
// ConnectionManager configures libp2p to use the given connection manager.
func ConnectionManager(connman ifconnmgr.ConnManager) Option {
return func(cfg *Config) error {
if cfg.ConnManager != nil {
return fmt.Errorf("cannot specify multiple connection managers")
}
cfg.ConnManager = connman
return nil
}
}
// AddrsFactory configures libp2p to use the given address factory.
func AddrsFactory(factory config.AddrsFactory) Option {
return func(cfg *Config) error {
if cfg.AddrsFactory != nil {
return fmt.Errorf("cannot specify multiple address factories")
}
cfg.AddrsFactory = factory
return nil
}
}
// EnableRelay configures libp2p to enable the relay transport.
func EnableRelay(options ...circuit.RelayOpt) Option {
return func(cfg *Config) error {
cfg.Relay = true
cfg.RelayOpts = options
return nil
}
}
// FilterAddresses configures libp2p to never dial nor accept connections from
// the given addresses.
func FilterAddresses(addrs ...*net.IPNet) Option {
return func(cfg *Config) error {
if cfg.Filters == nil {
cfg.Filters = filter.NewFilters()
}
for _, addr := range addrs {
cfg.Filters.AddDialFilter(addr)
}
return nil
}
}
// NATPortMap configures libp2p to use the default NATManager. The default
// NATManager will attempt to open a port in your network's firewall using UPnP.
func NATPortMap() Option {
return NATManager(bhost.NewNATManager)
}
// NATManager will configure libp2p to use the requested NATManager. This
// function should be passed a NATManager *constructor* that takes a libp2p Network.
func NATManager(nm config.NATManagerC) Option {
return func(cfg *Config) error {
if cfg.NATManager != nil {
return fmt.Errorf("cannot specify multiple NATManagers")
}
cfg.NATManager = nm
return nil
}
}
...@@ -8,7 +8,7 @@ import ( ...@@ -8,7 +8,7 @@ import (
bhost "github.com/libp2p/go-libp2p/p2p/host/basic" bhost "github.com/libp2p/go-libp2p/p2p/host/basic"
host "github.com/libp2p/go-libp2p-host" host "github.com/libp2p/go-libp2p-host"
netutil "github.com/libp2p/go-libp2p-netutil" swarmt "github.com/libp2p/go-libp2p-swarm/testing"
pstore "github.com/libp2p/go-libp2p-peerstore" pstore "github.com/libp2p/go-libp2p-peerstore"
) )
...@@ -28,8 +28,8 @@ func TestMdnsDiscovery(t *testing.T) { ...@@ -28,8 +28,8 @@ func TestMdnsDiscovery(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel() defer cancel()
a := bhost.New(netutil.GenSwarmNetwork(t, ctx)) a := bhost.New(swarmt.GenSwarm(t, ctx))
b := bhost.New(netutil.GenSwarmNetwork(t, ctx)) b := bhost.New(swarmt.GenSwarm(t, ctx))
sa, err := NewMdnsService(ctx, a, time.Second, "someTag") sa, err := NewMdnsService(ctx, a, time.Second, "someTag")
if err != nil { if err != nil {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment