resolve.go 4.91 KB
Newer Older
1 2 3
package commands

import (
4
	"errors"
5
	"fmt"
6 7
	"io"
	"strings"
8
	"time"
9

10
	cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
11
	ncmd "github.com/ipfs/go-ipfs/core/commands/name"
12
	ns "github.com/ipfs/go-ipfs/namesys"
13

Hector Sanjuan's avatar
Hector Sanjuan committed
14 15 16 17
	path "gx/ipfs/QmQ8Y8pKbrdAFuoHnnduWp81qS5LESWATnjmUEqhopRbJo/go-path"
	coreiface "gx/ipfs/QmVzvYWRABgGEv4iu3M9wivWbZKTW29qsU4VTZ2iZEoExX/interface-go-ipfs-core"
	options "gx/ipfs/QmVzvYWRABgGEv4iu3M9wivWbZKTW29qsU4VTZ2iZEoExX/interface-go-ipfs-core/options"
	nsopts "gx/ipfs/QmVzvYWRABgGEv4iu3M9wivWbZKTW29qsU4VTZ2iZEoExX/interface-go-ipfs-core/options/namesys"
Steven Allen's avatar
Steven Allen committed
18
	cmds "gx/ipfs/QmWmn1Fo7ECXJYGAUf6wFWd677wVuryWePqUD678Dkt4ok/go-ipfs-cmds"
Overbool's avatar
Overbool committed
19
	cmdkit "gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
Steven Allen's avatar
Steven Allen committed
20
	cidenc "gx/ipfs/Qmf3gRH2L1QZy92gJHJEwKmBJKJGVf8RpN2kPPD2NQWg8G/go-cidutil/cidenc"
21 22
)

Kejie Zhang's avatar
Kejie Zhang committed
23 24 25 26 27 28
const (
	resolveRecursiveOptionName      = "recursive"
	resolveDhtRecordCountOptionName = "dht-record-count"
	resolveDhtTimeoutOptionName     = "dht-timeout"
)

