@libp2p/interop 5.0.0 → 6.0.1
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.
- package/dist/index.min.js +5 -5
- package/dist/src/connect.js +2 -2
- package/dist/src/connect.js.map +1 -1
- package/dist/src/index.d.ts +4 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/pubsub/floodsub.d.ts.map +1 -1
- package/dist/src/pubsub/floodsub.js +12 -5
- package/dist/src/pubsub/floodsub.js.map +1 -1
- package/dist/src/pubsub/gossipsub.d.ts.map +1 -1
- package/dist/src/pubsub/gossipsub.js +7 -2
- package/dist/src/pubsub/gossipsub.js.map +1 -1
- package/dist/src/pubsub/hybrid.d.ts.map +1 -1
- package/dist/src/pubsub/hybrid.js +7 -2
- package/dist/src/pubsub/hybrid.js.map +1 -1
- package/dist/src/relay/index.d.ts +3 -0
- package/dist/src/relay/index.d.ts.map +1 -0
- package/dist/src/relay/index.js +62 -0
- package/dist/src/relay/index.js.map +1 -0
- package/dist/src/relay/pb/index.d.ts +93 -0
- package/dist/src/relay/pb/index.d.ts.map +1 -0
- package/dist/src/relay/pb/index.js +435 -0
- package/dist/src/relay/pb/index.js.map +1 -0
- package/dist/src/relay/util.d.ts +11 -0
- package/dist/src/relay/util.d.ts.map +1 -0
- package/dist/src/relay/util.js +24 -0
- package/dist/src/relay/util.js.map +1 -0
- package/package.json +16 -5
- package/src/connect.ts +2 -2
- package/src/index.ts +8 -1
- package/src/pubsub/floodsub.ts +14 -5
- package/src/pubsub/gossipsub.ts +10 -3
- package/src/pubsub/hybrid.ts +8 -2
- package/src/relay/index.ts +76 -0
- package/src/relay/pb/index.proto +67 -0
- package/src/relay/pb/index.ts +549 -0
- package/src/relay/util.ts +35 -0
package/src/pubsub/gossipsub.ts
CHANGED
|
@@ -4,6 +4,8 @@ import { expect } from 'aegir/chai'
|
|
|
4
4
|
import type { Daemon, DaemonFactory, NodeType, SpawnOptions } from '../index.js'
|
|
5
5
|
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
|
|
6
6
|
import first from 'it-first'
|
|
7
|
+
import pWaitFor from 'p-wait-for'
|
|
8
|
+
import type { IdentifyResult } from '@libp2p/daemon-client'
|
|
7
9
|
|
|
8
10
|
export function gossipsubTests (factory: DaemonFactory): void {
|
|
9
11
|
const nodeTypes: NodeType[] = ['js', 'go']
|
|
@@ -22,6 +24,7 @@ export function gossipsubTests (factory: DaemonFactory): void {
|
|
|
22
24
|
function runGossipsubTests (factory: DaemonFactory, optionsA: SpawnOptions, optionsB: SpawnOptions): void {
|
|
23
25
|
describe('pubsub.gossipsub', () => {
|
|
24
26
|
let daemons: Daemon[]
|
|
27
|
+
let identify1: IdentifyResult
|
|
25
28
|
|
|
26
29
|
// Start Daemons
|
|
27
30
|
before(async function () {
|
|
@@ -32,7 +35,7 @@ function runGossipsubTests (factory: DaemonFactory, optionsA: SpawnOptions, opti
|
|
|
32
35
|
factory.spawn(optionsB)
|
|
33
36
|
])
|
|
34
37
|
|
|
35
|
-
|
|
38
|
+
identify1 = await daemons[1].client.identify()
|
|
36
39
|
await daemons[0].client.connect(identify1.peerId, identify1.addrs)
|
|
37
40
|
})
|
|
38
41
|
|
|
@@ -40,7 +43,7 @@ function runGossipsubTests (factory: DaemonFactory, optionsA: SpawnOptions, opti
|
|
|
40
43
|
after(async function () {
|
|
41
44
|
if (daemons != null) {
|
|
42
45
|
await Promise.all(
|
|
43
|
-
daemons.map(async
|
|
46
|
+
daemons.map(async daemon => { await daemon.stop() })
|
|
44
47
|
)
|
|
45
48
|
}
|
|
46
49
|
})
|
|
@@ -59,7 +62,11 @@ function runGossipsubTests (factory: DaemonFactory, optionsA: SpawnOptions, opti
|
|
|
59
62
|
|
|
60
63
|
const publisher = async (): Promise<void> => {
|
|
61
64
|
// wait for subscription stream
|
|
62
|
-
await
|
|
65
|
+
await pWaitFor(async () => {
|
|
66
|
+
const peers = await daemons[0].client.pubsub.getSubscribers(topic)
|
|
67
|
+
return peers.map(p => p.toString()).includes(identify1.peerId.toString())
|
|
68
|
+
})
|
|
69
|
+
|
|
63
70
|
await daemons[0].client.pubsub.publish(topic, data)
|
|
64
71
|
}
|
|
65
72
|
|
package/src/pubsub/hybrid.ts
CHANGED
|
@@ -4,6 +4,8 @@ import { expect } from 'aegir/chai'
|
|
|
4
4
|
import type { Daemon, DaemonFactory, NodeType, SpawnOptions } from '../index.js'
|
|
5
5
|
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
|
|
6
6
|
import first from 'it-first'
|
|
7
|
+
import pWaitFor from 'p-wait-for'
|
|
8
|
+
import type { IdentifyResult } from '@libp2p/daemon-client'
|
|
7
9
|
|
|
8
10
|
export function hybridTests (factory: DaemonFactory): void {
|
|
9
11
|
const nodeTypes: NodeType[] = ['js', 'go']
|
|
@@ -22,6 +24,7 @@ export function hybridTests (factory: DaemonFactory): void {
|
|
|
22
24
|
function runHybridTests (factory: DaemonFactory, optionsA: SpawnOptions, optionsB: SpawnOptions): void {
|
|
23
25
|
describe('pubsub.hybrid', () => {
|
|
24
26
|
let daemons: Daemon[]
|
|
27
|
+
let identify1: IdentifyResult
|
|
25
28
|
|
|
26
29
|
// Start Daemons
|
|
27
30
|
before(async function () {
|
|
@@ -32,7 +35,7 @@ function runHybridTests (factory: DaemonFactory, optionsA: SpawnOptions, options
|
|
|
32
35
|
factory.spawn(optionsB)
|
|
33
36
|
])
|
|
34
37
|
|
|
35
|
-
|
|
38
|
+
identify1 = await daemons[1].client.identify()
|
|
36
39
|
await daemons[0].client.connect(identify1.peerId, identify1.addrs)
|
|
37
40
|
})
|
|
38
41
|
|
|
@@ -59,7 +62,10 @@ function runHybridTests (factory: DaemonFactory, optionsA: SpawnOptions, options
|
|
|
59
62
|
|
|
60
63
|
const publisher = async (): Promise<void> => {
|
|
61
64
|
// wait for subscription stream
|
|
62
|
-
await
|
|
65
|
+
await pWaitFor(async () => {
|
|
66
|
+
const peers = await daemons[0].client.pubsub.getSubscribers(topic)
|
|
67
|
+
return peers.map(p => p.toString()).includes(identify1.peerId.toString())
|
|
68
|
+
})
|
|
63
69
|
await daemons[0].client.pubsub.publish(topic, data)
|
|
64
70
|
}
|
|
65
71
|
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Multiaddr, multiaddr } from '@multiformats/multiaddr'
|
|
2
|
+
import { expect } from 'aegir/chai'
|
|
3
|
+
import type { Daemon, DaemonFactory, NodeType, SpawnOptions } from '../index.js'
|
|
4
|
+
import { Status } from './pb/index.js'
|
|
5
|
+
import { echoHandler, reserve } from './util.js'
|
|
6
|
+
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
|
|
7
|
+
import type { IdentifyResult } from '@libp2p/daemon-client'
|
|
8
|
+
import { handshake } from 'it-handshake'
|
|
9
|
+
|
|
10
|
+
export function relayTests (factory: DaemonFactory): void {
|
|
11
|
+
const t: NodeType[] = ['go', 'js']
|
|
12
|
+
t.forEach(a => { t.forEach(b => { t.forEach(r => { relayTest(factory, a, b, r) }) }) })
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function relayTest (factory: DaemonFactory, aType: NodeType, bType: NodeType, relayType: NodeType): void {
|
|
16
|
+
describe(`${aType} to ${bType} over relay ${relayType}`, () => {
|
|
17
|
+
const opts: SpawnOptions[] = [
|
|
18
|
+
{ type: aType, noise: true, noListen: true },
|
|
19
|
+
{ type: bType, noise: true, noListen: true },
|
|
20
|
+
{ type: relayType, noise: true, relay: true }
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
let aNode: Daemon
|
|
24
|
+
let bNode: Daemon
|
|
25
|
+
let relay: Daemon
|
|
26
|
+
let bId: IdentifyResult
|
|
27
|
+
let relayId: IdentifyResult
|
|
28
|
+
let bAddrViaRelay: Multiaddr
|
|
29
|
+
|
|
30
|
+
beforeEach(async function () {
|
|
31
|
+
this.timeout(20 * 1000)
|
|
32
|
+
;[aNode, bNode, relay] = await Promise.all(opts.map(async o => await factory.spawn(o)))
|
|
33
|
+
;[bId, relayId] = await Promise.all([bNode, relay].map(async d => await d.client.identify()))
|
|
34
|
+
|
|
35
|
+
// construct a relay address
|
|
36
|
+
bAddrViaRelay = multiaddr(`${relayId.addrs[0].toString()}/p2p/${relayId.peerId.toString()}/p2p-circuit/p2p/${bId.peerId.toString()}`)
|
|
37
|
+
|
|
38
|
+
// connect b to the relay
|
|
39
|
+
await bNode.client.connect(relayId.peerId, relayId.addrs)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
afterEach(async function () {
|
|
43
|
+
await Promise.all([aNode, bNode, relay].map(async d => { await d.stop() }))
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('connects', async () => {
|
|
47
|
+
// b makes reservation on relay
|
|
48
|
+
const reserveResponse = await reserve(bNode, relayId.peerId)
|
|
49
|
+
expect(reserveResponse.status).to.eq(Status.OK)
|
|
50
|
+
|
|
51
|
+
// a dials b through relay
|
|
52
|
+
await aNode.client.connect(bId.peerId, [bAddrViaRelay])
|
|
53
|
+
await new Promise(resolve => setTimeout(resolve, 500))
|
|
54
|
+
const connectedPeers = await aNode.client.listPeers()
|
|
55
|
+
expect(connectedPeers.filter(p => p.equals(bId.peerId))).to.have.length(1)
|
|
56
|
+
|
|
57
|
+
// run an echo test
|
|
58
|
+
await bNode.client.registerStreamHandler(echoHandler.protocol, echoHandler.handler)
|
|
59
|
+
const stream = await aNode.client.openStream(bId.peerId, echoHandler.protocol)
|
|
60
|
+
|
|
61
|
+
// send some data, read the response
|
|
62
|
+
const input = uint8ArrayFromString('test')
|
|
63
|
+
const shake = handshake(stream)
|
|
64
|
+
shake.write(input)
|
|
65
|
+
const output = await shake.read()
|
|
66
|
+
|
|
67
|
+
expect(output?.subarray()).to.deep.equal(input)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('fails to connect without a reservation', async () => {
|
|
71
|
+
// a dials b through relay
|
|
72
|
+
await expect(aNode.client.connect(bId.peerId, [bAddrViaRelay])).to.eventually.be.rejected
|
|
73
|
+
.with.property('message').that.matches(/NO_RESERVATION/)
|
|
74
|
+
})
|
|
75
|
+
})
|
|
76
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
syntax = "proto3";
|
|
2
|
+
|
|
3
|
+
message HopMessage {
|
|
4
|
+
enum Type {
|
|
5
|
+
RESERVE = 0;
|
|
6
|
+
CONNECT = 1;
|
|
7
|
+
STATUS = 2;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// the presence of this field is enforced at application level
|
|
11
|
+
optional Type type = 1;
|
|
12
|
+
|
|
13
|
+
optional Peer peer = 2;
|
|
14
|
+
optional Reservation reservation = 3;
|
|
15
|
+
optional Limit limit = 4;
|
|
16
|
+
|
|
17
|
+
optional Status status = 5;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
message StopMessage {
|
|
21
|
+
enum Type {
|
|
22
|
+
CONNECT = 0;
|
|
23
|
+
STATUS = 1;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// the presence of this field is enforced at application level
|
|
27
|
+
optional Type type = 1;
|
|
28
|
+
|
|
29
|
+
optional Peer peer = 2;
|
|
30
|
+
optional Limit limit = 3;
|
|
31
|
+
|
|
32
|
+
optional Status status = 4;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
message Peer {
|
|
36
|
+
bytes id = 1;
|
|
37
|
+
repeated bytes addrs = 2;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
message Reservation {
|
|
41
|
+
uint64 expire = 1; // Unix expiration time (UTC)
|
|
42
|
+
repeated bytes addrs = 2; // relay addrs for reserving peer
|
|
43
|
+
optional bytes voucher = 3; // reservation voucher
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
message Limit {
|
|
47
|
+
optional uint32 duration = 1; // seconds
|
|
48
|
+
optional uint64 data = 2; // bytes
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
enum Status {
|
|
52
|
+
UNUSED = 0;
|
|
53
|
+
OK = 100;
|
|
54
|
+
RESERVATION_REFUSED = 200;
|
|
55
|
+
RESOURCE_LIMIT_EXCEEDED = 201;
|
|
56
|
+
PERMISSION_DENIED = 202;
|
|
57
|
+
CONNECTION_FAILED = 203;
|
|
58
|
+
NO_RESERVATION = 204;
|
|
59
|
+
MALFORMED_MESSAGE = 400;
|
|
60
|
+
UNEXPECTED_MESSAGE = 401;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
message ReservationVoucher {
|
|
64
|
+
bytes relay = 1;
|
|
65
|
+
bytes peer = 2;
|
|
66
|
+
uint64 expiration = 3;
|
|
67
|
+
}
|