namesys.go 2.8 KB
Newer Older
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
1 2 3
package namesys

import (
4
	"strings"
5
	"time"
6

7
	path "github.com/ipfs/go-ipfs/path"
8
	routing "github.com/ipfs/go-ipfs/routing"
9
	ds "gx/ipfs/QmTxLSvdhwg68WJimdS6icLPhZi28aTp6b7uihC2Yb47Xk/go-datastore"
10
	ci "gx/ipfs/QmUWER4r4qMvaCnX5zREcfyiWN7cXN9g3a7fkRqNz8qWPP/go-libp2p-crypto"
Jeromy's avatar
Jeromy committed
11
	context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
12 13
)

14
// mpns (a multi-protocol NameSystem) implements generic IPFS naming.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
15
//
16
// Uses several Resolvers:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
17 18 19 20 21 22
// (a) ipfs routing naming: SFS-like PKI names.
// (b) dns domains: resolves using links in DNS TXT records
// (c) proquints: interprets string as the raw byte data.
//
// It can only publish to: (a) ipfs routing naming.
//
23 24 25
type mpns struct {
	resolvers  map[string]resolver
	publishers map[string]Publisher
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
26 27 28
}

// NewNameSystem will construct the IPFS naming system based on Routing
29
func NewNameSystem(r routing.ValueStore, ds ds.Datastore, cachesize int) NameSystem {
30 31
	return &mpns{
		resolvers: map[string]resolver{
32
			"dns":      newDNSResolver(),
33
			"proquint": new(ProquintResolver),
34
			"dht":      NewRoutingResolver(r, cachesize),
35 36
		},
		publishers: map[string]Publisher{
37
			"/ipns/": NewRoutingPublisher(r, ds),
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
38 39 40 41
		},
	}
}

42 43
const DefaultResolverCacheTTL = time.Minute

44 45 46 47 48 49 50 51 52
// Resolve implements Resolver.
func (ns *mpns) Resolve(ctx context.Context, name string) (path.Path, error) {
	return ns.ResolveN(ctx, name, DefaultDepthLimit)
}

// ResolveN implements Resolver.
func (ns *mpns) ResolveN(ctx context.Context, name string, depth int) (path.Path, error) {
	if strings.HasPrefix(name, "/ipfs/") {
		return path.ParsePath(name)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
53
	}
54 55 56 57 58 59

	if !strings.HasPrefix(name, "/") {
		return path.ParsePath("/ipfs/" + name)
	}

	return resolve(ctx, ns, name, depth, "/ipns/")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
60 61
}

62 63 64 65 66
// resolveOnce implements resolver.
func (ns *mpns) resolveOnce(ctx context.Context, name string) (path.Path, error) {
	if !strings.HasPrefix(name, "/ipns/") {
		name = "/ipns/" + name
	}
67
	segments := strings.SplitN(name, "/", 4)
68 69 70 71 72 73
	if len(segments) < 3 || segments[0] != "" {
		log.Warningf("Invalid name syntax for %s", name)
		return "", ErrResolveFailed
	}

	for protocol, resolver := range ns.resolvers {
74
		log.Debugf("Attempting to resolve %s with %s", segments[2], protocol)
75 76
		p, err := resolver.resolveOnce(ctx, segments[2])
		if err == nil {
77
			if len(segments) > 3 {
78
				return path.FromSegments("", strings.TrimRight(p.String(), "/"), segments[3])
79 80 81
			} else {
				return p, err
			}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
82 83
		}
	}
84 85
	log.Warningf("No resolver found for %s", name)
	return "", ErrResolveFailed
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
86 87 88
}

// Publish implements Publisher
89 90
func (ns *mpns) Publish(ctx context.Context, name ci.PrivKey, value path.Path) error {
	return ns.publishers["/ipns/"].Publish(ctx, name, value)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
91
}
92 93 94 95

func (ns *mpns) PublishWithEOL(ctx context.Context, name ci.PrivKey, val path.Path, eol time.Time) error {
	return ns.publishers["/ipns/"].PublishWithEOL(ctx, name, val, eol)
}