29
var ResolveCmd = &cmds.Command{
Jan Winkelmann's avatar
Jan Winkelmann committed
30
	Helptext: cmdkit.HelpText{
rht's avatar
rht committed
31
		Tagline: "Resolve the value of names to IPFS.",
32
		ShortDescription: `
33
There are a number of mutable name protocols that can link among
34
themselves and into IPNS. This command accepts any of these
35
identifiers and resolves them to the referenced item.
36 37
`,
		LongDescription: `
38
There are a number of mutable name protocols that can link among
39 40 41
themselves and into IPNS. For example IPNS references can (currently)
point at an IPFS object, and DNS links can point at other DNS links, IPNS
entries, or IPFS objects. This command accepts any of these
42
identifiers and resolves them to the referenced item.
43

44
EXAMPLES
45 46 47

Resolve the value of your identity:

48
  $ ipfs resolve /ipns/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy
49 50 51 52
  /ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj

Resolve the value of another name:

53
  $ ipfs resolve /ipns/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n
54
  /ipns/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy
55

56
Resolve the value of another name recursively:
57

58
  $ ipfs resolve -r /ipns/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n
59
  /ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj
60

61 62
Resolve the value of an IPFS DAG path:

63
  $ ipfs resolve /ipfs/QmeZy1fGbwgVSrqbfh9fKQrAWgeyRnj7h8fsHS1oy3k99x/beep/boop
64 65
  /ipfs/QmYRMjyvAiHKN9UTi8Bzt1HUspmSRD8T8DwxfSMzLgBon1

66
`,
67
	},
68

Jan Winkelmann's avatar
Jan Winkelmann committed
69 70
	Arguments: []cmdkit.Argument{
		cmdkit.StringArg("name", true, false, "The name to resolve.").EnableStdin(),
71
	},
Jan Winkelmann's avatar
Jan Winkelmann committed
72
	Options: []cmdkit.Option{
Kejie Zhang's avatar
Kejie Zhang committed
73 74 75
		cmdkit.BoolOption(resolveRecursiveOptionName, "r", "Resolve until the result is an IPFS name."),
		cmdkit.IntOption(resolveDhtRecordCountOptionName, "dhtrc", "Number of records to request for DHT resolution."),
		cmdkit.StringOption(resolveDhtTimeoutOptionName, "dhtt", "Max time to collect values during DHT resolution eg \"30s\". Pass 0 for no timeout."),
76
	},
77
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
78
		api, err := cmdenv.GetApi(env, req)
Łukasz Magiera's avatar
Łukasz Magiera committed
79
		if err != nil {
80
			return err
Łukasz Magiera's avatar
Łukasz Magiera committed
81 82
		}

83
		name := req.Arguments[0]
Kejie Zhang's avatar
Kejie Zhang committed
84
		recursive, _ := req.Options[resolveRecursiveOptionName].(bool)
85

86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
		var enc cidenc.Encoder
		switch {
		case !cmdenv.CidBaseDefined(req):
			// Not specified, check the path.
			enc, err = cmdenv.CidEncoderFromPath(name)
			if err == nil {
				break
			}
			// Nope, fallback on the default.
			fallthrough
		default:
			enc, err = cmdenv.GetCidEncoder(req)
			if err != nil {
				return err
			}
101 102
		}

103 104
		// the case when ipns is resolved step by step
		if strings.HasPrefix(name, "/ipns/") && !recursive {
Kejie Zhang's avatar
Kejie Zhang committed
105 106
			rc, rcok := req.Options[resolveDhtRecordCountOptionName].(uint)
			dhtt, dhttok := req.Options[resolveDhtTimeoutOptionName].(string)
107 108 109
			ropts := []options.NameResolveOption{
				options.Name.ResolveOption(nsopts.Depth(1)),
			}
Łukasz Magiera's avatar
Łukasz Magiera committed
110

111
			if rcok {
112
				ropts = append(ropts, options.Name.ResolveOption(nsopts.DhtRecordCount(rc)))
113 114
			}
			if dhttok {
115 116
				d, err := time.ParseDuration(dhtt)
				if err != nil {
117
					return err
118 119
				}
				if d < 0 {
120
					return errors.New("DHT timeout value must be >= 0")
121
				}
122
				ropts = append(ropts, options.Name.ResolveOption(nsopts.DhtTimeout(d)))
123
			}
Łukasz Magiera's avatar
Łukasz Magiera committed
124
			p, err := api.Name().Resolve(req.Context, name, ropts...)
125 126
			// ErrResolveRecursion is fine
			if err != nil && err != ns.ErrResolveRecursion {
127
				return err
128
			}
129
			return cmds.EmitOnce(res, &ncmd.ResolvedPath{Path: path.Path(p.String())})
130 131
		}

132
		// else, ipfs path or ipns with recursive flag
Łukasz Magiera's avatar
Łukasz Magiera committed
133
		p, err := coreiface.ParsePath(name)
134
		if err != nil {
135
			return err
136
		}
137

Łukasz Magiera's avatar
Łukasz Magiera committed
138
		rp, err := api.ResolvePath(req.Context, p)
139
		if err != nil {
140
			return err
141 142
		}

143 144 145
		encoded := "/" + rp.Namespace() + "/" + enc.Encode(rp.Cid())
		if remainder := rp.Remainder(); remainder != "" {
			encoded += "/" + remainder
146
		}
147

148
		return cmds.EmitOnce(res, &ncmd.ResolvedPath{Path: path.Path(encoded)})
149
	},
150
	Encoders: cmds.EncoderMap{
Overbool's avatar
Overbool committed
151 152
		cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, rp *ncmd.ResolvedPath) error {
			fmt.Fprintln(w, rp.Path.String())
153 154
			return nil
		}),
155
	},
156
	Type: ncmd.ResolvedPath{},
157
}