Skip to content

Commit

Permalink
Merge pull request #241 from libp2p/feat/builder
Browse files Browse the repository at this point in the history
first hack at a nice libp2p constructor
  • Loading branch information
whyrusleeping authored Jan 7, 2018
2 parents 4bba0bb + 5824305 commit 7db6e54
Show file tree
Hide file tree
Showing 4 changed files with 256 additions and 66 deletions.
51 changes: 9 additions & 42 deletions examples/echo/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,14 @@ import (
mrand "math/rand"

golog "github.com/ipfs/go-log"
libp2p "github.com/libp2p/go-libp2p"
crypto "github.com/libp2p/go-libp2p-crypto"
host "github.com/libp2p/go-libp2p-host"
net "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"
bhost "github.com/libp2p/go-libp2p/p2p/host/basic"
ma "github.com/multiformats/go-multiaddr"
gologging "github.com/whyrusleeping/go-logging"
msmux "github.com/whyrusleeping/go-smux-multistream"
yamux "github.com/whyrusleeping/go-smux-yamux"
)

// makeBasicHost creates a LibP2P host with a random peer ID listening on the
Expand All @@ -41,61 +38,31 @@ func makeBasicHost(listenPort int, secio bool, randseed int64) (host.Host, error

// Generate a key pair for this host. We will use it at least
// to obtain a valid host ID.
priv, pub, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, r)
priv, _, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, r)
if err != nil {
return nil, err
}

// Obtain Peer ID from public key
pid, err := peer.IDFromPublicKey(pub)
if err != nil {
return nil, err
opts := []libp2p.Option{
libp2p.ListenAddrStrings(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", listenPort)),
libp2p.Identity(priv),
}

// Create a multiaddress
addr, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", listenPort))

if err != nil {
return nil, err
if !secio {
opts = append(opts, libp2p.NoEncryption())
}

// Create a peerstore
ps := pstore.NewPeerstore()

// If using secio, we add the keys to the peerstore
// for this peer ID.
if secio {
ps.AddPrivKey(pid, priv)
ps.AddPubKey(pid, pub)
}

// Set up stream multiplexer
tpt := msmux.NewBlankTransport()
tpt.AddTransport("/yamux/1.0.0", yamux.DefaultTransport)

// Create swarm (implements libP2P Network)
swrm, err := swarm.NewSwarmWithProtector(
context.Background(),
[]ma.Multiaddr{addr},
pid,
ps,
nil,
tpt,
nil,
)
basicHost, err := libp2p.New(context.Background(), opts...)
if err != nil {
return nil, err
}

netw := (*swarm.Network)(swrm)

basicHost := bhost.New(netw)

// Build host multiaddress
hostAddr, _ := ma.NewMultiaddr(fmt.Sprintf("/ipfs/%s", basicHost.ID().Pretty()))

// Now we can build a full multiaddress to reach this host
// by encapsulating both addresses:
addr := basicHost.Addrs()[0]
fullAddr := addr.Encapsulate(hostAddr)
log.Printf("I am %s\n", fullAddr)
if secio {
Expand Down
44 changes: 20 additions & 24 deletions examples/libp2p-host/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,47 +5,43 @@ import (
"crypto/rand"
"fmt"

libp2p "github.com/libp2p/go-libp2p"
crypto "github.com/libp2p/go-libp2p-crypto"
peer "github.com/libp2p/go-libp2p-peer"
pstore "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"
)

func main() {
// Generate an identity keypair using go's cryptographic randomness source
priv, pub, err := crypto.GenerateEd25519Key(rand.Reader)
if err != nil {
panic(err)
}
// The context governs the lifetime of the libp2p node
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

// A peers ID is the hash of its public key
pid, err := peer.IDFromPublicKey(pub)
// To construct a simple host with all the default settings, just use `New`
h, err := libp2p.New(ctx)
if err != nil {
panic(err)
}

// We've created the identity, now we need to store it.
// A peerstore holds information about peers, including your own
ps := pstore.NewPeerstore()
ps.AddPrivKey(pid, priv)
ps.AddPubKey(pid, pub)
fmt.Printf("Hello World, my hosts ID is %s\n", h.ID())

// If you want more control over the configuration, you can specify some
// options to the constructor

maddr, err := ma.NewMultiaddr("/ip4/0.0.0.0/tcp/9000")
// Set your own keypair
priv, _, err := crypto.GenerateEd25519Key(rand.Reader)
if err != nil {
panic(err)
}

// Make a context to govern the lifespan of the swarm
ctx := context.Background()
h2, err := libp2p.New(ctx,
// Use your own created keypair
libp2p.Identity(priv),

// Put all this together
netw, err := swarm.NewNetwork(ctx, []ma.Multiaddr{maddr}, pid, ps, nil)
// Set your own listen address
// The config takes an array of addresses, specify as many as you want.
libp2p.ListenAddrStrings("/ip4/0.0.0.0/tcp/9000"),
)
if err != nil {
panic(err)
}

myhost := bhost.New(netw)
fmt.Printf("Hello World, my hosts ID is %s\n", myhost.ID())
fmt.Printf("Hello World, my second hosts ID is %s\n", h2.ID())
}
221 changes: 221 additions & 0 deletions libp2p.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
package libp2p

import (
"context"
"crypto/rand"
"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"
)

// Config describes a set of settings for a libp2p node
type Config struct {
Transports []transport.Transport
Muxer mux.Transport
ListenAddrs []ma.Multiaddr
PeerKey crypto.PrivKey
Peerstore pstore.Peerstore
Protector pnet.Protector
Reporter metrics.Reporter
DisableSecio bool
}

type Option func(cfg *Config) error

func Transports(tpts ...transport.Transport) Option {
return func(cfg *Config) error {
cfg.Transports = append(cfg.Transports, tpts...)
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
}
}

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 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
}
}

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
}
}

return newWithCfg(ctx, &cfg)
}

func newWithCfg(ctx context.Context, cfg *Config) (host.Host, error) {
// 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
}

// Create a new blank peerstore if none was passed in
ps := cfg.Peerstore
if ps == nil {
ps = pstore.NewPeerstore()
}

// 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, cfg.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()

// 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
}
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,12 @@
"hash": "QmSAJm4QdTJ3EGF2cvgNcQyXTEbxqWSW1x4kCVV1aJQUQr",
"name": "go-libp2p-interface-connmgr",
"version": "0.0.4"
},
{
"author": "whyrusleeping",
"hash": "QmREBy6TSjLQMtYFhjf97cypsUTzBagcwamWocKHFCTb1e",
"name": "go-smux-multiplex",
"version": "3.0.4"
}
],
"gxVersion": "0.4.0",
Expand Down

0 comments on commit 7db6e54

Please sign in to comment.