diff --git a/404.html b/404.html index d17b734..ae00a18 100644 --- a/404.html +++ b/404.html @@ -16,7 +16,7 @@ - + + + + + + +
+ + +
+
+ +
+ + + Send and Receive Messages Using Waku Relay With Angular v13 + + +
+ + + + + + +
+ + + +

+ Send and Receive Messages Using Waku Relay With Angular v13 + # +

+

It is easy to use Waku Connect with Angular v13.

+

In this guide, we will demonstrate how your Angular dApp can use Waku Relay +to send and receive messages.

+

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-angular-chat/1/chat/proto.

+

+ Setup + # +

+

Create a new Angular app:

+
npm install -g @angular/cli
+ng new relay-angular-chat
+cd relay-angular-chat
+

+ BigInt + # +

+

Some of js-waku’s dependencies use BigInt +that is only supported by modern browsers.

+

To ensure that Angular properly transpiles your webapp code, add the following configuration to the package.json file:

+
{
+  "browserslist": {
+    "production": [
+      ">0.2%",
+      "not ie <= 99",
+      "not android <= 4.4.4",
+      "not dead",
+      "not op_mini all"
+    ]
+  }
+}
+

+ Polyfills + # +

+

A number of Web3 and libp2p dependencies need polyfills. +These must be explicitly declared when using webpack 5.

+

The latest Angular version (v13) uses webpack 5.

+

We will describe below a method to configure polyfills when using Angular v13 / webpack v5. +This may not be necessary if you use webpack 4.

+

Start by installing the polyfill libraries:

+
yarn add assert buffer crypto-browserify process stream-browserify
+

Then add the following code to src/polyfills.ts:

+
import * as process from 'process';
+(window as any).process = process;
+(window as any).global = window;
+global.Buffer = global.Buffer || require('buffer').Buffer;
+

Now tell Angular where to find these libraries by adding the following to tsconfig.json +under "compilerOptions":

+
{
+  "paths": {
+    "assert": ["node_modules/assert"],
+    "buffer": ["node_modules/buffer"],
+    "crypto": ["node_modules/crypto-browserify"],
+    "stream": ["node_modules/stream-browserify"]
+  }
+}
+

Now under "angularCompilerOptions", add:

+
"allowSyntheticDefaultImports": true
+

Finally, set the "target" to be "es2020" due to the aforementioned BigInt usage.

+

+ Module loading warnings + # +

+

There will be some warnings due to module loading. +We can fix them by setting the "allowedCommonJsDependencies" key under +architect -> build -> options with the following:

+
{
+  "allowedCommonJsDependencies": [
+    "libp2p-gossipsub/src/utils",
+    "rlp",
+    "multiaddr/src/convert",
+    "varint",
+    "multihashes",
+    "@chainsafe/libp2p-noise/dist/src/noise",
+    "debug",
+    "libp2p",
+    "libp2p-bootstrap",
+    "libp2p-crypto",
+    "libp2p-websockets",
+    "libp2p-websockets/src/filters",
+    "libp2p/src/ping",
+    "multiaddr",
+    "peer-id",
+    "buffer",
+    "crypto",
+    "ecies-geth",
+    "secp256k1",
+    "libp2p-gossipsub",
+    "it-concat",
+    "protons"
+  ]
+}
+

+ Types + # +

+

There are some type definitions we need to install and some that we don’t have.

+
yarn add @types/bl protons
+

Create a new folder under src named @types with the following structure:

+
src/@types
+├── protons
+│   └── types.d.ts
+└── time-cache
+    └── types.d.ts
+

In the protons/types.d.ts file add:

+
declare module 'protons';
+

In the time-cache/types.d.ts file add:

+
declare module "time-cache" {
+
+  interface TimeCacheInterface {
+    put(key: string, value: any, validity: number): void;
+    get(key: string): any;
+    has(key: string): boolean;
+  }
+
+  type TimeCache = TimeCacheInterface;
+
+  function TimeCache(options: object): TimeCache;
+
+  export = TimeCache;
+}
+

+ js-waku + # +

+

Then, install js-waku:

+
yarn add js-waku
+

Start the dev server and open the dApp in your browser:

+
yarn run start
+

+ Create Waku Instance + # +

+

In order to interact with the Waku network, you first need a Waku instance. +We’re going to wrap the js-waku library in a Service so we can inject it to different components when needed.

+

Generate the Waku service:

+
ng generate service waku
+

Go to waku.service.ts and add the following imports:

+
import { Waku } from "js-waku";
+import { ReplaySubject } from "rxjs";
+

replace the WakuService class with the following:

+
export class WakuService {
+
+  // Create Subject Observable to 'store' the Waku instance
+  private wakuSubject = new Subject<Waku>();
+  public waku = this.wakuSubject.asObservable();
+
+  // Create BehaviorSubject Observable to 'store' the Waku status
+  private wakuStatusSubject = new BehaviorSubject('');
+  public wakuStatus = this.wakuStatusSubject.asObservable();
+
+  constructor() { }
+
+  init() {
+    // Connect node
+    Waku.create({ bootstrap: { default: true } }).then(waku => {
+      // Update Observable values
+      this.wakuSubject.next(waku);
+      this.wakuStatusSubject.next('Connecting...');
+
+      waku.waitForRemotePeer().then(() => {
+        // Update Observable value
+        this.wakuStatusSubject.next('Connected');
+      });
+    });
+  }
+}
+

