holepunch-hop 0.4.5 → 0.5.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.
Files changed (28) hide show
  1. package/.vscode/settings.json +3 -0
  2. package/package.json +11 -5
  3. package/src/adapters/timeConvertor.js +3 -0
  4. package/src/index.js +45 -10
  5. package/src/{peers.js → network/peers.js} +507 -136
  6. package/src/{bees.js → storage/bees.js} +142 -60
  7. package/src/{drive.js → storage/drive.js} +2 -3
  8. package/src/{fileParser.js → storage/fileParser.js} +7 -1
  9. package/test/datacommands/files/data/jan3-bitcoin.csv +17 -0
  10. package/test/datacommands/files/large-csv.test.js +7 -0
  11. package/test/datacommands/files/small-csv.test.js +76 -0
  12. package/test/datacommands/ledger/save-get-ledger.test.js +117 -0
  13. package/test/datacommands/results/save-get-results.test.js +122 -0
  14. package/test/holepunch-initiate.test.js +47 -0
  15. package/test/multipers/ten-peers-network.test.js +437 -0
  16. package/test/setup-bee-holepunch.test.js +45 -0
  17. package/test/setup-holepunch.test.js +14 -13
  18. package/test/threepers/peer3-geninvite-after.test.js +439 -0
  19. package/test/threepers/three-peers.test.js +159 -0
  20. package/test/threepers/two-then-three.test.js +434 -0
  21. package/test/twopeers/peerClient-Server.test.js +243 -0
  22. package/test/twopeers/reconnect-peers.test.js +257 -0
  23. package/test/twopeers/reconnect-serverthen-conerr.test.js +304 -0
  24. package/test/twopeers/reconnect-then-conerr.test.js +309 -0
  25. package/test/twopeers/two-peer-one-disconnect.test.js +162 -0
  26. package/test/twopeers/two-peer-server-disconnect.test.js +167 -0
  27. package/vitest.config.js +8 -0
  28. /package/src/{kbledger.js → ledger/kbledger.js} +0 -0
