js-waku/guides/relay-receive-send-messages.md

228 lines
5.9 KiB
Markdown

# Receive and Send Messages Using Waku Relay
Waku Relay is a gossip protocol that enables you to send and receive messages.
You can find Waku Relay's specifications on [Vac RFC](https://rfc.vac.dev/spec/11/).
Before starting, you need to choose a _Content Topic_ for your dApp.
Check out the [how to choose a content topic guide](choose-content-topic.md) to learn more about content topics.
For this guide, we are using a single content topic: `/relay-guide/1/chat/proto`.
# Installation
You can install [js-waku](https://npmjs.com/package/js-waku) using your favorite package manager:
```shell
npm install js-waku
```
# Create Waku Instance
In order to interact with the Waku network, you first need a Waku instance:
```js
import { Waku } from 'js-waku';
const wakuNode = await Waku.create({ bootstrap: true });
```
Passing the `bootstrap` option will connect your node to predefined Waku nodes.
If you want to bootstrap to your own nodes, you can pass an array of multiaddresses instead:
```js
import { Waku } from 'js-waku';
const wakuNode = await Waku.create({
bootstrap: [
'/dns4/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAkvWiyFsgRhuJEb9JfjYxEkoHLgnUQmr1N5mKWnYjxYRVm',
'/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ'
]
});
```
# Wait to be connected
When using the `bootstrap` option, it may take some time to connect to other peers.
To ensure that you have relay peers available to send and receive messages,
use the following function:
```js
await waku.waitForConnectedPeer();
```
The returned Promise will resolve once you are connected to a Waku Relay peer.
# Receive messages
To watch messages for your app, you need to register an observer on relay for your app's content topic:
```js
const processIncomingMessage = (wakuMessage) => {
console.log(`Message Received: ${wakuMessage.payloadAsUtf8}`);
};
waku.relay.addObserver(processIncomingMessage, ['/relay-guide/1/chat/proto']);
```
# Send Messages
You are now ready to send messages.
Let's start by sending simple strings as messages.
To send a message, you need to wrap the message in a `WakuMessage`.
When using a basic string payload, you can use the `WakuMessage.fromUtf8String` helper:
```js
import { WakuMessage } from 'js-waku';
const wakuMessage = await WakuMessage.fromUtf8String('Here is a message', `/relay-guide/1/chat/proto`);
```
Then, use the `relay` module to send the message to our peers,
the message will then be relayed to the rest of the network thanks to Waku Relay:
```js
await waku.relay.send(wakuMessage);
```
# Use Protobuf
Sending strings as messages in unlikely to cover your dApps needs.
Waku v2 protocols use [protobuf](https://developers.google.com/protocol-buffers/) [by default](https://rfc.vac.dev/spec/10/).
Let's review how you can use protobuf to include structured objects in Waku Messages.
First, define a data structure.
For this guide, we will use a simple chat message that contains a timestamp and text:
```js
{
timestamp: Date;
text: string;
}
```
To encode and decode protobuf payloads, you can use the [protons](https://www.npmjs.com/package/protons) package.
## Install Protobuf Library
First, install protons:
```shell
npm install protons
```
## Protobuf Definition
Then define the simple chat message:
```js
import protons from 'protons';
const proto = protons(`
message SimpleChatMessage {
uint64 timestamp = 1;
string text = 2;
}
`);
```
You can learn about protobuf message definitions here:
[Protocol Buffers Language Guide](https://developers.google.com/protocol-buffers/docs/proto).
## Encode Messages
Instead of wrapping an utf-8 string in a Waku Message,
you are going to wrap a protobuf payload.
First, encode the object:
```js
const payload = proto.SimpleChatMessage.encode({
timestamp: Date.now(),
text: 'Here is a message'
});
```
Then, wrap it in a Waku Message:
```js
const wakuMessage = await WakuMessage.fromBytes(payload, ContentTopic);
```
Now, you can send the message over Waku Relay the same way than before:
```js
await waku.relay.send(wakuMessage);
```
## Decode Messages
To decode the messages received over Waku Relay,
you need to extract the protobuf payload and decode it using `protons`.
```js
const processIncomingMessage = (wakuMessage) => {
// No need to attempt to decode a message if the payload is absent
if (!wakuMessage.payload) return;
const { timestamp, text } = proto.SimpleChatMessage.decode(
wakuMessage.payload
);
console.log(`Message Received: ${text}, sent at ${timestamp.toString()}`);
};
```
Like before, add this callback as an observer to Waku Relay:
```js
waku.relay.addObserver(processIncomingMessage, ['/relay-guide/1/chat/proto']);
```
# Conclusion
That is it! Now, you know how to send and receive messages over Waku using the Waku Relay protocol.
Feel free to check out other [guides](menu.md) or [examples](/examples/examples.md).
Here is the final code:
```js
import { getBootstrapNodes, Waku, WakuMessage } from 'js-waku';
import protons from 'protons';
const proto = protons(`
message SimpleChatMessage {
uint64 timestamp = 1;
string text = 2;
}
`);
const wakuNode = await Waku.create();
const nodes = await getBootstrapNodes();
await Promise.all(nodes.map((addr) => waku.dial(addr)));
const processIncomingMessage = (wakuMessage) => {
// No need to attempt to decode a message if the payload is absent
if (!wakuMessage.payload) return;
const { timestamp, text } = proto.SimpleChatMessage.decode(
wakuMessage.payload
);
console.log(`Message Received: ${text}, sent at ${timestamp.toString()}`);
};
waku.relay.addObserver(processIncomingMessage, ['/relay-guide/1/chat/proto']);
const payload = proto.SimpleChatMessage.encode({
timestamp: Date.now(),
text: 'Here is a message'
});
const wakuMessage = await WakuMessage.fromBytes(payload, ContentTopic);
await waku.relay.send(wakuMessage);
```