1
0
mirror of https://github.com/ipfs/kubo.git synced 2025-09-10 11:52:21 +08:00

refactored ipns records to point to paths

Also changed the ipns dns resolution to use the "dnslink" format
This commit is contained in:
Jeromy
2015-04-17 21:14:25 -07:00
parent fcb559eb9d
commit 3d80b9d27d
22 changed files with 222 additions and 108 deletions

View File

@ -154,6 +154,7 @@ func daemonFunc(req cmds.Request, res cmds.Response) {
node, err := nb.Build(ctx.Context)
if err != nil {
log.Error("error from node construction: ", err)
res.SetError(err, cmds.ErrNormal)
return
}

View File

@ -6,8 +6,6 @@ import (
"io"
"strings"
b58 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58"
cmds "github.com/ipfs/go-ipfs/commands"
core "github.com/ipfs/go-ipfs/core"
nsys "github.com/ipfs/go-ipfs/namesys"
@ -84,20 +82,14 @@ Publish an <ipfs-path> to another public key (not implemented):
pstr = args[0]
}
node, err := n.Resolver.ResolvePath(path.FromString(pstr))
p, err := path.ParsePath(pstr)
if err != nil {
res.SetError(fmt.Errorf("failed to resolve path: %v", err), cmds.ErrNormal)
return
}
key, err := node.Key()
if err != nil {
res.SetError(err, cmds.ErrNormal)
res.SetError(fmt.Errorf("failed to validate path: %v", err), cmds.ErrNormal)
return
}
// TODO n.Keychain.Get(name).PrivKey
output, err := publish(n, n.PrivateKey, key.Pretty())
output, err := publish(n, n.PrivateKey, p)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
@ -114,10 +106,10 @@ Publish an <ipfs-path> to another public key (not implemented):
Type: IpnsEntry{},
}
func publish(n *core.IpfsNode, k crypto.PrivKey, ref string) (*IpnsEntry, error) {
func publish(n *core.IpfsNode, k crypto.PrivKey, ref path.Path) (*IpnsEntry, error) {
pub := nsys.NewRoutingPublisher(n.Routing)
val := b58.Decode(ref)
err := pub.Publish(n.Context(), k, u.Key(val))
err := pub.Publish(n.Context(), k, ref)
if err != nil {
return nil, err
}
@ -129,6 +121,6 @@ func publish(n *core.IpfsNode, k crypto.PrivKey, ref string) (*IpnsEntry, error)
return &IpnsEntry{
Name: u.Key(hash).String(),
Value: ref,
Value: ref.String(),
}, nil
}

View File

@ -6,11 +6,12 @@ import (
"strings"
cmds "github.com/ipfs/go-ipfs/commands"
path "github.com/ipfs/go-ipfs/path"
u "github.com/ipfs/go-ipfs/util"
)
type ResolvedKey struct {
Key u.Key
type ResolvedPath struct {
Path path.Path
}
var resolveCmd = &cmds.Command{
@ -82,16 +83,16 @@ Resolve te value of another name:
// TODO: better errors (in the case of not finding the name, we get "failed to find any peer in table")
res.SetOutput(&ResolvedKey{output})
res.SetOutput(&ResolvedPath{output})
},
Marshalers: cmds.MarshalerMap{
cmds.Text: func(res cmds.Response) (io.Reader, error) {
output, ok := res.Output().(*ResolvedKey)
output, ok := res.Output().(*ResolvedPath)
if !ok {
return nil, u.ErrCast()
}
return strings.NewReader(output.Key.B58String()), nil
return strings.NewReader(output.Path.String()), nil
},
},
Type: ResolvedKey{},
Type: ResolvedPath{},
}

View File

@ -81,12 +81,12 @@ func (i *gatewayHandler) resolveNamePath(ctx context.Context, p string) (string,
if strings.HasPrefix(p, IpnsPathPrefix) {
elements := strings.Split(p[len(IpnsPathPrefix):], "/")
hash := elements[0]
k, err := i.node.Namesys.Resolve(ctx, hash)
rp, err := i.node.Namesys.Resolve(ctx, hash)
if err != nil {
return "", err
}
elements[0] = k.Pretty()
elements = append(rp.Segments(), elements[1:]...)
p = gopath.Join(elements...)
}
if !strings.HasPrefix(p, IpfsPathPrefix) {

View File

@ -2,37 +2,31 @@ package corehttp
import (
"errors"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"strings"
"testing"
b58 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58"
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
core "github.com/ipfs/go-ipfs/core"
coreunix "github.com/ipfs/go-ipfs/core/coreunix"
namesys "github.com/ipfs/go-ipfs/namesys"
ci "github.com/ipfs/go-ipfs/p2p/crypto"
path "github.com/ipfs/go-ipfs/path"
repo "github.com/ipfs/go-ipfs/repo"
config "github.com/ipfs/go-ipfs/repo/config"
u "github.com/ipfs/go-ipfs/util"
testutil "github.com/ipfs/go-ipfs/util/testutil"
)
type mockNamesys map[string]string
type mockNamesys map[string]path.Path
func (m mockNamesys) Resolve(ctx context.Context, name string) (value u.Key, err error) {
enc, ok := m[name]
func (m mockNamesys) Resolve(ctx context.Context, name string) (value path.Path, err error) {
p, ok := m[name]
if !ok {
return "", namesys.ErrResolveFailed
}
dec := b58.Decode(enc)
if len(dec) == 0 {
return "", fmt.Errorf("invalid b58 string for name %q: %q", name, enc)
}
return u.Key(dec), nil
return p, nil
}
func (m mockNamesys) CanResolve(name string) bool {
@ -40,7 +34,7 @@ func (m mockNamesys) CanResolve(name string) bool {
return ok
}
func (m mockNamesys) Publish(ctx context.Context, name ci.PrivKey, value u.Key) error {
func (m mockNamesys) Publish(ctx context.Context, name ci.PrivKey, value path.Path) error {
return errors.New("not implemented for mockNamesys")
}
@ -63,13 +57,14 @@ func newNodeWithMockNamesys(t *testing.T, ns mockNamesys) *core.IpfsNode {
}
func TestGatewayGet(t *testing.T) {
t.Skip("not sure whats going on here")
ns := mockNamesys{}
n := newNodeWithMockNamesys(t, ns)
k, err := coreunix.Add(n, strings.NewReader("fnord"))
if err != nil {
t.Fatal(err)
}
ns["example.com"] = k
ns["example.com"] = path.FromString("/ipfs/" + k)
h, err := makeHandler(n,
IPNSHostnameOption(),
@ -82,6 +77,7 @@ func TestGatewayGet(t *testing.T) {
ts := httptest.NewServer(h)
defer ts.Close()
t.Log(ts.URL)
for _, test := range []struct {
host string
path string

View File

@ -20,7 +20,7 @@ func IPNSHostnameOption() ServeOption {
host := strings.SplitN(r.Host, ":", 2)[0]
if k, err := n.Namesys.Resolve(ctx, host); err == nil {
r.URL.Path = "/ipfs/" + k.Pretty() + r.URL.Path
r.URL.Path = "/ipfs/" + k.String() + r.URL.Path
}
childMux.ServeHTTP(w, r)
})

View File

@ -1,6 +1,7 @@
package core
import (
"errors"
"fmt"
"strings"
@ -8,18 +9,27 @@ import (
path "github.com/ipfs/go-ipfs/path"
)
const maxLinks = 32
var ErrTooManyLinks = errors.New("exceeded maximum number of links in ipns entry")
// Resolves the given path by parsing out /ipns/ entries and then going
// through the /ipfs/ entries and returning the final merkledage node.
// Effectively enables /ipns/ in CLI commands.
func Resolve(n *IpfsNode, p path.Path) (*merkledag.Node, error) {
strpath := string(p)
return resolveRecurse(n, p, 0)
}
func resolveRecurse(n *IpfsNode, p path.Path, depth int) (*merkledag.Node, error) {
if depth >= maxLinks {
return nil, ErrTooManyLinks
}
// for now, we only try to resolve ipns paths if
// they begin with "/ipns/". Otherwise, ambiguity
// emerges when resolving just a <hash>. Is it meant
// to be an ipfs or an ipns resolution?
if strings.HasPrefix(strpath, "/ipns/") {
if strings.HasPrefix(p.String(), "/ipns/") {
// if it's an ipns path, try to resolve it.
// if we can't, we can give that error back to the user.
seg := p.Segments()
@ -29,17 +39,12 @@ func Resolve(n *IpfsNode, p path.Path) (*merkledag.Node, error) {
ipnsPath := seg[1]
extensions := seg[2:]
key, err := n.Namesys.Resolve(n.Context(), ipnsPath)
respath, err := n.Namesys.Resolve(n.Context(), ipnsPath)
if err != nil {
return nil, err
}
pathHead := make([]string, 2)
pathHead[0] = "ipfs"
pathHead[1] = key.Pretty()
p = path.FromSegments(append(pathHead, extensions...)...)
//p = path.RebasePath(path.FromSegments(extensions...), basePath)
return resolveRecurse(n, path.FromSegments(append(respath.Segments(), extensions...)...), depth+1)
}
// ok, we have an ipfs path now (or what we'll treat as one)

View File

@ -9,6 +9,7 @@ import (
mdag "github.com/ipfs/go-ipfs/merkledag"
nsys "github.com/ipfs/go-ipfs/namesys"
ci "github.com/ipfs/go-ipfs/p2p/crypto"
path "github.com/ipfs/go-ipfs/path"
ft "github.com/ipfs/go-ipfs/unixfs"
)
@ -35,7 +36,7 @@ func InitializeKeyspace(n *core.IpfsNode, key ci.PrivKey) error {
}
pub := nsys.NewRoutingPublisher(n.Routing)
err = pub.Publish(n.Context(), key, nodek)
err = pub.Publish(n.Context(), key, path.FromKey(nodek))
if err != nil {
return err
}

View File

@ -127,7 +127,7 @@ func setupIpnsTest(t *testing.T, node *core.IpfsNode) (*core.IpfsNode, *fstest.M
node.IpnsFs = ipnsfs
}
fs, err := NewFileSystem(node, node.PrivateKey, "")
fs, err := NewFileSystem(node, node.PrivateKey, "", "")
if err != nil {
t.Fatal(err)
}

View File

@ -7,6 +7,7 @@ package ipns
import (
"errors"
"os"
"strings"
fuse "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse"
fs "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs"
@ -30,8 +31,8 @@ type FileSystem struct {
}
// NewFileSystem constructs new fs using given core.IpfsNode instance.
func NewFileSystem(ipfs *core.IpfsNode, sk ci.PrivKey, ipfspath string) (*FileSystem, error) {
root, err := CreateRoot(ipfs, []ci.PrivKey{sk}, ipfspath)
func NewFileSystem(ipfs *core.IpfsNode, sk ci.PrivKey, ipfspath, ipnspath string) (*FileSystem, error) {
root, err := CreateRoot(ipfs, []ci.PrivKey{sk}, ipfspath, ipnspath)
if err != nil {
return nil, err
}
@ -58,6 +59,7 @@ type Root struct {
// Used for symlinking into ipfs
IpfsRoot string
IpnsRoot string
LocalDirs map[string]fs.Node
Roots map[string]*nsfs.KeyRoot
@ -65,7 +67,7 @@ type Root struct {
LocalLink *Link
}
func CreateRoot(ipfs *core.IpfsNode, keys []ci.PrivKey, ipfspath string) (*Root, error) {
func CreateRoot(ipfs *core.IpfsNode, keys []ci.PrivKey, ipfspath, ipnspath string) (*Root, error) {
ldirs := make(map[string]fs.Node)
roots := make(map[string]*nsfs.KeyRoot)
for _, k := range keys {
@ -95,6 +97,7 @@ func CreateRoot(ipfs *core.IpfsNode, keys []ci.PrivKey, ipfspath string) (*Root,
fs: ipfs.IpnsFs,
Ipfs: ipfs,
IpfsRoot: ipfspath,
IpnsRoot: ipnspath,
Keys: keys,
LocalDirs: ldirs,
LocalLink: &Link{ipfs.Identity.Pretty()},
@ -143,7 +146,17 @@ func (s *Root) Lookup(ctx context.Context, name string) (fs.Node, error) {
return nil, fuse.ENOENT
}
return &Link{s.IpfsRoot + "/" + resolved.B58String()}, nil
segments := resolved.Segments()
if segments[0] == "ipfs" {
p := strings.Join(resolved.Segments()[1:], "/")
return &Link{s.IpfsRoot + "/" + p}, nil
} else if segments[0] == "ipns" {
p := strings.Join(resolved.Segments()[1:], "/")
return &Link{s.IpnsRoot + "/" + p}, nil
} else {
log.Error("Invalid path.Path: ", resolved)
return nil, errors.New("invalid path from ipns record")
}
}
func (r *Root) Close() error {

View File

@ -13,7 +13,7 @@ func Mount(ipfs *core.IpfsNode, ipnsmp, ipfsmp string) (mount.Mount, error) {
cfg := ipfs.Repo.Config()
allow_other := cfg.Mounts.FuseAllowOther
fsys, err := NewFileSystem(ipfs, ipfs.PrivateKey, ipfsmp)
fsys, err := NewFileSystem(ipfs, ipfs.PrivateKey, ipfsmp, ipnsmp)
if err != nil {
return nil, err
}

View File

@ -20,6 +20,7 @@ import (
dag "github.com/ipfs/go-ipfs/merkledag"
namesys "github.com/ipfs/go-ipfs/namesys"
ci "github.com/ipfs/go-ipfs/p2p/crypto"
path "github.com/ipfs/go-ipfs/path"
pin "github.com/ipfs/go-ipfs/pin"
ft "github.com/ipfs/go-ipfs/unixfs"
u "github.com/ipfs/go-ipfs/util"
@ -38,6 +39,8 @@ type Filesystem struct {
nsys namesys.NameSystem
resolver *path.Resolver
pins pin.Pinner
roots map[string]*KeyRoot
@ -51,6 +54,7 @@ func NewFilesystem(ctx context.Context, ds dag.DAGService, nsys namesys.NameSyst
nsys: nsys,
dserv: ds,
pins: pins,
resolver: &path.Resolver{DAG: ds},
}
for _, k := range keys {
pkh, err := k.GetPublic().Hash()
@ -159,8 +163,7 @@ func (fs *Filesystem) newKeyRoot(parent context.Context, k ci.PrivKey) (*KeyRoot
}
}
tctx, _ := context.WithTimeout(parent, time.Second*5)
mnode, err := fs.dserv.Get(tctx, pointsTo)
mnode, err := fs.resolver.ResolvePath(pointsTo)
if err != nil {
log.Errorf("Failed to retreive value '%s' for ipns entry: %s\n", pointsTo, err)
return nil, err
@ -179,9 +182,9 @@ func (fs *Filesystem) newKeyRoot(parent context.Context, k ci.PrivKey) (*KeyRoot
switch pbn.GetType() {
case ft.TDirectory:
root.val = NewDirectory(pointsTo.B58String(), mnode, root, fs)
root.val = NewDirectory(pointsTo.String(), mnode, root, fs)
case ft.TFile, ft.TMetadata, ft.TRaw:
fi, err := NewFile(pointsTo.B58String(), mnode, root, fs)
fi, err := NewFile(pointsTo.String(), mnode, root, fs)
if err != nil {
return nil, err
}
@ -228,7 +231,7 @@ func (kr *KeyRoot) Publish(ctx context.Context) error {
// network operation
fmt.Println("Publishing!")
return kr.fs.nsys.Publish(ctx, kr.key, k)
return kr.fs.nsys.Publish(ctx, kr.key, path.FromKey(k))
}
// Republisher manages when to publish the ipns entry associated with a given key

View File

@ -1,14 +1,14 @@
package namesys
import (
"errors"
"net"
"strings"
b58 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58"
isd "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-is-domain"
mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
u "github.com/ipfs/go-ipfs/util"
path "github.com/ipfs/go-ipfs/path"
)
// DNSResolver implements a Resolver on DNS domains
@ -25,7 +25,7 @@ func (r *DNSResolver) CanResolve(name string) bool {
// Resolve implements Resolver
// TXT records for a given domain name should contain a b58
// encoded multihash.
func (r *DNSResolver) Resolve(ctx context.Context, name string) (u.Key, error) {
func (r *DNSResolver) Resolve(ctx context.Context, name string) (path.Path, error) {
log.Info("DNSResolver resolving %v", name)
txt, err := net.LookupTXT(name)
if err != nil {
@ -33,17 +33,29 @@ func (r *DNSResolver) Resolve(ctx context.Context, name string) (u.Key, error) {
}
for _, t := range txt {
chk := b58.Decode(t)
if len(chk) == 0 {
continue
p, err := parseEntry(t)
if err == nil {
return p, nil
}
_, err := mh.Cast(chk)
if err != nil {
continue
}
return u.Key(chk), nil
}
return "", ErrResolveFailed
}
func parseEntry(txt string) (path.Path, error) {
p, err := path.ParseKeyToPath(txt)
if err == nil {
return p, nil
}
return tryParseDnsLink(txt)
}
func tryParseDnsLink(txt string) (path.Path, error) {
parts := strings.Split(txt, "=")
if len(parts) == 1 || parts[0] != "dnslink" {
return "", errors.New("not a valid dnslink entry")
}
return path.ParsePath(parts[1])
}

42
namesys/dns_test.go Normal file
View File

@ -0,0 +1,42 @@
package namesys
import (
"testing"
)
func TestDnsEntryParsing(t *testing.T) {
goodEntries := []string{
"QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD",
"dnslink=/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD",
"dnslink=/ipns/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD",
"dnslink=/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/foo",
"dnslink=/ipns/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/bar",
"dnslink=/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/foo/bar/baz",
"dnslink=/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD",
}
badEntries := []string{
"QmYhE8xgFCjGcz6PHgnvJz5NOTCORRECT",
"quux=/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD",
"dnslink=",
"dnslink=/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/foo",
"dnslink=ipns/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/bar",
}
for _, e := range goodEntries {
_, err := parseEntry(e)
if err != nil {
t.Log("expected entry to parse correctly!")
t.Log(e)
t.Fatal(err)
}
}
for _, e := range badEntries {
_, err := parseEntry(e)
if err == nil {
t.Log("expected entry parse to fail!")
t.Fatal(err)
}
}
}

View File

@ -6,7 +6,7 @@ import (
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
ci "github.com/ipfs/go-ipfs/p2p/crypto"
u "github.com/ipfs/go-ipfs/util"
path "github.com/ipfs/go-ipfs/path"
)
// ErrResolveFailed signals an error when attempting to resolve.
@ -31,7 +31,7 @@ type NameSystem interface {
type Resolver interface {
// Resolve looks up a name, and returns the value previously published.
Resolve(ctx context.Context, name string) (value u.Key, err error)
Resolve(ctx context.Context, name string) (value path.Path, err error)
// CanResolve checks whether this Resolver can resolve a name
CanResolve(name string) bool
@ -42,5 +42,5 @@ type Publisher interface {
// Publish establishes a name-value mapping.
// TODO make this not PrivKey specific.
Publish(ctx context.Context, name ci.PrivKey, value u.Key) error
Publish(ctx context.Context, name ci.PrivKey, value path.Path) error
}

View File

@ -3,8 +3,8 @@ package namesys
import (
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
ci "github.com/ipfs/go-ipfs/p2p/crypto"
path "github.com/ipfs/go-ipfs/path"
routing "github.com/ipfs/go-ipfs/routing"
u "github.com/ipfs/go-ipfs/util"
)
// ipnsNameSystem implements IPNS naming.
@ -34,7 +34,7 @@ func NewNameSystem(r routing.IpfsRouting) NameSystem {
}
// Resolve implements Resolver
func (ns *ipns) Resolve(ctx context.Context, name string) (u.Key, error) {
func (ns *ipns) Resolve(ctx context.Context, name string) (path.Path, error) {
for _, r := range ns.resolvers {
if r.CanResolve(name) {
return r.Resolve(ctx, name)
@ -54,6 +54,6 @@ func (ns *ipns) CanResolve(name string) bool {
}
// Publish implements Publisher
func (ns *ipns) Publish(ctx context.Context, name ci.PrivKey, value u.Key) error {
func (ns *ipns) Publish(ctx context.Context, name ci.PrivKey, value path.Path) error {
return ns.publisher.Publish(ctx, name, value)
}

View File

@ -5,7 +5,7 @@ import (
proquint "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/bren2010/proquint"
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
u "github.com/ipfs/go-ipfs/util"
path "github.com/ipfs/go-ipfs/path"
)
type ProquintResolver struct{}
@ -17,10 +17,10 @@ func (r *ProquintResolver) CanResolve(name string) bool {
}
// Resolve implements Resolver. Decodes the proquint string.
func (r *ProquintResolver) Resolve(ctx context.Context, name string) (u.Key, error) {
func (r *ProquintResolver) Resolve(ctx context.Context, name string) (path.Path, error) {
ok := r.CanResolve(name)
if !ok {
return "", errors.New("not a valid proquint string")
}
return u.Key(proquint.Decode(name)), nil
return path.FromString(string(proquint.Decode(name))), nil
}

View File

@ -7,12 +7,12 @@ import (
"time"
proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto"
mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
dag "github.com/ipfs/go-ipfs/merkledag"
pb "github.com/ipfs/go-ipfs/namesys/internal/pb"
ci "github.com/ipfs/go-ipfs/p2p/crypto"
path "github.com/ipfs/go-ipfs/path"
pin "github.com/ipfs/go-ipfs/pin"
routing "github.com/ipfs/go-ipfs/routing"
record "github.com/ipfs/go-ipfs/routing/record"
@ -41,15 +41,9 @@ func NewRoutingPublisher(route routing.IpfsRouting) Publisher {
// Publish implements Publisher. Accepts a keypair and a value,
// and publishes it out to the routing system
func (p *ipnsPublisher) Publish(ctx context.Context, k ci.PrivKey, value u.Key) error {
func (p *ipnsPublisher) Publish(ctx context.Context, k ci.PrivKey, value path.Path) error {
log.Debugf("namesys: Publish %s", value)
// validate `value` is a ref (multihash)
_, err := mh.FromB58String(value.Pretty())
if err != nil {
return fmt.Errorf("publish value must be str multihash. %v", err)
}
data, err := createRoutingEntryData(k, value)
if err != nil {
return err
@ -84,7 +78,7 @@ func (p *ipnsPublisher) Publish(ctx context.Context, k ci.PrivKey, value u.Key)
return nil
}
func createRoutingEntryData(pk ci.PrivKey, val u.Key) ([]byte, error) {
func createRoutingEntryData(pk ci.PrivKey, val path.Path) ([]byte, error) {
entry := new(pb.IpnsEntry)
entry.Value = []byte(val)
@ -160,7 +154,7 @@ func InitializeKeyspace(ctx context.Context, ds dag.DAGService, pub Publisher, p
return err
}
err = pub.Publish(ctx, key, nodek)
err = pub.Publish(ctx, key, path.FromKey(nodek))
if err != nil {
return err
}

View File

@ -4,6 +4,7 @@ import (
"testing"
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
path "github.com/ipfs/go-ipfs/path"
mockrouting "github.com/ipfs/go-ipfs/routing/mock"
u "github.com/ipfs/go-ipfs/util"
testutil "github.com/ipfs/go-ipfs/util/testutil"
@ -20,12 +21,7 @@ func TestRoutingResolve(t *testing.T) {
t.Fatal(err)
}
err = publisher.Publish(context.Background(), privk, "Hello")
if err == nil {
t.Fatal("should have errored out when publishing a non-multihash val")
}
h := u.Key(u.Hash([]byte("Hello")))
h := path.FromString("/ipfs/QmZULkCELmmk5XNfCgTnCyFgAVxBRBXyDHGGMVoLFLiXEN")
err = publisher.Publish(context.Background(), privk, h)
if err != nil {
t.Fatal(err)

View File

@ -7,6 +7,7 @@ import (
mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
pb "github.com/ipfs/go-ipfs/namesys/internal/pb"
path "github.com/ipfs/go-ipfs/path"
routing "github.com/ipfs/go-ipfs/routing"
u "github.com/ipfs/go-ipfs/util"
)
@ -36,7 +37,7 @@ func (r *routingResolver) CanResolve(name string) bool {
// Resolve implements Resolver. Uses the IPFS routing system to resolve SFS-like
// names.
func (r *routingResolver) Resolve(ctx context.Context, name string) (u.Key, error) {
func (r *routingResolver) Resolve(ctx context.Context, name string) (path.Path, error) {
log.Debugf("RoutingResolve: '%s'", name)
hash, err := mh.FromB58String(name)
if err != nil {
@ -77,5 +78,15 @@ func (r *routingResolver) Resolve(ctx context.Context, name string) (u.Key, erro
}
// ok sig checks out. this is a valid name.
return u.Key(entry.GetValue()), nil
// check for old style record:
valh, err := mh.Cast(entry.GetValue())
if err != nil {
// Not a multihash, probably a new record
return path.ParsePath(string(entry.GetValue()))
} else {
// Its an old style multihash record
log.Warning("Detected old style multihash record")
return path.FromKey(u.Key(valh)), nil
}
}

View File

@ -1,11 +1,19 @@
package path
import (
u "github.com/ipfs/go-ipfs/util"
"errors"
"path"
"strings"
u "github.com/ipfs/go-ipfs/util"
b58 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58"
mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
)
// ErrBadPath is returned when a given path is incorrectly formatted
var ErrBadPath = errors.New("invalid ipfs ref path")
// TODO: debate making this a private struct wrapped in a public interface
// would allow us to control creation, and cache segments.
type Path string
@ -17,7 +25,7 @@ func FromString(s string) Path {
// FromKey safely converts a Key type to a Path type
func FromKey(k u.Key) Path {
return Path(k.String())
return Path("/ipfs/" + k.String())
}
func (p Path) Segments() []string {
@ -39,3 +47,42 @@ func (p Path) String() string {
func FromSegments(seg ...string) Path {
return Path(strings.Join(seg, "/"))
}
func ParsePath(txt string) (Path, error) {
kp, err := ParseKeyToPath(txt)
if err == nil {
return kp, nil
}
parts := strings.Split(txt, "/")
if len(parts) < 3 {
return "", ErrBadPath
}
if parts[0] != "" {
return "", ErrBadPath
}
if parts[1] != "ipfs" && parts[1] != "ipns" {
return "", ErrBadPath
}
_, err = ParseKeyToPath(parts[2])
if err != nil {
return "", err
}
return Path(txt), nil
}
func ParseKeyToPath(txt string) (Path, error) {
chk := b58.Decode(txt)
if len(chk) == 0 {
return "", errors.New("not a key")
}
_, err := mh.Cast(chk)
if err != nil {
return "", err
}
return FromKey(u.Key(chk)), nil
}

View File

@ -18,7 +18,7 @@ test_expect_success "'ipfs name publish' succeeds" '
'
test_expect_success "publish output looks good" '
echo "Published name $PEERID to $HASH_WELCOME_DOCS" >expected1 &&
echo "Published name $PEERID to /ipfs/$HASH_WELCOME_DOCS" >expected1 &&
test_cmp publish_out expected1
'
@ -27,7 +27,7 @@ test_expect_success "'ipfs name resolve' succeeds" '
'
test_expect_success "resolve output looks good" '
printf "%s" "$HASH_WELCOME_DOCS" >expected2 &&
printf "/ipfs/%s" "$HASH_WELCOME_DOCS" >expected2 &&
test_cmp output expected2
'
@ -39,7 +39,7 @@ test_expect_success "'ipfs name publish' succeeds" '
'
test_expect_success "publish a path looks good" '
echo "Published name $PEERID to $HASH_HELP_PAGE" >expected3 &&
echo "Published name $PEERID to /ipfs/$HASH_WELCOME_DOCS/help" >expected3 &&
test_cmp publish_out expected3
'
@ -48,7 +48,7 @@ test_expect_success "'ipfs name resolve' succeeds" '
'
test_expect_success "resolve output looks good" '
printf "%s" "$HASH_HELP_PAGE" >expected4 &&
printf "/ipfs/%s/help" "$HASH_WELCOME_DOCS" >expected4 &&
test_cmp output expected4
'