When using the bootstrap option, it may take some time to connect to other peers. +That’s why we use the waku.waitForRemotePeer function to ensure that there are relay peers available to send and receive messages.

+

Now we can inject the WakuService in to the AppComponent class to initialise the node and +subscribe to any status changes.

+

Firstly, import the WakuService:

+
import { WakuService } from "./waku.service";
+

Then update the AppComponent class with the following:

+
export class AppComponent {
+
+  title: string = 'relay-angular-chat';
+  wakuStatus!: string;
+
+  // Inject the service
+  constructor(private wakuService: WakuService) {}
+
+  ngOnInit(): void {
+    // Call the `init` function on the service
+    this.wakuService.init();
+    // Subscribe to the `wakuStatus` Observable and update the property when it changes
+    this.wakuService.wakuStatus.subscribe(wakuStatus => {
+      this.wakuStatus = wakuStatus;
+    });
+  }
+}
+

Add the following HTML to the app.component.html to show the title and render the connection status:

+
<h1>{{title}}</h1>
+<p>Waku node's status: {{ wakuStatus }}</p>
+

+ Messages + # +

+

Now we need to create a component to send, receive and render the messages.

+
ng generate component messages
+

You might need to add this to NgModule for Angular to pick up the new component. +Import and add MessagesComponent to the declarations array in app.module.ts.

+

We’re going to need the WakuService again but also the Waku and WakuMessage classes from js-waku. +We already installed protons +and we’re going to use that here so we’ll need to import it.

+
import { WakuService } from "../waku.service";
+import { Waku, WakuMessage } from "js-waku";
+import protons from "protons";
+

Let’s use protons to define the Protobuf message format with two fields: +timestamp and text:

+
const proto = protons(`
+message SimpleChatMessage {
+  uint64 timestamp = 1;
+  string text = 2;
+}
+`);
+

Let’s also define a message interface:

+
interface MessageInterface {
+  timestamp: Date;
+  text: string;
+}
+

+ Send Messages + # +

+

In order to send a message, we need to define a few things.

+

The contentTopic is the topic we want subscribe to and the payload is the message. +We’ve also defined a timestamp so let’s create that.

+

The messageCount property is just to distinguish between messages.

+

We also need our waku instance and wakuStatus property. +We will subscribe to the waku and wakuStatus Observables from the WakuService to get them.

+
export class MessagesComponent {
+
+  contentTopic: string = `/relay-angular-chat/1/chat/proto`;
+  messageCount: number = 0;
+  waku!: Waku;
+
+  // ...
+
+  // Inject the `WakuService`
+  constructor(private wakuService: WakuService) { }
+
+  ngOnInit(): void {
+    // Subscribe to the `wakuStatus` Observable and update the property when it changes
+    this.wakuService.wakuStatus.subscribe(wakuStatus => {
+      this.wakuStatus = wakuStatus;
+    });
+
+    // Subscribe to the `waku` Observable and update the property when it changes
+    this.wakuService.waku.subscribe(waku => {
+      this.waku = waku;
+    });
+  }
+
+  sendMessage(): void {
+    const time = new Date().getTime();
+
+    const payload = proto.SimpleChatMessage.encode({
+      timestamp: time,
+      text: `Here is a message #${this.messageCount}`,
+    });
+
+    WakuMessage.fromBytes(payload, this.contentTopic).then(wakuMessage => {
+      this.waku.relay.send(wakuMessage).then(() => {
+        console.log(`Message #${this.messageCount} sent`);
+        this.messageCount += 1;
+      });
+    });
+  }
+}
+

Then, add a button to the messages.component.html file to wire it up to the sendMessage() function. +It will also disable the button until the node is connected.

+
<button (click)="sendMessage()" [disabled]="wakuStatus !== 'Connected'">Send Message</button>
+

+ Receive Messages + # +

+

To process incoming messages, you need to register an observer on Waku Relay. +First, you need to define the observer function which decodes the message +and pushes it in to the messages array.

+

Again, in the messages.component.ts:

+
export class MessagesComponent {
+  // ...
+  // Store the messages in an array
+  messages: MessageInterface[] = [];
+  // ...
+
+  processIncomingMessages = (wakuMessage: WakuMessage) => {
+    if (!wakuMessage.payload) return;
+
+    const { timestamp, text } = proto.SimpleChatMessage.decode(
+      wakuMessage.payload
+    );
+
+    const time = new Date();
+    time.setTime(timestamp);
+    const message = { text, timestamp: time };
+
+    this.messages.push(message);
+  };
+}
+

We’ll also need to delete the observer when the component gets destroyed +to avoid memory leaks:

+
ngOnDestroy(): void {
+  this.waku.relay.deleteObserver(this.processIncomingMessages, [this.contentTopic]);
+}
+

Angular won’t delete the observer when the page reloads so we’ll have to hook that up ourselves. +Add the following to the ngOnInit() function:

+
window.onbeforeunload = () => this.ngOnDestroy();
+

+ Display Messages + # +

+

Congratulations! The Waku work is now done. +Your dApp is able to send and receive messages using Waku. +For the sake of completeness, let’s display received messages on the page.

+

We’ve already added the messages array and pushed the incoming message to it. +So all we have to do now is render them to the page.

+

In the messages.component.html, add the following under the button:

+
<h2>Messages</h2>
+<ul class="messages">
+  <li *ngFor="let message of messages">
+    <span>{{ message.timestamp }} {{ message.text }}</span>
+  </li>
+</ul>
+

And Voilà! You should now be able to send and receive messages. +Try it out by opening the app from different browsers!

+

You can see the complete code in the Relay Angular Chat Example App.

+
+ + + +
+ + + + + + + + + + +
+ + + +
+ +
+ + + + +
+ + + + +
+ + + + + + + + + + + + + + + + diff --git a/docs/guides/debug/index.html b/docs/guides/debug/index.html new file mode 100644 index 0000000..8d0fd95 --- /dev/null +++ b/docs/guides/debug/index.html @@ -0,0 +1,793 @@ + + + + + + + + + + + + + + +How to Debug your Waku dApp | Waku Connect Docs + + + + + + + + + + + +
+ + +
+
+ +
+ + + How to Debug your Waku dApp + + +
+ + + + + + +
+ + + +

+ How to Debug your Waku dApp + # +

+

JS-Waku and its most relevant dependencies (libp2p) uses debug to handle logs.

+

+ NodeJS + # +

+

To enable debug logs when running js-waku with NodeJS, simply set the DEBUG environment variable.

+

To only enable js-waku debug logs:

+
export DEBUG=waku*
+

To enable js-waku and libp2p debug logs:

+
export DEBUG=waku*,libp2p*
+

To enable all debug logs:

+
export DEBUG=*
+

+ Browser + # +

+

To see the debug logs in your browser’s console, you need to modify the local storage and add debug key.

+

Here are guides for some modern browsers:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
keyvalueeffect
debugwaku*enable js-waku debug logs
debugwaku*,libp2p*enable js-waku and libp2p debug logs
debug*enable all debug logs
+
+ + + +
+ + + + + + + + + + +
+ + + +
+ +
+ + + + +
+ + + + +
+ + + + + + + + + + + + + + + + diff --git a/docs/guides/index.html b/docs/guides/index.html index 7731d41..fa3cad9 100644 --- a/docs/guides/index.html +++ b/docs/guides/index.html @@ -15,7 +15,7 @@ - + + + + + + +
+ + +
+
+ +
+ + + Nwaku Service Node + + +
+ + + + + + +
+ + + +

+ Nwaku Service Node + # +

+

JS-Waku nodes join the Waku network by connecting to service nodes using secure websocket.

+

Nwaku (prev. nim-waku) +is the reference implementation of the Waku v2 protocol and can be used as a service node.

+

When using { bootstrap: { default: true } }, +the js-waku node connects to a fleet of nwaku nodes operated by Status.

+

It is also possible to deploy your own nwaku node by following these instructions. +Be sure to setup your nwaku node with a valid SSL certificate or js-waku nodes may fail silently to connect to it.

+
+ We are making it easier for operators to run their own nodes, +this is effort is tracked with status-im/nim-waku#828. +
+ +

You may wish to connect your nwaku node to the rest of the fleet. +This can be done with the --staticnode or --dns-discovery-url. +For example:

+
`wakunode2 \
+  --dns-discovery=true \
+  --dns-discovery-url=enrtree://ANTL4SLG2COUILKAPE7EF2BYNL2SHSHVCHLRD5J7ZJLN5R3PRJD2Y@prod.waku.nodes.status.im
+

You can then use bootstrap.peers +to pass the multiaddr of your node.

+

For example (replace the multiaddr with your node’s).

+
import { Waku } from "js-waku";
+
+const waku = await Waku.create({
+  bootstrap: {
+    peers: [
+      "/dns4/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAkvWiyFsgRhuJEb9JfjYxEkoHLgnUQmr1N5mKWnYjxYRVm",
+    ],
+  },
+});
+
+ + + +
+ + + + + + + + + + +
+ + + +
+ +
+ + + + +
+ + + + +
+ + + + + + + + + + + + + + + + diff --git a/docs/guides/vote_poll_sdk/dapp_creation/01_create_dapp/index.html b/docs/guides/vote_poll_sdk/dapp_creation/01_create_dapp/index.html index 1045280..80e54a2 100644 --- a/docs/guides/vote_poll_sdk/dapp_creation/01_create_dapp/index.html +++ b/docs/guides/vote_poll_sdk/dapp_creation/01_create_dapp/index.html @@ -23,7 +23,7 @@ The latest react-scripts version uses webpack 5." /> - +