Skip to content

Commit 5397137

Browse files
authored
fix: use placeholder dht/pubsub (#1193)
Instead of making the `.dht` and `.pubsub` properties optional, use dummy implementations that throw exceptions if they are not configured. This way we don't have to null guard everywhere they are accessed.
1 parent 1473044 commit 5397137

File tree

14 files changed

+186
-78
lines changed

14 files changed

+186
-78
lines changed

examples/discovery-mechanisms/3.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { createLibp2p } from 'libp2p'
44
import { TCP } from '@libp2p/tcp'
55
import { Mplex } from '@libp2p/mplex'
66
import { Noise } from '@chainsafe/libp2p-noise'
7-
import { Gossipsub } from '@achingbrain/libp2p-gossipsub'
7+
import { FloodSub } from '@libp2p/floodsub'
88
import { Bootstrap } from '@libp2p/bootstrap'
99
import { PubSubPeerDiscovery } from '@libp2p/pubsub-peer-discovery'
1010

@@ -16,7 +16,7 @@ const createNode = async (bootstrappers) => {
1616
transports: [new TCP()],
1717
streamMuxers: [new Mplex()],
1818
connectionEncryption: [new Noise()],
19-
pubsub: new Gossipsub(),
19+
pubsub: new FloodSub(),
2020
peerDiscovery: [
2121
new Bootstrap({
2222
list: bootstrappers
@@ -40,7 +40,7 @@ const createNode = async (bootstrappers) => {
4040
transports: [new TCP()],
4141
streamMuxers: [new Mplex()],
4242
connectionEncryption: [new Noise()],
43-
pubsub: new Gossipsub(),
43+
pubsub: new FloodSub(),
4444
peerDiscovery: [
4545
new PubSubPeerDiscovery({
4646
interval: 1000

examples/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
},
1010
"license": "MIT",
1111
"dependencies": {
12-
"@achingbrain/libp2p-gossipsub": "^0.13.5",
1312
"@libp2p/pubsub-peer-discovery": "^5.0.1",
13+
"@libp2p/floodsub": "^1.0.5",
1414
"execa": "^2.1.0",
1515
"fs-extra": "^8.1.0",
1616
"libp2p": "../",

examples/pubsub/1.js

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@ import { createLibp2p } from 'libp2p'
44
import { TCP } from '@libp2p/tcp'
55
import { Mplex } from '@libp2p/mplex'
66
import { Noise } from '@chainsafe/libp2p-noise'
7-
import { Gossipsub } from '@achingbrain/libp2p-gossipsub'
7+
import { FloodSub } from '@libp2p/floodsub'
88
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
99
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
10-
import { CustomEvent } from '@libp2p/interfaces'
1110

1211
const createNode = async () => {
1312
const node = await createLibp2p({
@@ -17,7 +16,7 @@ const createNode = async () => {
1716
transports: [new TCP()],
1817
streamMuxers: [new Mplex()],
1918
connectionEncryption: [new Noise()],
20-
pubsub: new Gossipsub()
19+
pubsub: new FloodSub()
2120
})
2221

2322
await node.start()
@@ -36,17 +35,19 @@ const createNode = async () => {
3635
await node1.peerStore.addressBook.set(node2.peerId, node2.getMultiaddrs())
3736
await node1.dial(node2.peerId)
3837

39-
node1.pubsub.addEventListener(topic, (evt) => {
40-
console.log(`node1 received: ${uint8ArrayToString(evt.detail.data)}`)
38+
node1.pubsub.subscribe(topic)
39+
node1.pubsub.addEventListener('message', (evt) => {
40+
console.log(`node1 received: ${uint8ArrayToString(evt.detail.data)} on topic ${evt.detail.topic}`)
4141
})
4242

4343
// Will not receive own published messages by default
44-
node2.pubsub.addEventListener(topic, (evt) => {
45-
console.log(`node2 received: ${uint8ArrayToString(evt.detail.data)}`)
44+
node2.pubsub.subscribe(topic)
45+
node2.pubsub.addEventListener('message', (evt) => {
46+
console.log(`node2 received: ${uint8ArrayToString(evt.detail.data)} on topic ${evt.detail.topic}`)
4647
})
4748

4849
// node2 publishes "news" every second
4950
setInterval(() => {
50-
node2.pubsub.dispatchEvent(new CustomEvent(topic, { detail: uint8ArrayFromString('Bird bird bird, bird is the word!') }))
51+
node2.pubsub.publish(topic, uint8ArrayFromString('Bird bird bird, bird is the word!'))
5152
}, 1000)
5253
})()

examples/pubsub/message-filtering/1.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@ import { createLibp2p } from 'libp2p'
44
import { TCP } from '@libp2p/tcp'
55
import { Mplex } from '@libp2p/mplex'
66
import { Noise } from '@chainsafe/libp2p-noise'
7-
import { Gossipsub } from '@achingbrain/libp2p-gossipsub'
7+
import { FloodSub } from '@libp2p/floodsub'
88
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
99
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
10-
import { CustomEvent } from '@libp2p/interfaces'
1110

1211
const createNode = async () => {
1312
const node = await createLibp2p({
@@ -17,7 +16,7 @@ const createNode = async () => {
1716
transports: [new TCP()],
1817
streamMuxers: [new Mplex()],
1918
connectionEncryption: [new Noise()],
20-
pubsub: new Gossipsub()
19+
pubsub: new FloodSub()
2120
})
2221

2322
await node.start()
@@ -45,7 +44,7 @@ const createNode = async () => {
4544
// Will not receive own published messages by default
4645
console.log(`node1 received: ${uint8ArrayToString(evt.detail.data)}`)
4746
})
48-
await node1.pubsub.subscribe(topic)
47+
node1.pubsub.subscribe(topic)
4948

5049
node2.pubsub.addEventListener(topic, (evt) => {
5150
console.log(`node2 received: ${uint8ArrayToString(evt.detail.data)}`)
@@ -75,7 +74,7 @@ const createNode = async () => {
7574
// car is not a fruit !
7675
setInterval(() => {
7776
console.log('############## fruit ' + myFruits[count] + ' ##############')
78-
node1.pubsub.dispatchEvent(new CustomEvent<Uint8Array>(topic, { detail: uint8ArrayFromString(myFruits[count]) }))
77+
node1.pubsub.publish(topic, uint8ArrayFromString(myFruits[count]))
7978
count++
8079
if (count == myFruits.length) {
8180
count = 0

package.json

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -96,16 +96,17 @@
9696
},
9797
"dependencies": {
9898
"@achingbrain/nat-port-mapper": "^1.0.0",
99-
"@libp2p/connection": "^1.1.4",
100-
"@libp2p/crypto": "^0.22.9",
101-
"@libp2p/interfaces": "^1.3.21",
102-
"@libp2p/logger": "^1.1.3",
103-
"@libp2p/multistream-select": "^1.0.3",
104-
"@libp2p/peer-id": "^1.1.8",
105-
"@libp2p/peer-id-factory": "^1.0.8",
99+
"@libp2p/connection": "^1.1.5",
100+
"@libp2p/crypto": "^0.22.11",
101+
"@libp2p/interfaces": "^1.3.22",
102+
"@libp2p/logger": "^1.1.4",
103+
"@libp2p/multistream-select": "^1.0.4",
104+
"@libp2p/peer-id": "^1.1.10",
105+
"@libp2p/peer-id-factory": "^1.0.9",
106106
"@libp2p/peer-record": "^1.0.8",
107-
"@libp2p/peer-store": "^1.0.6",
108-
"@libp2p/utils": "^1.0.9",
107+
"@libp2p/peer-store": "^1.0.10",
108+
"@libp2p/tracked-map": "^1.0.5",
109+
"@libp2p/utils": "^1.0.10",
109110
"@multiformats/mafmt": "^11.0.2",
110111
"@multiformats/multiaddr": "^10.1.8",
111112
"abortable-iterator": "^4.0.2",
@@ -128,6 +129,7 @@
128129
"it-length-prefixed": "^7.0.1",
129130
"it-map": "^1.0.6",
130131
"it-merge": "^1.0.3",
132+
"it-pair": "^2.0.2",
131133
"it-pipe": "^2.0.3",
132134
"it-sort": "^1.0.1",
133135
"it-stream-types": "^1.0.4",
@@ -154,25 +156,23 @@
154156
"xsalsa20": "^1.1.0"
155157
},
156158
"devDependencies": {
157-
"@achingbrain/libp2p-gossipsub": "^0.13.5",
158159
"@chainsafe/libp2p-noise": "^6.0.1",
159-
"@libp2p/bootstrap": "^1.0.2",
160-
"@libp2p/daemon-client": "^1.0.0",
161-
"@libp2p/daemon-server": "^1.0.0",
160+
"@libp2p/bootstrap": "^1.0.3",
161+
"@libp2p/daemon-client": "^1.0.2",
162+
"@libp2p/daemon-server": "^1.0.2",
162163
"@libp2p/delegated-content-routing": "^1.0.2",
163164
"@libp2p/delegated-peer-routing": "^1.0.2",
164-
"@libp2p/floodsub": "^1.0.2",
165-
"@libp2p/interface-compliance-tests": "^1.1.20",
165+
"@libp2p/floodsub": "^1.0.5",
166+
"@libp2p/interface-compliance-tests": "^1.1.23",
166167
"@libp2p/interop": "^1.0.3",
167-
"@libp2p/kad-dht": "^1.0.5",
168-
"@libp2p/mdns": "^1.0.3",
169-
"@libp2p/mplex": "^1.0.1",
170-
"@libp2p/pubsub": "^1.2.14",
171-
"@libp2p/tcp": "^1.0.6",
168+
"@libp2p/kad-dht": "^1.0.7",
169+
"@libp2p/mdns": "^1.0.4",
170+
"@libp2p/mplex": "^1.0.3",
171+
"@libp2p/pubsub": "^1.2.18",
172+
"@libp2p/tcp": "^1.0.8",
172173
"@libp2p/topology": "^1.1.7",
173-
"@libp2p/tracked-map": "^1.0.4",
174-
"@libp2p/webrtc-star": "^1.0.3",
175-
"@libp2p/websockets": "^1.0.3",
174+
"@libp2p/webrtc-star": "^1.0.7",
175+
"@libp2p/websockets": "^1.0.6",
176176
"@nodeutils/defaults-deep": "^1.1.0",
177177
"@types/node": "^16.11.26",
178178
"@types/node-forge": "^1.0.0",
@@ -187,7 +187,6 @@
187187
"go-libp2p": "^0.0.6",
188188
"into-stream": "^7.0.0",
189189
"ipfs-http-client": "^56.0.1",
190-
"it-pair": "^2.0.2",
191190
"it-pushable": "^2.0.1",
192191
"nock": "^13.0.3",
193192
"npm-run-all": "^4.1.5",

src/dht/dummy-dht.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import type { DualDHT, QueryEvent, SingleDHT } from '@libp2p/interfaces/dht'
2+
import type { PeerDiscoveryEvents } from '@libp2p/interfaces/peer-discovery'
3+
import errCode from 'err-code'
4+
import { messages, codes } from '../errors.js'
5+
import { EventEmitter } from '@libp2p/interfaces'
6+
7+
export class DummyDHT extends EventEmitter<PeerDiscoveryEvents> implements DualDHT {
8+
get wan (): SingleDHT {
9+
throw errCode(new Error(messages.DHT_DISABLED), codes.DHT_DISABLED)
10+
}
11+
12+
get lan (): SingleDHT {
13+
throw errCode(new Error(messages.DHT_DISABLED), codes.DHT_DISABLED)
14+
}
15+
16+
get (): AsyncIterable<QueryEvent> {
17+
throw errCode(new Error(messages.DHT_DISABLED), codes.DHT_DISABLED)
18+
}
19+
20+
findProviders (): AsyncIterable<QueryEvent> {
21+
throw errCode(new Error(messages.DHT_DISABLED), codes.DHT_DISABLED)
22+
}
23+
24+
findPeer (): AsyncIterable<QueryEvent> {
25+
throw errCode(new Error(messages.DHT_DISABLED), codes.DHT_DISABLED)
26+
}
27+
28+
getClosestPeers (): AsyncIterable<QueryEvent> {
29+
throw errCode(new Error(messages.DHT_DISABLED), codes.DHT_DISABLED)
30+
}
31+
32+
provide (): AsyncIterable<QueryEvent> {
33+
throw errCode(new Error(messages.DHT_DISABLED), codes.DHT_DISABLED)
34+
}
35+
36+
put (): AsyncIterable<QueryEvent> {
37+
throw errCode(new Error(messages.DHT_DISABLED), codes.DHT_DISABLED)
38+
}
39+
40+
async getMode (): Promise<'client' | 'server'> {
41+
throw errCode(new Error(messages.DHT_DISABLED), codes.DHT_DISABLED)
42+
}
43+
44+
async setMode (): Promise<void> {
45+
throw errCode(new Error(messages.DHT_DISABLED), codes.DHT_DISABLED)
46+
}
47+
48+
async refreshRoutingTable (): Promise<void> {
49+
throw errCode(new Error(messages.DHT_DISABLED), codes.DHT_DISABLED)
50+
}
51+
}

src/errors.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export enum messages {
22
NOT_STARTED_YET = 'The libp2p node is not started yet',
33
DHT_DISABLED = 'DHT is not available',
4+
PUBSUB_DISABLED = 'PubSub is not available',
45
CONN_ENCRYPTION_REQUIRED = 'At least one connection encryption module is required',
56
ERR_TRANSPORTS_REQUIRED = 'At least one transport module is required',
67
ERR_PROTECTOR_REQUIRED = 'Private network is enforced, but no protector was provided',
@@ -9,6 +10,7 @@ export enum messages {
910

1011
export enum codes {
1112
DHT_DISABLED = 'ERR_DHT_DISABLED',
13+
ERR_PUBSUB_DISABLED = 'ERR_PUBSUB_DISABLED',
1214
PUBSUB_NOT_STARTED = 'ERR_PUBSUB_NOT_STARTED',
1315
DHT_NOT_STARTED = 'ERR_DHT_NOT_STARTED',
1416
CONN_ENCRYPTION_REQUIRED = 'ERR_CONN_ENCRYPTION_REQUIRED',

src/index.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,8 @@ export interface Libp2p extends Startable, EventEmitter<Libp2pEvents> {
154154
connectionManager: ConnectionManager
155155
registrar: Registrar
156156
metrics?: Metrics
157-
158-
pubsub?: PubSub
159-
dht?: DualDHT
157+
pubsub: PubSub
158+
dht: DualDHT
160159

161160
/**
162161
* Load keychain keys from the datastore.

src/libp2p.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,15 @@ import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
4444
import errCode from 'err-code'
4545
import { unmarshalPublicKey } from '@libp2p/crypto/keys'
4646
import type { Metrics } from '@libp2p/interfaces/metrics'
47+
import { DummyDHT } from './dht/dummy-dht.js'
48+
import { DummyPubSub } from './pubsub/dummy-pubsub.js'
4749

4850
const log = logger('libp2p')
4951

5052
export class Libp2pNode extends EventEmitter<Libp2pEvents> implements Libp2p {
5153
public peerId: PeerId
52-
public dht?: DualDHT
53-
public pubsub?: PubSub
54+
public dht: DualDHT
55+
public pubsub: PubSub
5456
public identifyService?: IdentifyService
5557
public fetchService: FetchService
5658
public pingService: PingService
@@ -168,19 +170,23 @@ export class Libp2pNode extends EventEmitter<Libp2pEvents> implements Libp2p {
168170
// dht provided components (peerRouting, contentRouting, dht)
169171
if (init.dht != null) {
170172
this.dht = this.components.setDHT(this.configureComponent(init.dht))
173+
} else {
174+
this.dht = new DummyDHT()
171175
}
172176

173177
// Create pubsub if provided
174178
if (init.pubsub != null) {
175179
this.pubsub = this.components.setPubSub(this.configureComponent(init.pubsub))
180+
} else {
181+
this.pubsub = new DummyPubSub()
176182
}
177183

178184
// Attach remaining APIs
179185
// peer and content routing will automatically get modules from _modules and _dht
180186

181187
const peerRouters: PeerRouting[] = (init.peerRouters ?? []).map(component => this.configureComponent(component))
182188

183-
if (this.dht != null) {
189+
if (init.dht != null) {
184190
// add dht to routers
185191
peerRouters.push(this.configureComponent(new DHTPeerRouting(this.dht)))
186192

@@ -197,7 +203,7 @@ export class Libp2pNode extends EventEmitter<Libp2pEvents> implements Libp2p {
197203

198204
const contentRouters: ContentRouting[] = (init.contentRouters ?? []).map(component => this.configureComponent(component))
199205

200-
if (this.dht != null) {
206+
if (init.dht != null) {
201207
// add dht to routers
202208
contentRouters.push(this.configureComponent(new DHTContentRouting(this.dht)))
203209
}

src/pubsub/dummy-pubsub.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { EventEmitter } from '@libp2p/interfaces'
2+
import type { PeerId } from '@libp2p/interfaces/peer-id'
3+
import type { PubSub, PubSubEvents, StrictNoSign, StrictSign } from '@libp2p/interfaces/pubsub'
4+
import errCode from 'err-code'
5+
import { messages, codes } from '../errors.js'
6+
7+
export class DummyPubSub extends EventEmitter<PubSubEvents> implements PubSub {
8+
isStarted (): boolean {
9+
return false
10+
}
11+
12+
start (): void | Promise<void> {
13+
14+
}
15+
16+
stop (): void | Promise<void> {
17+
18+
}
19+
20+
get globalSignaturePolicy (): typeof StrictSign | typeof StrictNoSign {
21+
throw errCode(new Error(messages.PUBSUB_DISABLED), codes.ERR_PUBSUB_DISABLED)
22+
}
23+
24+
get multicodecs (): string[] {
25+
throw errCode(new Error(messages.PUBSUB_DISABLED), codes.ERR_PUBSUB_DISABLED)
26+
}
27+
28+
getPeers (): PeerId[] {
29+
throw errCode(new Error(messages.PUBSUB_DISABLED), codes.ERR_PUBSUB_DISABLED)
30+
}
31+
32+
getTopics (): string[] {
33+
throw errCode(new Error(messages.PUBSUB_DISABLED), codes.ERR_PUBSUB_DISABLED)
34+
}
35+
36+
subscribe (): void {
37+
throw errCode(new Error(messages.PUBSUB_DISABLED), codes.ERR_PUBSUB_DISABLED)
38+
}
39+
40+
unsubscribe (): void {
41+
throw errCode(new Error(messages.PUBSUB_DISABLED), codes.ERR_PUBSUB_DISABLED)
42+
}
43+
44+
getSubscribers (): PeerId[] {
45+
throw errCode(new Error(messages.PUBSUB_DISABLED), codes.ERR_PUBSUB_DISABLED)
46+
}
47+
48+
publish (): void {
49+
throw errCode(new Error(messages.PUBSUB_DISABLED), codes.ERR_PUBSUB_DISABLED)
50+
}
51+
}

0 commit comments

Comments
 (0)