master
go 167 lines 4.55 KB
Raw
1 package name
2
3 import (
4 "errors"
5 "fmt"
6 "io"
7 "strings"
8 "time"
9
10 "github.com/ipfs/boxo/namesys"
11 "github.com/ipfs/boxo/path"
12 cmds "github.com/ipfs/go-ipfs-cmds"
13 logging "github.com/ipfs/go-log/v2"
14 cmdenv "github.com/ipfs/kubo/core/commands/cmdenv"
15 options "github.com/ipfs/kubo/core/coreiface/options"
16 )
17
18 var log = logging.Logger("core/commands/ipns")
19
20 type ResolvedPath struct {
21 Path string
22 }
23
24 const (
25 recursiveOptionName = "recursive"
26 nocacheOptionName = "nocache"
27 dhtRecordCountOptionName = "dht-record-count"
28 dhtTimeoutOptionName = "dht-timeout"
29 streamOptionName = "stream"
30 )
31
32 var IpnsCmd = &cmds.Command{
33 Helptext: cmds.HelpText{
34 Tagline: "Resolve IPNS names.",
35 ShortDescription: `
36 IPNS is a PKI namespace, where names are the hashes of public keys, and
37 the private key enables publishing new (signed) values. In both publish
38 and resolve, the default name used is the node's own PeerID,
39 which is the hash of its public key.
40 `,
41 LongDescription: `
42 IPNS is a PKI namespace, where names are the hashes of public keys, and
43 the private key enables publishing new (signed) values. In both publish
44 and resolve, the default name used is the node's own PeerID,
45 which is the hash of its public key.
46
47 You can use the 'ipfs key' commands to list and generate more names and their
48 respective keys.
49
50 Examples:
51
52 Resolve the value of your name:
53
54 > ipfs name resolve
55 /ipfs/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy
56
57 Resolve the value of another name:
58
59 > ipfs name resolve QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ
60 /ipfs/QmSiTko9JZyabH56y2fussEt1A5oDqsFXB3CkvAqraFryz
61
62 Resolve the value of a dnslink:
63
64 > ipfs name resolve ipfs.io
65 /ipfs/QmaBvfZooxWkrv7D3r8LS9moNjzD2o525XMZze69hhoxf5
66
67 `,
68 },
69
70 Arguments: []cmds.Argument{
71 cmds.StringArg("name", false, false, "The IPNS name to resolve. Defaults to your node's peerID."),
72 },
73 Options: []cmds.Option{
74 cmds.BoolOption(recursiveOptionName, "r", "Resolve until the result is not an IPNS name.").WithDefault(true),
75 cmds.BoolOption(nocacheOptionName, "n", "Do not use cached entries."),
76 cmds.UintOption(dhtRecordCountOptionName, "dhtrc", "Number of records to request for DHT resolution.").WithDefault(uint(namesys.DefaultResolverDhtRecordCount)),
77 cmds.StringOption(dhtTimeoutOptionName, "dhtt", "Max time to collect values during DHT resolution e.g. \"30s\". Pass 0 for no timeout.").WithDefault(namesys.DefaultResolverDhtTimeout.String()),
78 cmds.BoolOption(streamOptionName, "s", "Stream entries as they are found."),
79 },
80 Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
81 api, err := cmdenv.GetApi(env, req)
82 if err != nil {
83 return err
84 }
85
86 nocache, _ := req.Options["nocache"].(bool)
87
88 var name string
89 if len(req.Arguments) == 0 {
90 self, err := api.Key().Self(req.Context)
91 if err != nil {
92 return err
93 }
94 name = self.ID().String()
95 } else {
96 name = req.Arguments[0]
97 }
98
99 recursive, _ := req.Options[recursiveOptionName].(bool)
100 rc, rcok := req.Options[dhtRecordCountOptionName].(uint)
101 dhtt, dhttok := req.Options[dhtTimeoutOptionName].(string)
102 stream, _ := req.Options[streamOptionName].(bool)
103
104 opts := []options.NameResolveOption{
105 options.Name.Cache(!nocache),
106 }
107
108 if !recursive {
109 opts = append(opts, options.Name.ResolveOption(namesys.ResolveWithDepth(1)))
110 }
111 if rcok {
112 opts = append(opts, options.Name.ResolveOption(namesys.ResolveWithDhtRecordCount(rc)))
113 }
114 if dhttok {
115 d, err := time.ParseDuration(dhtt)
116 if err != nil {
117 return err
118 }
119 if d < 0 {
120 return errors.New("DHT timeout value must be >= 0")
121 }
122 opts = append(opts, options.Name.ResolveOption(namesys.ResolveWithDhtTimeout(d)))
123 }
124
125 if !strings.HasPrefix(name, "/ipns/") {
126 name = "/ipns/" + name
127 }
128
129 if !stream {
130 output, err := api.Name().Resolve(req.Context, name, opts...)
131 if err != nil && (recursive || err != namesys.ErrResolveRecursion) {
132 return err
133 }
134
135 pth, err := path.NewPath(output.String())
136 if err != nil {
137 return err
138 }
139
140 return cmds.EmitOnce(res, &ResolvedPath{pth.String()})
141 }
142
143 output, err := api.Name().Search(req.Context, name, opts...)
144 if err != nil {
145 return err
146 }
147
148 for v := range output {
149 if v.Err != nil && (recursive || v.Err != namesys.ErrResolveRecursion) {
150 return v.Err
151 }
152 if err := res.Emit(&ResolvedPath{v.Path.String()}); err != nil {
153 return err
154 }
155
156 }
157
158 return nil
159 },
160 Encoders: cmds.EncoderMap{
161 cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, rp *ResolvedPath) error {
162 _, err := fmt.Fprintln(w, rp.Path)
163 return err
164 }),
165 },
166 Type: ResolvedPath{},
167 }