@cryptotaxi247 / kubo / commits / 16c584ce9

core/commands2: Added 'bootstrap' command

Matt Bell committed Nov 5, 2014 at 22:22 UTC 16c584ce93aea721527eb310c524054cbd1c2ab5
2 files changed +264 -11
core/commands2/bootstrap.go new
+252
@@ -0,0 +1,252 @@
1 +package commands
2 +
3 +import (
4 + "errors"
5 + "fmt"
6 + "strings"
7 +
8 + ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
9 + mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
10 +
11 + cmds "github.com/jbenet/go-ipfs/commands"
12 + config "github.com/jbenet/go-ipfs/config"
13 + //peer "github.com/jbenet/go-ipfs/peer"
14 + //u "github.com/jbenet/go-ipfs/util"
15 +)
16 +
17 +type BootstrapOutput struct {
18 + Peers []*config.BootstrapPeer
19 +}
20 +
21 +var bootstrapCmd = &cmds.Command{
22 + Help: `ipfs bootstrap - show, or manipulate bootstrap node addresses
23 +
24 +Running 'ipfs bootstrap' with no arguments will run 'ipfs bootstrap list'.
25 +
26 +Commands:
27 +
28 + list Show the boostrap list.
29 + add <address> Add a node's address to the bootstrap list.
30 + remove <address> Remove an address from the bootstrap list.
31 +
32 +` + bootstrapSecurityWarning,
33 + Run: bootstrapListCmd.Run,
34 + Marshallers: bootstrapListCmd.Marshallers,
35 + Subcommands: map[string]*cmds.Command{
36 + "list": bootstrapListCmd,
37 + "add": bootstrapAddCmd,
38 + "remove": bootstrapRemoveCmd,
39 + },
40 +}
41 +
42 +var bootstrapAddCmd = &cmds.Command{
43 + Arguments: []cmds.Argument{
44 + cmds.Argument{"peer", cmds.ArgString, true, true},
45 + },
46 + Help: `ipfs bootstrap add - add addresses to the bootstrap list
47 +` + bootstrapSecurityWarning,
48 + Run: func(res cmds.Response, req cmds.Request) {
49 + input, err := bootstrapInputToPeers(req.Arguments())
50 + if err != nil {
51 + res.SetError(err, cmds.ErrNormal)
52 + return
53 + }
54 +
55 + filename, err := config.Filename(req.Context().ConfigRoot)
56 + if err != nil {
57 + res.SetError(err, cmds.ErrNormal)
58 + return
59 + }
60 +
61 + added, err := bootstrapAdd(filename, req.Context().Config, input)
62 + if err != nil {
63 + res.SetError(err, cmds.ErrNormal)
64 + return
65 + }
66 +
67 + res.SetOutput(&BootstrapOutput{added})
68 + },
69 + Type: &BootstrapOutput{},
70 + Marshallers: map[cmds.EncodingType]cmds.Marshaller{
71 + cmds.Text: func(res cmds.Response) ([]byte, error) {
72 + v := res.Output().(*BootstrapOutput)
73 + s := fmt.Sprintf("Added %v peers to the bootstrap list:\n", len(v.Peers))
74 + marshalled, err := bootstrapMarshaller(res)
75 + if err != nil {
76 + return nil, err
77 + }
78 + return append([]byte(s), marshalled...), nil
79 + },
80 + },
81 +}
82 +
83 +var bootstrapRemoveCmd = &cmds.Command{
84 + Arguments: []cmds.Argument{
85 + cmds.Argument{"peer", cmds.ArgString, true, true},
86 + },
87 + Help: `ipfs bootstrap remove - remove addresses from the bootstrap list
88 +` + bootstrapSecurityWarning,
89 + Run: func(res cmds.Response, req cmds.Request) {
90 + input, err := bootstrapInputToPeers(req.Arguments())
91 + if err != nil {
92 + res.SetError(err, cmds.ErrNormal)
93 + return
94 + }
95 +
96 + filename, err := config.Filename(req.Context().ConfigRoot)
97 + if err != nil {
98 + res.SetError(err, cmds.ErrNormal)
99 + return
100 + }
101 +
102 + removed, err := bootstrapRemove(filename, req.Context().Config, input)
103 + if err != nil {
104 + res.SetError(err, cmds.ErrNormal)
105 + return
106 + }
107 +
108 + res.SetOutput(&BootstrapOutput{removed})
109 + },
110 + Type: &BootstrapOutput{},
111 + Marshallers: map[cmds.EncodingType]cmds.Marshaller{
112 + cmds.Text: func(res cmds.Response) ([]byte, error) {
113 + v := res.Output().(*BootstrapOutput)
114 + s := fmt.Sprintf("Removed %v peers from the bootstrap list:\n", len(v.Peers))
115 + marshalled, err := bootstrapMarshaller(res)
116 + if err != nil {
117 + return nil, err
118 + }
119 + return append([]byte(s), marshalled...), nil
120 + },
121 + },
122 +}
123 +
124 +var bootstrapListCmd = &cmds.Command{
125 + Help: "ipfs bootstrap list - Show addresses in the bootstrap list",
126 + Run: func(res cmds.Response, req cmds.Request) {
127 + peers := req.Context().Config.Bootstrap
128 + res.SetOutput(&BootstrapOutput{peers})
129 + },
130 + Type: &BootstrapOutput{},
131 + Marshallers: map[cmds.EncodingType]cmds.Marshaller{
132 + cmds.Text: bootstrapMarshaller,
133 + },
134 +}
135 +
136 +func bootstrapMarshaller(res cmds.Response) ([]byte, error) {
137 + v := res.Output().(*BootstrapOutput)
138 +
139 + s := ""
140 + for _, peer := range v.Peers {
141 + s += fmt.Sprintf("%s/%s\n", peer.Address, peer.PeerID)
142 + }
143 +
144 + return []byte(s), nil
145 +}
146 +
147 +func bootstrapInputToPeers(input []interface{}) ([]*config.BootstrapPeer, error) {
148 + split := func(addr string) (string, string) {
149 + idx := strings.LastIndex(addr, "/")
150 + if idx == -1 {
151 + return "", addr
152 + }
153 + return addr[:idx], addr[idx+1:]
154 + }
155 +
156 + peers := []*config.BootstrapPeer{}
157 + for _, v := range input {
158 + addr, ok := v.(string)
159 + if !ok {
160 + return nil, errors.New("cast error")
161 + }
162 +
163 + addrS, peeridS := split(addr)
164 +
165 + // make sure addrS parses as a multiaddr.
166 + if len(addrS) > 0 {
167 + maddr, err := ma.NewMultiaddr(addrS)
168 + if err != nil {
169 + return nil, err
170 + }
171 +
172 + addrS = maddr.String()
173 + }
174 +
175 + // make sure idS parses as a peer.ID
176 + _, err := mh.FromB58String(peeridS)
177 + if err != nil {
178 + return nil, err
179 + }
180 +
181 + // construct config entry
182 + peers = append(peers, &config.BootstrapPeer{
183 + Address: addrS,
184 + PeerID: peeridS,
185 + })
186 + }
187 + return peers, nil
188 +}
189 +
190 +func bootstrapAdd(filename string, cfg *config.Config, peers []*config.BootstrapPeer) ([]*config.BootstrapPeer, error) {
191 + added := make([]*config.BootstrapPeer, 0, len(peers))
192 +
193 + for _, peer := range peers {
194 + duplicate := false
195 + for _, peer2 := range cfg.Bootstrap {
196 + if peer.Address == peer2.Address {
197 + duplicate = true
198 + break
199 + }
200 + }
201 +
202 + if !duplicate {
203 + cfg.Bootstrap = append(cfg.Bootstrap, peer)
204 + added = append(added, peer)
205 + }
206 + }
207 +
208 + err := config.WriteConfigFile(filename, cfg)
209 + if err != nil {
210 + return nil, err
211 + }
212 +
213 + return added, nil
214 +}
215 +
216 +func bootstrapRemove(filename string, cfg *config.Config, peers []*config.BootstrapPeer) ([]*config.BootstrapPeer, error) {
217 + removed := make([]*config.BootstrapPeer, 0, len(peers))
218 + keep := make([]*config.BootstrapPeer, 0, len(cfg.Bootstrap))
219 +
220 + for _, peer := range cfg.Bootstrap {
221 + found := false
222 + for _, peer2 := range peers {
223 + if peer.Address == peer2.Address && peer.PeerID == peer2.PeerID {
224 + found = true
225 + removed = append(removed, peer)
226 + break
227 + }
228 + }
229 +
230 + if !found {
231 + keep = append(keep, peer)
232 + }
233 + }
234 + cfg.Bootstrap = keep
235 +
236 + err := config.WriteConfigFile(filename, cfg)
237 + if err != nil {
238 + return nil, err
239 + }
240 +
241 + return removed, nil
242 +}
243 +
244 +const bootstrapSecurityWarning = `
245 +SECURITY WARNING:
246 +
247 +The bootstrap command manipulates the "bootstrap list", which contains
248 +the addresses of bootstrap nodes. These are the *trusted peers* from
249 +which to learn about other peers in the network. Only edit this list
250 +if you understand the risks of adding or removing nodes from this list.
251 +
252 +`
core/commands2/root.go
+12 -11
@@ -56,17 +56,18 @@ Use "ipfs help <command>" for more information about a command.
56 }
57
58 var rootSubcommands = map[string]*cmds.Command{
59 - "cat": catCmd,
60 - "ls": lsCmd,
61 - "commands": commandsCmd,
62 - "name": nameCmd,
63 - "add": addCmd,
64 - "log": logCmd,
65 - "diag": diagCmd,
66 - "pin": pinCmd,
67 - "unpin": unpinCmd,
68 - "version": versionCmd,
69 - "config": configCmd,
59 + "cat": catCmd,
60 + "ls": lsCmd,
61 + "commands": commandsCmd,
62 + "name": nameCmd,
63 + "add": addCmd,
64 + "log": logCmd,
65 + "diag": diagCmd,
66 + "pin": pinCmd,
67 + "unpin": unpinCmd,
68 + "version": versionCmd,
69 + "config": configCmd,
70 + "bootstrap": bootstrapCmd,
71
72 // test subcommands
73 // TODO: remove these when we don't need them anymore