Last active
February 5, 2024 14:03
-
-
Save achingbrain/88f3e3409e21ebe7efd2c24beb9ee1a7 to your computer and use it in GitHub Desktop.
Node A and Node B, both connected to Node C
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { noise } from '@chainsafe/libp2p-noise' | |
import { yamux } from '@chainsafe/libp2p-yamux' | |
import { gossipsub } from '@chainsafe/libp2p-gossipsub' | |
import { webSockets } from '@libp2p/websockets' | |
import { createLibp2p } from 'libp2p' | |
import { identify } from '@libp2p/identify' | |
import * as filters from '@libp2p/websockets/filters' | |
const TOPIC_NAME = 'test-topic' | |
/** | |
* Creates a libp2p node, pass `listen = true` for it to listen on a WebSocket | |
* address or omit that to create a dial-only node | |
*/ | |
async function createNode(listen) { | |
const node = await createLibp2p({ | |
addresses: { | |
listen: listen === true ? [ | |
// listen on a random port | |
'/ip4/0.0.0.0/tcp/0/ws' | |
] : [] | |
}, | |
transports: [ | |
webSockets({ | |
// this filter allows connecting to insecure websocket addresses, it | |
// should not be used in production | |
filter: filters.all | |
}) | |
], | |
// stream muxers are required to run protocol streams | |
streamMuxers: [yamux()], | |
// only required for WebSocket and TCP transports | |
connectionEncryption: [noise()], | |
services: { | |
// required to run pubsub | |
pubsub: gossipsub(), | |
// required to run pubsub | |
identify: identify(), | |
} | |
}) | |
return node | |
} | |
export async function sleep (ms) { | |
await new Promise((r) => setTimeout(r, ms)) | |
} | |
const nodeA = await createNode() | |
console.info('nodeA running', nodeA.peerId) | |
const nodeB = await createNode() | |
console.info('nodeB running', nodeB.peerId) | |
const nodeC = await createNode(true) | |
console.info('nodeC running', nodeC.peerId) | |
console.info('nodeA dials nodeC') | |
await nodeA.dial(nodeC.getMultiaddrs()) | |
console.info('nodeB dials nodeC') | |
await nodeB.dial(nodeC.getMultiaddrs()) | |
// relay subscribes to topic - Important, this must be done in order to gossip | |
// messages between peers that are not directly connected (e.g nodeA and nodeB) | |
nodeC.services.pubsub.subscribe(TOPIC_NAME) | |
// nodeA subscribes to topic - Optional, a node does not need to be subscribed | |
// to a topic to send messages to it, only to receive them | |
nodeA.services.pubsub.subscribe(TOPIC_NAME) | |
// nodeB subscribes to topic - Important, must be done to receive messages | |
nodeB.services.pubsub.subscribe(TOPIC_NAME) | |
// PeerID -> name lookup | |
const peers = { | |
[nodeA.peerId.toString()]: 'nodeA', | |
[nodeB.peerId.toString()]: 'nodeB', | |
[nodeC.peerId.toString()]: 'nodeC' | |
} | |
// nodeB registers a listener for message events | |
nodeB.services.pubsub.addEventListener('message', (evt) => { | |
if (evt.detail.topic === TOPIC_NAME) { | |
console.info(`nodeB received message on "${TOPIC_NAME}" from ${peers[evt.detail.from.toString()]}`) | |
} | |
}) | |
// wait for nodeA to see some subscribers to the pubsub topic - Important if you | |
// skip this step or mask the "InsufficientPeers" error with the | |
// `"allowPublishToZeroPeers"` gossipsub option, published messages will not be | |
// received by any peers | |
while (true) { | |
const subscribers = nodeA.services.pubsub.getSubscribers(TOPIC_NAME) | |
if (subscribers.length === 0) { | |
console.info('nodeA waiting for pubsub topic peers') | |
await sleep(1000) | |
} else { | |
console.info('nodeA seen subscribers', subscribers.map(peer => peers[peer.toString()]).join(', ')) | |
break | |
} | |
} | |
// nodeA publishes a message | |
nodeA.services.pubsub.publish(TOPIC_NAME, Uint8Array.from([0, 1, 2, 3, 4])) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Sample output: