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

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

9
	cmds "github.com/ipfs/go-ipfs/commands"
10
	"github.com/ipfs/go-ipfs/core"
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"
13
	ns "github.com/ipfs/go-ipfs/namesys"
Dirk McCormick's avatar
Dirk McCormick committed
14
	nsopts "github.com/ipfs/go-ipfs/namesys/opts"
Steven Allen's avatar
Steven Allen committed
15
	path "gx/ipfs/QmX7uSbkNz76yNwBhuwYwRbhihLnJqM73VTCjS3UMJud9A/go-path"
Jan Winkelmann's avatar
Jan Winkelmann committed
16

17
	"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
18 19
)

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

35
EXAMPLES
36 37 38

Resolve the value of your identity:

39
  $ ipfs resolve /ipns/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy
40 41 42 43
  /ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj

Resolve the value of another name:

44
  $ ipfs resolve /ipns/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n
45
  /ipns/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy
46

47
Resolve the value of another name recursively:
48

49
  $ ipfs resolve -r /ipns/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n
50
  /ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj
51

52 53
Resolve the value of an IPFS DAG path:

54
  $ ipfs resolve /ipfs/QmeZy1fGbwgVSrqbfh9fKQrAWgeyRnj7h8fsHS1oy3k99x/beep/boop
55 56
  /ipfs/QmYRMjyvAiHKN9UTi8Bzt1HUspmSRD8T8DwxfSMzLgBon1

57
`,
58
	},
59

Jan Winkelmann's avatar
Jan Winkelmann committed
60 61
	Arguments: []cmdkit.Argument{
		cmdkit.StringArg("name", true, false, "The name to resolve.").EnableStdin(),
62
	},
Jan Winkelmann's avatar
Jan Winkelmann committed
63
	Options: []cmdkit.Option{
64
		cmdkit.BoolOption("recursive", "r", "Resolve until the result is an IPFS name."),
65
		cmdkit.UintOption("dht-record-count", "dhtrc", "Number of records to request for DHT resolution."),
66
		cmdkit.StringOption("dht-timeout", "dhtt", "Max time to collect values during DHT resolution eg \"30s\". Pass 0 for no timeout."),
67
	},
68
	Run: func(req cmds.Request, res cmds.Response) {
69

Jeromy's avatar
Jeromy committed
70
		n, err := req.InvocContext().GetNode()
71
		if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
72
			res.SetError(err, cmdkit.ErrNormal)
73
			return
74 75
		}

76 77 78
		if !n.OnlineMode() {
			err := n.SetupOfflineRouting()
			if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
79
				res.SetError(err, cmdkit.ErrNormal)
80 81
				return
			}
82 83
		}

84
		name := req.Arguments()[0]
85
		recursive, _, _ := req.Option("recursive").Bool()
86 87 88

		// the case when ipns is resolved step by step
		if strings.HasPrefix(name, "/ipns/") && !recursive {
89
			rc, rcok, _ := req.Option("dht-record-count").Int()
90
			dhtt, dhttok, _ := req.Option("dht-timeout").String()
Dirk McCormick's avatar
Dirk McCormick committed
91
			ropts := []nsopts.ResolveOpt{nsopts.Depth(1)}
92
			if rcok {
Dirk McCormick's avatar
Dirk McCormick committed
93
				ropts = append(ropts, nsopts.DhtRecordCount(uint(rc)))
94 95
			}
			if dhttok {
96 97 98 99 100 101 102 103 104 105
				d, err := time.ParseDuration(dhtt)
				if err != nil {
					res.SetError(err, cmdkit.ErrNormal)
					return
				}
				if d < 0 {
					res.SetError(errors.New("DHT timeout value must be >= 0"), cmdkit.ErrNormal)
					return
				}
				ropts = append(ropts, nsopts.DhtTimeout(d))
106
			}
Dirk McCormick's avatar
Dirk McCormick committed
107
			p, err := n.Namesys.Resolve(req.Context(), name, ropts...)
108 109
			// ErrResolveRecursion is fine
			if err != nil && err != ns.ErrResolveRecursion {
Jan Winkelmann's avatar
Jan Winkelmann committed
110
				res.SetError(err, cmdkit.ErrNormal)
111 112
				return
			}
113
			res.SetOutput(&ncmd.ResolvedPath{Path: p})
114
			return
115 116
		}

117 118 119
		// else, ipfs path or ipns with recursive flag
		p, err := path.ParsePath(name)
		if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
120
			res.SetError(err, cmdkit.ErrNormal)
121
			return
122
		}
123

124
		node, err := core.Resolve(req.Context(), n.Namesys, n.Resolver, p)
125
		if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
126
			res.SetError(err, cmdkit.ErrNormal)
127 128 129
			return
		}

Jeromy's avatar
Jeromy committed
130
		c := node.Cid()
131

132
		res.SetOutput(&ncmd.ResolvedPath{Path: path.FromCid(c)})
133
	},
134
	Marshalers: cmds.MarshalerMap{
135
		cmds.Text: func(res cmds.Response) (io.Reader, error) {
Jan Winkelmann's avatar
Jan Winkelmann committed
136 137 138 139 140
			v, err := unwrapOutput(res.Output())
			if err != nil {
				return nil, err
			}

141
			output, ok := v.(*ncmd.ResolvedPath)
142
			if !ok {
Jan Winkelmann's avatar
Jan Winkelmann committed
143
				return nil, e.TypeErr(output, v)
144
			}
145
			return strings.NewReader(output.Path.String() + "\n"), nil
146
		},
147
	},
148
	Type: ncmd.ResolvedPath{},
149
}