resolve.go 4.46 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
	uio "gx/ipfs/QmPL8bYtbACcSFFiSr4s2du7Na382NxRADR8hC7D9FkEA2/go-unixfs/io"
18
	"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
19
	resolver "gx/ipfs/QmX7uSbkNz76yNwBhuwYwRbhihLnJqM73VTCjS3UMJud9A/go-path/resolver"
20 21
)

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

37
EXAMPLES
38 39 40

Resolve the value of your identity:

41
  $ ipfs resolve /ipns/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy
42 43 44 45
  /ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj

Resolve the value of another name:

46
  $ ipfs resolve /ipns/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n
47
  /ipns/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy
48

49
Resolve the value of another name recursively:
50

51
  $ ipfs resolve -r /ipns/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n
52
  /ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj
53

54 55
Resolve the value of an IPFS DAG path:

56
  $ ipfs resolve /ipfs/QmeZy1fGbwgVSrqbfh9fKQrAWgeyRnj7h8fsHS1oy3k99x/beep/boop
57 58
  /ipfs/QmYRMjyvAiHKN9UTi8Bzt1HUspmSRD8T8DwxfSMzLgBon1

59
`,
60
	},
61

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

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

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

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

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

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

126 127 128 129 130 131
		r := &resolver.Resolver{
			DAG:         n.DAG,
			ResolveOnce: uio.ResolveUnixfsOnce,
		}

		node, err := core.Resolve(req.Context(), n.Namesys, r, p)
132
		if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
133
			res.SetError(err, cmdkit.ErrNormal)
134 135 136
			return
		}

Jeromy's avatar
Jeromy committed
137
		c := node.Cid()
138

139
		res.SetOutput(&ncmd.ResolvedPath{Path: path.FromCid(c)})
140
	},
141
	Marshalers: cmds.MarshalerMap{
142
		cmds.Text: func(res cmds.Response) (io.Reader, error) {
Jan Winkelmann's avatar
Jan Winkelmann committed
143 144 145 146 147
			v, err := unwrapOutput(res.Output())
			if err != nil {
				return nil, err
			}

148
			output, ok := v.(*ncmd.ResolvedPath)
149
			if !ok {
Jan Winkelmann's avatar
Jan Winkelmann committed
150
				return nil, e.TypeErr(output, v)
151
			}
152
			return strings.NewReader(output.Path.String() + "\n"), nil
153
		},
154
	},
155
	Type: ncmd.ResolvedPath{},
156
}