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

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

10
	"github.com/ipfs/go-ipfs/core"
11
	cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
Jan Winkelmann's avatar
Jan Winkelmann committed
12
	e "github.com/ipfs/go-ipfs/core/commands/e"
13
	ncmd "github.com/ipfs/go-ipfs/core/commands/name"
14
	ns "github.com/ipfs/go-ipfs/namesys"
Dirk McCormick's avatar
Dirk McCormick committed
15
	nsopts "github.com/ipfs/go-ipfs/namesys/opts"
Steven Allen's avatar
Steven Allen committed
16
	path "gx/ipfs/QmX7uSbkNz76yNwBhuwYwRbhihLnJqM73VTCjS3UMJud9A/go-path"
Jan Winkelmann's avatar
Jan Winkelmann committed
17

18
	uio "gx/ipfs/QmPL8bYtbACcSFFiSr4s2du7Na382NxRADR8hC7D9FkEA2/go-unixfs/io"
19
	"gx/ipfs/QmPTfgFTo9PFr1PvPKyKoeMgBvYPh6cX3aDP7DHKVbnCbi/go-ipfs-cmds"
20
	"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
21
	resolver "gx/ipfs/QmX7uSbkNz76yNwBhuwYwRbhihLnJqM73VTCjS3UMJud9A/go-path/resolver"
22 23
)

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

39
EXAMPLES
40 41 42

Resolve the value of your identity:

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

Resolve the value of another name:

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

51
Resolve the value of another name recursively:
52

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

56 57
Resolve the value of an IPFS DAG path:

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

61
`,
62
	},
63

Jan Winkelmann's avatar
Jan Winkelmann committed
64 65
	Arguments: []cmdkit.Argument{
		cmdkit.StringArg("name", true, false, "The name to resolve.").EnableStdin(),
66
	},
Jan Winkelmann's avatar
Jan Winkelmann committed
67
	Options: []cmdkit.Option{
68
		cmdkit.BoolOption("recursive", "r", "Resolve until the result is an IPFS name."),
69
		cmdkit.UintOption("dht-record-count", "dhtrc", "Number of records to request for DHT resolution."),
70
		cmdkit.StringOption("dht-timeout", "dhtt", "Max time to collect values during DHT resolution eg \"30s\". Pass 0 for no timeout."),
71
	},
72 73
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) {
		n, err := cmdenv.GetNode(env)
74
		if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
75
			res.SetError(err, cmdkit.ErrNormal)
76
			return
77 78
		}

79 80
		name := req.Arguments[0]
		recursive, _ := req.Options["recursive"].(bool)
81 82 83

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

112 113 114
		// else, ipfs path or ipns with recursive flag
		p, err := path.ParsePath(name)
		if err != nil {
Jan Winkelmann's avatar
Jan Winkelmann committed
115
			res.SetError(err, cmdkit.ErrNormal)
116
			return
117
		}
118

119 120 121 122 123
		r := &resolver.Resolver{
			DAG:         n.DAG,
			ResolveOnce: uio.ResolveUnixfsOnce,
		}

124
		node, err := core.Resolve(req.Context, n.Namesys, r, 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
		cmds.EmitOnce(res, &ncmd.ResolvedPath{Path: path.FromCid(c)})
133
	},
134 135
	Encoders: cmds.EncoderMap{
		cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
136
			output, ok := v.(*ncmd.ResolvedPath)
137
			if !ok {
138
				return e.TypeErr(output, v)
139
			}
140 141 142 143

			fmt.Fprintln(w, output.Path.String())
			return nil
		}),
144
	},
145
	Type: ncmd.ResolvedPath{},
146
}