resolve.go 4.18 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
	ns "github.com/ipfs/go-ipfs/namesys"
Dirk McCormick's avatar
Dirk McCormick committed
13
	nsopts "github.com/ipfs/go-ipfs/namesys/opts"
14
	path "gx/ipfs/QmdMPBephdLYNESkruDX2hcDTgFYhoCt4LimWhgnomSdV2/go-path"
Jan Winkelmann's avatar
Jan Winkelmann committed
15

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

19 20
type ResolvedPath struct {
	Path path.Path
21 22
}

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

38
EXAMPLES
39 40 41

Resolve the value of your identity:

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

Resolve the value of another name:

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

50
Resolve the value of another name recursively:
51

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

55 56
Resolve the value of an IPFS DAG path:

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

60
`,
61
	},
62

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

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

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

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

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

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

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

Jeromy's avatar
Jeromy committed
133
		c := node.Cid()
134

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

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