mirror of
https://github.com/ipfs/kubo.git
synced 2026-02-23 03:17:43 +08:00
This change adds the /ipfs/bitswap/1.1.0 protocol. The new protocol adds a 'payload' field to the protobuf message and deprecates the existing 'blocks' field. The 'payload' field is an array of pairs of cid prefixes and block data. The cid prefixes are used to ensure the correct codecs and hash functions are used to handle the block on the receiving end. License: MIT Signed-off-by: Jeromy <why@ipfs.io>
129 lines
3.5 KiB
Go
129 lines
3.5 KiB
Go
// Package path implements utilities for resolving paths within ipfs.
|
|
package path
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"context"
|
|
mh "gx/ipfs/QmYDds3421prZgqKbLpEK7T9Aa2eVdQ7o3YarX1LVLdP2J/go-multihash"
|
|
|
|
merkledag "github.com/ipfs/go-ipfs/merkledag"
|
|
logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log"
|
|
cid "gx/ipfs/QmXUuRadqDq5BuFWzVU6VuKaSjTcNm1gNCtLvvP1TJCW4z/go-cid"
|
|
)
|
|
|
|
var log = logging.Logger("path")
|
|
|
|
// Paths after a protocol must contain at least one component
|
|
var ErrNoComponents = errors.New(
|
|
"path must contain at least one component")
|
|
|
|
// ErrNoLink is returned when a link is not found in a path
|
|
type ErrNoLink struct {
|
|
Name string
|
|
Node mh.Multihash
|
|
}
|
|
|
|
func (e ErrNoLink) Error() string {
|
|
return fmt.Sprintf("no link named %q under %s", e.Name, e.Node.B58String())
|
|
}
|
|
|
|
// Resolver provides path resolution to IPFS
|
|
// It has a pointer to a DAGService, which is uses to resolve nodes.
|
|
type Resolver struct {
|
|
DAG merkledag.DAGService
|
|
}
|
|
|
|
// SplitAbsPath clean up and split fpath. It extracts the first component (which
|
|
// must be a Multihash) and return it separately.
|
|
func SplitAbsPath(fpath Path) (*cid.Cid, []string, error) {
|
|
|
|
log.Debugf("Resolve: '%s'", fpath)
|
|
|
|
parts := fpath.Segments()
|
|
if parts[0] == "ipfs" {
|
|
parts = parts[1:]
|
|
}
|
|
|
|
// if nothing, bail.
|
|
if len(parts) == 0 {
|
|
return nil, nil, ErrNoComponents
|
|
}
|
|
|
|
c, err := cid.Decode(parts[0])
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return c, parts[1:], nil
|
|
}
|
|
|
|
// ResolvePath fetches the node for given path. It returns the last item
|
|
// returned by ResolvePathComponents.
|
|
func (s *Resolver) ResolvePath(ctx context.Context, fpath Path) (*merkledag.Node, error) {
|
|
// validate path
|
|
if err := fpath.IsValid(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
nodes, err := s.ResolvePathComponents(ctx, fpath)
|
|
if err != nil || nodes == nil {
|
|
return nil, err
|
|
}
|
|
return nodes[len(nodes)-1], err
|
|
}
|
|
|
|
// ResolvePathComponents fetches the nodes for each segment of the given path.
|
|
// It uses the first path component as a hash (key) of the first node, then
|
|
// resolves all other components walking the links, with ResolveLinks.
|
|
func (s *Resolver) ResolvePathComponents(ctx context.Context, fpath Path) ([]*merkledag.Node, error) {
|
|
h, parts, err := SplitAbsPath(fpath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
log.Debug("resolve dag get")
|
|
nd, err := s.DAG.Get(ctx, h)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return s.ResolveLinks(ctx, nd, parts)
|
|
}
|
|
|
|
// ResolveLinks iteratively resolves names by walking the link hierarchy.
|
|
// Every node is fetched from the DAGService, resolving the next name.
|
|
// Returns the list of nodes forming the path, starting with ndd. This list is
|
|
// guaranteed never to be empty.
|
|
//
|
|
// ResolveLinks(nd, []string{"foo", "bar", "baz"})
|
|
// would retrieve "baz" in ("bar" in ("foo" in nd.Links).Links).Links
|
|
func (s *Resolver) ResolveLinks(ctx context.Context, ndd *merkledag.Node, names []string) ([]*merkledag.Node, error) {
|
|
|
|
result := make([]*merkledag.Node, 0, len(names)+1)
|
|
result = append(result, ndd)
|
|
nd := ndd // dup arg workaround
|
|
|
|
// for each of the path components
|
|
for _, name := range names {
|
|
|
|
var cancel context.CancelFunc
|
|
ctx, cancel = context.WithTimeout(ctx, time.Minute)
|
|
defer cancel()
|
|
|
|
nextnode, err := nd.GetLinkedNode(ctx, s.DAG, name)
|
|
if err == merkledag.ErrLinkNotFound {
|
|
n := nd.Multihash()
|
|
return result, ErrNoLink{Name: name, Node: n}
|
|
} else if err != nil {
|
|
return append(result, nextnode), err
|
|
}
|
|
|
|
nd = nextnode
|
|
result = append(result, nextnode)
|
|
}
|
|
return result, nil
|
|
}
|