eth, p2p, rpc/api: polish protocol info gathering

This commit is contained in:
Péter Szilágyi
2015-10-27 15:10:30 +02:00
parent 05f74077fb
commit e46ab3bdcd
11 changed files with 209 additions and 86 deletions

View File

@ -359,3 +359,49 @@ func (rw *protoRW) ReadMsg() (Msg, error) {
return Msg{}, io.EOF
}
}
// PeerInfo represents a short summary of the information known about a connected
// peer. Sub-protocol independent fields are contained and initialized here, with
// protocol specifics delegated to all connected sub-protocols.
type PeerInfo struct {
ID string `json:"id"` // Unique node identifier (also the encryption key)
Name string `json:"name"` // Name of the node, including client type, version, OS, custom data
Caps []string `json:"caps"` // Sum-protocols advertised by this particular peer
Network struct {
LocalAddress string `json:"localAddress"` // Local endpoint of the TCP data connection
RemoteAddress string `json:"remoteAddress"` // Remote endpoint of the TCP data connection
} `json:"network"`
Protocols map[string]interface{} `json:"protocols"` // Sub-protocol specific metadata fields
}
// Info gathers and returns a collection of metadata known about a peer.
func (p *Peer) Info() *PeerInfo {
// Gather the protocol capabilities
var caps []string
for _, cap := range p.Caps() {
caps = append(caps, cap.String())
}
// Assemble the generic peer metadata
info := &PeerInfo{
ID: p.ID().String(),
Name: p.Name(),
Caps: caps,
Protocols: make(map[string]interface{}),
}
info.Network.LocalAddress = p.LocalAddr().String()
info.Network.RemoteAddress = p.RemoteAddr().String()
// Gather all the running protocol infos
for _, proto := range p.running {
protoInfo := interface{}("unknown")
if query := proto.Protocol.PeerInfo; query != nil {
if metadata := query(p.ID()); metadata != nil {
protoInfo = metadata
} else {
protoInfo = "handshake"
}
}
info.Protocols[proto.Name] = protoInfo
}
return info
}

View File

@ -16,7 +16,11 @@
package p2p
import "fmt"
import (
"fmt"
"github.com/ethereum/go-ethereum/p2p/discover"
)
// Protocol represents a P2P subprotocol implementation.
type Protocol struct {
@ -39,6 +43,15 @@ type Protocol struct {
// any protocol-level error (such as an I/O error) that is
// encountered.
Run func(peer *Peer, rw MsgReadWriter) error
// NodeInfo is an optional helper method to retrieve protocol specific metadata
// about the host node.
NodeInfo func() interface{}
// PeerInfo is an optional helper method to retrieve protocol specific metadata
// about a certain peer in the network. If an info retrieval function is set,
// but returns nil, it is assumed that the protocol handshake is still running.
PeerInfo func(id discover.NodeID) interface{}
}
func (p Protocol) cap() Cap {

View File

@ -689,3 +689,66 @@ func (srv *Server) runPeer(p *Peer) {
NumConnections: srv.PeerCount(),
})
}
// NodeInfo represents a short summary of the information known about the host.
type NodeInfo struct {
ID string `json:"id"` // Unique node identifier (also the encryption key)
Name string `json:"name"` // Name of the node, including client type, version, OS, custom data
Enode string `json:"enode"` // Enode URL for adding this peer from remote peers
IP string `json:"ip"` // IP address of the node
Ports struct {
Discovery int `json:"discovery"` // UDP listening port for discovery protocol
Listener int `json:"listener"` // TCP listening port for RLPx
} `json:"ports"`
ListenAddr string `json:"listenAddr"`
Protocols map[string]interface{} `json:"protocols"`
}
// Info gathers and returns a collection of metadata known about the host.
func (srv *Server) NodeInfo() *NodeInfo {
node := srv.Self()
// Gather and assemble the generic node infos
info := &NodeInfo{
Name: srv.Name,
Enode: node.String(),
ID: node.ID.String(),
IP: node.IP.String(),
ListenAddr: srv.ListenAddr,
Protocols: make(map[string]interface{}),
}
info.Ports.Discovery = int(node.UDP)
info.Ports.Listener = int(node.TCP)
// Gather all the running protocol infos (only once per protocol type)
for _, proto := range srv.Protocols {
if _, ok := info.Protocols[proto.Name]; !ok {
nodeInfo := interface{}("unknown")
if query := proto.NodeInfo; query != nil {
nodeInfo = proto.NodeInfo()
}
info.Protocols[proto.Name] = nodeInfo
}
}
return info
}
// PeersInfo returns an array of metadata objects describing connected peers.
func (srv *Server) PeersInfo() []*PeerInfo {
// Gather all the generic and sub-protocol specific infos
infos := make([]*PeerInfo, 0, srv.PeerCount())
for _, peer := range srv.Peers() {
if peer != nil {
infos = append(infos, peer.Info())
}
}
// Sort the result array alphabetically by node identifier
for i := 0; i < len(infos); i++ {
for j := i + 1; j < len(infos); j++ {
if infos[i].ID > infos[j].ID {
infos[i], infos[j] = infos[j], infos[i]
}
}
}
return infos
}