Skip to content

Instantly share code, notes, and snippets.

@geoah
Last active September 7, 2016 22:56
Show Gist options
  • Save geoah/ff70271a3be05f57f37f911e54f549e7 to your computer and use it in GitHub Desktop.
Save geoah/ff70271a3be05f57f37f911e54f549e7 to your computer and use it in GitHub Desktop.
package main
import (
"context"
"flag"
"fmt"
"sync"
logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log"
peer "gx/ipfs/QmWXjJo15p4pzT7cayEwZi2sWgJqLnGDof6ZGMh9xBgU1p/go-libp2p-peer"
host "gx/ipfs/QmXnaDLonE9YBTVDdWBM6Jb5YxxmW1MHMkXzgsnu1jTEmK/go-libp2p/p2p/host"
bhost "gx/ipfs/QmXnaDLonE9YBTVDdWBM6Jb5YxxmW1MHMkXzgsnu1jTEmK/go-libp2p/p2p/host/basic"
swarm "gx/ipfs/QmXnaDLonE9YBTVDdWBM6Jb5YxxmW1MHMkXzgsnu1jTEmK/go-libp2p/p2p/net/swarm"
testutil "gx/ipfs/QmYpVUnnedgGrp6cX2pBii5HRQgcSr778FiKVe7o7nF5Z3/go-testutil"
ma "gx/ipfs/QmYzDkkgAEmrcNzFCiYo6L1dTX4EAG1gZkbtdbd9trL4vd/go-multiaddr"
ds "gx/ipfs/QmbzuUusHqaLLoNTDEVLcSF6vZDHZDLPC7p4bztRvvkXxU/go-datastore"
dssync "gx/ipfs/QmbzuUusHqaLLoNTDEVLcSF6vZDHZDLPC7p4bztRvvkXxU/go-datastore/sync"
key "gx/ipfs/Qmce4Y4zg3sYr7xKM5UueS67vhNni6EeWgCRnb7MbLJMew/go-key"
pstore "gx/ipfs/QmdMfSLMDBDYhtc4oF3NYGCZr5dy4wQb6Ji26N4D4mdxa2/go-libp2p-peerstore"
record "gx/ipfs/Qme7D9iKHYxwq28p6PzCymywsYSRBx9uyGzW7qNB3s9VbC/go-libp2p-record"
iaddr "github.com/ipfs/go-ipfs/thirdparty/ipfsaddr"
dht "github.com/libp2p/go-libp2p-kad-dht"
)
var log = logging.Logger("dht-example")
var defaultBootstrapAddresses = []string{
"/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io
// "/ip4/104.236.176.52/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z", // neptune.i.ipfs.io
// "/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", // pluto.i.ipfs.io
// "/ip4/162.243.248.213/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm", // uranus.i.ipfs.io
// "/ip4/128.199.219.111/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", // saturn.i.ipfs.io
// "/ip4/104.236.76.40/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", // venus.i.ipfs.io
// "/ip4/178.62.158.247/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", // earth.i.ipfs.io
// "/ip4/178.62.61.185/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3", // mercury.i.ipfs.io
// "/ip4/104.236.151.122/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx", // jupiter.i.ipfs.io
}
func init() {
logging.SetLogLevel("*", "CRIT")
}
// create a Host with a random peer to listen on the given address.
// shamelessly copy-pasted from libp2p examples, minus the secio.
func makeDummyHost(listen string) (host.Host, error) {
// create a new random identity
ident, err := testutil.RandIdentity()
if err != nil {
return nil, err
}
// create new peerstore
ps := pstore.NewPeerstore()
// and add our keys to it
ps.AddPrivKey(ident.ID(), ident.PrivateKey())
ps.AddPubKey(ident.ID(), ident.PublicKey())
// a context to pass around
ctx := context.Background()
// create a new multiaddr for our host
addr, err := ma.NewMultiaddr(listen)
if err != nil {
return nil, err
}
// create a new swarm to be used by the service host
s, err := swarm.NewNetwork(ctx, []ma.Multiaddr{addr}, ident.ID(), ps, nil)
if err != nil {
return nil, err
}
// print something
log.Debugf("I am %s/ipfs/%s\n", addr, ident.ID().Pretty())
// and return our new host, with enabled NAT
return bhost.New(s, bhost.NATPortMap), nil
}
func main() {
// get a port to listen to
listenF := flag.Int("l", 4000, "listen on port")
flag.Parse()
// and make a pretty multiaddr string
listenaddr := fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", *listenF)
// create a dummy host
ha, err := makeDummyHost(listenaddr)
if err != nil {
log.Fatal(err)
}
// with a simple context
ctx := context.Background()
// create a datastore for our DHT
dss := dssync.MutexWrap(ds.NewMapDatastore())
// and finaly create the DHT
d := dht.NewDHT(ctx, ha, dss)
// for the DHT GetValue to play nice, we seem to have to create a Selector
// the selector is chosen from the second part of the split-by-'/' key
// eg. for the key 'some/not/very/random/key' the 'not' validator will be chosen
// the selector then needs to select one of the returned values and return it, or error out
d.Selector["not"] = func(k key.Key, vals [][]byte) (int, error) {
return 0, nil
}
// in addition to the selector for any keys we want to put we must create a Validator.
// the validator again is chosen by the second part of the split-by-'/' key
d.Validator["not"] = &record.ValidChecker{
Func: func(key.Key, []byte) error {
return nil
},
Sign: false,
}
fmt.Println("Bootstrapping nodes; this might take a while.")
// TODO(geoah) There were some comments on IPFS code on why to do this async
// didn't actually have any issues running running it serially but let's leave it like this
// add boostrap nodes in peerstor for DHT to find.
var wg sync.WaitGroup
for _, addr := range defaultBootstrapAddresses {
wg.Add(1)
// extract the multiaddr
addr, _ := iaddr.ParseString(addr)
// make a PeerInfo that we can pass around
p := pstore.PeerInfo{
ID: addr.ID(),
Addrs: []ma.Multiaddr{addr.Transport()},
}
go func(p pstore.PeerInfo) {
defer wg.Done()
// add peer to peerstore
ha.Peerstore().AddAddrs(p.ID, p.Addrs, pstore.PermanentAddrTTL)
// dial the peer, so it can be added to the peerstore
if err := ha.Connect(ctx, p); err != nil {
log.Error("Could not connect to bootstrap peer.", err)
}
// Update peer in the DHT.
d.Update(ctx, p.ID)
}(p)
log.Debugf("Added ID=%v; Addr=%v; to our peerstore", p.ID, p.Addrs)
}
wg.Wait()
fmt.Println("> Done with bootstrapping.")
// everything should be ready by now
// let's have some fun with the DHT
// query the DHT for a peer (this is jupiter)
jup, _ := peer.IDB58Decode("QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx")
peer, err := d.FindPeer(ctx, jup)
fmt.Printf("DHT.FindPeer: peer=%v; err=%v.\n", peer, err)
// query the DHT for providers for an IPFS object (this is a pinned version of the go-key gx repo)
prov, err := d.FindProviders(ctx, key.B58KeyDecode("Qmce4Y4zg3sYr7xKM5UueS67vhNni6EeWgCRnb7MbLJMew"))
fmt.Printf("DHT.FindProviders: prov=%v; err=%v.\n", prov, err)
// now let's put a value on the DHT
err = d.PutValue(ctx, key.Key("some/not/very/random/key"), []byte("some-not-very-random-value"))
fmt.Printf("DHT.PutValue: err=%v.\n", err)
// and try to find it
value, err := d.GetValue(ctx, key.Key("some/not/very/random/key"))
fmt.Printf("DHT.GetValue: value=%v; err=%v.\n", string(value), err)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment