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

Hector Sanjuan's avatar
Hector Sanjuan committed
18
	cmds "gx/ipfs/QmWGm4AbZEbnmdgVTza52MSNpEmBdFVqzmAysRbjrRyGbH/go-ipfs-cmds"
Overbool's avatar
Overbool committed
19
	cmdkit "gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
20 21
)

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

28
var ResolveCmd = &cmds.Command{
Jan Winkelmann's avatar
Jan Winkelmann committed
29
	Helptext: cmdkit.HelpText{
rht's avatar
rht committed
30
		Tagline: "Resolve the value of names to IPFS.",
31
		ShortDescription: `
32
There are a number of mutable name protocols that can link among
33
themselves and into IPNS. This command accepts any of these
34
identifiers and resolves them to the referenced item.
35 36
`,
		LongDescription: `
37
There are a number of mutable name protocols that can link among
38 39 40
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
41
identifiers and resolves them to the referenced item.
42

43
EXAMPLES
44 45 46

Resolve the value of your identity:

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

Resolve the value of another name:

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

55
Resolve the value of another name recursively:
56

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

60 61
Resolve the value of an IPFS DAG path:

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

65
`,
66
	},
67

Jan Winkelmann's avatar
Jan Winkelmann committed
68 69
	Arguments: []cmdkit.Argument{
		cmdkit.StringArg("name", true, false, "The name to resolve.").EnableStdin(),
70
	},
Jan Winkelmann's avatar
Jan Winkelmann committed
71
	Options: []cmdkit.Option{
Kejie Zhang's avatar
Kejie Zhang committed
72 73 74
		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."),
75
	},
76
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
77
		api, err := cmdenv.GetApi(env, req)
Łukasz Magiera's avatar
Łukasz Magiera committed
78
		if err != nil {
79
			return err
Łukasz Magiera's avatar
Łukasz Magiera committed
80 81
		}

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

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

93
			if rcok {
94
				ropts = append(ropts, options.Name.ResolveOption(nsopts.DhtRecordCount(rc)))
95 96
			}
			if dhttok {
97 98
				d, err := time.ParseDuration(dhtt)
				if err != nil {
99
					return err
100 101
				}
				if d < 0 {
102
					return errors.New("DHT timeout value must be >= 0")
103
				}
104
				ropts = append(ropts, options.Name.ResolveOption(nsopts.DhtTimeout(d)))
105
			}
Łukasz Magiera's avatar
Łukasz Magiera committed
106
			p, err := api.Name().Resolve(req.Context, name, ropts...)
107 108
			// ErrResolveRecursion is fine
			if err != nil && err != ns.ErrResolveRecursion {
109
				return err
110
			}
111
			return cmds.EmitOnce(res, &ncmd.ResolvedPath{Path: path.Path(p.String())})
112 113
		}

114
		// else, ipfs path or ipns with recursive flag
Łukasz Magiera's avatar
Łukasz Magiera committed
115
		p, err := coreiface.ParsePath(name)
116
		if err != nil {
117
			return err
118
		}
119

Łukasz Magiera's avatar
Łukasz Magiera committed
120
		rp, err := api.ResolvePath(req.Context, p)
121
		if err != nil {
122
			return err
123 124
		}

125
		if rp.Remainder() != "" {
Steven Allen's avatar
Steven Allen committed
126 127 128
			// TODO: js expects this error. Instead of fixing this
			// error, we should fix #5703.
			return fmt.Errorf("found non-link at given path")
129
		}
130

131
		return cmds.EmitOnce(res, &ncmd.ResolvedPath{Path: path.Path("/" + rp.Namespace() + "/" + rp.Cid().String())})
132
	},
133
	Encoders: cmds.EncoderMap{
Overbool's avatar
Overbool committed
134 135
		cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, rp *ncmd.ResolvedPath) error {
			fmt.Fprintln(w, rp.Path.String())
136 137
			return nil
		}),
138
	},
139
	Type: ncmd.ResolvedPath{},
140
}