@@ -0,0 +1,257 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest'
2
+ import { spawn } from 'child_process'
3
+ import path from 'path'
4
+ import crypto from 'crypto'
5
+ import Hyperswarm from 'hyperswarm'
6
+ import NetworkPeers from '../../src/network/peers.js'
7
+
8
+ // Set global test timeout to 10 seconds
9
+ const testTimeout = 10000;
10
+
11
+ describe('peer reconnection', () => {
12
+ let hopProcess
13
+ let clientPeer
14
+ let serverPeer
15
+ let clientSwarm
16
+ let serverSwarm
17
+ let clientPublicKey
18
+ let serverPublicKey
19
+ let savedPeerNetworkClient = []
20
+ let savedPeerNetworkServer = []
21
+ let topicReconnect = ''
22
+ let testConfig
23
+
24
+ beforeEach(async () => {
25
+ // Start HOP server
26
+ const baseHOPStepsUp = path.join(__dirname, '../..')
27
+ // hopProcess = spawn('npm', ['run', 'start'], { stdio: 'inherit', cwd: baseHOPStepsUp })
28
+ // await new Promise((resolve) => setTimeout(resolve, 3000))
29
+
30
+ // Initialize peers
31
+ // Create real swarms
32
+ clientSwarm = new Hyperswarm()
33
+ serverSwarm = new Hyperswarm()
34
+
35
+ // Create client and server peers
36
+ clientPeer = new NetworkPeers({}, clientSwarm)
37
+ serverPeer = new NetworkPeers({}, serverSwarm)
38
+
39
+ testConfig = {
40
+ peer1to2: {
41
+ peer1: {
42
+ publicKey: clientPeer.swarm.keyPair.publicKey.toString('hex'),
43
+ client: true
44
+ },
45
+ peer2: {
46
+ publicKey: serverPeer.swarm.keyPair.publicKey.toString('hex'),
47
+ client: false
48
+ },
49
+ }
50
+ }
51
+
52
+ const randomString = crypto.randomBytes(32).toString('hex')
53
+ // Convert the random string to a buffer
54
+ const buffer = Buffer.from(randomString, 'hex')
55
+ topicReconnect = randomString
56
+
57
+ }, 10000) // 10 second timeout for setup
58
+
59
+ afterEach(async () => {
60
+ console.log('Cleaning up test environment')
61
+ await clientSwarm.destroy()
62
+ await serverSwarm.destroy()
63
+ clientPeer = null
64
+ serverPeer = null
65
+ }, 20000) // 20 second timeout for cleanup
66
+
67
+ describe('initial connection and relationship storage', () => {
68
+ it('should save relationship data for reconnection', async () => {
69
+ // make initial connection
70
+ console.log('FIRT TIME CONNECT start')
71
+ let connectionCount = 0
72
+ let mockServerPeer = {
73
+ publickey: clientPeer.swarm.keyPair.publicKey.toString('hex'),
74
+ live: false,
75
+ value: {
76
+ live: false,
77
+ key: clientPeer.swarm.keyPair.publicKey.toString('hex')
78
+ }
79
+ }
80
+ // make client listen
81
+ clientPeer.peerJoinClient()
82
+ // serverPeer.peerJoinClient()
83
+ console.log('start NETWORK plumbing client peer1 and server peer2')
84
+ serverPeer.peerJoin(mockServerPeer)
85
+ // Create connection promise to verify connection details
86
+ let connectionPromise = new Promise((resolve) => {
87
+ clientPeer.swarm.on('connection', (conn, info) => {
88
+ connectionCount++
89
+ // Verify client connection details
90
+ console.log('Client FIRST connection details:')
91
+ expect(info.publicKey).toBeDefined()
92
+ expect(info.publicKey.toString('hex')).toBeDefined()
93
+ expect(info.client).toBe(false) // Client sees itself as false
94
+ expect(info.topics.length).toBe(0)
95
+ expect(clientPeer.topicHolder['']).toBeUndefined()
96
+
97
+ // Store connection for verification
98
+ const publicKeyHex = info.publicKey.toString('hex')
99
+ // expect(clientPeer.peerConnect[publicKeyHex]).toBeDefined()
100
+
101
+ // Save the peer network data for reconnection
102
+ savedPeerNetworkClient.push({
103
+ key: publicKeyHex,
104
+ value: {
105
+ name: 'peer2',
106
+ publickey: publicKeyHex,
107
+ roletaken: true,
108
+ longterm: true,
109
+ settopic: true,
110
+ topic: topicReconnect,
111
+ live: false,
112
+ livePeerkey: ''
113
+ }
114
+ })
115
+ // Resolve when client connection is established
116
+ if (connectionCount === 2) {
117
+ console.log('resolve peer two')
118
+ resolve()
119
+ }
120
+ })
121
+
122
+ serverPeer.swarm.on('connection', (conn, info) => {
123
+ console.log('Server FIRST connection details:')
124
+ connectionCount++
125
+ const publicKeyHex2 = info.publicKey.toString('hex')
126
+ // Verify server connection details
127
+ expect(info.publicKey).toBeDefined()
128
+ expect(info.publicKey.toString('hex')).toBeDefined()
129
+ expect(info.client).toBe(true) // Server sees itself as true
130
+ expect(info.topics.length).toBe(0)
131
+ expect(serverPeer.topicHolder['']).toBeUndefined()
132
+
133
+ // Store connection for verification on reconnect
134
+ savedPeerNetworkServer.push({
135
+ key: publicKeyHex2,
136
+ value: {
137
+ name: 'peer1',
138
+ publickey: publicKeyHex2,
139
+ roletaken: false,
140
+ longterm: true,
141
+ settopic: false,
142
+ topic: topicReconnect,
143
+ live: false,
144
+ livePeerkey: ''
145
+ }
146
+ })
147
+
148
+ // Resolve when server connection is established
149
+ if (connectionCount === 2) {
150
+ console.log('resolve peer two')
151
+ resolve()
152
+ }
153
+ })
154
+ })
155
+
156
+ // Wait for connection to be established
157
+ await connectionPromise
158
+
159
+ // Add timeout to prevent hanging
160
+ const timeout = setTimeout(() => {
161
+ throw new Error('Connection did not establish within timeout period')
162
+ }, 30000)
163
+
164
+ // Clear timeout if connection was successful
165
+ clearTimeout(timeout)
166
+ }, 50000) // 50 second timeout
167
+ })
168
+
169
+ describe('reconnection using saved data', async() => {
170
+ it('should use saved relationship data for reconnection', async () => {
171
+ let connectionCount = 0
172
+ console.log('reconnection using saved data')
173
+ let logicPrepserverStatus = async function (holePunch, info, publicKey) {
174
+ return await holePunch.prepareConnectionInfo(info, publicKey)
175
+ }
176
+
177
+ // Reconnect using saved peer network data
178
+ clientPeer.setupConnectionBegin(savedPeerNetworkClient)
179
+
180
+ // Add 3 second delay before starting serverPeer
181
+ await new Promise(resolve => setTimeout(resolve, 3000));
182
+ serverPeer.setupConnectionBegin(savedPeerNetworkServer)
183
+
184
+ // Create connection promise to verify reconnection details
185
+ let reconnectionPromise = new Promise(async (resolve) => {
186
+ clientPeer.swarm.on('connection', async (conn, info) => {
187
+ console.log('Client2 RECON connection details:')
188
+ connectionCount++
189
+ // Verify reconnection details
190
+ expect(info.publicKey).toBeDefined()
191
+ expect(info.publicKey.toString('hex')).toBeDefined()
192
+ expect(info.client).toBe(false) // Client sees itself as false
193
+ expect(info.topics.length).toBe(0)
194
+ expect(clientPeer.topicHolder['']).toBeUndefined()
195
+
196
+ // Store connection for verification
197
+ const publicKeyHex = info.publicKey.toString('hex')
198
+ // check logic
199
+ let logicInfo = await logicPrepserverStatus(clientPeer, info)
200
+ // Verify reconnection logic
201
+ if (info.client === testConfig.peer1to2.peer1.client) {
202
+ expect(logicInfo.discoveryTopicInfo.firstTime).toBe(false)
203
+ } else {
204
+ // Either serverStatus is true or there's a topic set
205
+ }
206
+ // Resolve when reconnection is established
207
+ console.log('TEST COMPLERE 111')
208
+ if (connectionCount === 2) {
209
+ console.log('resolve peer two')
210
+ resolve()
211
+ }
212
+ })
213
+
214
+ serverPeer.swarm.on('connection', async (conn, info) => {
215
+ console.log('Server2 RECON connection details:')
216
+ connectionCount++
217
+ // Verify server reconnection details
218
+ expect(info.publicKey).toBeDefined()
219
+ expect(info.publicKey.toString('hex')).toBeDefined()
220
+ expect(info.client).toBe(true) // Server sees itself as true
221
+ expect(info.topics.length).toBe(1)
222
+ expect(serverPeer.topicHolder['']).toBeUndefined()
223
+
224
+ // Store connection for verification
225
+ const publicKeyHex = info.publicKey.toString('hex')
226
+ // expect(serverPeer.peerConnect[publicKeyHex]).toBeDefined()
227
+
228
+ // check logic
229
+ let logicInfo = await logicPrepserverStatus(serverPeer, info)
230
+ // Verify reconnection logic
231
+ if (info.client === testConfig.peer1to2.peer2.client) {
232
+ expect(logicInfo.discoveryTopicInfo.firstTime).toBe(false)
233
+ } else {
234
+ // Either serverStatus is true or there's a topic set
235
+ }
236
+ console.log('TEST COMPLERE 222')
237
+ if (connectionCount === 2) {
238
+ console.log('resolve peer two')
239
+ resolve()
240
+ }
241
+ })
242
+
243
+ })
244
+
245
+ // Wait for connection to be established
246
+ await reconnectionPromise
247
+
248
+ // Add timeout to prevent hanging
249
+ const timeout = setTimeout(() => {
250
+ throw new Error('Connection did not establish within timeout period')
251
+ }, 30000)
252
+
253
+ // Clear timeout if connection was successful
254
+ clearTimeout(timeout)
255
+ }, 20000) // 50 second timeout
256
+ })
257
+ })
@@ -0,0 +1,304 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest'
2
+ import { spawn } from 'child_process'
3
+ import path from 'path'
4
+ import crypto from 'crypto'
5
+ import Hyperswarm from 'hyperswarm'
6
+ import NetworkPeers from '../../src/network/peers.js'
7
+
8
+ // Set global test timeout to 10 seconds
9
+ const testTimeout = 10000;
10
+
11
+ describe('peer reconnection', () => {
12
+ let hopProcess
13
+ let clientPeer
14
+ let serverPeer
15
+ let clientSwarm
16
+ let serverSwarm
17
+ let clientPublicKey
18
+ let serverPublicKey
19
+ let savedPeerNetworkClient = []
20
+ let savedPeerNetworkServer = []
21
+ let topicReconnect = ''
22
+ let testConfig
23
+ let peerNetworkMock = []
24
+
25
+ beforeEach(async () => {
26
+ // Start HOP server
27
+ const baseHOPStepsUp = path.join(__dirname, '../..')
28
+ // hopProcess = spawn('npm', ['run', 'start'], { stdio: 'inherit', cwd: baseHOPStepsUp })
29
+ // await new Promise((resolve) => setTimeout(resolve, 3000))
30
+
31
+ // Initialize peers
32
+ // Create real swarms
33
+ clientSwarm = new Hyperswarm()
34
+ serverSwarm = new Hyperswarm()
35
+
36
+ // Create client and server peers
37
+ clientPeer = new NetworkPeers({}, clientSwarm)
38
+ serverPeer = new NetworkPeers({}, serverSwarm)
39
+
40
+ testConfig = {
41
+ peer1to2: {
42
+ peer1: {
43
+ publicKey: clientPeer.swarm.keyPair.publicKey.toString('hex'),
44
+ client: true
45
+ },
46
+ peer2: {
47
+ publicKey: serverPeer.swarm.keyPair.publicKey.toString('hex'),
48
+ client: false
49
+ },
50
+ }
51
+ }
52
+
53
+ const randomString = crypto.randomBytes(32).toString('hex')
54
+ // Convert the random string to a buffer
55
+ const buffer = Buffer.from(randomString, 'hex')
56
+ topicReconnect = randomString
57
+
58
+ }, 10000) // 10 second timeout for setup
59
+
60
+ afterEach(async () => {
61
+ console.log('Cleaning up test environment')
62
+ await clientSwarm.destroy()
63
+ await serverSwarm.destroy()
64
+ clientPeer = null
65
+ serverPeer = null
66
+ }, 20000) // 20 second timeout for cleanup
67
+
68
+ describe('initial connection and relationship storage', () => {
69
+ it('should save relationship data for reconnection', async () => {
70
+ // make initial connection
71
+ console.log('FIRT TIME CONNECT start')
72
+ let connectionCount = 0
73
+ let mockServerPeer = {
74
+ publickey: clientPeer.swarm.keyPair.publicKey.toString('hex'),
75
+ live: false,
76
+ value: {
77
+ live: false,
78
+ key: clientPeer.swarm.keyPair.publicKey.toString('hex')
79
+ }
80
+ }
81
+ // make client listen
82
+ clientPeer.peerJoinClient()
83
+ // serverPeer.peerJoinClient()
84
+ console.log('start NETWORK plumbing client peer1 and server peer2')
85
+ serverPeer.peerJoin(mockServerPeer)
86
+ // Create connection promise to verify connection details
87
+ let connectionPromise = new Promise((resolve) => {
88
+ clientPeer.swarm.on('connection', (conn, info) => {
89
+ connectionCount++
90
+ // Verify client connection details
91
+ console.log('Client FIRST connection details:')
92
+ expect(info.publicKey).toBeDefined()
93
+ expect(info.publicKey.toString('hex')).toBeDefined()
94
+ expect(info.client).toBe(false) // Client sees itself as false
95
+ expect(info.topics.length).toBe(0)
96
+ expect(clientPeer.topicHolder['']).toBeUndefined()
97
+
98
+ // Store connection for verification
99
+ const publicKeyHex = info.publicKey.toString('hex')
100
+ // expect(clientPeer.peerConnect[publicKeyHex]).toBeDefined()
101
+
102
+ // Save the peer network data for reconnection
103
+ savedPeerNetworkClient.push({
104
+ key: publicKeyHex,
105
+ value: {
106
+ name: 'peer2',
107
+ publickey: publicKeyHex,
108
+ roletaken: true,
109
+ longterm: true,
110
+ settopic: true,
111
+ topic: topicReconnect,
112
+ live: false,
113
+ livePeerkey: ''
114
+ }
115
+ })
116
+ // Resolve when client connection is established
117
+ if (connectionCount === 2) {
118
+ console.log('resolve peer two')
119
+ resolve()
120
+ }
121
+ })
122
+
123
+ serverPeer.swarm.on('connection', (conn, info) => {
124
+ console.log('Server FIRST connection details:')
125
+ connectionCount++
126
+ const publicKeyHex2 = info.publicKey.toString('hex')
127
+ // Verify server connection details
128
+ expect(info.publicKey).toBeDefined()
129
+ expect(info.publicKey.toString('hex')).toBeDefined()
130
+ expect(info.client).toBe(true) // Server sees itself as true
131
+ expect(info.topics.length).toBe(0)
132
+ expect(serverPeer.topicHolder['']).toBeUndefined()
133
+
134
+ // Store connection for verification on reconnect
135
+ savedPeerNetworkServer.push({
136
+ key: publicKeyHex2,
137
+ value: {
138
+ name: 'peer1',
139
+ publickey: publicKeyHex2,
140
+ roletaken: false,
141
+ longterm: true,
142
+ settopic: false,
143
+ topic: topicReconnect,
144
+ live: false,
145
+ livePeerkey: ''
146
+ }
147
+ })
148
+
149
+ // Resolve when server connection is established
150
+ if (connectionCount === 2) {
151
+ console.log('resolve peer two')
152
+ resolve()
153
+ }
154
+ })
155
+ })
156
+
157
+ // Wait for connection to be established
158
+ await connectionPromise
159
+
160
+ // Add timeout to prevent hanging
161
+ const timeout = setTimeout(() => {
162
+ throw new Error('Connection did not establish within timeout period')
163
+ }, 30000)
164
+
165
+ // Clear timeout if connection was successful
166
+ clearTimeout(timeout)
167
+ }, 50000) // 50 second timeout
168
+ })
169
+
170
+ describe('reconnection using saved data', async() => {
171
+ it('should use saved relationship data for reconnection', async () => {
172
+ let connectionCount = 0
173
+ console.log('reconnection using saved data')
174
+ let logicPrepserverStatus = async function (holePunch, info, publicKey) {
175
+ return await holePunch.prepareConnectionInfo(info, publicKey)
176
+ }
177
+
178
+ // Reconnect using saved peer network data
179
+ clientPeer.setupConnectionBegin(savedPeerNetworkClient)
180
+
181
+ // Add 3 second delay before starting serverPeer
182
+ await new Promise(resolve => setTimeout(resolve, 3000));
183
+ serverPeer.setupConnectionBegin(savedPeerNetworkServer)
184
+
185
+ // Create connection promise to verify reconnection details
186
+ let reconnectionPromise = new Promise(async (resolve) => {
187
+ clientPeer.swarm.on('connection', async (conn, info) => {
188
+ console.log('Client2 RECON connection details:')
189
+ connectionCount++
190
+ // Verify reconnection details
191
+ expect(info.publicKey).toBeDefined()
192
+ expect(info.publicKey.toString('hex')).toBeDefined()
193
+ expect(info.client).toBe(false) // Client sees itself as false
194
+ expect(info.topics.length).toBe(0)
195
+ expect(clientPeer.topicHolder['']).toBeUndefined()
196
+
197
+
198
+
199
+ // Store connection for verification
200
+ const publicKeyHex = info.publicKey.toString('hex')
201
+ // check logic
202
+ let logicInfo = await logicPrepserverStatus(clientPeer, info)
203
+ // Verify reconnection logic
204
+ if (info.client === testConfig.peer1to2.peer1.client) {
205
+ expect(logicInfo.discoveryTopicInfo.firstTime).toBe(false)
206
+ } else {
207
+ // Either serverStatus is true or there's a topic set
208
+ }
209
+
210
+
211
+ clientPeer.peerConnect = {}
212
+ clientPeer.peerConnect[testConfig.peer1to2.peer2.publicKey] = conn
213
+
214
+ peerNetworkMock.push({
215
+ key: testConfig.peer1to2.peer2.publicKey,
216
+ value: {
217
+ name: 'peer2',
218
+ publickey: testConfig.peer1to2.peer2.publicKey,
219
+ roletaken: true,
220
+ longterm: true,
221
+ settopic: true,
222
+ topic: 'letitbe',
223
+ live: false,
224
+ livePeerkey: testConfig.peer1to2.peer2.publicKey
225
+ }
226
+ })
227
+
228
+
229
+ let disconnectCount = 0
230
+ // listen for error
231
+ conn.on('error', data => {
232
+ console.log('error incoming, which peer?')
233
+ disconnectCount++
234
+ expect(info).toBeDefined()
235
+ expect(info.publicKey).toBeDefined()
236
+ expect(info.publicKey.toString('hex')).toBe(testConfig.peer1to2.peer2.publicKey)
237
+ // match to peer info. and inform beebee ui
238
+ let connectLivekeys = Object.keys(clientPeer.peerConnect)
239
+ for (let peer of peerNetworkMock) {
240
+ for (let pconn of connectLivekeys) {
241
+ if (peer.value.livePeerkey === pconn) {
242
+ // check if connect is close?
243
+ // let keysNoise = Object.keys(serverPeer.peerConnect[pconn]['noiseStream']['_writableState']['stream']['_writableState']['stream']['_writableState']['stream']['_writableState']['stream']['rawStream']['_closed'])
244
+ // console.log(this.peerConnect[pconn]['noiseStream']['_writableState']['stream']['_writableState']['stream']['_writableState']['stream']['_writableState']['stream']['rawStream']['_closed'])
245
+ let closeStatus = clientPeer.peerConnect[pconn]['noiseStream']['_writableState']['stream']['_writableState']['stream']['_writableState']['stream']['_writableState']['stream']['rawStream']['_closed']
246
+ expect(closeStatus).toBe(true)
247
+ resolve()
248
+ }
249
+ }
250
+ }
251
+ })
252
+
253
+ })
254
+
255
+ serverPeer.swarm.on('connection', async (conn, info) => {
256
+ console.log('Server2 RECON connection details:')
257
+ connectionCount++
258
+ // Verify server reconnection details
259
+ expect(info.publicKey).toBeDefined()
260
+ expect(info.publicKey.toString('hex')).toBeDefined()
261
+ expect(info.client).toBe(true) // Server sees itself as true
262
+ expect(info.topics.length).toBe(1)
263
+ expect(serverPeer.topicHolder['']).toBeUndefined()
264
+
265
+ // Store connection for verification
266
+ const publicKeyHex = info.publicKey.toString('hex')
267
+ // expect(serverPeer.peerConnect[publicKeyHex]).toBeDefined()
268
+
269
+ // Store connection for later disconnection
270
+ serverPeer.peerConnect = {}
271
+ serverPeer.peerConnect[testConfig.peer1to2.peer1.publicKey] = conn
272
+
273
+ // check logic
274
+ let logicInfo = await logicPrepserverStatus(serverPeer, info)
275
+ // Verify reconnection logic
276
+ if (info.client === testConfig.peer1to2.peer2.client) {
277
+ expect(logicInfo.discoveryTopicInfo.firstTime).toBe(false)
278
+ } else {
279
+ // Either serverStatus is true or there's a topic set
280
+ }
281
+
282
+ await new Promise(resolve => setTimeout(resolve, 3000))
283
+ if (connectionCount === 2) {
284
+ console.log('resolve peer two server shutdown')
285
+ serverSwarm.destroy()
286
+ serverPeer = null
287
+ }
288
+
289
+ })
290
+ })
291
+
292
+ // Wait for connection to be established
293
+ await reconnectionPromise
294
+
295
+ // Add timeout to prevent hanging
296
+ const timeout = setTimeout(() => {
297
+ throw new Error('Connection did not establish within timeout period')
298
+ }, 30000)
299
+
300
+ // Clear timeout if connection was successful
301
+ clearTimeout(timeout)
302
+ }, 40000) // 50 second timeout
303
+ })
304
+ })