-
Notifications
You must be signed in to change notification settings - Fork 232
/
subscriber_notifee.go
194 lines (162 loc) · 5.84 KB
/
subscriber_notifee.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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
package dht
import (
"context"
"fmt"
"github.com/libp2p/go-libp2p-core/event"
"github.com/libp2p/go-libp2p-core/network"
"github.com/libp2p/go-libp2p-core/peer"
"github.com/libp2p/go-eventbus"
"github.com/jbenet/goprocess"
ma "github.com/multiformats/go-multiaddr"
)
// subscriberNotifee implements network.Notifee and also manages the subscriber to the event bus. We consume peer
// identification events to trigger inclusion in the routing table, and we consume Disconnected events to eject peers
// from it.
type subscriberNotifee struct {
dht *IpfsDHT
subs event.Subscription
}
func newSubscriberNotifiee(dht *IpfsDHT) (*subscriberNotifee, error) {
bufSize := eventbus.BufSize(256)
evts := []interface{}{
// register for event bus notifications of when peers successfully complete identification in order to update
// the routing table
new(event.EvtPeerIdentificationCompleted),
// register for event bus protocol ID changes in order to update the routing table
new(event.EvtPeerProtocolsUpdated),
// register for event bus notifications for when our local address/addresses change so we can
// advertise those to the network
new(event.EvtLocalAddressesUpdated),
}
// register for event bus local routability changes in order to trigger switching between client and server modes
// only register for events if the DHT is operating in ModeAuto
if dht.auto == ModeAuto || dht.auto == ModeAutoServer {
evts = append(evts, new(event.EvtLocalReachabilityChanged))
}
subs, err := dht.host.EventBus().Subscribe(evts, bufSize)
if err != nil {
return nil, fmt.Errorf("dht could not subscribe to eventbus events; err: %s", err)
}
nn := &subscriberNotifee{
dht: dht,
subs: subs,
}
// register for network notifications
dht.host.Network().Notify(nn)
return nn, nil
}
func (nn *subscriberNotifee) subscribe(proc goprocess.Process) {
dht := nn.dht
defer dht.host.Network().StopNotify(nn)
defer nn.subs.Close()
for {
select {
case e, more := <-nn.subs.Out():
if !more {
return
}
switch evt := e.(type) {
case event.EvtLocalAddressesUpdated:
// when our address changes, we should proactively tell our closest peers about it so
// we become discoverable quickly. The Identify protocol will push a signed peer record
// with our new address to all peers we are connected to. However, we might not necessarily be connected
// to our closet peers & so in the true spirit of Zen, searching for ourself in the network really is the best way
// to to forge connections with those matter.
if dht.autoRefresh || dht.testAddressUpdateProcessing {
dht.rtRefreshManager.RefreshNoWait()
}
case event.EvtPeerProtocolsUpdated:
handlePeerChangeEvent(dht, evt.Peer)
case event.EvtPeerIdentificationCompleted:
handlePeerChangeEvent(dht, evt.Peer)
case event.EvtLocalReachabilityChanged:
if dht.auto == ModeAuto || dht.auto == ModeAutoServer {
handleLocalReachabilityChangedEvent(dht, evt)
} else {
// something has gone really wrong if we get an event we did not subscribe to
logger.Errorf("received LocalReachabilityChanged event that was not subscribed to")
}
default:
// something has gone really wrong if we get an event for another type
logger.Errorf("got wrong type from subscription: %T", e)
}
case <-proc.Closing():
return
}
}
}
func handlePeerChangeEvent(dht *IpfsDHT, p peer.ID) {
valid, err := dht.validRTPeer(p)
if err != nil {
logger.Errorf("could not check peerstore for protocol support: err: %s", err)
return
} else if valid {
dht.peerFound(dht.ctx, p, false)
dht.fixRTIfNeeded()
} else {
dht.peerStoppedDHT(dht.ctx, p)
}
}
func handleLocalReachabilityChangedEvent(dht *IpfsDHT, e event.EvtLocalReachabilityChanged) {
var target mode
switch e.Reachability {
case network.ReachabilityPrivate:
target = modeClient
case network.ReachabilityUnknown:
if dht.auto == ModeAutoServer {
target = modeServer
} else {
target = modeClient
}
case network.ReachabilityPublic:
target = modeServer
}
logger.Infof("processed event %T; performing dht mode switch", e)
err := dht.setMode(target)
// NOTE: the mode will be printed out as a decimal.
if err == nil {
logger.Infow("switched DHT mode successfully", "mode", target)
} else {
logger.Errorw("switching DHT mode failed", "mode", target, "error", err)
}
}
// validRTPeer returns true if the peer supports the DHT protocol and false otherwise. Supporting the DHT protocol means
// supporting the primary protocols, we do not want to add peers that are speaking obsolete secondary protocols to our
// routing table
func (dht *IpfsDHT) validRTPeer(p peer.ID) (bool, error) {
b, err := dht.peerstore.FirstSupportedProtocol(p, dht.protocolsStrs...)
if len(b) == 0 || err != nil {
return false, err
}
return dht.routingTablePeerFilter == nil || dht.routingTablePeerFilter(dht, p), nil
}
type disconnector interface {
OnDisconnect(ctx context.Context, p peer.ID)
}
func (nn *subscriberNotifee) Disconnected(n network.Network, v network.Conn) {
dht := nn.dht
ms, ok := dht.msgSender.(disconnector)
if !ok {
return
}
select {
case <-dht.Process().Closing():
return
default:
}
p := v.RemotePeer()
// Lock and check to see if we're still connected. We lock to make sure
// we don't concurrently process a connect event.
dht.plk.Lock()
defer dht.plk.Unlock()
if dht.host.Network().Connectedness(p) == network.Connected {
// We're still connected.
return
}
ms.OnDisconnect(dht.Context(), p)
}
func (nn *subscriberNotifee) Connected(network.Network, network.Conn) {}
func (nn *subscriberNotifee) OpenedStream(network.Network, network.Stream) {}
func (nn *subscriberNotifee) ClosedStream(network.Network, network.Stream) {}
func (nn *subscriberNotifee) Listen(network.Network, ma.Multiaddr) {}
func (nn *subscriberNotifee) ListenClose(network.Network, ma.Multiaddr) {}