go-libp2p/libp2p.go

228 lines
5.1 KiB
Go
Raw Normal View History

package libp2p
import (
"context"
"crypto/rand"
2017-12-16 00:02:30 +00:00
"fmt"
crypto "github.com/libp2p/go-libp2p-crypto"
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"
)
2017-11-05 15:28:59 +00:00
// Config describes a set of settings for a libp2p node
type Config struct {
2017-12-14 21:10:09 +00:00
Transports []transport.Transport
Muxer mux.Transport
ListenAddrs []ma.Multiaddr
PeerKey crypto.PrivKey
Peerstore pstore.Peerstore
Protector pnet.Protector
Reporter metrics.Reporter
DisableSecio bool
}
2017-12-14 23:40:24 +00:00
type Option func(cfg *Config) error
2017-12-16 00:02:30 +00:00
func Transports(tpts ...transport.Transport) Option {
2017-12-14 23:40:24 +00:00
return func(cfg *Config) error {
2017-12-16 00:02:30 +00:00
cfg.Transports = append(cfg.Transports, tpts...)
2017-12-14 23:40:24 +00:00
return nil
}
}
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
}
}
2017-12-16 00:02:30 +00:00
func ListenAddrs(addrs ...ma.Multiaddr) Option {
2017-12-14 23:40:24 +00:00
return func(cfg *Config) error {
cfg.ListenAddrs = append(cfg.ListenAddrs, addrs...)
return nil
}
}
2017-12-16 00:02:30 +00:00
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
}
2017-12-14 23:40:24 +00:00
}
2017-12-16 00:02:30 +00:00
func NoEncryption() Option {
return TransportEncryption(EncPlaintext)
}
func Muxer(m mux.Transport) Option {
2017-12-14 23:40:24 +00:00
return func(cfg *Config) error {
2017-12-16 00:02:30 +00:00
if cfg.Muxer != nil {
return fmt.Errorf("cannot specify multiple muxer options")
}
2017-12-14 23:40:24 +00:00
cfg.Muxer = m
return nil
}
}
2017-12-16 00:02:30 +00:00
func Peerstore(ps pstore.Peerstore) Option {
2017-12-14 23:40:24 +00:00
return func(cfg *Config) error {
2017-12-16 00:02:30 +00:00
if cfg.Peerstore != nil {
return fmt.Errorf("cannot specify multiple peerstore options")
}
2017-12-14 23:40:24 +00:00
cfg.Peerstore = ps
return nil
}
}
2017-12-16 00:02:30 +00:00
func PrivateNetwork(prot pnet.Protector) Option {
2017-12-14 23:40:24 +00:00
return func(cfg *Config) error {
2017-12-16 00:02:30 +00:00
if cfg.Protector != nil {
return fmt.Errorf("cannot specify multiple private network options")
}
2017-12-14 23:40:24 +00:00
cfg.Protector = prot
return nil
}
}
2017-12-16 00:02:30 +00:00
func BandwidthReporter(rep metrics.Reporter) Option {
2017-12-14 23:40:24 +00:00
return func(cfg *Config) error {
2017-12-16 00:02:30 +00:00
if cfg.Reporter != nil {
return fmt.Errorf("cannot specify multiple bandwidth reporter options")
}
2017-12-14 23:40:24 +00:00
cfg.Reporter = rep
return nil
}
}
2017-12-16 00:02:30 +00:00
func Identity(sk crypto.PrivKey) Option {
return func(cfg *Config) error {
if cfg.PeerKey != nil {
return fmt.Errorf("cannot specify multiple identities")
2017-12-14 23:40:24 +00:00
}
cfg.PeerKey = sk
return nil
}
2017-11-05 15:28:59 +00:00
}
2017-12-16 00:02:30 +00:00
func New(ctx context.Context, opts ...Option) (host.Host, error) {
var cfg Config
for _, opt := range opts {
if err := opt(&cfg); err != nil {
return nil, err
}
}
2017-12-16 00:02:30 +00:00
return newWithCfg(ctx, &cfg)
}
func newWithCfg(ctx context.Context, cfg *Config) (host.Host, error) {
2017-11-05 15:28:59 +00:00
// If no key was given, generate a random 2048 bit RSA key
if cfg.PeerKey == nil {
priv, _, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, rand.Reader)
if err != nil {
return nil, err
}
cfg.PeerKey = priv
}
// Obtain Peer ID from public key
pid, err := peer.IDFromPublicKey(cfg.PeerKey.GetPublic())
if err != nil {
return nil, err
}
2017-11-05 15:28:59 +00:00
// 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()
}
2017-12-14 21:10:09 +00:00
// 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
}
netw := (*swarm.Network)(swrm)
return bhost.New(netw), nil
}
func DefaultMuxer() mux.Transport {
// Set up stream multiplexer
tpt := msmux.NewBlankTransport()
2017-11-05 15:28:59 +00:00
// By default, support yamux and multiplex
tpt.AddTransport("/yamux/1.0.0", yamux.DefaultTransport)
tpt.AddTransport("/mplex/6.3.0", mplex.DefaultTransport)
2017-11-05 15:28:59 +00:00
return tpt
}
2017-12-16 00:02:30 +00:00
func Defaults(cfg *Config) error {
2017-11-05 15:28:59 +00:00
// 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 {
2017-12-16 00:02:30 +00:00
return err
}
2017-12-16 00:02:30 +00:00
cfg.ListenAddrs = []ma.Multiaddr{addr}
cfg.Peerstore = pstore.NewPeerstore()
cfg.Muxer = DefaultMuxer()
return nil
}