Skip to content

Commit aabd907

Browse files
authored
Merge pull request #1852 from waku-org/feat/messages-subscription-rest
feat: switches to REST for calling nwaku messages/subscription endpoints
2 parents a787e30 + 739f2bc commit aabd907

File tree

4 files changed

+99
-34
lines changed

4 files changed

+99
-34
lines changed

packages/tests/src/lib/dockerode.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import fs from "fs";
33
import { Logger } from "@waku/utils";
44
import Docker from "dockerode";
55

6-
import { Args } from "../types.js";
6+
import { Args, Ports } from "../types.js";
77

88
const log = new Logger("test:docker");
99

@@ -87,12 +87,12 @@ export default class Dockerode {
8787
}
8888

8989
async startContainer(
90-
ports: number[],
90+
ports: Ports,
9191
args: Args,
9292
logPath: string,
9393
wakuServiceNodeParams?: string
9494
): Promise<Docker.Container> {
95-
const [rpcPort, tcpPort, websocketPort, discv5UdpPort] = ports;
95+
const { rpcPort, restPort, tcpPort, websocketPort, discv5UdpPort } = ports;
9696

9797
await this.confirmImageExistsOrPull();
9898

@@ -109,6 +109,7 @@ export default class Dockerode {
109109
HostConfig: {
110110
AutoRemove: true,
111111
PortBindings: {
112+
[`${restPort}/tcp`]: [{ HostPort: restPort.toString() }],
112113
[`${rpcPort}/tcp`]: [{ HostPort: rpcPort.toString() }],
113114
[`${tcpPort}/tcp`]: [{ HostPort: tcpPort.toString() }],
114115
[`${websocketPort}/tcp`]: [{ HostPort: websocketPort.toString() }],
@@ -118,6 +119,7 @@ export default class Dockerode {
118119
}
119120
},
120121
ExposedPorts: {
122+
[`${restPort}/tcp`]: {},
121123
[`${rpcPort}/tcp`]: {},
122124
[`${tcpPort}/tcp`]: {},
123125
[`${websocketPort}/tcp`]: {},

packages/tests/src/lib/service_node.ts

+83-31
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ import {
1313
KeyPair,
1414
LogLevel,
1515
MessageRpcQuery,
16-
MessageRpcResponse
16+
MessageRpcResponse,
17+
Ports
1718
} from "../types.js";
1819
import { existsAsync, mkdirAsync, openAsync } from "../utils/async_fs.js";
1920
import { delay } from "../utils/delay.js";
@@ -49,6 +50,7 @@ export class ServiceNode {
4950
private websocketPort?: number;
5051
private readonly logPath: string;
5152
private rpcPort?: number;
53+
private restPort?: number;
5254

5355
/**
5456
* Convert a [[WakuMessage]] to a [[WakuRelayMessage]]. The latter is used
@@ -116,18 +118,26 @@ export class ServiceNode {
116118
// we also randomize the first port that portfinder will try
117119
const startPort = Math.floor(Math.random() * (65535 - 1025) + 1025);
118120

119-
const ports: number[] = await new Promise((resolve, reject) => {
120-
portfinder.getPorts(4, { port: startPort }, (err, ports) => {
121+
const ports: Ports = await new Promise((resolve, reject) => {
122+
portfinder.getPorts(5, { port: startPort }, (err, ports) => {
121123
if (err) reject(err);
122-
resolve(ports);
124+
resolve({
125+
rpcPort: ports[0],
126+
tcpPort: ports[1],
127+
websocketPort: ports[2],
128+
restPort: ports[3],
129+
discv5UdpPort: ports[4]
130+
});
123131
});
124132
});
125133

126134
if (isGoWaku && !args.logLevel) {
127135
args.logLevel = LogLevel.Debug;
128136
}
129137

130-
const [rpcPort, tcpPort, websocketPort, discv5UdpPort] = ports;
138+
const { rpcPort, tcpPort, websocketPort, restPort, discv5UdpPort } =
139+
ports;
140+
this.restPort = restPort;
131141
this.rpcPort = rpcPort;
132142
this.websocketPort = websocketPort;
133143

@@ -138,13 +148,15 @@ export class ServiceNode {
138148
Object.assign(
139149
mergedArgs,
140150
{
151+
rest: true,
152+
restPort,
141153
rpcPort,
142154
tcpPort,
143155
websocketPort,
144156
...(args?.peerExchange && { discv5UdpPort }),
145157
...(isGoWaku && { minRelayPeersToPublish: 0, legacyFilter })
146158
},
147-
{ rpcAddress: "0.0.0.0" },
159+
{ rpcAddress: "0.0.0.0", restAddress: "0.0.0.0" },
148160
_args
149161
);
150162

@@ -210,21 +222,40 @@ export class ServiceNode {
210222
async ensureSubscriptions(
211223
pubsubTopics: string[] = [DefaultPubsubTopic]
212224
): Promise<boolean> {
213-
this.checkProcess();
225+
return this.restCall<boolean>(
226+
"/relay/v1/subscriptions",
227+
"POST",
228+
pubsubTopics,
229+
async (response) => response.status === 200
230+
);
231+
}
214232

215-
return this.rpcCall<boolean>("post_waku_v2_relay_v1_subscriptions", [
216-
pubsubTopics
217-
]);
233+
async messages(
234+
pubsubTopic: string = DefaultPubsubTopic
235+
): Promise<MessageRpcResponse[]> {
236+
pubsubTopic = encodeURIComponent(pubsubTopic);
237+
return this.restCall<MessageRpcResponse[]>(
238+
`/relay/v1/messages/${pubsubTopic}`,
239+
"GET",
240+
null,
241+
async (response) => {
242+
const data = await response.json();
243+
return data?.length ? data : [];
244+
}
245+
);
218246
}
219247

220248
async ensureSubscriptionsAutosharding(
221249
contentTopics: string[]
222250
): Promise<boolean> {
223251
this.checkProcess();
224252

225-
return this.rpcCall<boolean>("post_waku_v2_relay_v1_auto_subscriptions", [
226-
contentTopics
227-
]);
253+
return this.restCall<boolean>(
254+
"/relay/v1/subscriptions",
255+
"POST",
256+
contentTopics,
257+
async (response) => response.status === 200
258+
);
228259
}
229260

230261
async sendMessage(
@@ -255,30 +286,21 @@ export class ServiceNode {
255286
]);
256287
}
257288

258-
async messages(
259-
pubsubTopic: string = DefaultPubsubTopic
260-
): Promise<MessageRpcResponse[]> {
261-
this.checkProcess();
262-
263-
const msgs = await this.rpcCall<MessageRpcResponse[]>(
264-
"get_waku_v2_relay_v1_messages",
265-
[pubsubTopic]
266-
);
267-
268-
return msgs.filter(isDefined);
269-
}
270-
271289
async messagesAutosharding(
272290
contentTopic: string
273291
): Promise<MessageRpcResponse[]> {
274292
this.checkProcess();
275293

276-
const msgs = await this.rpcCall<MessageRpcResponse[]>(
277-
"get_waku_v2_relay_v1_auto_messages",
278-
[contentTopic]
294+
contentTopic = encodeURIComponent(contentTopic);
295+
return this.restCall<MessageRpcResponse[]>(
296+
`/relay/v1/auto/messages/${contentTopic}`,
297+
"GET",
298+
null,
299+
async (response) => {
300+
const data = await response.json();
301+
return data?.length ? data.filter(isDefined) : [];
302+
}
279303
);
280-
281-
return msgs.filter(isDefined);
282304
}
283305

284306
async getAsymmetricKeyPair(): Promise<KeyPair> {
@@ -411,6 +433,10 @@ export class ServiceNode {
411433
return `http://127.0.0.1:${this.rpcPort}/`;
412434
}
413435

436+
get httpUrl(): string {
437+
return `http://127.0.0.1:${this.restPort}`;
438+
}
439+
414440
async rpcCall<T>(
415441
method: string,
416442
params: Array<string | number | unknown>
@@ -442,6 +468,31 @@ export class ServiceNode {
442468
);
443469
}
444470

471+
async restCall<T>(
472+
endpoint: string,
473+
method: "GET" | "POST",
474+
body: any = null,
475+
processResponse: (response: Response) => Promise<T>
476+
): Promise<T> {
477+
this.checkProcess();
478+
479+
try {
480+
log.info("Making a REST Call: ", endpoint, body);
481+
const options: RequestInit = {
482+
method,
483+
headers: new Headers({ "Content-Type": "application/json" })
484+
};
485+
if (body) options.body = JSON.stringify(body);
486+
487+
const response = await fetch(`${this.httpUrl}${endpoint}`, options);
488+
log.info(`Received REST Response: `, response.status);
489+
return await processResponse(response);
490+
} catch (error) {
491+
log.error(`${this.httpUrl} failed with error:`, error);
492+
throw error;
493+
}
494+
}
495+
445496
private checkProcess(): void {
446497
if (!this.docker?.container) {
447498
throw `${this.type} container hasn't started`;
@@ -454,6 +505,7 @@ export function defaultArgs(): Args {
454505
listenAddress: "0.0.0.0",
455506
rpc: true,
456507
relay: false,
508+
rest: true,
457509
rpcAdmin: true,
458510
websocketSupport: true,
459511
logLevel: LogLevel.Trace

packages/tests/src/types.ts

+10
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export interface Args {
33
nat?: "none";
44
listenAddress?: string;
55
relay?: boolean;
6+
rest?: boolean;
67
rpc?: boolean;
78
rpcAdmin?: boolean;
89
nodekey?: string;
@@ -18,6 +19,7 @@ export interface Args {
1819
rpcPrivate?: boolean;
1920
websocketSupport?: boolean;
2021
tcpPort?: number;
22+
restPort?: number;
2123
rpcPort?: number;
2224
websocketPort?: number;
2325
discv5BootstrapNode?: string;
@@ -27,6 +29,14 @@ export interface Args {
2729
clusterId?: number;
2830
}
2931

32+
export interface Ports {
33+
rpcPort: number;
34+
tcpPort: number;
35+
websocketPort: number;
36+
restPort: number;
37+
discv5UdpPort: number;
38+
}
39+
3040
export enum LogLevel {
3141
Error = "ERROR",
3242
Info = "INFO",

packages/tests/tests/nwaku.node.spec.ts

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ describe("nwaku", () => {
1414
"--listen-address=0.0.0.0",
1515
"--rpc=true",
1616
"--relay=false",
17+
"--rest=true",
1718
"--rpc-admin=true",
1819
"--websocket-support=true",
1920
"--log-level=TRACE",

0 commit comments

Comments
 (0)