diff --git a/README.md b/README.md index 902df87e56..d215c9f6c3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,24 @@ A JavaScript implementation of the [Waku v2 protocol](https://specs.vac.dev/specs/waku/v2/waku-v2). -**This repo is a Work In Progress** +## This is a Work In Progress + +You can track progress on the [project board](https://github.com/status-im/js-waku/projects/1). + +## Examples + +## Chat app + +A node chat app is provided as a working example of the library. +It is interoperable with the [nim-waku chat app example](https://github.com/status-im/nim-waku/blob/master/examples/v2/chat2.nim). +To run the chat app: + +```shell +npm install +npm run chat:app -- --staticNode /ip4/134.209.139.210/tcp/30303/p2p/16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ --listenAddr /ip4/0.0.0.0/tcp/55123 +``` + +The `--listenAddr` parameter is optional, however [NAT passthrough](https://github.com/status-im/js-waku/issues/12) is not yet supported, so you'll need the listening port to be open to receive messages from the fleet. ## Contributing diff --git a/buf.gen.yaml b/buf.gen.yaml index d04c651fb3..40edf9635d 100644 --- a/buf.gen.yaml +++ b/buf.gen.yaml @@ -3,4 +3,4 @@ version: v1beta1 plugins: - name: ts_proto out: ./src/proto - opt: grpc_js + opt: grpc_js,esModuleInterop=true diff --git a/package.json b/package.json index de887e04dd..4970d432d1 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "waku-js-chat", + "name": "js-waku", "version": "1.0.0", "description": "A chat application running on node and waku", "main": "build/main/index.js", @@ -19,6 +19,7 @@ "pretest": "run-s pretest:*", "pretest:1-init-git-submodules": "[ -f './nim-waku/build/wakunode2' ] || git submodule update --init --recursive", "pretest:2-build-nim-waku": "cd nim-waku; [ -f './build/wakunode2' ] || make -j$(nproc --all 2>/dev/null || echo 2) wakunode2", + "chat:start": "ts-node src/chat/index.ts", "test": "run-s build test:*", "test:lint": "eslint src --ext .ts", "test:prettier": "prettier \"src/**/*.ts\" --list-different", diff --git a/proto/chat/v2/chat_message.proto b/proto/chat/v2/chat_message.proto new file mode 100644 index 0000000000..9d33bec91f --- /dev/null +++ b/proto/chat/v2/chat_message.proto @@ -0,0 +1,9 @@ +syntax = "proto3"; + +package chat.v2; + +message ChatMessageProto { + uint64 timestamp = 1; + string nick = 2; + bytes payload = 3; +} diff --git a/proto/waku/v2/waku.proto b/proto/waku/v2/waku.proto index 1ce9976156..6082c8efea 100644 --- a/proto/waku/v2/waku.proto +++ b/proto/waku/v2/waku.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package waku.v2; -message WakuMessage { +message WakuMessageProto { optional bytes payload = 1; optional uint32 content_topic = 2; optional uint32 version = 3; diff --git a/src/chat/chat_message.spec.ts b/src/chat/chat_message.spec.ts new file mode 100644 index 0000000000..a33d08c22c --- /dev/null +++ b/src/chat/chat_message.spec.ts @@ -0,0 +1,26 @@ +import { expect } from 'chai'; +import fc from 'fast-check'; + +import { ChatMessage } from './chat_message'; + +describe('Chat Message', function () { + it('Chat message round trip binary serialization', function () { + fc.assert( + fc.property( + fc.date({ min: new Date(0) }), + fc.string(), + fc.string(), + (timestamp, nick, message) => { + const msg = new ChatMessage(timestamp, nick, message); + const buf = msg.encode(); + const actual = ChatMessage.decode(buf); + + // Date.toString does not include ms, as we loose this precision by design + expect(actual.timestamp.toString()).to.eq(timestamp.toString()); + expect(actual.nick).to.eq(nick); + expect(actual.message).to.eq(message); + } + ) + ); + }); +}); diff --git a/src/chat/chat_message.ts b/src/chat/chat_message.ts new file mode 100644 index 0000000000..855245aca1 --- /dev/null +++ b/src/chat/chat_message.ts @@ -0,0 +1,35 @@ +import { Reader } from 'protobufjs/minimal'; + +import { ChatMessageProto } from '../proto/chat/v2/chat_message'; + +export class ChatMessage { + public constructor( + public timestamp: Date, + public nick: string, + public message: string + ) {} + + static decode(bytes: Uint8Array): ChatMessage { + const protoMsg = ChatMessageProto.decode(Reader.create(bytes)); + const timestamp = new Date(protoMsg.timestamp * 1000); + const message = protoMsg.payload + ? Array.from(protoMsg.payload) + .map((char) => { + return String.fromCharCode(char); + }) + .join('') + : ''; + return new ChatMessage(timestamp, protoMsg.nick, message); + } + + encode(): Uint8Array { + const timestamp = Math.floor(this.timestamp.valueOf() / 1000); + const payload = Buffer.from(this.message, 'utf-8'); + + return ChatMessageProto.encode({ + timestamp, + nick: this.nick, + payload, + }).finish(); + } +} diff --git a/src/chat/index.ts b/src/chat/index.ts new file mode 100644 index 0000000000..9be295e75b --- /dev/null +++ b/src/chat/index.ts @@ -0,0 +1,108 @@ +import readline from 'readline'; +import util from 'util'; + +import Waku from '../lib/waku'; +import { WakuMessage } from '../lib/waku_message'; +import { TOPIC } from '../lib/waku_relay'; +import { delay } from '../test_utils/delay'; + +import { ChatMessage } from './chat_message'; + +(async function () { + const opts = processArguments(); + + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + }); + + const question = util.promisify(rl.question).bind(rl); + + // Looks like wrong type definition of promisify is picked. + // May be related to https://github.com/DefinitelyTyped/DefinitelyTyped/issues/20497 + const nick = ((await question( + 'Please choose a nickname: ' + )) as unknown) as string; + console.log(`Hi ${nick}!`); + + const waku = await Waku.create({ listenAddresses: [opts.listenAddr] }); + + // TODO: Bubble event to waku, infer topic, decode msg + // Tracked with https://github.com/status-im/js-waku/issues/19 + waku.libp2p.pubsub.on(TOPIC, (event) => { + const wakuMsg = WakuMessage.decode(event.data); + if (wakuMsg.payload) { + const chatMsg = ChatMessage.decode(wakuMsg.payload); + const timestamp = chatMsg.timestamp.toLocaleString([], { + month: 'short', + day: 'numeric', + hour: 'numeric', + minute: '2-digit', + hour12: false, + }); + console.log(`<${timestamp}> ${chatMsg.nick}: ${chatMsg.message}`); + } + }); + + console.log('Waku started'); + + if (opts.staticNode) { + console.log(`dialing ${opts.staticNode}`); + await waku.dial(opts.staticNode); + } + + await new Promise((resolve) => + waku.libp2p.pubsub.once('gossipsub:heartbeat', resolve) + ); + + // TODO: identify if it is possible to listen to an event to confirm dial + // finished instead of an arbitrary delay. Tracked with + // https://github.com/status-im/js-waku/issues/18 + await delay(2000); + // TODO: Automatically subscribe, tracked with + // https://github.com/status-im/js-waku/issues/17 + await waku.relay.subscribe(); + console.log('Subscribed to waku relay'); + + await new Promise((resolve) => + waku.libp2p.pubsub.once('gossipsub:heartbeat', resolve) + ); + + console.log('Ready to chat!'); + rl.prompt(); + for await (const line of rl) { + rl.prompt(); + const chatMessage = new ChatMessage(new Date(), nick, line); + + const msg = WakuMessage.fromBytes(chatMessage.encode()); + await waku.relay.publish(msg); + } +})(); + +interface Options { + staticNode?: string; + listenAddr: string; +} + +function processArguments(): Options { + const passedArgs = process.argv.slice(2); + + let opts: Options = { listenAddr: '/ip4/0.0.0.0/tcp/0' }; + + while (passedArgs.length) { + const arg = passedArgs.shift(); + switch (arg) { + case '--staticNode': + opts = Object.assign(opts, { staticNode: passedArgs.shift() }); + break; + case '--listenAddr': + opts = Object.assign(opts, { listenAddr: passedArgs.shift() }); + break; + default: + console.log(`Unsupported argument: ${arg}`); + process.exit(1); + } + } + + return opts; +} diff --git a/src/lib/waku.spec.ts b/src/lib/waku.spec.ts index 89c9421a10..690feccb86 100644 --- a/src/lib/waku.spec.ts +++ b/src/lib/waku.spec.ts @@ -11,7 +11,7 @@ describe('Waku', function () { describe('Interop: Nim', function () { it('nim connects to js', async function () { this.timeout(10_000); - const waku = await Waku.create(NOISE_KEY_1); + const waku = await Waku.create({ staticNoiseKey: NOISE_KEY_1 }); const peerId = waku.libp2p.peerId.toB58String(); diff --git a/src/lib/waku.ts b/src/lib/waku.ts index f9c3e0c9f7..129313047c 100644 --- a/src/lib/waku.ts +++ b/src/lib/waku.ts @@ -8,24 +8,38 @@ import PeerId from 'peer-id'; import { CODEC, WakuRelay, WakuRelayPubsub } from './waku_relay'; +export interface CreateOptions { + listenAddresses: string[]; + staticNoiseKey: bytes | undefined; +} + export default class Waku { private constructor(public libp2p: Libp2p, public relay: WakuRelay) {} /** * Create new waku node + * @param listenAddresses: Array of Multiaddrs on which the node should listen. If not present, defaults to ['/ip4/0.0.0.0/tcp/0']. * @param staticNoiseKey: A static key to use for noise, * mainly used for test to reduce entropy usage. * @returns {Promise} */ - static async create(staticNoiseKey?: bytes): Promise { + static async create(options: Partial): Promise { + const opts = Object.assign( + { + listenAddresses: ['/ip4/0.0.0.0/tcp/0'], + staticNoiseKey: undefined, + }, + options + ); + const libp2p = await Libp2p.create({ addresses: { - listen: ['/ip4/0.0.0.0/tcp/0'], + listen: opts.listenAddresses, }, modules: { transport: [TCP], streamMuxer: [Mplex], - connEncryption: [new Noise(staticNoiseKey)], + connEncryption: [new Noise(opts.staticNoiseKey)], // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore: Type needs update pubsub: WakuRelayPubsub, @@ -37,6 +51,14 @@ export default class Waku { return new Waku(libp2p, new WakuRelay(libp2p.pubsub)); } + /** + * Dials to the provided peer. If successful, the known metadata of the peer will be added to the nodes peerStore, and the Connection will be returned + * @param peer The peer to dial + */ + async dial(peer: PeerId | Multiaddr | string) { + return this.libp2p.dialProtocol(peer, CODEC); + } + async dialWithMultiAddr(peerId: PeerId, multiaddr: Multiaddr[]) { this.libp2p.peerStore.addressBook.set(peerId, multiaddr); await this.libp2p.dialProtocol(peerId, CODEC); diff --git a/src/lib/waku_message.spec.ts b/src/lib/waku_message.spec.ts index 5d82f8db8c..8b1f386697 100644 --- a/src/lib/waku_message.spec.ts +++ b/src/lib/waku_message.spec.ts @@ -1,17 +1,28 @@ import fc from 'fast-check'; -import { Message } from './waku_message'; +import { WakuMessage } from './waku_message'; describe('Waku Message', function () { it('Waku message round trip binary serialization', function () { fc.assert( fc.property(fc.string(), (s) => { - const msg = Message.fromUtf8String(s); + const msg = WakuMessage.fromUtf8String(s); const binary = msg.toBinary(); - const actual = Message.fromBinary(binary); + const actual = WakuMessage.decode(binary); return actual.isEqualTo(msg); }) ); }); + + it('Payload to utf-8', function () { + fc.assert( + fc.property(fc.string(), (s) => { + const msg = WakuMessage.fromUtf8String(s); + const utf8 = msg.utf8Payload(); + + return utf8 === s; + }) + ); + }); }); diff --git a/src/lib/waku_message.ts b/src/lib/waku_message.ts index f7734d4ba1..0a37e9296c 100644 --- a/src/lib/waku_message.ts +++ b/src/lib/waku_message.ts @@ -2,12 +2,12 @@ import { Reader } from 'protobufjs/minimal'; // Protecting the user from protobuf oddities -import { WakuMessage } from '../proto/waku/v2/waku'; +import { WakuMessageProto } from '../proto/waku/v2/waku'; const DEFAULT_CONTENT_TOPIC = 1; const DEFAULT_VERSION = 0; -export class Message { +export class WakuMessage { private constructor( public payload?: Uint8Array, public contentTopic?: number, @@ -15,32 +15,57 @@ export class Message { ) {} /** - * Create Message from utf-8 string - * @param message - * @returns {Message} + * Create Message with a utf-8 string as payload + * @param payload + * @returns {WakuMessage} */ - static fromUtf8String(message: string): Message { - const payload = Buffer.from(message, 'utf-8'); - return new Message(payload, DEFAULT_CONTENT_TOPIC, DEFAULT_VERSION); + static fromUtf8String(payload: string): WakuMessage { + const buf = Buffer.from(payload, 'utf-8'); + return new WakuMessage(buf, DEFAULT_CONTENT_TOPIC, DEFAULT_VERSION); } - static fromBinary(bytes: Uint8Array): Message { - const wakuMsg = WakuMessage.decode(Reader.create(bytes)); - return new Message(wakuMsg.payload, wakuMsg.contentTopic, wakuMsg.version); + /** + * Create Message with a byte array as payload + * @param payload + * @returns {WakuMessage} + */ + static fromBytes(payload: Uint8Array): WakuMessage { + return new WakuMessage(payload, DEFAULT_CONTENT_TOPIC, DEFAULT_VERSION); + } + + static decode(bytes: Uint8Array): WakuMessage { + const wakuMsg = WakuMessageProto.decode(Reader.create(bytes)); + return new WakuMessage( + wakuMsg.payload, + wakuMsg.contentTopic, + wakuMsg.version + ); } toBinary(): Uint8Array { - return WakuMessage.encode({ + return WakuMessageProto.encode({ payload: this.payload, version: this.version, contentTopic: this.contentTopic, }).finish(); } + utf8Payload(): string { + if (!this.payload) { + return ''; + } + + return Array.from(this.payload) + .map((char) => { + return String.fromCharCode(char); + }) + .join(''); + } + // Purely for tests purposes. // We do consider protobuf field when checking equality // As the content is held by the other fields. - isEqualTo(other: Message) { + isEqualTo(other: WakuMessage) { const payloadsAreEqual = this.payload && other.payload ? Buffer.compare(this.payload, other.payload) === 0 diff --git a/src/lib/waku_relay.spec.ts b/src/lib/waku_relay.spec.ts index ba1d02a86d..bedcacd766 100644 --- a/src/lib/waku_relay.spec.ts +++ b/src/lib/waku_relay.spec.ts @@ -2,11 +2,12 @@ import { expect } from 'chai'; import Pubsub from 'libp2p-interfaces/src/pubsub'; import { NOISE_KEY_1, NOISE_KEY_2 } from '../test_utils/constants'; +import { delay } from '../test_utils/delay'; import { makeLogFileName } from '../test_utils/log_file'; import { NimWaku } from '../test_utils/nim_waku'; import Waku from './waku'; -import { Message } from './waku_message'; +import { WakuMessage } from './waku_message'; import { CODEC, TOPIC } from './waku_relay'; describe('Waku Relay', () => { @@ -20,8 +21,8 @@ describe('Waku Relay', () => { let waku2: Waku; beforeEach(async function () { [waku1, waku2] = await Promise.all([ - Waku.create(NOISE_KEY_1), - Waku.create(NOISE_KEY_2), + Waku.create({ staticNoiseKey: NOISE_KEY_1 }), + Waku.create({ staticNoiseKey: NOISE_KEY_2 }), ]); await waku1.dialWithMultiAddr(waku2.libp2p.peerId, waku2.libp2p.multiaddrs); @@ -76,7 +77,7 @@ describe('Waku Relay', () => { it.skip('Publish', async function () { this.timeout(10000); - const message = Message.fromUtf8String('JS to JS communication works'); + const message = WakuMessage.fromUtf8String('JS to JS communication works'); // waku.libp2p.pubsub.globalSignaturePolicy = 'StrictSign'; const receivedPromise = waitForNextData(waku2.libp2p.pubsub); @@ -108,7 +109,7 @@ describe('Waku Relay', () => { beforeEach(async function () { this.timeout(10_000); - waku = await Waku.create(NOISE_KEY_1); + waku = await Waku.create({ staticNoiseKey: NOISE_KEY_1 }); const peerId = waku.libp2p.peerId.toB58String(); const localMultiaddr = waku.libp2p.multiaddrs.find((addr) => @@ -140,7 +141,7 @@ describe('Waku Relay', () => { it('Js publishes to nim', async function () { this.timeout(5000); - const message = Message.fromUtf8String('This is a message'); + const message = WakuMessage.fromUtf8String('This is a message'); await waku.relay.publish(message); @@ -157,13 +158,77 @@ describe('Waku Relay', () => { it('Nim publishes to js', async function () { this.timeout(5000); - const message = Message.fromUtf8String('Here is another message.'); + const message = WakuMessage.fromUtf8String('Here is another message.'); + + const receivedPromise = waitForNextData(waku.libp2p.pubsub); + + await nimWaku.sendMessage(message); + + const receivedMsg = await receivedPromise; + + expect(receivedMsg.contentTopic).to.eq(message.contentTopic); + expect(receivedMsg.version).to.eq(message.version); + + const payload = Buffer.from(receivedMsg.payload!); + expect(Buffer.compare(payload, message.payload!)).to.eq(0); + }); + }); + + describe('Js connects to nim', function () { + let waku: Waku; + let nimWaku: NimWaku; + + beforeEach(async function () { + this.timeout(10_000); + waku = await Waku.create({ staticNoiseKey: NOISE_KEY_1 }); + + nimWaku = new NimWaku(this.test!.ctx!.currentTest!.title); + await nimWaku.start(); + + await waku.dial(await nimWaku.getMultiaddrWithId()); + + await delay(100); + await new Promise((resolve) => + waku.libp2p.pubsub.once('gossipsub:heartbeat', resolve) + ); await waku.relay.subscribe(); await new Promise((resolve) => waku.libp2p.pubsub.once('gossipsub:heartbeat', resolve) ); + }); + + afterEach(async function () { + nimWaku ? nimWaku.stop() : null; + waku ? await waku.stop() : null; + }); + + it('nim subscribes to js', async function () { + const subscribers = waku.libp2p.pubsub.getSubscribers(TOPIC); + + const nimPeerId = await nimWaku.getPeerId(); + expect(subscribers).to.contain(nimPeerId.toB58String()); + }); + + it('Js publishes to nim', async function () { + const message = WakuMessage.fromUtf8String('This is a message'); + + await waku.relay.publish(message); + + await nimWaku.waitForLog('WakuMessage received'); + + const msgs = await nimWaku.messages(); + + expect(msgs[0].contentTopic).to.equal(message.contentTopic); + expect(msgs[0].version).to.equal(message.version); + + const payload = Buffer.from(msgs[0].payload); + expect(Buffer.compare(payload, message.payload!)).to.equal(0); + }); + + it('Nim publishes to js', async function () { + const message = WakuMessage.fromUtf8String('Here is another message.'); const receivedPromise = waitForNextData(waku.libp2p.pubsub); @@ -185,14 +250,12 @@ describe('Waku Relay', () => { beforeEach(async function () { this.timeout(10_000); - waku = await Waku.create(NOISE_KEY_1); + waku = await Waku.create({ staticNoiseKey: NOISE_KEY_1 }); nimWaku = new NimWaku(makeLogFileName(this)); await nimWaku.start(); - const nimPeerId = await nimWaku.getPeerId(); - - await waku.dialWithMultiAddr(nimPeerId, [nimWaku.multiaddr]); + await waku.dial(await nimWaku.getMultiaddrWithId()); await new Promise((resolve) => waku.libp2p.pubsub.once('gossipsub:heartbeat', resolve) @@ -218,7 +281,7 @@ describe('Waku Relay', () => { }); it('Js publishes to nim', async function () { - const message = Message.fromUtf8String('This is a message'); + const message = WakuMessage.fromUtf8String('This is a message'); await waku.relay.publish(message); @@ -234,7 +297,7 @@ describe('Waku Relay', () => { }); it('Nim publishes to js', async function () { - const message = Message.fromUtf8String('Here is another message.'); + const message = WakuMessage.fromUtf8String('Here is another message.'); const receivedPromise = waitForNextData(waku.libp2p.pubsub); @@ -249,13 +312,86 @@ describe('Waku Relay', () => { expect(Buffer.compare(payload, message.payload!)).to.eq(0); }); }); + + describe('js to nim to js', function () { + let waku1: Waku; + let waku2: Waku; + let nimWaku: NimWaku; + + beforeEach(async function () { + this.timeout(10_000); + [waku1, waku2] = await Promise.all([ + Waku.create({ staticNoiseKey: NOISE_KEY_1 }), + Waku.create({ staticNoiseKey: NOISE_KEY_2 }), + ]); + + nimWaku = new NimWaku(this.test!.ctx!.currentTest!.title); + await nimWaku.start(); + + const nimWakuMultiaddr = await nimWaku.getMultiaddrWithId(); + await Promise.all([ + waku1.dial(nimWakuMultiaddr), + waku2.dial(nimWakuMultiaddr), + ]); + + await delay(100); + await Promise.all([ + new Promise((resolve) => + waku1.libp2p.pubsub.once('gossipsub:heartbeat', resolve) + ), + new Promise((resolve) => + waku2.libp2p.pubsub.once('gossipsub:heartbeat', resolve) + ), + ]); + + await Promise.all([waku1.relay.subscribe(), waku2.relay.subscribe()]); + + await Promise.all([ + new Promise((resolve) => + waku1.libp2p.pubsub.once('gossipsub:heartbeat', resolve) + ), + new Promise((resolve) => + waku2.libp2p.pubsub.once('gossipsub:heartbeat', resolve) + ), + ]); + }); + + afterEach(async function () { + nimWaku ? nimWaku.stop() : null; + await Promise.all([ + waku1 ? await waku1.stop() : null, + waku2 ? await waku2.stop() : null, + ]); + }); + + it('Js publishes, other Js receives', async function () { + // Check that the two JS peers are NOT directly connected + expect( + waku1.libp2p.peerStore.peers.has(waku2.libp2p.peerId.toB58String()) + ).to.be.false; + expect( + waku2.libp2p.peerStore.peers.has(waku1.libp2p.peerId.toB58String()) + ).to.be.false; + + const msgStr = 'Hello there!'; + const message = WakuMessage.fromUtf8String(msgStr); + + const waku2ReceivedPromise = waitForNextData(waku2.libp2p.pubsub); + + await waku1.relay.publish(message); + + const waku2ReceivedMsg = await waku2ReceivedPromise; + + expect(waku2ReceivedMsg.utf8Payload()).to.eq(msgStr); + }); + }); }); }); -function waitForNextData(pubsub: Pubsub): Promise { +function waitForNextData(pubsub: Pubsub): Promise { return new Promise((resolve) => { pubsub.once(TOPIC, resolve); }).then((msg: any) => { - return Message.fromBinary(msg.data); + return WakuMessage.decode(msg.data); }); } diff --git a/src/lib/waku_relay.ts b/src/lib/waku_relay.ts index 76a03caec3..1069e1f159 100644 --- a/src/lib/waku_relay.ts +++ b/src/lib/waku_relay.ts @@ -4,7 +4,7 @@ import Pubsub from 'libp2p-interfaces/src/pubsub'; import { SignaturePolicy } from 'libp2p-interfaces/src/pubsub/signature-policy'; import { getWakuPeers } from './get_waku_peers'; -import { Message } from './waku_message'; +import { WakuMessage } from './waku_message'; export const CODEC = '/vac/waku/relay/2.0.0-beta2'; @@ -16,11 +16,10 @@ export class WakuRelayPubsub extends Gossipsub { /** * * @param libp2p: Libp2p - * @param options: Partial */ constructor(libp2p: Libp2p) { super(libp2p, { - emitSelf: true, + emitSelf: false, // Ensure that no signature is expected in the messages. globalSignaturePolicy: SignaturePolicy.StrictNoSign, }); @@ -100,7 +99,7 @@ export class WakuRelay { await this.pubsub.subscribe(TOPIC); } - async publish(message: Message) { + async publish(message: WakuMessage) { const msg = message.toBinary(); await this.pubsub.publish(TOPIC, msg); } diff --git a/src/test_utils/nim_waku.ts b/src/test_utils/nim_waku.ts index 34e7e6e9f1..11bd4030fc 100644 --- a/src/test_utils/nim_waku.ts +++ b/src/test_utils/nim_waku.ts @@ -7,7 +7,7 @@ import Multiaddr from 'multiaddr'; import multiaddr from 'multiaddr'; import PeerId from 'peer-id'; -import { Message } from '../lib/waku_message'; +import { WakuMessage } from '../lib/waku_message'; import { TOPIC } from '../lib/waku_relay'; import { existsAsync, mkdirAsync, openAsync } from './async_fs'; @@ -36,6 +36,7 @@ export class NimWaku { private pid?: number; private portsShift: number; private peerId?: PeerId; + private multiaddrWithId?: Multiaddr; private logPath: string; constructor(logName: string) { @@ -131,7 +132,7 @@ export class NimWaku { return res.result; } - async sendMessage(message: Message) { + async sendMessage(message: WakuMessage) { this.checkProcess(); if (!message.payload) { @@ -160,14 +161,25 @@ export class NimWaku { } async getPeerId(): Promise { - if (this.peerId) { - return this.peerId; - } + return await this.setPeerId().then((res) => res.peerId); + } - const res = await this.info(); - const strPeerId = multiaddr(res.listenStr).getPeerId(); + async getMultiaddrWithId(): Promise { + return await this.setPeerId().then((res) => res.multiaddrWithId); + } - return PeerId.createFromB58String(strPeerId); + private async setPeerId(): Promise<{ + peerId: PeerId; + multiaddrWithId: Multiaddr; + }> { + if (this.peerId && this.multiaddrWithId) { + return { peerId: this.peerId, multiaddrWithId: this.multiaddrWithId }; + } + const res = await this.info(); + this.multiaddrWithId = multiaddr(res.listenStr); + const peerIdStr = this.multiaddrWithId.getPeerId(); + this.peerId = PeerId.createFromB58String(peerIdStr); + return { peerId: this.peerId, multiaddrWithId: this.multiaddrWithId }; } get multiaddr(): Multiaddr {