mirror of
https://github.com/ipfs/kubo.git
synced 2025-05-20 00:18:12 +08:00
163 lines
4.0 KiB
Go
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
|
|
}
|