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  `