Use ipfs as a library, package problem

hi, I’m using ipfs to implemen a small cli tool. The code is mainly depends on example code. And my code is

package main

import (
	"context"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"sync"

	config "github.com/ipfs/go-ipfs-config"
	ipfsfiles "github.com/ipfs/go-ipfs-files"
	icore "github.com/ipfs/interface-go-ipfs-core"
	path "github.com/ipfs/interface-go-ipfs-core/path"
	peer "github.com/libp2p/go-libp2p-peer"
	peerstore "github.com/libp2p/go-libp2p-peerstore"
	ma "github.com/multiformats/go-multiaddr"

	"github.com/abiosoft/ishell"
	"github.com/ipfs/go-ipfs/core"
	"github.com/ipfs/go-ipfs/core/coreapi"
	"github.com/ipfs/go-ipfs/core/node/libp2p"
	"github.com/ipfs/go-ipfs/plugin/loader"
	"github.com/ipfs/go-ipfs/repo/fsrepo"
)

func setupPlugins(externalPluginsPath string) error {
	// Load any external plugins if available on externalPluginsPath
	plugins, err := loader.NewPluginLoader(filepath.Join(externalPluginsPath, "plugins"))
	if err != nil {
		return fmt.Errorf("error loading plugins: %s", err)
	}

	// Load preloaded and external plugins
	if err := plugins.Initialize(); err != nil {
		return fmt.Errorf("error initializing plugins: %s", err)
	}

	if err := plugins.Inject(); err != nil {
		return fmt.Errorf("error initializing plugins: %s", err)
	}

	return nil
}

// Creates an IPFS node and returns its coreAPI
func createNode(ctx context.Context, repoPath string) (*core.IpfsNode, error) {
	// Open the repo
	repo, err := fsrepo.Open(repoPath)
	if err != nil {
		fmt.Println(err)
		return nil, err
	}

	// Construct the node

	nodeOptions := &core.BuildCfg{
		Online:  true,
		Routing: libp2p.DHTOption, // This option sets the node to be a full DHT node (both fetching and storing DHT Records)
		// Routing: libp2p.DHTClientOption, // This option sets the node to be a client DHT node (only fetching records)
		Repo: repo,
	}

	return core.NewNode(ctx, nodeOptions)
}

func spawnDefault(ctx context.Context) (*core.IpfsNode, error) {
	defaultPath, err := config.PathRoot()
	fmt.Println(defaultPath)
	if err != nil {
		fmt.Println("in spawn", err)
		return nil, err
	}

	if err := setupPlugins(defaultPath); err != nil {
		return nil, err
	}

	return createNode(ctx, defaultPath)
}

func connectToPeers(ctx context.Context, ipfs icore.CoreAPI, peers []string) error {
	var wg sync.WaitGroup
	peerInfos := make(map[peer.ID]*peerstore.PeerInfo, len(peers))
	for _, addrStr := range peers {
		addr, err := ma.NewMultiaddr(addrStr)
		if err != nil {
			return err
		}
		pii, err := peerstore.InfoFromP2pAddr(addr)
		if err != nil {
			return err
		}
		pi, ok := peerInfos[pii.ID]
		if !ok {
			pi = &peerstore.PeerInfo{ID: pii.ID}
			peerInfos[pi.ID] = pi
		}
		pi.Addrs = append(pi.Addrs, pii.Addrs...)
	}

	wg.Add(len(peerInfos))
	for _, peerInfo := range peerInfos {
		go func(peerInfo *peerstore.PeerInfo) {
			defer wg.Done()
			err := ipfs.Swarm().Connect(ctx, *peerInfo)
			if err != nil {
				log.Printf("failed to connect to %s: %s", peerInfo.ID, err)
			}
		}(peerInfo)
	}
	wg.Wait()
	return nil
}

func getUnixfsFile(path string) (ipfsfiles.File, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	st, err := file.Stat()
	if err != nil {
		return nil, err
	}

	f, err := ipfsfiles.NewReaderPathFile(path, file, st)
	if err != nil {
		return nil, err
	}

	return f, nil
}

func getUnixfsNode(path string) (ipfsfiles.Node, error) {
	st, err := os.Stat(path)
	if err != nil {
		return nil, err
	}

	f, err := ipfsfiles.NewSerialFile(path, false, st)
	if err != nil {
		return nil, err
	}

	return f, nil
}

