resolve.go 4.72 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"
Jan Winkelmann's avatar
Jan Winkelmann committed
11
	e "github.com/ipfs/go-ipfs/core/commands/e"
12
	ncmd "github.com/ipfs/go-ipfs/core/commands/name"
Łukasz Magiera's avatar
Łukasz Magiera committed
13
	coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
14
	options "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
15
	ns "github.com/ipfs/go-ipfs/namesys"
16
	nsopts "github.com/ipfs/go-ipfs/namesys/opts"
Steven Allen's avatar
Steven Allen committed
17
	path "gx/ipfs/QmRG3XuGwT7GYuAqgWDJBKTzdaHMwAnc1x7J2KHEXNHxzG/go-path"
Jan Winkelmann's avatar
Jan Winkelmann committed
18

Steven Allen's avatar
Steven Allen committed
19
	"gx/ipfs/Qma6uuSyjkecGhMFFLfzyJDPyoDtNJSHJNweDccZhaWkgU/go-ipfs-cmds"
20
	"gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
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 {
Łukasz Magiera's avatar
Łukasz Magiera committed
78 79
		api, err := cmdenv.GetApi(env)
		if err != nil {
80
			return err
Łukasz Magiera's avatar
Łukasz Magiera committed
81 82
		}

83
		n, err := cmdenv.GetNode(env)
84
		if err != nil {
85
			return err
86 87
		}

Łukasz Magiera's avatar
Łukasz Magiera committed
88 89 90
		if !n.OnlineMode() {
			err := n.SetupOfflineRouting()
			if err != nil {
91
				return err
Łukasz Magiera's avatar
Łukasz Magiera committed
92 93 94
			}
		}

95
		name := req.Arguments[0]
Kejie Zhang's avatar
Kejie Zhang committed
96
		recursive, _ := req.Options[resolveRecursiveOptionName].(bool)
97 98 99

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

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

127
		// else, ipfs path or ipns with recursive flag
Łukasz Magiera's avatar
Łukasz Magiera committed
128
		p, err := coreiface.ParsePath(name)
129
		if err != nil {
130
			return err
131
		}
132

Łukasz Magiera's avatar
Łukasz Magiera committed
133
		rp, err := api.ResolvePath(req.Context, p)
134
		if err != nil {
135
			return err
136 137
		}

138
		if rp.Remainder() != "" {
Steven Allen's avatar
Steven Allen committed
139 140 141
			// TODO: js expects this error. Instead of fixing this
			// error, we should fix #5703.
			return fmt.Errorf("found non-link at given path")
142
		}
143

144
		return cmds.EmitOnce(res, &ncmd.ResolvedPath{Path: path.Path("/" + rp.Namespace() + "/" + rp.Cid().String())})
145
	},
146 147
	Encoders: cmds.EncoderMap{
		cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
148
			output, ok := v.(*ncmd.ResolvedPath)
149
			if !ok {
150
				return e.TypeErr(output, v)
151
			}
152 153 154 155

			fmt.Fprintln(w, output.Path.String())
			return nil
		}),
156
	},
157
	Type: ncmd.ResolvedPath{},
158
}