Skip to content

Commit 35336fb

Browse files
authored
fix!: remove @libp2p/components (#60)
`@libp2p/components` is a choke-point for our dependency graph as it depends on every interface, meaning when one interface revs a major `@libp2p/components` major has to change too which means every module depending on it also needs a major. Switch instead to constructor injection of simple objects that let modules declare their dependencies on interfaces directly instead of indirectly via `@libp2p/components` Refs libp2p/js-libp2p-components#6 BREAKING CHANGE: modules no longer implement `Initializable` instead switching to constructor injection
1 parent 0072812 commit 35336fb

File tree

7 files changed

+98
-103
lines changed

7 files changed

+98
-103
lines changed

README.md

+13-14
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
# @libp2p/pubsub-peer-discovery <!-- omit in toc -->
22

33
[![libp2p.io](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](http://libp2p.io/)
4-
[![IRC](https://img.shields.io/badge/freenode-%23libp2p-yellow.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23libp2p)
54
[![Discuss](https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg?style=flat-square)](https://discuss.libp2p.io)
65
[![codecov](https://img.shields.io/codecov/c/github/libp2p/js-libp2p-pubsub-peer-discovery.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-pubsub-peer-discovery)
7-
[![CI](https://img.shields.io/github/workflow/status/libp2p/js-libp2p-interfaces/test%20&%20maybe%20release/master?style=flat-square)](https://github.com/libp2p/js-libp2p-pubsub-peer-discovery/actions/workflows/js-test-and-release.yml)
6+
[![CI](https://img.shields.io/github/workflow/status/libp2p/js-libp2p-pubsub-peer-discovery/test%20&%20maybe%20release/master?style=flat-square)](https://github.com/libp2p/js-libp2p-pubsub-peer-discovery/actions/workflows/js-test-and-release.yml)
87

98
> A libp2p module that uses pubsub for mdns like peer discovery
109
@@ -22,7 +21,7 @@
2221
- [Default Topic](#default-topic)
2322
- [Contribute](#contribute)
2423
- [License](#license)
25-
- [Contribution](#contribution)
24+
- [Contribute](#contribute-1)
2625

2726
## Install
2827

@@ -55,25 +54,25 @@ If you are only interested in listening to the global pubsub topic the minimal c
5554

5655
```js
5756
import { createLibp2p } from 'libp2p'
58-
import { Websockets } from '@libp2p/websockets'
59-
import { Mplex } from '@libp2p/mplex'
60-
import { Noise } from '@libp2p/noise'
61-
import GossipSub from 'libp2p-gossipsub'
62-
import { PubSubPeerDiscovery } from '@libp2p/pubsub-peer-discovery'
57+
import { websockets } from '@libp2p/websockets'
58+
import { mplex } from '@libp2p/mplex'
59+
import { noise } from '@chainsafe/libp2p-noise'
60+
import { gossipsub } from '@chainsafe/libp2p-gossipsub'
61+
import { pubsubPeerDiscovery } from '@libp2p/pubsub-peer-discovery'
6362

6463
const node = await createLibp2p({
6564
transports: [
66-
new Websockets()
65+
websockets()
6766
], // Any libp2p transport(s) can be used
6867
streamMuxers: [
69-
new Mplex()
68+
mplex()
7069
],
7170
connectionEncryption: [
72-
new Noise()
71+
noise()
7372
],
7473
pubsub: new GossipSub(), // Can also be `libp2p-floodsub` if desired
7574
peerDiscovery: [
76-
new PubSubPeerDiscovery()
75+
pubsubPeerDiscovery()
7776
]
7877
})
7978
```
@@ -95,7 +94,7 @@ const topics = [
9594
const node = await createLibp2p({
9695
// ...
9796
peerDiscovery: [
98-
new PubSubPeerDiscovery({
97+
pubsubPeerDiscovery({
9998
interval: 10000,
10099
topics: topics, // defaults to ['_peer-discovery._p2p._pubsub']
101100
listenOnly: false
@@ -131,6 +130,6 @@ Licensed under either of
131130
- Apache 2.0, ([LICENSE-APACHE](LICENSE-APACHE) / <http://www.apache.org/licenses/LICENSE-2.0>)
132131
- MIT ([LICENSE-MIT](LICENSE-MIT) / <http://opensource.org/licenses/MIT>)
133132

134-
## Contribution
133+
## Contribute
135134

136135
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

package.json

+7-7
Original file line numberDiff line numberDiff line change
@@ -143,24 +143,24 @@
143143
"release": "semantic-release"
144144
},
145145
"dependencies": {
146-
"@libp2p/components": "^2.0.4",
147146
"@libp2p/interface-peer-discovery": "^1.0.1",
147+
"@libp2p/interface-peer-id": "^1.0.5",
148148
"@libp2p/interface-peer-info": "^1.0.2",
149-
"@libp2p/interface-pubsub": "^2.0.1",
149+
"@libp2p/interface-pubsub": "^3.0.0",
150150
"@libp2p/interfaces": "^3.0.3",
151151
"@libp2p/logger": "^2.0.1",
152152
"@libp2p/peer-id": "^1.1.15",
153-
"@multiformats/multiaddr": "^10.4.0",
154-
"protons-runtime": "^3.1.0"
153+
"@multiformats/multiaddr": "^11.0.5",
154+
"protons-runtime": "^4.0.1"
155155
},
156156
"devDependencies": {
157-
"@libp2p/interface-address-manager": "^1.0.2",
158-
"@libp2p/interface-peer-discovery-compliance-tests": "^1.0.1",
157+
"@libp2p/interface-address-manager": "^2.0.0",
158+
"@libp2p/interface-peer-discovery-compliance-tests": "^2.0.0",
159159
"@libp2p/peer-id-factory": "^1.0.18",
160160
"aegir": "^37.2.0",
161161
"p-defer": "^4.0.0",
162162
"p-wait-for": "^5.0.0",
163-
"protons": "^5.1.0",
163+
"protons": "^6.0.0",
164164
"sinon": "^14.0.0",
165165
"ts-sinon": "^2.0.2"
166166
}

src/index.ts

+25-17
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import { logger } from '@libp2p/logger'
22
import { CustomEvent, EventEmitter } from '@libp2p/interfaces/events'
33
import type { Startable } from '@libp2p/interfaces/startable'
4-
import { Multiaddr } from '@multiformats/multiaddr'
4+
import { multiaddr } from '@multiformats/multiaddr'
55
import { Peer as PBPeer } from './peer.js'
66
import { peerIdFromKeys } from '@libp2p/peer-id'
77
import type { PeerDiscovery, PeerDiscoveryEvents } from '@libp2p/interface-peer-discovery'
8-
import { Components, Initializable } from '@libp2p/components'
9-
import type { Message } from '@libp2p/interface-pubsub'
8+
import type { Message, PubSub } from '@libp2p/interface-pubsub'
109
import type { PeerInfo } from '@libp2p/interface-peer-info'
1110
import { symbol } from '@libp2p/interface-peer-discovery'
11+
import type { AddressManager } from '@libp2p/interface-address-manager'
12+
import type { PeerId } from '@libp2p/interface-peer-id'
1213

1314
const log = logger('libp2p:discovery:pubsub')
1415
export const TOPIC = '_peer-discovery._p2p._pubsub'
@@ -30,17 +31,23 @@ export interface PubsubPeerDiscoveryInit {
3031
listenOnly?: boolean
3132
}
3233

34+
export interface PubSubPeerDiscoveryComponents {
35+
peerId: PeerId
36+
pubsub: PubSub
37+
addressManager: AddressManager
38+
}
39+
3340
/**
3441
* A Peer Discovery Service that leverages libp2p Pubsub to find peers.
3542
*/
36-
export class PubSubPeerDiscovery extends EventEmitter<PeerDiscoveryEvents> implements PeerDiscovery, Startable, Initializable {
43+
export class PubSubPeerDiscovery extends EventEmitter<PeerDiscoveryEvents> implements PeerDiscovery, Startable {
3744
private readonly interval: number
3845
private readonly listenOnly: boolean
3946
private readonly topics: string[]
4047
private intervalId?: ReturnType<typeof setInterval>
41-
private components: Components = new Components()
48+
private readonly components: PubSubPeerDiscoveryComponents
4249

43-
constructor (init: PubsubPeerDiscoveryInit = {}) {
50+
constructor (components: PubSubPeerDiscoveryComponents, init: PubsubPeerDiscoveryInit = {}) {
4451
super()
4552

4653
const {
@@ -49,6 +56,7 @@ export class PubSubPeerDiscovery extends EventEmitter<PeerDiscoveryEvents> imple
4956
listenOnly
5057
} = init
5158

59+
this.components = components
5260
this.interval = interval ?? 10000
5361
this.listenOnly = listenOnly ?? false
5462

@@ -70,10 +78,6 @@ export class PubSubPeerDiscovery extends EventEmitter<PeerDiscoveryEvents> imple
7078
return '@libp2p/pubsub-peer-discovery'
7179
}
7280

73-
init (components: Components) {
74-
this.components = components
75-
}
76-
7781
isStarted () {
7882
return this.intervalId != null
7983
}
@@ -91,7 +95,7 @@ export class PubSubPeerDiscovery extends EventEmitter<PeerDiscoveryEvents> imple
9195
return
9296
}
9397

94-
const pubsub = this.components.getPubSub()
98+
const pubsub = this.components.pubsub
9599

96100
if (pubsub == null) {
97101
throw new Error('PubSub not configured')
@@ -118,7 +122,7 @@ export class PubSubPeerDiscovery extends EventEmitter<PeerDiscoveryEvents> imple
118122
}
119123

120124
beforeStop () {
121-
const pubsub = this.components.getPubSub()
125+
const pubsub = this.components.pubsub
122126

123127
if (pubsub == null) {
124128
throw new Error('PubSub not configured')
@@ -144,19 +148,19 @@ export class PubSubPeerDiscovery extends EventEmitter<PeerDiscoveryEvents> imple
144148
* Performs a broadcast via Pubsub publish
145149
*/
146150
_broadcast () {
147-
const peerId = this.components.getPeerId()
151+
const peerId = this.components.peerId
148152

149153
if (peerId.publicKey == null) {
150154
throw new Error('PeerId was missing public key')
151155
}
152156

153157
const peer = {
154158
publicKey: peerId.publicKey,
155-
addrs: this.components.getAddressManager().getAddresses().map(ma => ma.bytes)
159+
addrs: this.components.addressManager.getAddresses().map(ma => ma.bytes)
156160
}
157161

158162
const encodedPeer = PBPeer.encode(peer)
159-
const pubsub = this.components.getPubSub()
163+
const pubsub = this.components.pubsub
160164

161165
if (pubsub == null) {
162166
throw new Error('PubSub not configured')
@@ -186,7 +190,7 @@ export class PubSubPeerDiscovery extends EventEmitter<PeerDiscoveryEvents> imple
186190

187191
void peerIdFromKeys(peer.publicKey).then(peerId => {
188192
// Ignore if we received our own response
189-
if (peerId.equals(this.components.getPeerId())) {
193+
if (peerId.equals(this.components.peerId)) {
190194
return
191195
}
192196

@@ -195,7 +199,7 @@ export class PubSubPeerDiscovery extends EventEmitter<PeerDiscoveryEvents> imple
195199
this.dispatchEvent(new CustomEvent<PeerInfo>('peer', {
196200
detail: {
197201
id: peerId,
198-
multiaddrs: peer.addrs.map(b => new Multiaddr(b)),
202+
multiaddrs: peer.addrs.map(b => multiaddr(b)),
199203
protocols: []
200204
}
201205
}))
@@ -204,3 +208,7 @@ export class PubSubPeerDiscovery extends EventEmitter<PeerDiscoveryEvents> imple
204208
})
205209
}
206210
}
211+
212+
export function pubsubPeerDiscovery (init: PubsubPeerDiscoveryInit = {}): (components: PubSubPeerDiscoveryComponents) => PeerDiscovery {
213+
return (components: PubSubPeerDiscoveryComponents) => new PubSubPeerDiscovery(components, init)
214+
}

src/peer.proto

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
syntax = "proto3";
22

33
message Peer {
4-
required bytes publicKey = 0;
5-
repeated bytes addrs = 1;
6-
}
4+
bytes publicKey = 1;
5+
repeated bytes addrs = 2;
6+
}

src/peer.ts

+12-18
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
/* eslint-disable import/export */
2+
/* eslint-disable complexity */
23
/* eslint-disable @typescript-eslint/no-namespace */
4+
/* eslint-disable @typescript-eslint/no-unnecessary-boolean-literal-compare */
35

46
import { encodeMessage, decodeMessage, message } from 'protons-runtime'
57
import type { Uint8ArrayList } from 'uint8arraylist'
@@ -15,29 +17,25 @@ export namespace Peer {
1517

1618
export const codec = (): Codec<Peer> => {
1719
if (_codec == null) {
18-
_codec = message<Peer>((obj, writer, opts = {}) => {
20+
_codec = message<Peer>((obj, w, opts = {}) => {
1921
if (opts.lengthDelimited !== false) {
20-
writer.fork()
22+
w.fork()
2123
}
2224

23-
if (obj.publicKey != null) {
24-
writer.uint32(2)
25-
writer.bytes(obj.publicKey)
26-
} else {
27-
throw new Error('Protocol error: required field "publicKey" was not found in object')
25+
if (opts.writeDefaults === true || (obj.publicKey != null && obj.publicKey.byteLength > 0)) {
26+
w.uint32(10)
27+
w.bytes(obj.publicKey)
2828
}
2929

3030
if (obj.addrs != null) {
3131
for (const value of obj.addrs) {
32-
writer.uint32(10)
33-
writer.bytes(value)
32+
w.uint32(18)
33+
w.bytes(value)
3434
}
35-
} else {
36-
throw new Error('Protocol error: required field "addrs" was not found in object')
3735
}
3836

3937
if (opts.lengthDelimited !== false) {
40-
writer.ldelim()
38+
w.ldelim()
4139
}
4240
}, (reader, length) => {
4341
const obj: any = {
@@ -51,10 +49,10 @@ export namespace Peer {
5149
const tag = reader.uint32()
5250

5351
switch (tag >>> 3) {
54-
case 0:
52+
case 1:
5553
obj.publicKey = reader.bytes()
5654
break
57-
case 1:
55+
case 2:
5856
obj.addrs.push(reader.bytes())
5957
break
6058
default:
@@ -63,10 +61,6 @@ export namespace Peer {
6361
}
6462
}
6563

66-
if (obj.publicKey == null) {
67-
throw new Error('Protocol error: value for required field "publicKey" was not found in protobuf')
68-
}
69-
7064
return obj
7165
})
7266
}

test/compliance.spec.ts

+10-13
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
/* eslint-env mocha */
22

33
import tests from '@libp2p/interface-peer-discovery-compliance-tests'
4-
import { PubSubPeerDiscovery, TOPIC } from '../src/index.js'
4+
import { pubsubPeerDiscovery, TOPIC } from '../src/index.js'
55
import { createEd25519PeerId } from '@libp2p/peer-id-factory'
6-
import { Components } from '@libp2p/components'
76
import { stubInterface } from 'ts-sinon'
87
import type { PubSub } from '@libp2p/interface-pubsub'
98
import { CustomEvent } from '@libp2p/interfaces/events'
109
import type { AddressManager } from '@libp2p/interface-address-manager'
11-
import { Multiaddr } from '@multiformats/multiaddr'
10+
import { multiaddr } from '@multiformats/multiaddr'
1211
import { Peer as PBPeer } from '../src/peer.js'
1312

1413
describe('compliance tests', () => {
@@ -21,26 +20,24 @@ describe('compliance tests', () => {
2120

2221
const addressManager = stubInterface<AddressManager>()
2322
addressManager.getAddresses.returns([
24-
new Multiaddr(`/ip4/43.10.1.2/tcp/39832/p2p/${peerId.toString()}`)
23+
multiaddr(`/ip4/43.10.1.2/tcp/39832/p2p/${peerId.toString()}`)
2524
])
2625

27-
const pubsubDiscovery = new PubSubPeerDiscovery()
28-
29-
const components = new Components()
30-
components.setPubSub(stubInterface<PubSub>())
31-
components.setPeerId(await createEd25519PeerId())
32-
components.setAddressManager(addressManager)
33-
34-
pubsubDiscovery.init(components)
26+
const pubsubDiscovery = pubsubPeerDiscovery()({
27+
pubsub: stubInterface<PubSub>(),
28+
peerId: await createEd25519PeerId(),
29+
addressManager
30+
})
3531

3632
intervalId = setInterval(() => {
3733
const peer = PBPeer.encode({
3834
publicKey: peerId.publicKey,
3935
addrs: [
40-
new Multiaddr('/ip4/166.10.1.2/tcp/80').bytes
36+
multiaddr('/ip4/166.10.1.2/tcp/80').bytes
4137
]
4238
}).subarray()
4339

40+
// @ts-expect-error private field
4441
pubsubDiscovery._onMessage(new CustomEvent('message', {
4542
detail: {
4643
type: 'unsigned',

0 commit comments

Comments
 (0)