func main() {
	bootstrapNodes := []string{
		// IPFS Bootstrapper nodes.
		"/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
		"/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa",
		"/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb",
		"/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt",

		// IPFS Cluster Pinning nodes
		"/ip4/138.201.67.219/tcp/4001/p2p/QmUd6zHcbkbcs7SMxwLs48qZVX3vpcM8errYS7xEczwRMA",
		"/ip4/138.201.67.220/tcp/4001/p2p/QmNSYxZAiJHeLdkBg38roksAR9So7Y5eojks1yjEcUtZ7i",
		"/ip4/138.201.68.74/tcp/4001/p2p/QmdnXwLrC8p1ueiq2Qya8joNvk3TVVDAut7PrikmZwubtR",
		"/ip4/94.130.135.167/tcp/4001/p2p/QmUEMvxS2e7iDrereVYc5SWPauXPyNwxcy9BXZrC1QTcHE",
		"/ip4/192.168.31.125/tcp/4001/ipfs/QmcgLqX5dvAjp9PjtkRqj2mDoVKeokHd2QEJ9cnUHMRw7f",

		"ipfs/QmdCAWG4bniPnqsusiX4UbX7vjSBzfnzX4Uj1eLubW2XKK",
	}

	fmt.Println("Starting IPFS")

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	node, err := spawnDefault(ctx)
	if err != nil {
		fmt.Println("Cann't create node")
	}
	ipfs, err := coreapi.NewCoreAPI(node)
	if err != nil {
		fmt.Println("No IPFS repo on default path")
	}

	go connectToPeers(ctx, ipfs, bootstrapNodes)
	fmt.Println("IPFS running")

	shell := ishell.New()

	shell.AddCmd(&ishell.Cmd{
		Name: "add",
		Help: "add file to current node",
		Func: func(c *ishell.Context) {
			fileName := c.Args[0]
			filePath := "./" + fileName
			file, err := getUnixfsNode(filePath)
			if err != nil {
				fmt.Errorf("Could not get File: %s", err)
			}

			cidFile, err := ipfs.Unixfs().Add(ctx, file)
			if err != nil {
				fmt.Errorf("Could not add File: %s", err)
			}
			fmt.Printf("Added file with HASH: %s\n", cidFile.String())
		},
	})

	shell.AddCmd(&ishell.Cmd{
		Name: "get",
		Help: "get a fiile or directory from ipfs",
		Func: func(c *ishell.Context) {
			fileHash := c.Args[0]
			filePath := "./" + fileHash
			cidFile := path.New("/ipfs/" + fileHash)
			fileNode, err := ipfs.Unixfs().Get(ctx, cidFile)
			if err != nil {
				fmt.Errorf("Could not get file with Hash: %s", err)
			}

			err = ipfsfiles.WriteTo(fileNode, filePath)
			if err != nil {
				fmt.Errorf("Could not write out file: %s", err)
			}
		},
	})

	shell.Run()
}

And my problem is:

  1. When I build the project, error occurs as follows:
# github.com/ipfs/go-ipfs/core/bootstrap
../../pkg/mod/github.com/ipfs/go-ipfs@v0.4.23/core/bootstrap/bootstrap.go:220:14: undefined: config.BootstrapPeer
# github.com/ipfs/go-ipfs/repo/fsrepo
../../pkg/mod/github.com/ipfs/go-ipfs@v0.4.23/repo/fsrepo/datastores.go:247:20: cannot use measure.New(c.prefix, child) (type *measure.measure) as type repo.Datastore in return argument:
       *measure.measure does not implement repo.Datastore (missing Sync method)
 ../../pkg/mod/github.com/ipfs/go-ipfs@v0.4.23/repo/fsrepo/fsrepo.go:432:7: cannot use measure.New(prefix, r.ds) (type *measure.measure) as type repo.Datastore in assignment:
         *measure.measure does not implement repo.Datastore (missing Sync method)
 # github.com/ipfs/go-ds-flatfs
 ../../pkg/mod/github.com/ipfs/go-ds-flatfs@v0.0.2/flatfs.go:91:5: cannot use (*Datastore)(nil) (type *Datastore) as type datastore.Datastore in assignment:
        *Datastore does not implement datastore.Datastore (missing Sync method)

It seems that I got some package errors, I don’t know where I got wrong.
2. But if I move source file to the $GOPATH/src/github.com/ipfs/go-ipfs/docs/examples/test/, and run cmmmand go build main.go, executable file shows up and it works well.
I don’t konw how to solve ths problem, can anybody helps me. Thanks a lot. Ask questions if my presentation isn’t clear.

Other informations:
OS: 4.19.108-1-MANJARO
golang version:go version go1.14 linux/amd64
ipfs package version:go-ipfs@v0.4.23

1 Like

It seems a dependency problem. Try using a go.mod file as close to the go-ipfs go.mod as possible.