131 lines
3.7 KiB
Go
131 lines
3.7 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"log"
|
|
"net/http"
|
|
"sync"
|
|
|
|
"github.com/libp2p/go-libp2p-core/host"
|
|
"github.com/libp2p/go-libp2p-core/peer"
|
|
"github.com/libp2p/go-libp2p-core/peerstore"
|
|
|
|
ma "github.com/multiformats/go-multiaddr"
|
|
)
|
|
|
|
var (
|
|
IPFS_PEERS = convertPeers([]string{
|
|
"/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
|
|
"/ip4/104.236.179.241/tcp/4001/p2p/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM",
|
|
"/ip4/128.199.219.111/tcp/4001/p2p/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu",
|
|
"/ip4/104.236.76.40/tcp/4001/p2p/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64",
|
|
"/ip4/178.62.158.247/tcp/4001/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd",
|
|
"/ip6/2604:a880:1:20::203:d001/tcp/4001/p2p/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM",
|
|
"/ip6/2400:6180:0:d0::151:6001/tcp/4001/p2p/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu",
|
|
"/ip6/2604:a880:800:10::4a:5001/tcp/4001/p2p/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64",
|
|
"/ip6/2a03:b0c0:0:1010::23:1001/tcp/4001/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd",
|
|
})
|
|
LOCAL_PEER_ENDPOINT = "http://localhost:5001/api/v0/id"
|
|
)
|
|
|
|
// Borrowed from ipfs code to parse the results of the command `ipfs id`
|
|
type IdOutput struct {
|
|
ID string
|
|
PublicKey string
|
|
Addresses []string
|
|
AgentVersion string
|
|
ProtocolVersion string
|
|
}
|
|
|
|
// quick and dirty function to get the local ipfs daemons address for bootstrapping
|
|
func getLocalPeerInfo() []peer.AddrInfo {
|
|
resp, err := http.Get(LOCAL_PEER_ENDPOINT)
|
|
if err != nil {
|
|
log.Fatalln(err)
|
|
}
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
log.Fatalln(err)
|
|
}
|
|
var js IdOutput
|
|
err = json.Unmarshal(body, &js)
|
|
if err != nil {
|
|
log.Fatalln(err)
|
|
}
|
|
for _, addr := range js.Addresses {
|
|
// For some reason, possibly NAT traversal, we need to grab the loopback ip address
|
|
if addr[0:8] == "/ip4/127" {
|
|
return convertPeers([]string{addr})
|
|
}
|
|
}
|
|
log.Fatalln(err)
|
|
return make([]peer.AddrInfo, 1) // not reachable, but keeps the compiler happy
|
|
}
|
|
|
|
func convertPeers(peers []string) []peer.AddrInfo {
|
|
pinfos := make([]peer.AddrInfo, len(peers))
|
|
for i, addr := range peers {
|
|
maddr := ma.StringCast(addr)
|
|
p, err := peer.AddrInfoFromP2pAddr(maddr)
|
|
if err != nil {
|
|
log.Fatalln(err)
|
|
}
|
|
pinfos[i] = *p
|
|
}
|
|
return pinfos
|
|
}
|
|
|
|
// This code is borrowed from the go-ipfs bootstrap process
|
|
func bootstrapConnect(ctx context.Context, ph host.Host, peers []peer.AddrInfo) error {
|
|
if len(peers) < 1 {
|
|
return errors.New("not enough bootstrap peers")
|
|
}
|
|
|
|
errs := make(chan error, len(peers))
|
|
var wg sync.WaitGroup
|
|
for _, p := range peers {
|
|
|
|
// performed asynchronously because when performed synchronously, if
|
|
// one `Connect` call hangs, subsequent calls are more likely to
|
|
// fail/abort due to an expiring context.
|
|
// Also, performed asynchronously for dial speed.
|
|
|
|
wg.Add(1)
|
|
go func(p peer.AddrInfo) {
|
|
defer wg.Done()
|
|
defer log.Println(ctx, "bootstrapDial", ph.ID(), p.ID)
|
|
log.Printf("%s bootstrapping to %s", ph.ID(), p.ID)
|
|
|
|
ph.Peerstore().AddAddrs(p.ID, p.Addrs, peerstore.PermanentAddrTTL)
|
|
if err := ph.Connect(ctx, p); err != nil {
|
|
log.Println(ctx, "bootstrapDialFailed", p.ID)
|
|
log.Printf("failed to bootstrap with %v: %s", p.ID, err)
|
|
errs <- err
|
|
return
|
|
}
|
|
log.Println(ctx, "bootstrapDialSuccess", p.ID)
|
|
log.Printf("bootstrapped with %v", p.ID)
|
|
}(p)
|
|
}
|
|
wg.Wait()
|
|
|
|
// our failure condition is when no connection attempt succeeded.
|
|
// So drain the errs channel, counting the results.
|
|
close(errs)
|
|
count := 0
|
|
var err error
|
|
for err = range errs {
|
|
if err != nil {
|
|
count++
|
|
}
|
|
}
|
|
if count == len(peers) {
|
|
return fmt.Errorf("failed to bootstrap. %s", err)
|
|
}
|
|
return nil
|
|
}
|