forked from alexbakker/gonano
/
peers.go
115 lines (95 loc) · 2.46 KB
/
peers.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package node
import (
"errors"
"net"
"github.com/BananoCoin/gobanano/nano/crypto/random"
)
var (
ErrMaxPeers = errors.New("max amount of peers reached")
ErrPeerExists = errors.New("this peer already exists in the list")
)
// PeerList represents a list of peers.
type PeerList struct {
peers []*Peer
max int
}
// NewPeerList creates a new peer list with the given maximum capacity.
func NewPeerList(max int) *PeerList {
return &PeerList{max: max}
}
// Add creates a new peer instance with the given address, adds it to the
// internal peer list and returns it.
func (l *PeerList) Add(addr *net.UDPAddr) (*Peer, error) {
// enforce a maximum amount of peers
if l.Full() {
return nil, ErrMaxPeers
}
// check if we already have this peer in our list
if l.Get(addr) != nil {
return nil, ErrPeerExists
}
peer := &Peer{Addr: addr}
l.peers = append(l.peers, peer)
return peer, nil
}
// Get retrieves a peer with the given address. If no such peer exists, nil is
// returned.
func (l *PeerList) Get(addr *net.UDPAddr) *Peer {
for _, peer := range l.peers {
if peer.Addr.IP.Equal(addr.IP) && peer.Addr.Port == addr.Port {
return peer
}
}
return nil
}
// Remove removes the given peer from the list.
func (l *PeerList) Remove(peer *Peer) {
for i := range l.peers {
if l.peers[i] == peer {
l.peers = append(l.peers[:i], l.peers[i+1:]...)
return
}
}
panic("peer not in list")
}
// Full reports whether the internal peer list has reached its maximum capacity.
func (l *PeerList) Full() bool {
return len(l.peers) >= l.max
}
// Len returns the length of the internal peer list.
func (l *PeerList) Len() int {
return len(l.peers)
}
// Pick returns 8 random peers from the internal peer list. This function is
// usually used to populate a KeepAlivePacket.
func (l *PeerList) Pick() ([]*Peer, error) {
var size int
if len(l.peers) > 8 {
size = 8
} else {
size = len(l.peers)
}
perm, err := random.Perm(len(l.peers))
if err != nil {
return nil, err
}
peers := make([]*Peer, size)
for i := 0; i < size; i++ {
peers[i] = l.peers[perm[i]]
}
return peers, nil
}
// Random picks one random peer from the internal peer list and returns it.
func (l *PeerList) Random() (*Peer, error) {
i, err := random.Intn(len(l.peers))
if err != nil {
return nil, err
}
return l.peers[i], nil
}
// Peers returns a copy of the internal peer list.
func (l *PeerList) Peers() []*Peer {
peers := make([]*Peer, len(l.peers))
copy(peers, l.peers)
return peers
}