helia-coord 1.9.1 → 1.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -81,7 +81,10 @@ class CreateHeliaNode {
|
|
|
81
81
|
// Configure services
|
|
82
82
|
const services = {
|
|
83
83
|
identify: identify(),
|
|
84
|
-
pubsub: gossipsub({
|
|
84
|
+
pubsub: gossipsub({
|
|
85
|
+
allowPublishToZeroTopicPeers: true,
|
|
86
|
+
emitSelf: true // Enable receiving own messages for testing
|
|
87
|
+
})
|
|
85
88
|
}
|
|
86
89
|
|
|
87
90
|
// libp2p is the networking layer that underpins Helia
|
package/examples/start-node.js
CHANGED
|
@@ -15,7 +15,10 @@ class PubsubAdapter {
|
|
|
15
15
|
// Dependency Injection
|
|
16
16
|
this.ipfs = localConfig.ipfsAdapter
|
|
17
17
|
if (!this.ipfs) {
|
|
18
|
-
|
|
18
|
+
// Only log if log is available (may not be during construction)
|
|
19
|
+
if (this.log) {
|
|
20
|
+
this.log.statusLog(3, `this.ipfs: ${this.ipfs}`)
|
|
21
|
+
}
|
|
19
22
|
throw new Error(
|
|
20
23
|
'Instance of IPFS adapter required when instantiating Pubsub Adapter.'
|
|
21
24
|
)
|
|
@@ -89,13 +92,14 @@ class PubsubAdapter {
|
|
|
89
92
|
|
|
90
93
|
throw new Error('Pubsub service not initialized. Ensure gossipsub is configured in libp2p services.')
|
|
91
94
|
} catch (err) {
|
|
95
|
+
this.log.statusLog(1, `Error getting pubsub service: ${err.message}`)
|
|
92
96
|
console.error('Error getting pubsub service:', err)
|
|
93
97
|
throw err
|
|
94
98
|
}
|
|
95
99
|
}
|
|
96
100
|
|
|
97
101
|
// Set up a single global message listener that routes to topic-specific handlers
|
|
98
|
-
_setupGlobalMessageListener () {
|
|
102
|
+
async _setupGlobalMessageListener () {
|
|
99
103
|
if (this._globalListenerSetup) {
|
|
100
104
|
this.log.statusLog(3, 'Global message listener already set up, skipping')
|
|
101
105
|
return
|
|
@@ -104,19 +108,73 @@ class PubsubAdapter {
|
|
|
104
108
|
try {
|
|
105
109
|
const pubsub = this._getPubsubService()
|
|
106
110
|
|
|
111
|
+
this.log.statusLog(3, `Pubsub service: ${pubsub.constructor?.name || 'unknown'}, type: ${typeof pubsub}`)
|
|
112
|
+
this.log.statusLog(3, `Has addEventListener: ${typeof pubsub.addEventListener}, has on: ${typeof pubsub.on}`)
|
|
113
|
+
|
|
107
114
|
this.log.statusLog(2, 'Setting up global pubsub message listener...')
|
|
108
115
|
|
|
109
|
-
//
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
116
|
+
// Try multiple event listener patterns for compatibility
|
|
117
|
+
let listenerAttached = false
|
|
118
|
+
|
|
119
|
+
// Check if service is started (it's a property, not a method)
|
|
120
|
+
// Services are typically started automatically by libp2p, but verify
|
|
121
|
+
if (pubsub.isStarted === false && typeof pubsub.start === 'function') {
|
|
122
|
+
this.log.statusLog(2, 'Pubsub service not started, starting...')
|
|
123
|
+
await pubsub.start()
|
|
124
|
+
this.log.statusLog(2, 'Pubsub service started')
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Pattern 1: addEventListener (EventTarget pattern) - for 'message' event
|
|
128
|
+
if (typeof pubsub.addEventListener === 'function') {
|
|
129
|
+
this.log.statusLog(3, 'Using addEventListener pattern for "message" event')
|
|
130
|
+
const messageHandler = (event) => {
|
|
131
|
+
this.log.statusLog(3, `Pubsub message event received (addEventListener), topic: ${event.detail?.topic || 'unknown'}`)
|
|
132
|
+
this._routeMessage(event)
|
|
133
|
+
}
|
|
134
|
+
pubsub.addEventListener('message', messageHandler)
|
|
135
|
+
// Store handler reference for potential cleanup
|
|
136
|
+
this._messageHandler = messageHandler
|
|
137
|
+
listenerAttached = true
|
|
138
|
+
this.log.statusLog(3, 'addEventListener attached successfully')
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Pattern 2: on() method (EventEmitter pattern) - for 'message' event
|
|
142
|
+
if (typeof pubsub.on === 'function') {
|
|
143
|
+
this.log.statusLog(3, 'Using on() pattern for "message" event')
|
|
144
|
+
pubsub.on('message', (event) => {
|
|
145
|
+
this.log.statusLog(3, `Pubsub message event received (on), topic: ${event.detail?.topic || 'unknown'}`)
|
|
146
|
+
this._routeMessage(event)
|
|
147
|
+
})
|
|
148
|
+
listenerAttached = true
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Pattern 3: Also listen for 'gossipsub:message' event (gossipsub-specific)
|
|
152
|
+
if (typeof pubsub.addEventListener === 'function') {
|
|
153
|
+
this.log.statusLog(3, 'Also listening for "gossipsub:message" event')
|
|
154
|
+
const gossipsubMessageHandler = (event) => {
|
|
155
|
+
// Convert gossipsub:message to message format
|
|
156
|
+
if (event.detail?.msg) {
|
|
157
|
+
const convertedEvent = {
|
|
158
|
+
detail: event.detail.msg
|
|
159
|
+
}
|
|
160
|
+
this.log.statusLog(3, `Pubsub gossipsub:message event received, converting, topic: ${event.detail.msg?.topic || 'unknown'}`)
|
|
161
|
+
this._routeMessage(convertedEvent)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
pubsub.addEventListener('gossipsub:message', gossipsubMessageHandler)
|
|
165
|
+
this._gossipsubMessageHandler = gossipsubMessageHandler
|
|
166
|
+
this.log.statusLog(3, 'gossipsub:message listener attached successfully')
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (!listenerAttached) {
|
|
170
|
+
throw new Error('No supported event listener method found on pubsub service')
|
|
171
|
+
}
|
|
114
172
|
|
|
115
173
|
this._globalListenerSetup = true
|
|
116
174
|
this.log.statusLog(0, 'Global pubsub message listener successfully set up')
|
|
117
175
|
} catch (err) {
|
|
118
|
-
console.error('Error setting up global message listener:', err)
|
|
119
176
|
this.log.statusLog(1, `Error setting up global message listener: ${err.message}`)
|
|
177
|
+
console.error('Error setting up global message listener:', err)
|
|
120
178
|
throw err
|
|
121
179
|
}
|
|
122
180
|
}
|
|
@@ -124,13 +182,12 @@ class PubsubAdapter {
|
|
|
124
182
|
// Route incoming messages to the appropriate handler based on topic
|
|
125
183
|
async _routeMessage (event) {
|
|
126
184
|
try {
|
|
127
|
-
//
|
|
128
|
-
//
|
|
129
|
-
|
|
130
|
-
const msgDetail = event.detail || event
|
|
185
|
+
// In Helia v6/gossipsub, the 'message' event has event.detail as the Message object directly
|
|
186
|
+
// Message structure: { type: 'signed'|'unsigned', topic: string, data: Uint8Array, from?: PeerId, sequenceNumber?: bigint, ... }
|
|
187
|
+
const message = event.detail || event
|
|
131
188
|
|
|
132
|
-
// Extract topic
|
|
133
|
-
const topic =
|
|
189
|
+
// Extract topic from the Message object
|
|
190
|
+
const topic = message.topic
|
|
134
191
|
|
|
135
192
|
if (!topic) {
|
|
136
193
|
this.log.statusLog(1, `Received pubsub message without topic. Event keys: ${Object.keys(event).join(', ')}`)
|
|
@@ -143,14 +200,14 @@ class PubsubAdapter {
|
|
|
143
200
|
const handler = this.topicHandlers.get(topic)
|
|
144
201
|
|
|
145
202
|
if (handler) {
|
|
146
|
-
// Wrap
|
|
147
|
-
//
|
|
203
|
+
// Wrap message in expected format (msg.detail structure) for backward compatibility
|
|
204
|
+
// The existing handlers expect: { detail: { topic, from, data, sequenceNumber } }
|
|
148
205
|
const wrappedEvent = {
|
|
149
206
|
detail: {
|
|
150
|
-
topic,
|
|
151
|
-
from:
|
|
152
|
-
data:
|
|
153
|
-
sequenceNumber:
|
|
207
|
+
topic: message.topic,
|
|
208
|
+
from: message.from, // PeerId object
|
|
209
|
+
data: message.data, // Uint8Array
|
|
210
|
+
sequenceNumber: message.sequenceNumber // bigint
|
|
154
211
|
}
|
|
155
212
|
}
|
|
156
213
|
|
|
@@ -163,8 +220,8 @@ class PubsubAdapter {
|
|
|
163
220
|
this.log.statusLog(3, `No handler registered for topic: ${topic}. Registered topics: ${Array.from(this.topicHandlers.keys()).join(', ')}`)
|
|
164
221
|
}
|
|
165
222
|
} catch (err) {
|
|
166
|
-
console.error('Error routing pubsub message:', err)
|
|
167
223
|
this.log.statusLog(1, `Error routing pubsub message: ${err.message}`)
|
|
224
|
+
console.error('Error routing pubsub message:', err)
|
|
168
225
|
}
|
|
169
226
|
}
|
|
170
227
|
|
|
@@ -179,7 +236,7 @@ class PubsubAdapter {
|
|
|
179
236
|
async subscribeToPubsubChannel (chanName, handler, thisNode) {
|
|
180
237
|
try {
|
|
181
238
|
// Ensure global listener is set up
|
|
182
|
-
this._setupGlobalMessageListener()
|
|
239
|
+
await this._setupGlobalMessageListener()
|
|
183
240
|
|
|
184
241
|
// Get and validate pubsub service
|
|
185
242
|
const pubsub = this._getPubsubService()
|
|
@@ -232,8 +289,8 @@ class PubsubAdapter {
|
|
|
232
289
|
|
|
233
290
|
return true
|
|
234
291
|
} catch (err) {
|
|
235
|
-
console.error('Error in subscribeToPubsubChannel():', err)
|
|
236
292
|
this.log.statusLog(1, `Error subscribing to pubsub channel ${chanName}: ${err.message}`)
|
|
293
|
+
console.error('Error in subscribeToPubsubChannel():', err)
|
|
237
294
|
throw err
|
|
238
295
|
}
|
|
239
296
|
}
|
|
@@ -246,7 +303,7 @@ class PubsubAdapter {
|
|
|
246
303
|
const { chanName, handler } = inObj
|
|
247
304
|
|
|
248
305
|
// Ensure global listener is set up
|
|
249
|
-
this._setupGlobalMessageListener()
|
|
306
|
+
await this._setupGlobalMessageListener()
|
|
250
307
|
|
|
251
308
|
// Get and validate pubsub service
|
|
252
309
|
const pubsub = this._getPubsubService()
|
|
@@ -263,8 +320,8 @@ class PubsubAdapter {
|
|
|
263
320
|
|
|
264
321
|
return true
|
|
265
322
|
} catch (err) {
|
|
266
|
-
console.error('Error in subscribeToCoordChannel():', err)
|
|
267
323
|
this.log.statusLog(1, `Error subscribing to coordination channel: ${err.message}`)
|
|
324
|
+
console.error('Error in subscribeToCoordChannel():', err)
|
|
268
325
|
throw err
|
|
269
326
|
}
|
|
270
327
|
}
|
|
@@ -294,7 +351,8 @@ class PubsubAdapter {
|
|
|
294
351
|
|
|
295
352
|
return false
|
|
296
353
|
} catch (err) {
|
|
297
|
-
|
|
354
|
+
this.log.statusLog(1, `Error in handleNewMessage(): ${err.message}`)
|
|
355
|
+
console.error('Error in handleNewMessage()', err)
|
|
298
356
|
throw err
|
|
299
357
|
}
|
|
300
358
|
}
|
|
@@ -340,9 +398,9 @@ class PubsubAdapter {
|
|
|
340
398
|
}
|
|
341
399
|
|
|
342
400
|
// This is not an /about JSON RPC query.
|
|
343
|
-
// console.log('JSON RPC is not targeting the /about endpoint')
|
|
344
401
|
return false
|
|
345
402
|
} catch (err) {
|
|
403
|
+
this.log.statusLog(1, `Error in captureMetrics: ${err.message}`)
|
|
346
404
|
console.error('Error in captureMetrics: ', err)
|
|
347
405
|
return false
|
|
348
406
|
}
|
|
@@ -404,8 +462,8 @@ class PubsubAdapter {
|
|
|
404
462
|
|
|
405
463
|
return true
|
|
406
464
|
} catch (err) {
|
|
407
|
-
console.error('Error in parsePubsubMessage(): ', err.message)
|
|
408
465
|
this.log.statusLog(2, `Error in parsePubsubMessage(): ${err.message}`)
|
|
466
|
+
console.error('Error in parsePubsubMessage(): ', err)
|
|
409
467
|
// Do not throw an error. This is a top-level function.
|
|
410
468
|
|
|
411
469
|
return false
|
|
@@ -453,14 +511,21 @@ class PubsubAdapter {
|
|
|
453
511
|
const topics = pubsub.getTopics ? pubsub.getTopics() : []
|
|
454
512
|
const registeredHandlers = Array.from(this.topicHandlers.keys())
|
|
455
513
|
|
|
514
|
+
// Log debug info at level 2
|
|
515
|
+
this.log.statusLog(2, `Pubsub service available: ${!!pubsub}, listener setup: ${this._globalListenerSetup}, topics: ${topics.length}, handlers: ${this.topicHandlers.size}`)
|
|
516
|
+
|
|
456
517
|
return {
|
|
457
518
|
serviceAvailable: true,
|
|
458
519
|
globalListenerSetup: this._globalListenerSetup,
|
|
459
520
|
subscribedTopics: topics,
|
|
460
521
|
registeredHandlers,
|
|
461
|
-
handlerCount: this.topicHandlers.size
|
|
522
|
+
handlerCount: this.topicHandlers.size,
|
|
523
|
+
hasAddEventListener: typeof pubsub.addEventListener === 'function',
|
|
524
|
+
hasOn: typeof pubsub.on === 'function'
|
|
462
525
|
}
|
|
463
526
|
} catch (err) {
|
|
527
|
+
this.log.statusLog(1, `Error in getPubsubStatus: ${err.message}`)
|
|
528
|
+
console.error('Error in getPubsubStatus:', err)
|
|
464
529
|
return {
|
|
465
530
|
serviceAvailable: false,
|
|
466
531
|
error: err.message,
|
|
@@ -74,7 +74,8 @@ class Messaging {
|
|
|
74
74
|
|
|
75
75
|
return true
|
|
76
76
|
} catch (err) {
|
|
77
|
-
|
|
77
|
+
this.log.statusLog(1, `Error in messaging.js/sendMsg(): ${err.message}`)
|
|
78
|
+
console.error('Error in messaging.js/sendMsg()', err)
|
|
78
79
|
throw err
|
|
79
80
|
}
|
|
80
81
|
}
|
|
@@ -90,12 +91,13 @@ class Messaging {
|
|
|
90
91
|
|
|
91
92
|
return true
|
|
92
93
|
} catch (err) {
|
|
93
|
-
|
|
94
|
+
this.log.statusLog(1, `Error in sendAck(): ${err.message}`)
|
|
95
|
+
console.error('Error in sendAck()', err)
|
|
94
96
|
throw err
|
|
95
97
|
}
|
|
96
98
|
}
|
|
97
99
|
|
|
98
|
-
// A handler function that is called when a new message is
|
|
100
|
+
// A handler function that is called when a new message is received on the
|
|
99
101
|
// pubsub channel for this IPFS node. It does the following:
|
|
100
102
|
// - Decrypts the message.
|
|
101
103
|
// - Sends an ACK message to the sender of the message.
|
|
@@ -180,6 +182,7 @@ class Messaging {
|
|
|
180
182
|
|
|
181
183
|
return retObj
|
|
182
184
|
} catch (err) {
|
|
185
|
+
this.log.statusLog(1, `Error in handleIncomingData(): ${err.message}`)
|
|
183
186
|
console.error('Error in helia-coord/lib/adpaters/pubsub-adapter/messaging.js/handleIncomingData(): ', err)
|
|
184
187
|
|
|
185
188
|
// Do not throw an error. This is a top-level function called by an Interval.
|
|
@@ -218,7 +221,8 @@ class Messaging {
|
|
|
218
221
|
|
|
219
222
|
return outMsgObj
|
|
220
223
|
} catch (err) {
|
|
221
|
-
|
|
224
|
+
this.log.statusLog(1, `Error in generateMsgObj(): ${err.message}`)
|
|
225
|
+
console.error('Error in generateMsgObj()', err)
|
|
222
226
|
throw err
|
|
223
227
|
}
|
|
224
228
|
}
|
|
@@ -240,7 +244,7 @@ class Messaging {
|
|
|
240
244
|
// 3/24/24 CT - Debugging issue with passing data between ipfs-bch-wallet
|
|
241
245
|
// -service and -consumer.
|
|
242
246
|
if (!peerData || !peerData[0] || !peerData[0].data) {
|
|
243
|
-
|
|
247
|
+
this.log.statusLog(3, `peerData[0]: ${JSON.stringify(peerData[0])}`)
|
|
244
248
|
throw new Error('Required encryption information for peer is not available.')
|
|
245
249
|
}
|
|
246
250
|
|
|
@@ -274,6 +278,7 @@ class Messaging {
|
|
|
274
278
|
|
|
275
279
|
return outMsgObj
|
|
276
280
|
} catch (err) {
|
|
281
|
+
this.log.statusLog(1, `Error in generateAckMsg(): ${err.message}`)
|
|
277
282
|
console.error('Error in generateAckMsg()', err)
|
|
278
283
|
throw err
|
|
279
284
|
}
|
|
@@ -302,6 +307,7 @@ class Messaging {
|
|
|
302
307
|
|
|
303
308
|
throw new Error('Pubsub service not initialized. Ensure gossipsub is configured in libp2p services.')
|
|
304
309
|
} catch (err) {
|
|
310
|
+
this.log.statusLog(1, `Error getting pubsub service: ${err.message}`)
|
|
305
311
|
console.error('Error getting pubsub service:', err)
|
|
306
312
|
throw err
|
|
307
313
|
}
|
|
@@ -335,8 +341,8 @@ class Messaging {
|
|
|
335
341
|
|
|
336
342
|
return true
|
|
337
343
|
} catch (err) {
|
|
338
|
-
console.error('Error in publishToPubsubChannel():', err)
|
|
339
344
|
this.log.statusLog(1, `Error publishing to channel ${chanName}: ${err.message}`)
|
|
345
|
+
console.error('Error in publishToPubsubChannel():', err)
|
|
340
346
|
throw err
|
|
341
347
|
}
|
|
342
348
|
}
|
|
@@ -410,7 +416,8 @@ class Messaging {
|
|
|
410
416
|
|
|
411
417
|
return msgObj
|
|
412
418
|
} catch (err) {
|
|
413
|
-
|
|
419
|
+
this.log.statusLog(1, `Error in addMsgToQueue: ${err.message}`)
|
|
420
|
+
console.error('Error in addMsgToQueue', err)
|
|
414
421
|
throw err
|
|
415
422
|
}
|
|
416
423
|
}
|
|
@@ -21,7 +21,11 @@ class ResendMsg {
|
|
|
21
21
|
// console.log(`resendMsg() msgObj: ${JSON.stringify(msgObj, null, 2)}`)
|
|
22
22
|
|
|
23
23
|
if (!this.msgObj) {
|
|
24
|
-
|
|
24
|
+
if (this.msgLib?.log) {
|
|
25
|
+
this.msgLib.log.statusLog(3, 'resend() given empty message object. Can not resend message. Skipping.')
|
|
26
|
+
} else {
|
|
27
|
+
console.log('ipfs-coord-esm/lib/adapters/pubsub-adapter/resend-msg.js/resend() given empty message object. Can not resend message. Skipping.')
|
|
28
|
+
}
|
|
25
29
|
return 0
|
|
26
30
|
}
|
|
27
31
|
|
|
@@ -48,6 +52,9 @@ class ResendMsg {
|
|
|
48
52
|
return 2
|
|
49
53
|
}
|
|
50
54
|
} catch (err) {
|
|
55
|
+
if (this.msgLib?.log) {
|
|
56
|
+
this.msgLib.log.statusLog(1, `Error in resendMsg(): ${err.message}`)
|
|
57
|
+
}
|
|
51
58
|
console.error('Error in resendMsg(): ', err)
|
|
52
59
|
// Do not throw an error. This is a top-level function called by an Interval.
|
|
53
60
|
return 0
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "helia-coord",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.2",
|
|
4
4
|
"description": "A JS library for helping IPFS peers coordinate, find a common interest, and stay connected around that interest.",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"cross-env": "7.0.3",
|
|
38
38
|
"datastore-fs": "10.0.2",
|
|
39
39
|
"delay": "6.0.0",
|
|
40
|
-
"helia": "
|
|
40
|
+
"helia": "6.0.16",
|
|
41
41
|
"lodash.clonedeep": "4.5.0",
|
|
42
42
|
"minimal-slp-wallet": "7.1.4",
|
|
43
43
|
"mocha": "10.0.0",
|