github.com/zignig/go-ipfs@v0.0.0-20141111235910-c9e5fdf55a52/core/commands2/bootstrap.go (about) 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 ) 14 15 type BootstrapOutput struct { 16 Peers []*config.BootstrapPeer 17 } 18 19 var peerOptionDesc = "A peer to add to the bootstrap list (in the format '<multiaddr>/<peerID>')" 20 21 var bootstrapCmd = &cmds.Command{ 22 Description: "Show or edit the list of bootstrap peers", 23 Help: `Running 'ipfs bootstrap' with no arguments will run 'ipfs bootstrap list'. 24 ` + bootstrapSecurityWarning, 25 26 Run: bootstrapListCmd.Run, 27 Marshallers: bootstrapListCmd.Marshallers, 28 Subcommands: map[string]*cmds.Command{ 29 "list": bootstrapListCmd, 30 "add": bootstrapAddCmd, 31 "remove": bootstrapRemoveCmd, 32 }, 33 } 34 35 var bootstrapAddCmd = &cmds.Command{ 36 Description: "Add peers to the bootstrap list", 37 Help: `Outputs a list of peers that were added (that weren't already 38 in the bootstrap list). 39 ` + bootstrapSecurityWarning, 40 41 Arguments: []cmds.Argument{ 42 cmds.StringArg("peer", true, true, peerOptionDesc), 43 }, 44 Run: func(req cmds.Request) (interface{}, error) { 45 input, err := bootstrapInputToPeers(req.Arguments()) 46 if err != nil { 47 return nil, err 48 } 49 50 filename, err := config.Filename(req.Context().ConfigRoot) 51 if err != nil { 52 return nil, err 53 } 54 55 added, err := bootstrapAdd(filename, req.Context().Config, input) 56 if err != nil { 57 return nil, err 58 } 59 60 return &BootstrapOutput{added}, nil 61 }, 62 Type: &BootstrapOutput{}, 63 Marshallers: map[cmds.EncodingType]cmds.Marshaller{ 64 cmds.Text: func(res cmds.Response) ([]byte, error) { 65 v := res.Output().(*BootstrapOutput) 66 s := fmt.Sprintf("Added %v peers to the bootstrap list:\n", len(v.Peers)) 67 marshalled, err := bootstrapMarshaller(res) 68 if err != nil { 69 return nil, err 70 } 71 return append([]byte(s), marshalled...), nil 72 }, 73 }, 74 } 75 76 var bootstrapRemoveCmd = &cmds.Command{ 77 Description: "Removes peers from the bootstrap list", 78 Help: `Outputs the list of peers that were removed. 79 ` + bootstrapSecurityWarning, 80 81 Arguments: []cmds.Argument{ 82 cmds.StringArg("peer", true, true, peerOptionDesc), 83 }, 84 Run: func(req cmds.Request) (interface{}, error) { 85 input, err := bootstrapInputToPeers(req.Arguments()) 86 if err != nil { 87 return nil, err 88 } 89 90 filename, err := config.Filename(req.Context().ConfigRoot) 91 if err != nil { 92 return nil, err 93 } 94 95 removed, err := bootstrapRemove(filename, req.Context().Config, input) 96 if err != nil { 97 return nil, err 98 } 99 100 return &BootstrapOutput{removed}, nil 101 }, 102 Type: &BootstrapOutput{}, 103 Marshallers: map[cmds.EncodingType]cmds.Marshaller{ 104 cmds.Text: func(res cmds.Response) ([]byte, error) { 105 v := res.Output().(*BootstrapOutput) 106 s := fmt.Sprintf("Removed %v peers from the bootstrap list:\n", len(v.Peers)) 107 marshalled, err := bootstrapMarshaller(res) 108 if err != nil { 109 return nil, err 110 } 111 return append([]byte(s), marshalled...), nil 112 }, 113 }, 114 } 115 116 var bootstrapListCmd = &cmds.Command{ 117 Description: "Show peers in the bootstrap list", 118 Help: `Peers are output in the format '<multiaddr>/<peerID>'. 119 `, 120 121 Run: func(req cmds.Request) (interface{}, error) { 122 peers := req.Context().Config.Bootstrap 123 return &BootstrapOutput{peers}, nil 124 }, 125 Type: &BootstrapOutput{}, 126 Marshallers: map[cmds.EncodingType]cmds.Marshaller{ 127 cmds.Text: bootstrapMarshaller, 128 }, 129 } 130 131 func bootstrapMarshaller(res cmds.Response) ([]byte, error) { 132 v := res.Output().(*BootstrapOutput) 133 134 s := "" 135 for _, peer := range v.Peers { 136 s += fmt.Sprintf("%s/%s\n", peer.Address, peer.PeerID) 137 } 138 139 return []byte(s), nil 140 } 141 142 func bootstrapInputToPeers(input []interface{}) ([]*config.BootstrapPeer, error) { 143 split := func(addr string) (string, string) { 144 idx := strings.LastIndex(addr, "/") 145 if idx == -1 { 146 return "", addr 147 } 148 return addr[:idx], addr[idx+1:] 149 } 150 151 peers := []*config.BootstrapPeer{} 152 for _, v := range input { 153 addr, ok := v.(string) 154 if !ok { 155 return nil, errors.New("cast error") 156 } 157 158 addrS, peeridS := split(addr) 159 160 // make sure addrS parses as a multiaddr. 161 if len(addrS) > 0 { 162 maddr, err := ma.NewMultiaddr(addrS) 163 if err != nil { 164 return nil, err 165 } 166 167 addrS = maddr.String() 168 } 169 170 // make sure idS parses as a peer.ID 171 _, err := mh.FromB58String(peeridS) 172 if err != nil { 173 return nil, err 174 } 175 176 // construct config entry 177 peers = append(peers, &config.BootstrapPeer{ 178 Address: addrS, 179 PeerID: peeridS, 180 }) 181 } 182 return peers, nil 183 } 184 185 func bootstrapAdd(filename string, cfg *config.Config, peers []*config.BootstrapPeer) ([]*config.BootstrapPeer, error) { 186 added := make([]*config.BootstrapPeer, 0, len(peers)) 187 188 for _, peer := range peers { 189 duplicate := false 190 for _, peer2 := range cfg.Bootstrap { 191 if peer.Address == peer2.Address { 192 duplicate = true 193 break 194 } 195 } 196 197 if !duplicate { 198 cfg.Bootstrap = append(cfg.Bootstrap, peer) 199 added = append(added, peer) 200 } 201 } 202 203 err := config.WriteConfigFile(filename, cfg) 204 if err != nil { 205 return nil, err 206 } 207 208 return added, nil 209 } 210 211 func bootstrapRemove(filename string, cfg *config.Config, peers []*config.BootstrapPeer) ([]*config.BootstrapPeer, error) { 212 removed := make([]*config.BootstrapPeer, 0, len(peers)) 213 keep := make([]*config.BootstrapPeer, 0, len(cfg.Bootstrap)) 214 215 for _, peer := range cfg.Bootstrap { 216 found := false 217 for _, peer2 := range peers { 218 if peer.Address == peer2.Address && peer.PeerID == peer2.PeerID { 219 found = true 220 removed = append(removed, peer) 221 break 222 } 223 } 224 225 if !found { 226 keep = append(keep, peer) 227 } 228 } 229 cfg.Bootstrap = keep 230 231 err := config.WriteConfigFile(filename, cfg) 232 if err != nil { 233 return nil, err 234 } 235 236 return removed, nil 237 } 238 239 const bootstrapSecurityWarning = ` 240 SECURITY WARNING: 241 242 The bootstrap command manipulates the "bootstrap list", which contains 243 the addresses of bootstrap nodes. These are the *trusted peers* from 244 which to learn about other peers in the network. Only edit this list 245 if you understand the risks of adding or removing nodes from this list. 246 247 `