@libp2p/interop 4.0.2 → 6.0.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 (67) hide show
  1. package/dist/index.min.js +5 -5
  2. package/dist/src/connect.d.ts.map +1 -1
  3. package/dist/src/connect.js +3 -3
  4. package/dist/src/connect.js.map +1 -1
  5. package/dist/src/dht/content-fetching.d.ts.map +1 -1
  6. package/dist/src/dht/content-fetching.js +1 -1
  7. package/dist/src/dht/content-fetching.js.map +1 -1
  8. package/dist/src/dht/content-routing.d.ts.map +1 -1
  9. package/dist/src/dht/content-routing.js +1 -1
  10. package/dist/src/dht/content-routing.js.map +1 -1
  11. package/dist/src/dht/index.d.ts.map +1 -1
  12. package/dist/src/dht/index.js +3 -3
  13. package/dist/src/dht/index.js.map +1 -1
  14. package/dist/src/dht/peer-routing.d.ts.map +1 -1
  15. package/dist/src/dht/peer-routing.js +1 -1
  16. package/dist/src/dht/peer-routing.js.map +1 -1
  17. package/dist/src/index.d.ts +4 -1
  18. package/dist/src/index.d.ts.map +1 -1
  19. package/dist/src/index.js +4 -2
  20. package/dist/src/index.js.map +1 -1
  21. package/dist/src/pubsub/floodsub.d.ts.map +1 -1
  22. package/dist/src/pubsub/floodsub.js +7 -5
  23. package/dist/src/pubsub/floodsub.js.map +1 -1
  24. package/dist/src/pubsub/gossipsub.d.ts.map +1 -1
  25. package/dist/src/pubsub/gossipsub.js +1 -1
  26. package/dist/src/pubsub/gossipsub.js.map +1 -1
  27. package/dist/src/pubsub/hybrid.d.ts.map +1 -1
  28. package/dist/src/pubsub/hybrid.js +1 -1
  29. package/dist/src/pubsub/hybrid.js.map +1 -1
  30. package/dist/src/pubsub/index.d.ts.map +1 -1
  31. package/dist/src/pubsub/index.js +3 -3
  32. package/dist/src/pubsub/index.js.map +1 -1
  33. package/dist/src/relay/index.d.ts +3 -0
  34. package/dist/src/relay/index.d.ts.map +1 -0
  35. package/dist/src/relay/index.js +62 -0
  36. package/dist/src/relay/index.js.map +1 -0
  37. package/dist/src/relay/pb/index.d.ts +93 -0
  38. package/dist/src/relay/pb/index.d.ts.map +1 -0
  39. package/dist/src/relay/pb/index.js +435 -0
  40. package/dist/src/relay/pb/index.js.map +1 -0
  41. package/dist/src/relay/util.d.ts +11 -0
  42. package/dist/src/relay/util.d.ts.map +1 -0
  43. package/dist/src/relay/util.js +24 -0
  44. package/dist/src/relay/util.js.map +1 -0
  45. package/dist/src/streams/echo.d.ts.map +1 -1
  46. package/dist/src/streams/echo.js +1 -1
  47. package/dist/src/streams/echo.js.map +1 -1
  48. package/dist/src/streams/index.d.ts.map +1 -1
  49. package/dist/src/streams/index.js +2 -2
  50. package/dist/src/streams/index.js.map +1 -1
  51. package/package.json +14 -7
  52. package/src/connect.ts +5 -5
  53. package/src/dht/content-fetching.ts +3 -3
  54. package/src/dht/content-routing.ts +3 -3
  55. package/src/dht/index.ts +4 -4
  56. package/src/dht/peer-routing.ts +3 -3
  57. package/src/index.ts +10 -3
  58. package/src/pubsub/floodsub.ts +11 -9
  59. package/src/pubsub/gossipsub.ts +5 -5
  60. package/src/pubsub/hybrid.ts +5 -5
  61. package/src/pubsub/index.ts +4 -4
  62. package/src/relay/index.ts +76 -0
  63. package/src/relay/pb/index.proto +67 -0
  64. package/src/relay/pb/index.ts +549 -0
  65. package/src/relay/util.ts +35 -0
  66. package/src/streams/echo.ts +3 -3
  67. package/src/streams/index.ts +3 -3
