package coreapi import ( "context" "errors" "fmt" coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface" caopts "github.com/ipfs/go-ipfs/core/coreapi/interface/options" dag "gx/ipfs/QmNr4E8z9bGTztvHJktp7uQaMdx9p3r9Asrq6eYk7iCh4a/go-merkledag" offline "gx/ipfs/QmPuLWvxK1vg6ckKUpT53Dow9VLCcQGdL5Trwxa8PTLp7r/go-ipfs-exchange-offline" cidutil "gx/ipfs/QmPyxJ2QS7L5FhGkNYkNcXHGjDhvGHueJ4auqAstFHYxy5/go-cidutil" blockservice "gx/ipfs/QmQLG22wSEStiociTSKQpZAuuaaWoF1B3iKyjPFvWiTQ77/go-blockservice" peer "gx/ipfs/QmQsErDt8Qgw1XrsXf2BpEzDgGWtB1YLsTAARBup5b6B9W/go-libp2p-peer" routing "gx/ipfs/QmY9JUvS8kbgao3XbPh6WAV3ChE2nxGKhcGTHiwMC4gmcU/go-libp2p-routing" cid "gx/ipfs/QmZFbDTY9jfSBms2MchvYM9oYRbAF19K7Pby47yDBfpPrb/go-cid" pstore "gx/ipfs/Qmda4cPRvSRyox3SqgJN6DfSZGU5TtHufPTp9uXjFj71X6/go-libp2p-peerstore" blockstore "gx/ipfs/Qmeg56ecxRnVv7VWViMrDeEMoBHaNFMs4vQnyQrJ79Zz7i/go-ipfs-blockstore" ) type DhtAPI CoreAPI func (api *DhtAPI) FindPeer(ctx context.Context, p peer.ID) (pstore.PeerInfo, error) { pi, err := api.node.Routing.FindPeer(ctx, peer.ID(p)) if err != nil { return pstore.PeerInfo{}, err } return pi, nil } func (api *DhtAPI) FindProviders(ctx context.Context, p coreiface.Path, opts ...caopts.DhtFindProvidersOption) (<-chan pstore.PeerInfo, error) { settings, err := caopts.DhtFindProvidersOptions(opts...) if err != nil { return nil, err } rp, err := api.core().ResolvePath(ctx, p) if err != nil { return nil, err } numProviders := settings.NumProviders if numProviders < 1 { return nil, fmt.Errorf("number of providers must be greater than 0") } pchan := api.node.Routing.FindProvidersAsync(ctx, rp.Cid(), numProviders) return pchan, nil } func (api *DhtAPI) Provide(ctx context.Context, path coreiface.Path, opts ...caopts.DhtProvideOption) error { settings, err := caopts.DhtProvideOptions(opts...) if err != nil { return err } if api.node.Routing == nil { return errors.New("cannot provide in offline mode") } rp, err := api.core().ResolvePath(ctx, path) if err != nil { return err } c := rp.Cid() has, err := api.node.Blockstore.Has(c) if err != nil { return err } if !has { return fmt.Errorf("block %s not found locally, cannot provide", c) } if settings.Recursive { err = provideKeysRec(ctx, api.node.Routing, api.node.Blockstore, []*cid.Cid{c}) } else { err = provideKeys(ctx, api.node.Routing, []*cid.Cid{c}) } if err != nil { return err } return nil } func provideKeys(ctx context.Context, r routing.IpfsRouting, cids []*cid.Cid) error { for _, c := range cids { err := r.Provide(ctx, c, true) if err != nil { return err } } return nil } func provideKeysRec(ctx context.Context, r routing.IpfsRouting, bs blockstore.Blockstore, cids []*cid.Cid) error { provided := cidutil.NewStreamingSet() errCh := make(chan error) go func() { dserv := dag.NewDAGService(blockservice.New(bs, offline.Exchange(bs))) for _, c := range cids { err := dag.EnumerateChildrenAsync(ctx, dag.GetLinksDirect(dserv), c, provided.Visitor(ctx)) if err != nil { errCh <- err } } }() for { select { case k := <-provided.New: err := r.Provide(ctx, k, true) if err != nil { return err } case err := <-errCh: return err case <-ctx.Done(): return ctx.Err() } } } func (api *DhtAPI) core() coreiface.CoreAPI { return (*CoreAPI)(api) }