1
0
mirror of https://github.com/ipfs/kubo.git synced 2025-05-20 00:18:12 +08:00
Files
kubo/cmd/ipfs/add_migrations.go
2023-03-28 22:05:25 -04:00

163 lines
4.0 KiB
Go

package main
import (
"context"
"errors"
"fmt"
"io"
"os"
"path/filepath"
coreiface "github.com/ipfs/boxo/coreiface"
"github.com/ipfs/boxo/coreiface/options"
ipath "github.com/ipfs/boxo/coreiface/path"
"github.com/ipfs/boxo/files"
"github.com/ipfs/kubo/core"
"github.com/ipfs/kubo/core/coreapi"
"github.com/ipfs/kubo/repo/fsrepo/migrations"
"github.com/ipfs/kubo/repo/fsrepo/migrations/ipfsfetcher"
"github.com/libp2p/go-libp2p/core/peer"
)
// addMigrations adds any migration downloaded by the fetcher to the IPFS node
func addMigrations(ctx context.Context, node *core.IpfsNode, fetcher migrations.Fetcher, pin bool) error {
var fetchers []migrations.Fetcher
if mf, ok := fetcher.(*migrations.MultiFetcher); ok {
fetchers = mf.Fetchers()
} else {
fetchers = []migrations.Fetcher{fetcher}
}
for _, fetcher := range fetchers {
switch f := fetcher.(type) {
case *ipfsfetcher.IpfsFetcher:
// Add migrations by connecting to temp node and getting from IPFS
err := addMigrationPaths(ctx, node, f.AddrInfo(), f.FetchedPaths(), pin)
if err != nil {
return err
}
case *migrations.HttpFetcher, *migrations.RetryFetcher: // https://github.com/ipfs/kubo/issues/8780
// Add the downloaded migration files directly
if migrations.DownloadDirectory != "" {
var paths []string
err := filepath.Walk(migrations.DownloadDirectory, func(filePath string, info os.FileInfo, err error) error {
if info.IsDir() {
return nil
}
paths = append(paths, filePath)
return nil
})
if err != nil {
return err
}
err = addMigrationFiles(ctx, node, paths, pin)
if err != nil {
return err
}
}
default:
return errors.New("cannot get migrations from unknown fetcher type")
}
}
return nil
}
// addMigrationFiles adds the files at paths to IPFS, optionally pinning them
func addMigrationFiles(ctx context.Context, node *core.IpfsNode, paths []string, pin bool) error {
if len(paths) == 0 {
return nil
}
ifaceCore, err := coreapi.NewCoreAPI(node)
if err != nil {
return err
}
ufs := ifaceCore.Unixfs()
// Add migration files
for _, filePath := range paths {
f, err := os.Open(filePath)
if err != nil {
return err
}
fi, err := f.Stat()
if err != nil {
return err
}
ipfsPath, err := ufs.Add(ctx, files.NewReaderStatFile(f, fi), options.Unixfs.Pin(pin))
if err != nil {
return err
}
fmt.Printf("Added migration file %q: %s\n", filepath.Base(filePath), ipfsPath)
}
return nil
}
// addMigrationPaths adds the files at paths to IPFS, optionally pinning
// them. This is done after connecting to the peer.
func addMigrationPaths(ctx context.Context, node *core.IpfsNode, peerInfo peer.AddrInfo, paths []ipath.Path, pin bool) error {
if len(paths) == 0 {
return errors.New("nothing downloaded by ipfs fetcher")
}
if len(peerInfo.Addrs) == 0 {
return errors.New("no local swarm address for migration node")
}
ipfs, err := coreapi.NewCoreAPI(node)
if err != nil {
return err
}
// Connect to temp node
if err := ipfs.Swarm().Connect(ctx, peerInfo); err != nil {
return fmt.Errorf("could not connect to migration peer %q: %s", peerInfo.ID, err)
}
fmt.Printf("connected to migration peer %q\n", peerInfo)
if pin {
pinAPI := ipfs.Pin()
for _, ipfsPath := range paths {
err := pinAPI.Add(ctx, ipfsPath)
if err != nil {
return err
}
fmt.Printf("Added and pinned migration file: %q\n", ipfsPath)
}
return nil
}
ufs := ipfs.Unixfs()
// Add migration files
for _, ipfsPath := range paths {
err = ipfsGet(ctx, ufs, ipfsPath)
if err != nil {
return err
}
}
return nil
}
func ipfsGet(ctx context.Context, ufs coreiface.UnixfsAPI, ipfsPath ipath.Path) error {
nd, err := ufs.Get(ctx, ipfsPath)
if err != nil {
return err
}
defer nd.Close()
fnd, ok := nd.(files.File)
if !ok {
return fmt.Errorf("not a file node: %q", ipfsPath)
}
_, err = io.Copy(io.Discard, fnd)
if err != nil {
return fmt.Errorf("cannot read migration: %w", err)
}
fmt.Printf("Added migration file: %q\n", ipfsPath)
return nil
}