@@ -13,7 +13,7 @@ const record = {
13
13
  value: uint8ArrayFromString('080012a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100c2588f998971dac9e3eef76a311bf9159505aff69ea3b664c55a36aa28ee08de1127228a4d431bb9c0840240c75f6e98a0843a78d945491a3ea5e1f7cee2bc71383510db5290702383975b7bffae9fb40c84cc1220fb4a7db862fffb0de42f8fd8fb33a17deb20f30e2d0f194791fe69355a392f77df35f101e08a2fc95b2c018768938814fcb52482f899f5e90a1905e8abbcdbb1647ad80a5b0417e1ce8320d64197a6ba3848926375c63adebabdf6eb82109bcadfee13b62bf922bbb6f74c1a26c9bc6122d1436787e0e6de3c152b1959701092abef84599f73eaedb2fcef9f87293e1bbe8e0fef3f1a7fd2e8b94c7e633f88473644a63cb948e4d25c54490203010001', 'hex')
14
14
  }
15
15
 
16
- export function contentFetchingTests (factory: DaemonFactory) {
16
+ export function contentFetchingTests (factory: DaemonFactory): void {
17
17
  const nodeTypes: NodeType[] = ['js', 'go']
18
18
 
19
19
  for (const typeA of nodeTypes) {
@@ -27,7 +27,7 @@ export function contentFetchingTests (factory: DaemonFactory) {
27
27
  }
28
28
  }
29
29
 
30
- function runContentFetchingTests (factory: DaemonFactory, optionsA: SpawnOptions, optionsB: SpawnOptions) {
30
+ function runContentFetchingTests (factory: DaemonFactory, optionsA: SpawnOptions, optionsB: SpawnOptions): void {
31
31
  describe('dht.contentFetching', () => {
32
32
  let daemons: Daemon[]
33
33
 
@@ -53,7 +53,7 @@ function runContentFetchingTests (factory: DaemonFactory, optionsA: SpawnOptions
53
53
  after(async function () {
54
54
  if (daemons != null) {
55
55
  await Promise.all(
56
- daemons.map(async (daemon) => await daemon.stop())
56
+ daemons.map(async (daemon) => { await daemon.stop() })
57
57
  )
58
58
  }
59
59
  })
@@ -6,7 +6,7 @@ import all from 'it-all'
6
6
  import type { Daemon, DaemonFactory, NodeType, SpawnOptions } from '../index.js'
7
7
  import type { IdentifyResult } from '@libp2p/daemon-client'
8
8
 
9
- export function contentRoutingTests (factory: DaemonFactory) {
9
+ export function contentRoutingTests (factory: DaemonFactory): void {
10
10
  const nodeTypes: NodeType[] = ['js', 'go']
11
11
 
12
12
  for (const typeA of nodeTypes) {
@@ -25,7 +25,7 @@ export function contentRoutingTests (factory: DaemonFactory) {
25
25
  }
26
26
  }
27
27
 
28
- function runContentRoutingTests (factory: DaemonFactory, optionsA: SpawnOptions, optionsB: SpawnOptions) {
28
+ function runContentRoutingTests (factory: DaemonFactory, optionsA: SpawnOptions, optionsB: SpawnOptions): void {
29
29
  describe('dht.contentRouting', () => {
30
30
  let daemons: Daemon[]
31
31
  let identify: IdentifyResult[]
@@ -55,7 +55,7 @@ function runContentRoutingTests (factory: DaemonFactory, optionsA: SpawnOptions,
55
55
  after(async function () {
56
56
  if (daemons != null) {
57
57
  await Promise.all(
58
- daemons.map(async (daemon) => await daemon.stop())
58
+ daemons.map(async (daemon) => { await daemon.stop() })
59
59
  )
60
60
  }
61
61
  })
package/src/dht/index.ts CHANGED
@@ -3,8 +3,8 @@ import { contentFetchingTests } from './content-fetching.js'
3
3
  import { contentRoutingTests } from './content-routing.js'
4
4
  import { peerRoutingTests } from './peer-routing.js'
5
5
 
6
- export async function dhtTests (factory: DaemonFactory) {
7
- await contentFetchingTests(factory)
8
- await contentRoutingTests(factory)
9
- await peerRoutingTests(factory)
6
+ export async function dhtTests (factory: DaemonFactory): Promise<void> {
7
+ contentFetchingTests(factory)
8
+ contentRoutingTests(factory)
9
+ peerRoutingTests(factory)
10
10
  }
@@ -5,7 +5,7 @@ import type { Daemon, DaemonFactory, NodeType, SpawnOptions } from '../index.js'
5
5
  import pRetry from 'p-retry'
6
6
  import type { PeerInfo } from '@libp2p/interface-peer-info'
7
7
 
8
- export function peerRoutingTests (factory: DaemonFactory) {
8
+ export function peerRoutingTests (factory: DaemonFactory): void {
9
9
  const nodeTypes: NodeType[] = ['js', 'go']
10
10
 
11
11
  for (const typeA of nodeTypes) {
@@ -19,7 +19,7 @@ export function peerRoutingTests (factory: DaemonFactory) {
19
19
  }
20
20
  }
21
21
 
22
- function runPeerRoutingTests (factory: DaemonFactory, optionsA: SpawnOptions, optionsB: SpawnOptions) {
22
+ function runPeerRoutingTests (factory: DaemonFactory, optionsA: SpawnOptions, optionsB: SpawnOptions): void {
23
23
  describe('dht.peerRouting', () => {
24
24
  let daemons: Daemon[]
25
25
 
@@ -38,7 +38,7 @@ function runPeerRoutingTests (factory: DaemonFactory, optionsA: SpawnOptions, op
38
38
  after(async function () {
39
39
  if (daemons != null) {
40
40
  await Promise.all(
41
- daemons.map(async (daemon) => await daemon.stop())
41
+ daemons.map(async (daemon) => { await daemon.stop() })
42
42
  )
43
43
  }
44
44
  })
package/src/index.ts CHANGED
@@ -2,6 +2,7 @@ import { connectTests } from './connect.js'
2
2
  import { dhtTests } from './dht/index.js'
3
3
  import { pubsubTests } from './pubsub/index.js'
4
4
  import { streamTests } from './streams/index.js'
5
+ import { relayTests } from './relay/index.js'
5
6
  import type { DaemonClient } from '@libp2p/daemon-client'
6
7
 
7
8
  export interface Daemon {
@@ -22,14 +23,19 @@ export interface SpawnOptions {
22
23
  pubsub?: boolean
23
24
  pubsubRouter?: PubSubRouter
24
25
  muxer?: Muxer
26
+ relay?: boolean
27
+ // the node will not listen on any
28
+ // addresses if true
29
+ noListen?: boolean
25
30
  }
26
31
 
27
32
  export interface DaemonFactory {
28
33
  spawn: (options: SpawnOptions) => Promise<Daemon>
29
34
  }
30
35
 
31
- export async function interopTests (factory: DaemonFactory) {
32
- await connectTests(factory)
36
+ export async function interopTests (factory: DaemonFactory): Promise<void> {
37
+ connectTests(factory)
38
+ relayTests(factory)
33
39
  await dhtTests(factory)
34
40
  await pubsubTests(factory)
35
41
  await streamTests(factory)
@@ -39,5 +45,6 @@ export {
39
45
  connectTests as connectInteropTests,
40
46
  dhtTests as dhtInteropTests,
41
47
  pubsubTests as pubsubInteropTests,
42
- streamTests as streamInteropTests
48
+ streamTests as streamInteropTests,
49
+ relayTests as relayInteropTests
43
50
  }
@@ -5,7 +5,7 @@ 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
7
 
8
- export function floodsubTests (factory: DaemonFactory) {
8
+ export function floodsubTests (factory: DaemonFactory): void {
9
9
  const nodeTypes: NodeType[] = ['js', 'go']
10
10
 
11
11
  for (const typeA of nodeTypes) {
@@ -19,7 +19,7 @@ export function floodsubTests (factory: DaemonFactory) {
19
19
  }
20
20
  }
21
21
 
22
- function runFloodsubTests (factory: DaemonFactory, optionsA: SpawnOptions, optionsB: SpawnOptions) {
22
+ function runFloodsubTests (factory: DaemonFactory, optionsA: SpawnOptions, optionsB: SpawnOptions): void {
23
23
  describe('pubsub.floodSub', () => {
24
24
  let daemons: Daemon[]
25
25
 
@@ -32,15 +32,16 @@ function runFloodsubTests (factory: DaemonFactory, optionsA: SpawnOptions, optio
32
32
  factory.spawn(optionsB)
33
33
  ])
34
34
 
35
- const identify1 = await daemons[1].client.identify()
36
- await daemons[0].client.connect(identify1.peerId, identify1.addrs)
35
+ const [peerA, peerB] = daemons
36
+ const identifyB = await peerB.client.identify()
37
+ await peerA.client.connect(identifyB.peerId, identifyB.addrs)
37
38
  })
38
39
 
39
40
  // Stop daemons
40
41
  after(async function () {
41
42
  if (daemons != null) {
42
43
  await Promise.all(
43
- daemons.map(async (daemon) => await daemon.stop())
44
+ daemons.map(async (daemon) => { await daemon.stop() })
44
45
  )
45
46
  }
46
47
  })
@@ -48,19 +49,20 @@ function runFloodsubTests (factory: DaemonFactory, optionsA: SpawnOptions, optio
48
49
  it(`${optionsA.type} peer to ${optionsB.type} peer`, async function () {
49
50
  const topic = 'test-topic'
50
51
  const data = uint8ArrayFromString('test-data')
52
+ const [peerA, peerB] = daemons
51
53
 
52
- const subscribeIterator = daemons[1].client.pubsub.subscribe(topic)
53
- const subscriber = async () => {
54
+ const subscribeIterator = peerB.client.pubsub.subscribe(topic)
55
+ const subscriber = async (): Promise<void> => {
54
56
  const message = await first(subscribeIterator)
55
57
 
56
58
  expect(message).to.exist()
57
59
  expect(message).to.have.property('data').that.equalBytes(data)
58
60
  }
59
61
 
60
- const publisher = async () => {
62
+ const publisher = async (): Promise<void> => {
61
63
  // wait for subscription stream
62
64
  await new Promise(resolve => setTimeout(resolve, 800))
63
- await daemons[0].client.pubsub.publish(topic, data)
65
+ await peerA.client.pubsub.publish(topic, data)
64
66
  }
65
67
 
66
68
  return await Promise.all([
@@ -5,7 +5,7 @@ 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
7
 
8
- export function gossipsubTests (factory: DaemonFactory) {
8
+ export function gossipsubTests (factory: DaemonFactory): void {
9
9
  const nodeTypes: NodeType[] = ['js', 'go']
10
10
 
11
11
  for (const typeA of nodeTypes) {
@@ -19,7 +19,7 @@ export function gossipsubTests (factory: DaemonFactory) {
19
19
  }
20
20
  }
21
21
 
22
- function runGossipsubTests (factory: DaemonFactory, optionsA: SpawnOptions, optionsB: SpawnOptions) {
22
+ function runGossipsubTests (factory: DaemonFactory, optionsA: SpawnOptions, optionsB: SpawnOptions): void {
23
23
  describe('pubsub.gossipsub', () => {
24
24
  let daemons: Daemon[]
25
25
 
@@ -40,7 +40,7 @@ function runGossipsubTests (factory: DaemonFactory, optionsA: SpawnOptions, opti
40
40
  after(async function () {
41
41
  if (daemons != null) {
42
42
  await Promise.all(
43
- daemons.map(async (daemon) => await daemon.stop())
43
+ daemons.map(async daemon => { await daemon.stop() })
44
44
  )
45
45
  }
46
46
  })
@@ -50,14 +50,14 @@ function runGossipsubTests (factory: DaemonFactory, optionsA: SpawnOptions, opti
50
50
  const data = uint8ArrayFromString('test-data')
51
51
 
52
52
  const subscribeIterator = daemons[1].client.pubsub.subscribe(topic)
53
- const subscriber = async () => {
53
+ const subscriber = async (): Promise<void> => {
54
54
  const message = await first(subscribeIterator)
55
55
 
56
56
  expect(message).to.exist()
57
57
  expect(message).to.have.property('data').that.equalBytes(data)
58
58
  }
59
59
 
60
- const publisher = async () => {
60
+ const publisher = async (): Promise<void> => {
61
61
  // wait for subscription stream
62
62
  await new Promise(resolve => setTimeout(resolve, 800))
63
63
  await daemons[0].client.pubsub.publish(topic, data)
@@ -5,7 +5,7 @@ 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
7
 
8
- export function hybridTests (factory: DaemonFactory) {
8
+ export function hybridTests (factory: DaemonFactory): void {
9
9
  const nodeTypes: NodeType[] = ['js', 'go']
10
10
 
11
11
  for (const typeA of nodeTypes) {
@@ -19,7 +19,7 @@ export function hybridTests (factory: DaemonFactory) {
19
19
  }
20
20
  }
21
21
 
22
- function runHybridTests (factory: DaemonFactory, optionsA: SpawnOptions, optionsB: SpawnOptions) {
22
+ function runHybridTests (factory: DaemonFactory, optionsA: SpawnOptions, optionsB: SpawnOptions): void {
23
23
  describe('pubsub.hybrid', () => {
24
24
  let daemons: Daemon[]
25
25
 
@@ -40,7 +40,7 @@ function runHybridTests (factory: DaemonFactory, optionsA: SpawnOptions, options
40
40
  after(async function () {
41
41
  if (daemons != null) {
42
42
  await Promise.all(
43
- daemons.map(async (daemon) => await daemon.stop())
43
+ daemons.map(async (daemon) => { await daemon.stop() })
44
44
  )
45
45
  }
46
46
  })
@@ -50,14 +50,14 @@ function runHybridTests (factory: DaemonFactory, optionsA: SpawnOptions, options
50
50
  const data = uint8ArrayFromString('test-data')
51
51
 
52
52
  const subscribeIterator = daemons[1].client.pubsub.subscribe(topic)
53
- const subscriber = async () => {
53
+ const subscriber = async (): Promise<void> => {
54
54
  const message = await first(subscribeIterator)
55
55
 
56
56
  expect(message).to.exist()
57
57
  expect(message).to.have.property('data').that.equalBytes(data)
58
58
  }
59
59
 
60
- const publisher = async () => {
60
+ const publisher = async (): Promise<void> => {
61
61
  // wait for subscription stream
62
62
  await new Promise(resolve => setTimeout(resolve, 800))
63
63
  await daemons[0].client.pubsub.publish(topic, data)
@@ -3,8 +3,8 @@ import { floodsubTests } from './floodsub.js'
3
3
  import { gossipsubTests } from './gossipsub.js'
4
4
  import { hybridTests } from './hybrid.js'
5
5
 
6
- export async function pubsubTests (factory: DaemonFactory) {
7
- await floodsubTests(factory)
8
- await gossipsubTests(factory)
9
- await hybridTests(factory)
6
+ export async function pubsubTests (factory: DaemonFactory): Promise<void> {
7
+ floodsubTests(factory)
8
+ gossipsubTests(factory)
9
+ hybridTests(factory)
10
10
  }
@@ -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
+ }