helia-coord 1.6.0 → 1.7.0

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.
@@ -92,7 +92,8 @@ class CreateHeliaNode {
92
92
  '/ip4/127.0.0.1/tcp/0',
93
93
  '/ip4/0.0.0.0/tcp/4001',
94
94
  '/ip4/0.0.0.0/tcp/4003/ws',
95
- '/webrtc'
95
+ '/webrtc',
96
+ '/p2p-circuit'
96
97
  ]
97
98
  },
98
99
  transports: [
@@ -0,0 +1,5 @@
1
+ # webRTC example
2
+
3
+ This directory contains example code that attempts to follow the [this libp2p webRTC README](https://github.com/libp2p/js-libp2p/tree/main/packages/transport-webrtc) in order to connect a two nodes running behind NATs, through a public Circuit Relay server.
4
+
5
+
@@ -0,0 +1,159 @@
1
+ /*
2
+ This library creates a Helia IPFS node. This is done prior to attaching
3
+ helia-coord to the node.
4
+ This library is called by start-node.js.
5
+ */
6
+
7
+ // Global npm libraries
8
+ import { createHelia } from 'helia'
9
+ import fs from 'fs'
10
+ import { FsBlockstore } from 'blockstore-fs'
11
+ import { FsDatastore } from 'datastore-fs'
12
+ import { createLibp2p } from 'libp2p'
13
+ import { tcp } from '@libp2p/tcp'
14
+ import { noise } from '@chainsafe/libp2p-noise'
15
+ import { yamux } from '@chainsafe/libp2p-yamux'
16
+ // import { bootstrap } from '@libp2p/bootstrap'
17
+ // import { identifyService } from 'libp2p/identify'
18
+ import { identify } from '@libp2p/identify'
19
+ // import { circuitRelayTransport } from 'libp2p/circuit-relay'
20
+ import { circuitRelayTransport } from '@libp2p/circuit-relay-v2'
21
+ import { gossipsub } from '@chainsafe/libp2p-gossipsub'
22
+ import { webSockets } from '@libp2p/websockets'
23
+ import { publicIpv4 } from 'public-ip'
24
+ import { multiaddr } from '@multiformats/multiaddr'
25
+ import { webRTC } from '@libp2p/webrtc'
26
+ import { ping } from '@libp2p/ping'
27
+
28
+ const ROOT_DIR = './'
29
+ const IPFS_DIR = './.ipfsdata/ipfs'
30
+
31
+ class CreateHeliaNode {
32
+ constructor () {
33
+ this.publicIp = publicIpv4
34
+ }
35
+
36
+ // Start an IPFS node.
37
+ async start () {
38
+ try {
39
+ // Ensure the directory structure exists that is needed by the IPFS node to store data.
40
+ this.ensureBlocksDir()
41
+
42
+ // Create an IPFS node
43
+ const ipfs = await this.createNode()
44
+ // console.log('ipfs: ', ipfs)
45
+
46
+ this.id = ipfs.libp2p.peerId.toString()
47
+ console.log('IPFS ID: ', this.id)
48
+
49
+ // Attempt to guess our ip4 IP address.
50
+ const ip4 = await this.publicIp()
51
+ let detectedMultiaddr = `/ip4/${ip4}/tcp/4001/p2p/${this.id}`
52
+ detectedMultiaddr = multiaddr(detectedMultiaddr)
53
+
54
+ // Get the multiaddrs for the node.
55
+ const multiaddrs = ipfs.libp2p.getMultiaddrs()
56
+ multiaddrs.push(detectedMultiaddr)
57
+ console.log('Multiaddrs: ', multiaddrs)
58
+
59
+ this.multiaddrs = multiaddrs
60
+
61
+ // Signal that this adapter is ready.
62
+ this.isReady = true
63
+
64
+ this.ipfs = ipfs
65
+
66
+ return this.ipfs
67
+ } catch (err) {
68
+ console.error('Error in start()')
69
+
70
+ throw err
71
+ }
72
+ }
73
+
74
+ // This function creates an IPFS node using Helia.
75
+ // It returns the node as an object.
76
+ async createNode () {
77
+ try {
78
+ // Create block and data stores.
79
+ const blockstore = new FsBlockstore(`${IPFS_DIR}/blockstore`)
80
+ const datastore = new FsDatastore(`${IPFS_DIR}/datastore`)
81
+
82
+ // Configure services
83
+ const services = {
84
+ identify: identify(),
85
+ pubsub: gossipsub({ allowPublishToZeroTopicPeers: true }),
86
+ ping: ping()
87
+ }
88
+
89
+ // libp2p is the networking layer that underpins Helia
90
+ const libp2p = await createLibp2p({
91
+ datastore,
92
+ addresses: {
93
+ listen: [
94
+ '/ip4/127.0.0.1/tcp/0',
95
+ '/ip4/0.0.0.0/tcp/4001',
96
+ '/ip4/0.0.0.0/tcp/4003/ws',
97
+ '/webrtc',
98
+ '/p2p-circuit'
99
+ ]
100
+ },
101
+ transports: [
102
+ tcp(),
103
+ webSockets(),
104
+ circuitRelayTransport({ discoverRelays: 3 }),
105
+ webRTC()
106
+ ],
107
+ connectionEncrypters: [
108
+ noise()
109
+ ],
110
+ streamMuxers: [
111
+ yamux()
112
+ ],
113
+ services
114
+ })
115
+
116
+ // create a Helia node
117
+ const helia = await createHelia({
118
+ blockstore,
119
+ datastore,
120
+ libp2p
121
+ })
122
+
123
+ return helia
124
+ } catch (err) {
125
+ console.error('Error creating Helia node: ', err)
126
+
127
+ throw err
128
+ }
129
+ }
130
+
131
+ async stop () {
132
+ await this.ipfs.stop()
133
+
134
+ return true
135
+ }
136
+
137
+ // Ensure that the directories exist to store blocks from the IPFS network.
138
+ // This function is called at startup, before the IPFS node is started.
139
+ ensureBlocksDir () {
140
+ try {
141
+ !fs.existsSync(`${ROOT_DIR}.ipfsdata`) && fs.mkdirSync(`${ROOT_DIR}.ipfsdata`)
142
+
143
+ !fs.existsSync(`${IPFS_DIR}`) && fs.mkdirSync(`${IPFS_DIR}`)
144
+
145
+ !fs.existsSync(`${IPFS_DIR}/blockstore`) && fs.mkdirSync(`${IPFS_DIR}/blockstore`)
146
+
147
+ !fs.existsSync(`${IPFS_DIR}/datastore`) && fs.mkdirSync(`${IPFS_DIR}/datastore`)
148
+
149
+ // !fs.existsSync(`${IPFS_DIR}/datastore/peers`) && fs.mkdirSync(`${IPFS_DIR}/datastore/peers`)
150
+
151
+ return true
152
+ } catch (err) {
153
+ console.error('Error in ensureBlocksDir(): ', err)
154
+ throw err
155
+ }
156
+ }
157
+ }
158
+
159
+ export default CreateHeliaNode
@@ -0,0 +1,77 @@
1
+ /*
2
+ 1. Starts node.
3
+ 2. Waits to connect to Circuit Relay.
4
+ 3. Connects to remote node.
5
+ */
6
+
7
+ // Global npm libraries
8
+ import SlpWallet from 'minimal-slp-wallet'
9
+ import { WebRTC } from '@multiformats/multiaddr-matcher'
10
+ import { multiaddr } from '@multiformats/multiaddr'
11
+ import delay from 'delay'
12
+
13
+ // Local libraries
14
+ // import IpfsCoord from '../index.js'
15
+ import CreateHeliaNode from './create-helia-node.js'
16
+
17
+ const relayMA = '/ip4/5.78.70.29/tcp/4001/p2p/12D3KooWNbQrdvEpzKuZ6rxkAF9vBH56HeGJ9drmrF9bhBJBa2Nq'
18
+ // const remoteMa = '12D3KooWDaKkuwzCNEWUEfjYSh7SCjqpEdx7PW4pAD5P5CFZQmqW'
19
+
20
+ async function start () {
21
+ try {
22
+ // Create an instance of bch-js and IPFS.
23
+ const wallet = new SlpWallet()
24
+ await wallet.walletInfoPromise
25
+
26
+ const createHeliaNode = new CreateHeliaNode()
27
+ const thisNode = await createHeliaNode.start()
28
+
29
+ const relayMultiaddr = multiaddr(relayMA)
30
+ console.log('Relay multiaddr: ', relayMultiaddr)
31
+ await thisNode.libp2p.dial(relayMultiaddr, {
32
+ signal: AbortSignal.timeout(10000)
33
+ })
34
+
35
+ console.log('Connected to relay.')
36
+
37
+ let webRTCMultiaddr
38
+
39
+ // wait for the listener to make a reservation on the relay
40
+ while (true) {
41
+ webRTCMultiaddr = thisNode.libp2p.getMultiaddrs().find(ma => WebRTC.matches(ma))
42
+ console.log('WebRTC multiaddr: ', webRTCMultiaddr)
43
+ const allAddrs = thisNode.libp2p.getMultiaddrs()
44
+ console.log('All multiaddrs: ', allAddrs)
45
+
46
+ // const mas = thisNode.libp2p.getMultiaddrs()
47
+ // console.log('Multiaddrs: ', mas)
48
+
49
+ if (webRTCMultiaddr != null) {
50
+ break
51
+ }
52
+
53
+ // try again later
54
+ const now = new Date()
55
+ console.log('Waiting for reservation...', now.toISOString())
56
+ await delay(1000)
57
+ }
58
+ console.log('WebRTC multiaddr: ', webRTCMultiaddr)
59
+
60
+ // Pass bch-js and IPFS to ipfs-coord when instantiating it.
61
+ // const ipfsCoord = new IpfsCoord({
62
+ // ipfs,
63
+ // wallet,
64
+ // type: 'node.js',
65
+ // // type: 'browser'
66
+ // nodeType: 'external',
67
+ // debugLevel: 2
68
+ // })
69
+
70
+ // await ipfsCoord.start()
71
+ // console.log('IPFS and the coordination library is ready.')
72
+ } catch (err) {
73
+ console.error('Error in start(): ', err)
74
+ }
75
+ }
76
+
77
+ start()
@@ -0,0 +1,171 @@
1
+ /*
2
+ This library creates a Helia IPFS node. This is done prior to attaching
3
+ helia-coord to the node.
4
+ This library is called by start-node.js.
5
+ */
6
+
7
+ // Global npm libraries
8
+ import { createHelia } from 'helia'
9
+ import fs from 'fs'
10
+ import { FsBlockstore } from 'blockstore-fs'
11
+ import { FsDatastore } from 'datastore-fs'
12
+ import { createLibp2p } from 'libp2p'
13
+ import { tcp } from '@libp2p/tcp'
14
+ import { noise } from '@chainsafe/libp2p-noise'
15
+ import { yamux } from '@chainsafe/libp2p-yamux'
16
+ // import { bootstrap } from '@libp2p/bootstrap'
17
+ // import { identifyService } from 'libp2p/identify'
18
+ import { identify } from '@libp2p/identify'
19
+ // import { circuitRelayTransport } from '@libp2p/circuit-relay-v2'
20
+ import { circuitRelayServer, circuitRelayTransport } from '@libp2p/circuit-relay-v2'
21
+ import { gossipsub } from '@chainsafe/libp2p-gossipsub'
22
+ import { webSockets } from '@libp2p/websockets'
23
+ import { publicIpv4 } from 'public-ip'
24
+ import { multiaddr } from '@multiformats/multiaddr'
25
+ import { webRTC } from '@libp2p/webrtc'
26
+ import { ping } from '@libp2p/ping'
27
+
28
+ const ROOT_DIR = './'
29
+ const IPFS_DIR = './.ipfsdata/ipfs'
30
+
31
+ class CreateHeliaNode {
32
+ constructor () {
33
+ this.publicIp = publicIpv4
34
+ }
35
+
36
+ // Start an IPFS node.
37
+ async start () {
38
+ try {
39
+ // Ensure the directory structure exists that is needed by the IPFS node to store data.
40
+ this.ensureBlocksDir()
41
+
42
+ // Create an IPFS node
43
+ const ipfs = await this.createNode()
44
+ // console.log('ipfs: ', ipfs)
45
+
46
+ this.id = ipfs.libp2p.peerId.toString()
47
+ console.log('IPFS ID: ', this.id)
48
+
49
+ // Attempt to guess our ip4 IP address.
50
+ const ip4 = await this.publicIp()
51
+ let detectedMultiaddr = `/ip4/${ip4}/tcp/4001/p2p/${this.id}`
52
+ detectedMultiaddr = multiaddr(detectedMultiaddr)
53
+
54
+ // Get the multiaddrs for the node.
55
+ const multiaddrs = ipfs.libp2p.getMultiaddrs()
56
+ multiaddrs.push(detectedMultiaddr)
57
+ console.log('Multiaddrs: ', multiaddrs)
58
+
59
+ this.multiaddrs = multiaddrs
60
+
61
+ // Signal that this adapter is ready.
62
+ this.isReady = true
63
+
64
+ this.ipfs = ipfs
65
+
66
+ return this.ipfs
67
+ } catch (err) {
68
+ console.error('Error in start()')
69
+
70
+ throw err
71
+ }
72
+ }
73
+
74
+ // This function creates an IPFS node using Helia.
75
+ // It returns the node as an object.
76
+ async createNode () {
77
+ try {
78
+ // Create block and data stores.
79
+ const blockstore = new FsBlockstore(`${IPFS_DIR}/blockstore`)
80
+ const datastore = new FsDatastore(`${IPFS_DIR}/datastore`)
81
+
82
+ // Configure services
83
+ const services = {
84
+ identify: identify(),
85
+ pubsub: gossipsub({ allowPublishToZeroTopicPeers: true }),
86
+ ping: ping(),
87
+ relay: circuitRelayServer({ // makes the node function as a relay server
88
+ hopTimeout: 30 * 1000, // incoming relay requests must be resolved within this time limit
89
+ advertise: true,
90
+ reservations: {
91
+ maxReservations: 15, // how many peers are allowed to reserve relay slots on this server
92
+ reservationClearInterval: 300 * 1000, // how often to reclaim stale reservations
93
+ applyDefaultLimit: true, // whether to apply default data/duration limits to each relayed connection
94
+ defaultDurationLimit: 2 * 60 * 1000, // the default maximum amount of time a relayed connection can be open for
95
+ defaultDataLimit: BigInt(2 << 7), // the default maximum number of bytes that can be transferred over a relayed connection
96
+ maxInboundHopStreams: 32, // how many inbound HOP streams are allow simultaneously
97
+ maxOutboundHopStreams: 64 // how many outbound HOP streams are allow simultaneously
98
+ }
99
+ })
100
+ }
101
+
102
+ // libp2p is the networking layer that underpins Helia
103
+ const libp2p = await createLibp2p({
104
+ datastore,
105
+ addresses: {
106
+ listen: [
107
+ '/ip4/127.0.0.1/tcp/0',
108
+ '/ip4/0.0.0.0/tcp/4001',
109
+ '/ip4/0.0.0.0/tcp/4003/ws',
110
+ '/webrtc'
111
+ ]
112
+ },
113
+ transports: [
114
+ tcp(),
115
+ webSockets(),
116
+ circuitRelayTransport({ discoverRelays: 3 }),
117
+ webRTC()
118
+ ],
119
+ connectionEncrypters: [
120
+ noise()
121
+ ],
122
+ streamMuxers: [
123
+ yamux()
124
+ ],
125
+ services
126
+ })
127
+
128
+ // create a Helia node
129
+ const helia = await createHelia({
130
+ blockstore,
131
+ datastore,
132
+ libp2p
133
+ })
134
+
135
+ return helia
136
+ } catch (err) {
137
+ console.error('Error creating Helia node: ', err)
138
+
139
+ throw err
140
+ }
141
+ }
142
+
143
+ async stop () {
144
+ await this.ipfs.stop()
145
+
146
+ return true
147
+ }
148
+
149
+ // Ensure that the directories exist to store blocks from the IPFS network.
150
+ // This function is called at startup, before the IPFS node is started.
151
+ ensureBlocksDir () {
152
+ try {
153
+ !fs.existsSync(`${ROOT_DIR}.ipfsdata`) && fs.mkdirSync(`${ROOT_DIR}.ipfsdata`)
154
+
155
+ !fs.existsSync(`${IPFS_DIR}`) && fs.mkdirSync(`${IPFS_DIR}`)
156
+
157
+ !fs.existsSync(`${IPFS_DIR}/blockstore`) && fs.mkdirSync(`${IPFS_DIR}/blockstore`)
158
+
159
+ !fs.existsSync(`${IPFS_DIR}/datastore`) && fs.mkdirSync(`${IPFS_DIR}/datastore`)
160
+
161
+ // !fs.existsSync(`${IPFS_DIR}/datastore/peers`) && fs.mkdirSync(`${IPFS_DIR}/datastore/peers`)
162
+
163
+ return true
164
+ } catch (err) {
165
+ console.error('Error in ensureBlocksDir(): ', err)
166
+ throw err
167
+ }
168
+ }
169
+ }
170
+
171
+ export default CreateHeliaNode
@@ -0,0 +1,71 @@
1
+ /*
2
+ 1. Starts node.
3
+ 2. Waits to connect to Circuit Relay.
4
+ 3. Connects to remote node.
5
+ */
6
+
7
+ // Global npm libraries
8
+ import SlpWallet from 'minimal-slp-wallet'
9
+ import { WebRTC } from '@multiformats/multiaddr-matcher'
10
+ import { multiaddr } from '@multiformats/multiaddr'
11
+ import delay from 'delay'
12
+
13
+ // Local libraries
14
+ // import IpfsCoord from '../index.js'
15
+ import CreateHeliaNode from './create-helia-node.js'
16
+
17
+ const relayMA = '/ip4/5.78.70.29/tcp/4001/p2p/12D3KooWNbQrdvEpzKuZ6rxkAF9vBH56HeGJ9drmrF9bhBJBa2Nq'
18
+ // const remoteMa = '12D3KooWDaKkuwzCNEWUEfjYSh7SCjqpEdx7PW4pAD5P5CFZQmqW'
19
+
20
+ async function start () {
21
+ try {
22
+ // Create an instance of bch-js and IPFS.
23
+ const wallet = new SlpWallet()
24
+ await wallet.walletInfoPromise
25
+
26
+ const createHeliaNode = new CreateHeliaNode()
27
+ const thisNode = await createHeliaNode.start()
28
+
29
+ await thisNode.libp2p.dial(multiaddr(relayMA), {
30
+ signal: AbortSignal.timeout(10000)
31
+ })
32
+
33
+ console.log('Connected to relay.')
34
+
35
+ let webRTCMultiaddr
36
+
37
+ // wait for the listener to make a reservation on the relay
38
+ while (true) {
39
+ webRTCMultiaddr = thisNode.libp2p.getMultiaddrs().find(ma => WebRTC.matches(ma))
40
+ // const mas = thisNode.libp2p.getMultiaddrs()
41
+ // console.log('Multiaddrs: ', mas)
42
+
43
+ if (webRTCMultiaddr != null) {
44
+ break
45
+ }
46
+
47
+ // try again later
48
+ const now = new Date()
49
+ console.log('Waiting for reservation...', now.toISOString())
50
+ await delay(1000)
51
+ }
52
+ console.log('WebRTC multiaddr: ', webRTCMultiaddr)
53
+
54
+ // Pass bch-js and IPFS to ipfs-coord when instantiating it.
55
+ // const ipfsCoord = new IpfsCoord({
56
+ // ipfs,
57
+ // wallet,
58
+ // type: 'node.js',
59
+ // // type: 'browser'
60
+ // nodeType: 'external',
61
+ // debugLevel: 2
62
+ // })
63
+
64
+ // await ipfsCoord.start()
65
+ // console.log('IPFS and the coordination library is ready.')
66
+ } catch (err) {
67
+ console.error('Error in start(): ', err)
68
+ }
69
+ }
70
+
71
+ start()
@@ -48,6 +48,7 @@ class TimerControllers {
48
48
  this.relaySearchInterval = 63000 * 2
49
49
  this.checkBlacklistInterval = 64000 * 2
50
50
  this.listPubsubChannelsInterval = 65000 * 2
51
+ this.getWebRtcMultiaddrInterval = 66000 * 2
51
52
 
52
53
  // Bind 'this' object to all subfunctions
53
54
  this.startTimers = this.startTimers.bind(this)
@@ -58,6 +59,7 @@ class TimerControllers {
58
59
  this.managePeers = this.managePeers.bind(this)
59
60
  this.blacklist = this.blacklist.bind(this)
60
61
  this.searchForRelays = this.searchForRelays.bind(this)
62
+ this.getWebRtcMultiaddr = this.getWebRtcMultiaddr.bind(this)
61
63
  }
62
64
 
63
65
  startTimers (thisNode) {
@@ -89,6 +91,10 @@ class TimerControllers {
89
91
  await _this.listPubsubChannels()
90
92
  }, this.listPubsubChannelsInterval)
91
93
 
94
+ this.getWebRtcMultiaddrHandle = setInterval(async function () {
95
+ await _this.getWebRtcMultiaddr(thisNode, useCases)
96
+ }, this.getWebRtcMultiaddrInterval)
97
+
92
98
  // DEBUG: report the state of thisNode.
93
99
  // setInterval(function () {
94
100
  // const tempThisNode = clonedeep(thisNode)
@@ -114,7 +120,8 @@ class TimerControllers {
114
120
  peerTimerHandle: this.peerTimerHandle,
115
121
  relaySearchHandle: this.relaySearchHandle,
116
122
  checkBlacklistHandle: this.checkBlacklistHandle,
117
- listPubsubChannelsHandle: this.listPubsubChannelsHandle
123
+ listPubsubChannelsHandle: this.listPubsubChannelsHandle,
124
+ getWebRtcMultiaddrHandle: this.getWebRtcMultiaddrHandle
118
125
  }
119
126
  }
120
127
 
@@ -126,6 +133,7 @@ class TimerControllers {
126
133
  clearInterval(this.relaySearchHandle)
127
134
  clearInterval(this.checkBlacklistHandle)
128
135
  clearInterval(this.listPubsubChannelsHandle)
136
+ clearInterval(this.getWebRtcMultiaddrHandle)
129
137
  }
130
138
 
131
139
  async listPubsubChannels () {
@@ -405,6 +413,21 @@ class TimerControllers {
405
413
  return false
406
414
  }
407
415
  }
416
+
417
+ // Extract any webRTC multiaddrs from the node's list of multiaddrs.
418
+ // Add them to the announcement object.
419
+ getWebRtcMultiaddr (thisNode, useCases) {
420
+ try {
421
+ console.log('---->Entering getWebRtcMultiaddr() Timer Controller.<----')
422
+
423
+ useCases.peer.getWebRtcMultiaddr({ thisNode })
424
+ } catch (err) {
425
+ console.error('Error in timer-controller.js/getWebRtcMultiaddr(): ', err)
426
+
427
+ // Note: Do not throw an error. This is a top-level function.
428
+ return false
429
+ }
430
+ }
408
431
  }
409
432
 
410
433
  export default TimerControllers
@@ -5,6 +5,7 @@
5
5
  // Global npm libraries
6
6
  import { multiaddr } from '@multiformats/multiaddr'
7
7
  import globalConfig from '../../config/global-config.js'
8
+ import { WebRTC } from '@multiformats/multiaddr-matcher'
8
9
 
9
10
  // Local libraries
10
11
  import Util from '../util/utils.js'
@@ -32,7 +33,6 @@ class PeerUseCases {
32
33
 
33
34
  // Bind 'this' object to all subfunctions.
34
35
  this.updateThisNode = this.updateThisNode.bind(this)
35
- this.updateThisNode = this.updateThisNode.bind(this)
36
36
  this.connectToPeer = this.connectToPeer.bind(this)
37
37
  this.sendPrivateMessage = this.sendPrivateMessage.bind(this)
38
38
  this.addSubnetPeer = this.addSubnetPeer.bind(this)
@@ -41,6 +41,7 @@ class PeerUseCases {
41
41
  this.queryAbout = this.queryAbout.bind(this)
42
42
  this.sendRPC = this.sendRPC.bind(this)
43
43
  this.relayMetricsHandler = this.relayMetricsHandler.bind(this)
44
+ this.getWebRtcMultiaddr = this.getWebRtcMultiaddr.bind(this)
44
45
 
45
46
  // Inject the relayMetricsHandler function into the pubsub adapter.
46
47
  this.adapters.pubsub.injectMetricsHandler(this.relayMetricsHandler)
@@ -315,7 +316,7 @@ class PeerUseCases {
315
316
  // console.log('this.thisNode: ', this.thisNode)
316
317
 
317
318
  // const relays = this.cr.state.relays
318
- const relays = this.thisNode.relayData
319
+ // const relays = this.thisNode.relayData
319
320
  const peers = this.thisNode.peerList
320
321
  // console.log('peers: ', peers)
321
322
 
@@ -387,7 +388,7 @@ class PeerUseCases {
387
388
  for (let j = 0; j < filteredMultiaddrs.length; j++) {
388
389
  const multiaddr = filteredMultiaddrs[j]
389
390
  this.adapters.log.statusLog(1,
390
- `Trying a direct connecto to peer ${thisPeer} with this multiaddr: ${multiaddr}.`
391
+ `Trying a direct connection to peer ${thisPeer} with this multiaddr: ${multiaddr}.`
391
392
  )
392
393
 
393
394
  // Attempt to connect to the node through a circuit relay.
@@ -426,6 +427,49 @@ class PeerUseCases {
426
427
 
427
428
  // Skip this section if the peer has a preference for direct connection.
428
429
  if (connectPref !== 'direct') {
430
+ // Retrieve the webRTC multiaddrs from the peers announcement object.
431
+ const filteredMultiaddrs = peerData.data.ipfsMultiaddrs.filter(x => x.includes('/p2p-circuit/webrtc'))
432
+ this.adapters.log.statusLog(1, 'webRTC filteredMultiaddrs: ', filteredMultiaddrs)
433
+
434
+ // If the peer has no webRTC multiaddrs, then skip this peer
435
+ if (filteredMultiaddrs.length === 0) {
436
+ this.adapters.log.statusLog(1, `Peer ${thisPeer} has no webRTC multiaddrs. Skipping.`)
437
+ continue
438
+ }
439
+
440
+ // Loop through each webRTC multiaddr and attempt to connect to the peer.
441
+ for (let j = 0; j < filteredMultiaddrs.length; j++) {
442
+ const multiaddr = filteredMultiaddrs[j]
443
+ this.adapters.log.statusLog(1, `Trying to connect to peer ${thisPeer} through webRTC multiaddr: ${multiaddr}.`)
444
+
445
+ connected = await this.adapters.ipfs.connectToPeer({ multiaddr })
446
+
447
+ // If the connection was successful, break out of the relay loop.
448
+ // Otherwise try to connect through the next relay.
449
+ if (connected.success) {
450
+ this.adapters.log.statusLog(1,
451
+ `Successfully connected to peer ${thisPeer} through CR connection: ${multiaddr}.`
452
+ )
453
+
454
+ // Add the connection multiaddr for this peer to the thisNode object.
455
+ this.updatePeerConnectionInfo({ thisPeer })
456
+
457
+ // Add the connection multiaddr to the peer, so that we can see
458
+ // exactly how we're connected to the peer.
459
+ const thisPeerData = this.thisNode.peerData.filter(x => x.from === thisPeer)
460
+ thisPeerData[0].data.connectionAddr = multiaddr
461
+ peerData.data.connectionAddr = multiaddr
462
+
463
+ // Break out of the loop once we've made a successful connection.
464
+ break
465
+ } else {
466
+ this.adapters.log.statusLog(1,
467
+ `Failed to connect to peer ${thisPeer} through CR connection: ${multiaddr}. Reason: ${connected.details}`
468
+ )
469
+ }
470
+ }
471
+
472
+ /*
429
473
  // Sort the Circuit Relays by the average of the aboutLatency
430
474
  // array. Connect to peers through the Relays with the lowest latencies
431
475
  // first.
@@ -483,6 +527,7 @@ class PeerUseCases {
483
527
  }
484
528
  }
485
529
  }
530
+ */
486
531
  }
487
532
 
488
533
  if (connected.success) {
@@ -636,6 +681,43 @@ class PeerUseCases {
636
681
  relayMetricsHandler (inData) {
637
682
  this.incomingData = inData
638
683
  }
684
+
685
+ // Extract any webRTC multiaddrs from the node's list of multiaddrs.
686
+ // Add them to the announcement object.
687
+ getWebRtcMultiaddr (inObj = {}) {
688
+ try {
689
+ console.log('---->Entering getWebRtcMultiaddr() Use Case.<----')
690
+
691
+ const { thisNode } = inObj
692
+
693
+ // Get multiaddrs that can be used to connect to this node.
694
+ const addrs = this.adapters.ipfs.ipfs.libp2p.getMultiaddrs()
695
+
696
+ const webRtcAddrs = addrs.filter(x => WebRTC.matches(x))
697
+ console.log('webRTC addrs: ', webRtcAddrs)
698
+
699
+ // If there are any webRTC multiaddrs, add them to the announcement object.
700
+ if (webRtcAddrs.length) {
701
+ // Remove any previous webRTC multiaddrs from the announcement object.
702
+ const existingMultiaddrs = thisNode.ipfsMultiaddrs
703
+ const noRtcAddrs = existingMultiaddrs.filter(x => !x.includes('/p2p-circuit/webrtc'))
704
+
705
+ // Add the new webRTC multiaddrs to the announcement object.
706
+ webRtcAddrs.forEach(x => {
707
+ noRtcAddrs.push(x.toString())
708
+ })
709
+
710
+ // Add the new webRTC multiaddrs to the announcement object.
711
+ thisNode.ipfsMultiaddrs = noRtcAddrs
712
+ console.log(`Updated thisNode.ipfsMultiaddrs: ${JSON.stringify(thisNode.ipfsMultiaddrs, null, 2)}`)
713
+ }
714
+
715
+ // return webRtcAddrs
716
+ } catch (err) {
717
+ console.error('Error in peer-use-cases.js/getWebRtcMultiaddr(): ', err)
718
+ return false
719
+ }
720
+ }
639
721
  }
640
722
 
641
723
  export default PeerUseCases
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "helia-coord",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
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",
@@ -26,14 +26,17 @@
26
26
  "@istanbuljs/esm-loader-hook": "0.2.0",
27
27
  "@libp2p/circuit-relay-v2": "3.1.11",
28
28
  "@libp2p/identify": "3.0.18",
29
+ "@libp2p/ping": "2.0.18",
29
30
  "@libp2p/tcp": "10.0.18",
30
31
  "@libp2p/webrtc": "4.1.6",
31
32
  "@libp2p/websockets": "9.1.5",
32
33
  "@multiformats/multiaddr": "12.3.5",
34
+ "@multiformats/multiaddr-matcher": "1.6.0",
33
35
  "blockstore-fs": "2.0.2",
34
36
  "chai": "4.3.6",
35
37
  "cross-env": "7.0.3",
36
38
  "datastore-fs": "10.0.2",
39
+ "delay": "6.0.0",
37
40
  "helia": "5.2.0",
38
41
  "lodash.clonedeep": "4.5.0",
39
42
  "minimal-slp-wallet": "5.12.0",
@@ -434,31 +434,32 @@ describe('#Use-Cases-Peer', () => {
434
434
  assert.equal(result, true)
435
435
  })
436
436
 
437
- it('should refresh a connection', async () => {
438
- // await uut.createSelf({ type: 'node.js' })
439
- // Add a peer that is not in the list of connected peers.
440
- const ipfsId = 'QmbyYXKbnAmMbMGo8LRBZ58jYs58anqUzY1m4jxDmhDsje'
441
- uut.thisNode.peerList = [ipfsId]
442
- uut.thisNode.peerData = [{ from: ipfsId, data: {} }]
437
+ // 2/16/25 CT: Commented out to try new webRTC connection logic.
438
+ // it('should refresh a connection', async () => {
439
+ // // await uut.createSelf({ type: 'node.js' })
440
+ // // Add a peer that is not in the list of connected peers.
441
+ // const ipfsId = 'QmbyYXKbnAmMbMGo8LRBZ58jYs58anqUzY1m4jxDmhDsje'
442
+ // uut.thisNode.peerList = [ipfsId]
443
+ // uut.thisNode.peerData = [{ from: ipfsId, data: {} }]
443
444
 
444
- // Add a peer
445
- await uut.addSubnetPeer(mockData.announceObj)
445
+ // // Add a peer
446
+ // await uut.addSubnetPeer(mockData.announceObj)
446
447
 
447
- // Force circuit relay to be used.
448
- uut.thisNode.relayData = mockData.mockRelayData
448
+ // // Force circuit relay to be used.
449
+ // uut.thisNode.relayData = mockData.mockRelayData
449
450
 
450
- // Mock dependencies
451
- sandbox.stub(uut.adapters.ipfs, 'getPeers').resolves(mockData.swarmPeers)
452
- sandbox.stub(uut.adapters.ipfs, 'connectToPeer').resolves(true)
453
- sandbox.stub(uut, 'isFreshPeer').returns(true)
454
- sandbox.stub(uut.utils, 'filterMultiaddrs').returns([])
455
- sandbox.stub(uut.relayUseCases, 'sortRelays').returns(mockData.mockRelayData)
451
+ // // Mock dependencies
452
+ // sandbox.stub(uut.adapters.ipfs, 'getPeers').resolves(mockData.swarmPeers)
453
+ // sandbox.stub(uut.adapters.ipfs, 'connectToPeer').resolves(true)
454
+ // sandbox.stub(uut, 'isFreshPeer').returns(true)
455
+ // sandbox.stub(uut.utils, 'filterMultiaddrs').returns([])
456
+ // sandbox.stub(uut.relayUseCases, 'sortRelays').returns(mockData.mockRelayData)
456
457
 
457
- // Connect to that peer.
458
- const result = await uut.refreshPeerConnections()
458
+ // // Connect to that peer.
459
+ // const result = await uut.refreshPeerConnections()
459
460
 
460
- assert.equal(result, true)
461
- })
461
+ // assert.equal(result, true)
462
+ // })
462
463
 
463
464
  it('should connect directly to circuit relays advertised IP and port', async () => {
464
465
  // Add a circuit relay peer with advertised IP and port.
@@ -520,62 +521,64 @@ describe('#Use-Cases-Peer', () => {
520
521
  assert.equal(result, true)
521
522
  })
522
523
 
523
- it('should report connection errors when connecting directly to IPFS peers multiaddr', async () => {
524
- // Add a circuit relay peer with advertised IP and port.
525
- const ipfsId = 'QmbyYXKbnAmMbMGo8LRBZ58jYs58anqUzY1m4jxDmhDsje'
526
- uut.thisNode.peerList = [ipfsId]
527
- uut.thisNode.peerData = [{ from: ipfsId, data: {} }]
528
-
529
- // Add a peer
530
- await uut.addSubnetPeer(mockData.announceObj)
531
-
532
- // Force circuit relay to be used.
533
- uut.thisNode.relayData = mockData.mockRelayData
534
-
535
- // Mock dependencies
536
- sandbox.stub(uut.adapters.ipfs, 'getPeers').resolves(mockData.swarmPeers)
537
- sandbox.stub(uut, 'isFreshPeer').returns(true)
538
- sandbox.stub(uut.adapters.ipfs, 'connectToPeer')
539
- .onCall(0).resolves({ success: false })
540
- .onCall(1).resolves({ sucdess: true })
541
- sandbox.stub(uut.utils, 'filterMultiaddrs').returns(['/ip4/123.45.6.7/p2p/ipfs-id'])
542
- sandbox.stub(uut.relayUseCases, 'sortRelays').returns(mockData.mockRelayData)
543
-
544
- // Connect to that peer.
545
- const result = await uut.refreshPeerConnections()
546
-
547
- assert.equal(result, true)
548
- })
549
-
550
- it('should connect through v2 Circuit Relay', async () => {
551
- // Add a circuit relay peer with advertised IP and port.
552
- const ipfsId = 'QmbyYXKbnAmMbMGo8LRBZ58jYs58anqUzY1m4jxDmhDsje'
553
- uut.thisNode.peerList = [ipfsId]
554
- uut.thisNode.peerData = [{ from: ipfsId, data: {} }]
555
-
556
- // Add a peer
557
- await uut.addSubnetPeer(mockData.announceObj)
558
-
559
- // Force circuit relay to be used.
560
- uut.thisNode.relayData = mockData.mockRelayData
561
-
562
- // Mock dependencies
563
- sandbox.stub(uut.adapters.ipfs, 'getPeers').resolves(mockData.swarmPeers)
564
- sandbox.stub(uut, 'isFreshPeer').returns(true)
565
- sandbox.stub(uut.adapters.ipfs, 'connectToPeer')
566
- .onCall(0).resolves({ success: true })
567
- sandbox.stub(uut.utils, 'filterMultiaddrs').returns([])
568
- sandbox.stub(uut.relayUseCases, 'sortRelays').returns([{
569
- multiaddr: '/ip4/123.45.6.7/p2p/ipfs-id',
570
- connected: true
571
- }])
572
- sandbox.stub(uut, 'updatePeerConnectionInfo').returns()
573
-
574
- // Connect to that peer.
575
- const result = await uut.refreshPeerConnections()
576
-
577
- assert.equal(result, true)
578
- })
524
+ // 2/16/25 CT: Commented out to try new webRTC connection logic.
525
+ // it('should report connection errors when connecting directly to IPFS peers multiaddr', async () => {
526
+ // // Add a circuit relay peer with advertised IP and port.
527
+ // const ipfsId = 'QmbyYXKbnAmMbMGo8LRBZ58jYs58anqUzY1m4jxDmhDsje'
528
+ // uut.thisNode.peerList = [ipfsId]
529
+ // uut.thisNode.peerData = [{ from: ipfsId, data: {} }]
530
+
531
+ // // Add a peer
532
+ // await uut.addSubnetPeer(mockData.announceObj)
533
+
534
+ // // Force circuit relay to be used.
535
+ // uut.thisNode.relayData = mockData.mockRelayData
536
+
537
+ // // Mock dependencies
538
+ // sandbox.stub(uut.adapters.ipfs, 'getPeers').resolves(mockData.swarmPeers)
539
+ // sandbox.stub(uut, 'isFreshPeer').returns(true)
540
+ // sandbox.stub(uut.adapters.ipfs, 'connectToPeer')
541
+ // .onCall(0).resolves({ success: false })
542
+ // .onCall(1).resolves({ sucdess: true })
543
+ // sandbox.stub(uut.utils, 'filterMultiaddrs').returns(['/ip4/123.45.6.7/p2p/ipfs-id'])
544
+ // sandbox.stub(uut.relayUseCases, 'sortRelays').returns(mockData.mockRelayData)
545
+
546
+ // // Connect to that peer.
547
+ // const result = await uut.refreshPeerConnections()
548
+
549
+ // assert.equal(result, true)
550
+ // })
551
+
552
+ // 2/16/25 CT: Commented out to try new webRTC connection logic.
553
+ // it('should connect through v2 Circuit Relay', async () => {
554
+ // // Add a circuit relay peer with advertised IP and port.
555
+ // const ipfsId = 'QmbyYXKbnAmMbMGo8LRBZ58jYs58anqUzY1m4jxDmhDsje'
556
+ // uut.thisNode.peerList = [ipfsId]
557
+ // uut.thisNode.peerData = [{ from: ipfsId, data: {} }]
558
+
559
+ // // Add a peer
560
+ // await uut.addSubnetPeer(mockData.announceObj)
561
+
562
+ // // Force circuit relay to be used.
563
+ // uut.thisNode.relayData = mockData.mockRelayData
564
+
565
+ // // Mock dependencies
566
+ // sandbox.stub(uut.adapters.ipfs, 'getPeers').resolves(mockData.swarmPeers)
567
+ // sandbox.stub(uut, 'isFreshPeer').returns(true)
568
+ // sandbox.stub(uut.adapters.ipfs, 'connectToPeer')
569
+ // .onCall(0).resolves({ success: true })
570
+ // sandbox.stub(uut.utils, 'filterMultiaddrs').returns([])
571
+ // sandbox.stub(uut.relayUseCases, 'sortRelays').returns([{
572
+ // multiaddr: '/ip4/123.45.6.7/p2p/ipfs-id',
573
+ // connected: true
574
+ // }])
575
+ // sandbox.stub(uut, 'updatePeerConnectionInfo').returns()
576
+
577
+ // // Connect to that peer.
578
+ // const result = await uut.refreshPeerConnections()
579
+
580
+ // assert.equal(result, true)
581
+ // })
579
582
 
580
583
  it('should skip if peer is stale', async () => {
581
584
  // Add a peer that is not in the list of connected peers.