// package peer implements an object used to represent peers in the ipfs network. package peer import ( "encoding/hex" "encoding/json" "fmt" "strings" b58 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58" ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash" ic "github.com/ipfs/go-ipfs/p2p/crypto" u "github.com/ipfs/go-ipfs/util" ) var log = u.Logger("peer") // ID represents the identity of a peer. type ID string // Pretty returns a b58-encoded string of the ID func (id ID) Pretty() string { return IDB58Encode(id) } func (id ID) Loggable() map[string]interface{} { return map[string]interface{}{ "peerID": id.Pretty(), } } // String prints out the peer. // // TODO(brian): ensure correctness at ID generation and // enforce this by only exposing functions that generate // IDs safely. Then any peer.ID type found in the // codebase is known to be correct. func (id ID) String() string { pid := id.Pretty() //All sha256 nodes start with Qm //We can skip the Qm to make the peer.ID more useful if strings.HasPrefix(pid, "Qm") { pid = pid[2:] } maxRunes := 6 if len(pid) < maxRunes { maxRunes = len(pid) } return fmt.Sprintf("", pid[:maxRunes]) } // MatchesPrivateKey tests whether this ID was derived from sk func (id ID) MatchesPrivateKey(sk ic.PrivKey) bool { return id.MatchesPublicKey(sk.GetPublic()) } // MatchesPublicKey tests whether this ID was derived from pk func (id ID) MatchesPublicKey(pk ic.PubKey) bool { oid, err := IDFromPublicKey(pk) if err != nil { return false } return oid == id } // IDFromString cast a string to ID type, and validate // the id to make sure it is a multihash. func IDFromString(s string) (ID, error) { if _, err := mh.Cast([]byte(s)); err != nil { return ID(""), err } return ID(s), nil } // IDFromBytes cast a string to ID type, and validate // the id to make sure it is a multihash. func IDFromBytes(b []byte) (ID, error) { if _, err := mh.Cast(b); err != nil { return ID(""), err } return ID(b), nil } // IDB58Decode returns a b58-decoded Peer func IDB58Decode(s string) (ID, error) { m, err := mh.FromB58String(s) if err != nil { return "", err } return ID(m), err } // IDB58Encode returns b58-encoded string func IDB58Encode(id ID) string { return b58.Encode([]byte(id)) } // IDHexDecode returns a b58-decoded Peer func IDHexDecode(s string) (ID, error) { m, err := mh.FromHexString(s) if err != nil { return "", err } return ID(m), err } // IDHexEncode returns b58-encoded string func IDHexEncode(id ID) string { return hex.EncodeToString([]byte(id)) } // IDFromPublicKey returns the Peer ID corresponding to pk func IDFromPublicKey(pk ic.PubKey) (ID, error) { b, err := pk.Bytes() if err != nil { return "", err } hash := u.Hash(b) return ID(hash), nil } // IDFromPrivateKey returns the Peer ID corresponding to sk func IDFromPrivateKey(sk ic.PrivKey) (ID, error) { return IDFromPublicKey(sk.GetPublic()) } // Map maps a Peer ID to a struct. type Set map[ID]struct{} // PeerInfo is a small struct used to pass around a peer with // a set of addresses (and later, keys?). This is not meant to be // a complete view of the system, but rather to model updates to // the peerstore. It is used by things like the routing system. type PeerInfo struct { ID ID Addrs []ma.Multiaddr } func (pi *PeerInfo) MarshalJSON() ([]byte, error) { out := make(map[string]interface{}) out["ID"] = IDB58Encode(pi.ID) var addrs []string for _, a := range pi.Addrs { addrs = append(addrs, a.String()) } out["Addrs"] = addrs return json.Marshal(out) } func (pi *PeerInfo) UnmarshalJSON(b []byte) error { var data map[string]interface{} err := json.Unmarshal(b, &data) if err != nil { return err } pid, err := IDB58Decode(data["ID"].(string)) if err != nil { return err } pi.ID = pid addrs, ok := data["Addrs"].([]interface{}) if ok { for _, a := range addrs { pi.Addrs = append(pi.Addrs, ma.StringCast(a.(string))) } } return nil } // IDSlice for sorting peers type IDSlice []ID func (es IDSlice) Len() int { return len(es) } func (es IDSlice) Swap(i, j int) { es[i], es[j] = es[j], es[i] } func (es IDSlice) Less(i, j int) bool { return string(es[i]) < string(es[j]) }