github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/core/commands/id.go (about)

     1  package commands
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/base64"
     6  	"encoding/json"
     7  	"errors"
     8  	"io"
     9  	"strings"
    10  
    11  	b58 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58"
    12  
    13  	cmds "github.com/ipfs/go-ipfs/commands"
    14  	core "github.com/ipfs/go-ipfs/core"
    15  	ic "github.com/ipfs/go-ipfs/p2p/crypto"
    16  	"github.com/ipfs/go-ipfs/p2p/peer"
    17  	identify "github.com/ipfs/go-ipfs/p2p/protocol/identify"
    18  	kb "github.com/ipfs/go-ipfs/routing/kbucket"
    19  	u "github.com/ipfs/go-ipfs/util"
    20  )
    21  
    22  const offlineIdErrorMessage = `ID command fails when run without daemon, we are working to fix this.
    23  In the meantime, please run the daemon if you want to use 'ipfs id':
    24  
    25      ipfs daemon &
    26      ipfs id QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ
    27  `
    28  
    29  type IdOutput struct {
    30  	ID              string
    31  	PublicKey       string
    32  	Addresses       []string
    33  	AgentVersion    string
    34  	ProtocolVersion string
    35  }
    36  
    37  var IDCmd = &cmds.Command{
    38  	Helptext: cmds.HelpText{
    39  		Tagline: "Show IPFS Node ID info",
    40  		ShortDescription: `
    41  Prints out information about the specified peer,
    42  if no peer is specified, prints out local peers info.
    43  
    44  ipfs id supports the format option for output with the following keys:
    45  <id> : the peers id
    46  <aver>: agent version
    47  <pver>: protocol version
    48  <pubkey>: public key
    49  <addrs>: addresses (newline delimited)
    50  `,
    51  	},
    52  	Arguments: []cmds.Argument{
    53  		cmds.StringArg("peerid", false, false, "peer.ID of node to look up").EnableStdin(),
    54  	},
    55  	Options: []cmds.Option{
    56  		cmds.StringOption("f", "format", "optional output format"),
    57  	},
    58  	Run: func(req cmds.Request, res cmds.Response) {
    59  		node, err := req.InvocContext().GetNode()
    60  		if err != nil {
    61  			res.SetError(err, cmds.ErrNormal)
    62  			return
    63  		}
    64  
    65  		if len(req.Arguments()) == 0 {
    66  			output, err := printSelf(node)
    67  			if err != nil {
    68  				res.SetError(err, cmds.ErrNormal)
    69  				return
    70  			}
    71  			res.SetOutput(output)
    72  			return
    73  		}
    74  
    75  		pid := req.Arguments()[0]
    76  
    77  		id := peer.ID(b58.Decode(pid))
    78  		if len(id) == 0 {
    79  			res.SetError(cmds.ClientError("Invalid peer id"), cmds.ErrClient)
    80  			return
    81  		}
    82  
    83  		// TODO handle offline mode with polymorphism instead of conditionals
    84  		if !node.OnlineMode() {
    85  			res.SetError(errors.New(offlineIdErrorMessage), cmds.ErrClient)
    86  			return
    87  		}
    88  
    89  		p, err := node.Routing.FindPeer(req.Context(), id)
    90  		if err == kb.ErrLookupFailure {
    91  			res.SetError(errors.New(offlineIdErrorMessage), cmds.ErrClient)
    92  			return
    93  		}
    94  		if err != nil {
    95  			res.SetError(err, cmds.ErrNormal)
    96  			return
    97  		}
    98  
    99  		output, err := printPeer(node.Peerstore, p.ID)
   100  		if err != nil {
   101  			res.SetError(err, cmds.ErrNormal)
   102  			return
   103  		}
   104  		res.SetOutput(output)
   105  	},
   106  	Marshalers: cmds.MarshalerMap{
   107  		cmds.Text: func(res cmds.Response) (io.Reader, error) {
   108  			val, ok := res.Output().(*IdOutput)
   109  			if !ok {
   110  				return nil, u.ErrCast()
   111  			}
   112  
   113  			format, found, err := res.Request().Option("format").String()
   114  			if err != nil {
   115  				return nil, err
   116  			}
   117  			if found {
   118  				output := format
   119  				output = strings.Replace(output, "<id>", val.ID, -1)
   120  				output = strings.Replace(output, "<aver>", val.AgentVersion, -1)
   121  				output = strings.Replace(output, "<pver>", val.ProtocolVersion, -1)
   122  				output = strings.Replace(output, "<pubkey>", val.PublicKey, -1)
   123  				output = strings.Replace(output, "<addrs>", strings.Join(val.Addresses, "\n"), -1)
   124  				output = strings.Replace(output, "\\n", "\n", -1)
   125  				output = strings.Replace(output, "\\t", "\t", -1)
   126  				return strings.NewReader(output), nil
   127  			} else {
   128  
   129  				marshaled, err := json.MarshalIndent(val, "", "\t")
   130  				if err != nil {
   131  					return nil, err
   132  				}
   133  				return bytes.NewReader(marshaled), nil
   134  			}
   135  		},
   136  	},
   137  	Type: IdOutput{},
   138  }
   139  
   140  func printPeer(ps peer.Peerstore, p peer.ID) (interface{}, error) {
   141  	if p == "" {
   142  		return nil, errors.New("Attempted to print nil peer!")
   143  	}
   144  
   145  	info := new(IdOutput)
   146  	info.ID = p.Pretty()
   147  
   148  	if pk := ps.PubKey(p); pk != nil {
   149  		pkb, err := ic.MarshalPublicKey(pk)
   150  		if err != nil {
   151  			return nil, err
   152  		}
   153  		info.PublicKey = base64.StdEncoding.EncodeToString(pkb)
   154  	}
   155  
   156  	for _, a := range ps.Addrs(p) {
   157  		info.Addresses = append(info.Addresses, a.String())
   158  	}
   159  
   160  	if v, err := ps.Get(p, "ProtocolVersion"); err == nil {
   161  		if vs, ok := v.(string); ok {
   162  			info.ProtocolVersion = vs
   163  		}
   164  	}
   165  	if v, err := ps.Get(p, "AgentVersion"); err == nil {
   166  		if vs, ok := v.(string); ok {
   167  			info.AgentVersion = vs
   168  		}
   169  	}
   170  
   171  	return info, nil
   172  }
   173  
   174  // printing self is special cased as we get values differently.
   175  func printSelf(node *core.IpfsNode) (interface{}, error) {
   176  	info := new(IdOutput)
   177  	info.ID = node.Identity.Pretty()
   178  
   179  	if node.PrivateKey == nil {
   180  		if err := node.LoadPrivateKey(); err != nil {
   181  			return nil, err
   182  		}
   183  	}
   184  
   185  	pk := node.PrivateKey.GetPublic()
   186  	pkb, err := ic.MarshalPublicKey(pk)
   187  	if err != nil {
   188  		return nil, err
   189  	}
   190  	info.PublicKey = base64.StdEncoding.EncodeToString(pkb)
   191  
   192  	if node.PeerHost != nil {
   193  		for _, a := range node.PeerHost.Addrs() {
   194  			s := a.String() + "/ipfs/" + info.ID
   195  			info.Addresses = append(info.Addresses, s)
   196  		}
   197  	}
   198  	info.ProtocolVersion = identify.IpfsVersion
   199  	info.AgentVersion = identify.ClientVersion
   200  	return info, nil
   201  }