kubo/test/dependencies/graphsync-get/graphsync-get.go
2022-09-09 17:09:38 +02:00

129 lines
3.1 KiB
Go

package main
import (
"context"
"fmt"
"io"
"log"
"os"
"github.com/ipfs/go-blockservice"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-datastore"
dssync "github.com/ipfs/go-datastore/sync"
graphsync "github.com/ipfs/go-graphsync"
gsimpl "github.com/ipfs/go-graphsync/impl"
"github.com/ipfs/go-graphsync/network"
"github.com/ipfs/go-graphsync/storeutil"
blockstore "github.com/ipfs/go-ipfs-blockstore"
offline "github.com/ipfs/go-ipfs-exchange-offline"
"github.com/ipfs/go-merkledag"
uio "github.com/ipfs/go-unixfs/io"
"github.com/ipld/go-ipld-prime"
cidlink "github.com/ipld/go-ipld-prime/linking/cid"
basicnode "github.com/ipld/go-ipld-prime/node/basicnode"
ipldselector "github.com/ipld/go-ipld-prime/traversal/selector"
"github.com/ipld/go-ipld-prime/traversal/selector/builder"
"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/multiformats/go-multiaddr"
)
func newGraphsync(ctx context.Context, p2p host.Host, bs blockstore.Blockstore) (graphsync.GraphExchange, error) {
network := network.NewFromLibp2pHost(p2p)
return gsimpl.New(ctx,
network,
storeutil.LinkSystemForBlockstore(bs),
), nil
}
var selectAll ipld.Node = func() ipld.Node {
ssb := builder.NewSelectorSpecBuilder(basicnode.Prototype.Any)
return ssb.ExploreRecursive(
ipldselector.RecursionLimitDepth(100), // default max
ssb.ExploreAll(ssb.ExploreRecursiveEdge()),
).Node()
}()
func fetch(ctx context.Context, gs graphsync.GraphExchange, p peer.ID, c cid.Cid) error {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
resps, errs := gs.Request(ctx, p, cidlink.Link{Cid: c}, selectAll)
for {
select {
case <-ctx.Done():
return ctx.Err()
case _, ok := <-resps:
if !ok {
resps = nil
}
case err, ok := <-errs:
if !ok {
// done.
return nil
}
if err != nil {
return fmt.Errorf("got an unexpected error: %s", err)
}
}
}
}
func main() {
if len(os.Args) != 3 {
log.Fatalf("expected a multiaddr and a CID, got %d args", len(os.Args)-1)
}
addr, err := multiaddr.NewMultiaddr(os.Args[1])
if err != nil {
log.Fatalf("failed to multiaddr '%q': %s", os.Args[1], err)
}
ai, err := peer.AddrInfoFromP2pAddr(addr)
if err != nil {
log.Fatal(err)
}
target, err := cid.Decode(os.Args[2])
if err != nil {
log.Fatalf("failed to decode CID '%q': %s", os.Args[2], err)
}
p2p, err := libp2p.New(libp2p.NoListenAddrs)
if err != nil {
log.Fatal(err)
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
err = p2p.Connect(ctx, *ai)
if err != nil {
log.Fatal(err)
}
bs := blockstore.NewBlockstore(dssync.MutexWrap(datastore.NewMapDatastore()))
gs, err := newGraphsync(ctx, p2p, bs)
if err != nil {
log.Fatal("failed to start", err)
}
err = fetch(ctx, gs, ai.ID, target)
if err != nil {
log.Fatal(err)
}
dag := merkledag.NewDAGService(blockservice.New(bs, offline.Exchange(bs)))
root, err := dag.Get(ctx, target)
if err != nil {
log.Fatal(err)
}
reader, err := uio.NewDagReader(ctx, root, dag)
if err != nil {
log.Fatal(err)
}
_, err = io.Copy(os.Stdout, reader)
if err != nil {
log.Fatal(err)
}
}