@@ -59,17 +59,53 @@ class FloodSub extends EventEmitter {
59
59
this . _dialPeer = this . _dialPeer . bind ( this )
60
60
}
61
61
62
+ _addPeer ( peer ) {
63
+ const id = peer . info . id . toB58String ( )
64
+
65
+ /*
66
+ Always use an existing peer.
67
+
68
+ What is happening here is: "If the other peer has already dialed to me, we already have
69
+ an establish link between the two, what might be missing is a
70
+ Connection specifically between me and that Peer"
71
+ */
72
+ let existing = this . peers . get ( id )
73
+ if ( existing ) {
74
+ log ( 'already existing peer' , id )
75
+ ++ existing . _references
76
+ } else {
77
+ log ( 'new peer' , id )
78
+ this . peers . set ( id , peer )
79
+ existing = peer
80
+ }
81
+
82
+ return existing
83
+ }
84
+
85
+ _removePeer ( peer ) {
86
+ const id = peer . info . id . toB58String ( )
87
+
88
+ log ( 'remove' , id , peer . _references )
89
+ // Only delete when no one else is referencing this peer.
90
+ if ( -- peer . _references === 0 ) {
91
+ log ( 'delete peer' , id )
92
+ this . peers . delete ( id )
93
+ }
94
+
95
+ return peer
96
+ }
97
+
62
98
_dialPeer ( peerInfo , callback ) {
63
99
callback = callback || function noop ( ) { }
64
100
const idB58Str = peerInfo . id . toB58String ( )
65
- log ( 'dialing %s' , idB58Str )
66
101
67
102
// If already have a PubSub conn, ignore
68
103
const peer = this . peers . get ( idB58Str )
69
104
if ( peer && peer . isConnected ) {
70
105
return setImmediate ( ( ) => callback ( ) )
71
106
}
72
107
108
+ log ( 'dialing %s' , idB58Str )
73
109
this . libp2p . dial ( peerInfo , multicodec , ( err , conn ) => {
74
110
if ( err ) {
75
111
log . err ( err )
@@ -82,13 +118,9 @@ class FloodSub extends EventEmitter {
82
118
83
119
_onDial ( peerInfo , conn , callback ) {
84
120
const idB58Str = peerInfo . id . toB58String ( )
121
+ log ( 'connected' , idB58Str )
85
122
86
- // If already had a dial to me, just add the conn
87
- if ( ! this . peers . has ( idB58Str ) ) {
88
- this . peers . set ( idB58Str , new Peer ( peerInfo ) )
89
- }
90
-
91
- const peer = this . peers . get ( idB58Str )
123
+ const peer = this . _addPeer ( new Peer ( peerInfo ) )
92
124
peer . attachConnection ( conn )
93
125
94
126
// Immediately send my own subscriptions to the newly established conn
@@ -104,24 +136,20 @@ class FloodSub extends EventEmitter {
104
136
}
105
137
106
138
const idB58Str = peerInfo . id . toB58String ( )
139
+ const peer = this . _addPeer ( new Peer ( peerInfo ) )
107
140
108
- if ( ! this . peers . has ( idB58Str ) ) {
109
- log ( 'new peer' , idB58Str )
110
- this . peers . set ( idB58Str , new Peer ( peerInfo ) )
111
- }
112
-
113
- this . _processConnection ( idB58Str , conn )
141
+ this . _processConnection ( idB58Str , conn , peer )
114
142
} )
115
143
}
116
144
117
- _processConnection ( idB58Str , conn ) {
145
+ _processConnection ( idB58Str , conn , peer ) {
118
146
pull (
119
147
conn ,
120
148
lp . decode ( ) ,
121
149
pull . map ( ( data ) => pb . rpc . RPC . decode ( data ) ) ,
122
150
pull . drain (
123
151
( rpc ) => this . _onRpc ( idB58Str , rpc ) ,
124
- ( err ) => this . _onConnectionEnd ( idB58Str , err )
152
+ ( err ) => this . _onConnectionEnd ( idB58Str , peer , err )
125
153
)
126
154
)
127
155
}
@@ -131,11 +159,12 @@ class FloodSub extends EventEmitter {
131
159
return
132
160
}
133
161
162
+ log ( 'rpc from' , idB58Str )
134
163
const subs = rpc . subscriptions
135
164
const msgs = rpc . msgs
136
165
137
166
if ( msgs && msgs . length ) {
138
- this . _processRpcMessages ( rpc . msgs )
167
+ this . _processRpcMessages ( utils . normalizeInRpcMessages ( rpc . msgs ) )
139
168
}
140
169
141
170
if ( subs && subs . length ) {
@@ -164,13 +193,14 @@ class FloodSub extends EventEmitter {
164
193
} )
165
194
}
166
195
167
- _onConnectionEnd ( idB58Str , err ) {
196
+ _onConnectionEnd ( idB58Str , peer , err ) {
168
197
// socket hang up, means the one side canceled
169
198
if ( err && err . message !== 'socket hang up' ) {
170
199
log . err ( err )
171
200
}
172
201
173
- this . peers . delete ( idB58Str )
202
+ log ( 'connection ended' , idB58Str , err ? err . message : '' )
203
+ this . _removePeer ( peer )
174
204
}
175
205
176
206
_emitMessages ( topics , messages ) {
@@ -191,7 +221,7 @@ class FloodSub extends EventEmitter {
191
221
return
192
222
}
193
223
194
- peer . sendMessages ( messages )
224
+ peer . sendMessages ( utils . normalizeOutRpcMessages ( messages ) )
195
225
196
226
log ( 'publish msgs on topics' , topics , peer . info . id . toB58String ( ) )
197
227
} )
@@ -241,11 +271,15 @@ class FloodSub extends EventEmitter {
241
271
this . libp2p . unhandle ( multicodec )
242
272
this . libp2p . removeListener ( 'peer:connect' , this . _dialPeer )
243
273
274
+ log ( 'stopping' )
244
275
asyncEach ( this . peers . values ( ) , ( peer , cb ) => peer . close ( cb ) , ( err ) => {
245
276
if ( err ) {
246
277
return callback ( err )
247
278
}
279
+
280
+ log ( 'stopped' )
248
281
this . peers = new Map ( )
282
+ this . subscriptions = new Set ( )
249
283
this . started = false
250
284
callback ( )
251
285
} )
@@ -287,7 +321,7 @@ class FloodSub extends EventEmitter {
287
321
this . _emitMessages ( topics , msgObjects )
288
322
289
323
// send to all the other peers
290
- this . _forwardMessages ( topics , messages . map ( buildMessage ) )
324
+ this . _forwardMessages ( topics , msgObjects )
291
325
}
292
326
293
327
/**
@@ -303,14 +337,18 @@ class FloodSub extends EventEmitter {
303
337
304
338
topics . forEach ( ( topic ) => this . subscriptions . add ( topic ) )
305
339
306
- this . peers . forEach ( ( peer ) => checkIfReady ( peer ) )
340
+ this . peers . forEach ( ( peer ) => sendSubscriptionsOnceReady ( peer ) )
307
341
// make sure that FloodSub is already mounted
308
- function checkIfReady ( peer ) {
342
+ function sendSubscriptionsOnceReady ( peer ) {
309
343
if ( peer && peer . isWritable ) {
310
- peer . sendSubscriptions ( topics )
311
- } else {
312
- setImmediate ( checkIfReady . bind ( peer ) )
344
+ return peer . sendSubscriptions ( topics )
345
+ }
346
+ const onConnection = ( ) => {
347
+ peer . removeListener ( 'connection' , onConnection )
348
+ sendSubscriptionsOnceReady ( peer )
313
349
}
350
+ peer . on ( 'connection' , onConnection )
351
+ peer . once ( 'close' , ( ) => peer . removeListener ( 'connection' , onConnection ) )
314
352
}
315
353
}
316
354
@@ -321,7 +359,11 @@ class FloodSub extends EventEmitter {
321
359
* @returns {undefined }
322
360
*/
323
361
unsubscribe ( topics ) {
324
- assert ( this . started , 'FloodSub is not started' )
362
+ // Avoid race conditions, by quietly ignoring unsub when shutdown.
363
+ if ( ! this . started ) {
364
+ return
365
+ }
366
+
325
367
topics = ensureArray ( topics )
326
368
327
369
topics . forEach ( ( topic ) => this . subscriptions . delete ( topic ) )
0 commit comments