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

5.9 KiB

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.

Before starting, you need to choose a Content Topic for your dApp. Check out the how to choose a content topic guide 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 using your favorite package manager:

npm install js-waku

Create Waku Instance

In order to interact with the Waku network, you first need a Waku instance:

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:

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:

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:

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:

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:

await waku.relay.send(wakuMessage);

Use Protobuf

Sending strings as messages in unlikely to cover your dApps needs.

Waku v2 protocols use protobuf by default.

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:

{
  timestamp: Date;
  text: string;
}

To encode and decode protobuf payloads, you can use the protons package.

Install Protobuf Library

First, install protons:

npm install protons

Protobuf Definition

Then define the simple chat message:

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.

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:

const payload = proto.SimpleChatMessage.encode({
  timestamp: Date.now(),
  text: 'Here is a message'
});

Then, wrap it in a Waku Message:

const wakuMessage = await WakuMessage.fromBytes(payload, ContentTopic);

Now, you can send the message over Waku Relay the same way than before:

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.

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:

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 or examples.

Here is the final code:

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);