allow to change pubsub topic

This commit is contained in:
Sasha 2023-12-06 01:27:34 +05:30
parent f510cc9881
commit 6a0a5ed31f
No known key found for this signature in database
5 changed files with 97 additions and 38 deletions

View File

@ -3,12 +3,15 @@ import { Block } from "@/components/Block";
import { Subtitle } from "@/components/Subtitle"; import { Subtitle } from "@/components/Subtitle";
import { Button } from "@/components/Button"; import { Button } from "@/components/Button";
import { MessageContent } from "@/hooks"; import { MessageContent } from "@/hooks";
import { SUPPORTED_PUBSUB_TOPICS } from "@/constants";
type WakuProps = { type WakuProps = {
onSend: (nick: string, text: string) => Promise<void>; onSend: (nick: string, text: string) => Promise<void>;
activeContentTopic: string; activeContentTopic: string;
activePubsubTopic: string;
messages: MessageContent[]; messages: MessageContent[];
onActiveContentTopicChange: (contentTopic: string) => void; onActiveContentTopicChange: (contentTopic: string) => void;
onActivePubsubTopicChange: (pubsubTopic: string) => void;
} }
export const Waku: React.FunctionComponent<WakuProps> = (props) => { export const Waku: React.FunctionComponent<WakuProps> = (props) => {
@ -19,10 +22,14 @@ export const Waku: React.FunctionComponent<WakuProps> = (props) => {
onMessageChange, onMessageChange,
resetText, resetText,
} = useMessage(); } = useMessage();
const { const [
contentTopic, contentTopic,
onContentTopicChange, onContentTopicChange,
} = useContentTopic(props.activeContentTopic); ] = useTopic<HTMLInputElement>(props.activeContentTopic);
const [
pubsubTopic,
onPubsubTopicChange,
] = useTopic<HTMLSelectElement>(props.activePubsubTopic);
const onSendClick = async () => { const onSendClick = async () => {
await props.onSend(nick, text); await props.onSend(nick, text);
@ -38,18 +45,40 @@ export const Waku: React.FunctionComponent<WakuProps> = (props) => {
<Block className="mt-10 flex flex-col md:flex-row lg:flex-row"> <Block className="mt-10 flex flex-col md:flex-row lg:flex-row">
<Block> <Block>
<Block> <Block>
<Subtitle> <Subtitle>Chat</Subtitle>
Waku </Block>
</Subtitle>
<Block className="mt-5">
<label <label
htmlFor="contentTopic-input" htmlFor="pubsubTopic"
className="block mb-2 mt-2 text-sm font-medium text-gray-900 dark:text-white" className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
>
Pubsub topic
</label>
<select
id="pubsubTopic"
value={pubsubTopic}
onChange={onPubsubTopicChange}
className="w-96 mr-2 bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5 pr-4 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
>
{SUPPORTED_PUBSUB_TOPICS.map((v) => (
<option key={v} value={v}>{v}</option>
))}
</select>
<Button className="mt-1" onClick={() => { props.onActivePubsubTopicChange(pubsubTopic); }}>Change</Button>
</Block>
<Block className="mt-5">
<label
htmlFor="contentTopic"
className="block text-sm mb-2 font-medium text-gray-900 dark:text-white"
> >
Content topic Content topic
</label> </label>
<input <input
type="text" type="text"
id="contentTopic-input" id="contentTopic"
value={contentTopic} value={contentTopic}
onChange={onContentTopicChange} onChange={onContentTopicChange}
className="w-96 mr-2 bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" className="w-96 mr-2 bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
@ -59,14 +88,14 @@ export const Waku: React.FunctionComponent<WakuProps> = (props) => {
<Block className="mt-4 mr-10 min-w-fit"> <Block className="mt-4 mr-10 min-w-fit">
<label <label
htmlFor="nick-input" htmlFor="nick"
className="block mb-2 text-sm font-medium text-gray-900 dark:text-white" className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
> >
Your nickname Your nickname
</label> </label>
<input <input
type="text" type="text"
id="nick-input" id="nick"
placeholder="Choose a nickname" placeholder="Choose a nickname"
value={nick} value={nick}
onChange={onNickChange} onChange={onNickChange}
@ -74,16 +103,16 @@ export const Waku: React.FunctionComponent<WakuProps> = (props) => {
/> />
</Block> </Block>
<Block className="mt-4"> <Block className="mt-5">
<Block className="mb-2"> <Block className="mb-2">
<label <label
htmlFor="message-input" htmlFor="message"
className="block mb-2 text-sm font-medium text-gray-900 dark:text-white" className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
> >
Message Message
</label> </label>
<textarea <textarea
id="message-input" id="message"
value={text} value={text}
onChange={onMessageChange} onChange={onMessageChange}
placeholder="Text your message here" placeholder="Text your message here"
@ -104,21 +133,22 @@ export const Waku: React.FunctionComponent<WakuProps> = (props) => {
); );
}; };
function useContentTopic(globalContentTopic: string) { function useTopic<T>(globalTopic: string): [string, (e: React.SyntheticEvent<T>) => void] {
const [contentTopic, setContentTopic] = React.useState<string>(globalContentTopic); const [topic, setTopic] = React.useState<string>(globalTopic);
React.useEffect(() => { React.useEffect(() => {
setContentTopic(globalContentTopic); setTopic(globalTopic);
}, [globalContentTopic]); }, [globalTopic]);
const onContentTopicChange = (e: React.SyntheticEvent<HTMLInputElement>) => { const onTopicChange = (e: React.SyntheticEvent<T>) => {
setContentTopic(e.currentTarget.value || ""); const target = e.currentTarget as any;
setTopic(target?.value || "");
}; };
return { return [
contentTopic, topic,
onContentTopicChange, onTopicChange,
}; ];
} }
function useMessage() { function useMessage() {

View File

@ -10,7 +10,9 @@ export default function Home() {
messages, messages,
debugInfo, debugInfo,
contentTopic, contentTopic,
onContentTopicChange onContentTopicChange,
pubsubTopic,
onPubsubTopicChange
} = useWaku(); } = useWaku();
return ( return (
@ -23,6 +25,8 @@ export default function Home() {
messages={messages} messages={messages}
activeContentTopic={contentTopic} activeContentTopic={contentTopic}
onActiveContentTopicChange={onContentTopicChange} onActiveContentTopicChange={onContentTopicChange}
activePubsubTopic={pubsubTopic}
onActivePubsubTopicChange={onPubsubTopicChange}
/> />
</main> </main>
); );

View File

@ -1,5 +1,15 @@
export const CONTENT_TOPIC = "/toy-chat/2/luzhou/proto"; export const CONTENT_TOPIC = "/toy-chat/2/luzhou/proto";
export const PUBSUB_TOPIC = "/waku/2/default-waku/proto"; export const PUBSUB_TOPIC = "/waku/2/rs/1/0";
export const SUPPORTED_PUBSUB_TOPICS = [
"/waku/2/rs/1/0",
"/waku/2/rs/1/1",
"/waku/2/rs/1/2",
"/waku/2/rs/1/3",
"/waku/2/rs/1/4",
"/waku/2/rs/1/5",
"/waku/2/rs/1/6",
"/waku/2/rs/1/7",
];
export const SIGNATURE_MESSAGE = export const SIGNATURE_MESSAGE =
"The signature of this message will be used to generate your RLN credentials. Anyone accessing it may send messages on your behalf, please only share with the RLN dApp"; "The signature of this message will be used to generate your RLN credentials. Anyone accessing it may send messages on your behalf, please only share with the RLN dApp";

View File

@ -1,5 +1,5 @@
import React from "react"; import React from "react";
import { CONTENT_TOPIC } from "@/constants"; import { CONTENT_TOPIC, PUBSUB_TOPIC } from "@/constants";
import { DebugInfo, Message, waku } from "@/services/waku"; import { DebugInfo, Message, waku } from "@/services/waku";
export type MessageContent = { export type MessageContent = {
@ -10,6 +10,7 @@ export type MessageContent = {
export const useWaku = () => { export const useWaku = () => {
const [contentTopic, setContentTopic] = React.useState<string>(CONTENT_TOPIC); const [contentTopic, setContentTopic] = React.useState<string>(CONTENT_TOPIC);
const [pubsubTopic, setPubsubTopic] = React.useState<string>(PUBSUB_TOPIC);
const [messages, setMessages] = React.useState<Map<string, MessageContent>>(new Map()); const [messages, setMessages] = React.useState<Map<string, MessageContent>>(new Map());
const [debugInfo, setDebugInfo] = React.useState<undefined | DebugInfo>(); const [debugInfo, setDebugInfo] = React.useState<undefined | DebugInfo>();
@ -58,10 +59,10 @@ export const useWaku = () => {
}; };
}, [debugInfo, setDebugInfo]); }, [debugInfo, setDebugInfo]);
const onSend = React.useCallback( const onSend =
async (nick: string, text: string) => { async (nick: string, text: string) => {
const timestamp = Date.now(); const timestamp = Date.now();
await waku.relay.send({ await waku.relay.send(pubsubTopic, {
version: 0, version: 0,
timestamp, timestamp,
contentTopic, contentTopic,
@ -79,9 +80,7 @@ export const useWaku = () => {
next.set(id, { nick, timestamp, text }); next.set(id, { nick, timestamp, text });
return next; return next;
}); });
}, };
[setMessages]
);
const onContentTopicChange = async (nextContentTopic: string) => { const onContentTopicChange = async (nextContentTopic: string) => {
if (nextContentTopic === contentTopic) { if (nextContentTopic === contentTopic) {
@ -91,11 +90,22 @@ export const useWaku = () => {
setContentTopic(nextContentTopic); setContentTopic(nextContentTopic);
}; };
const onPubsubTopicChange = async (nextPubsubTopic: string) => {
if (nextPubsubTopic === pubsubTopic) {
return;
}
setPubsubTopic(nextPubsubTopic);
waku.relay.changeActivePubsubTopic(nextPubsubTopic);
};
return { return {
onSend, onSend,
debugInfo, debugInfo,
contentTopic, contentTopic,
onContentTopicChange, onContentTopicChange,
messages: Array.from(messages.values()) pubsubTopic,
onPubsubTopicChange,
messages: Array.from(messages.values()),
}; };
}; };

View File

@ -1,4 +1,4 @@
import { PUBSUB_TOPIC } from "@/constants"; import { PUBSUB_TOPIC, SUPPORTED_PUBSUB_TOPICS } from "@/constants";
import { http } from "@/utils/http"; import { http } from "@/utils/http";
export type Message = { export type Message = {
@ -17,6 +17,7 @@ const RELAY = "/relay/v1";
const buildURL = (endpoint: string) => `${LOCAL_NODE}${endpoint}`; const buildURL = (endpoint: string) => `${LOCAL_NODE}${endpoint}`;
class Relay { class Relay {
private activePubsubTopic = SUPPORTED_PUBSUB_TOPICS[0];
private subscribing = false; private subscribing = false;
private readonly subscriptionsEmitter = new EventTarget(); private readonly subscriptionsEmitter = new EventTarget();
// only one content topic subscriptions is possible now // only one content topic subscriptions is possible now
@ -43,13 +44,13 @@ class Relay {
this.subscribing = true; this.subscribing = true;
try { try {
await http.post(buildURL(`${RELAY}/subscriptions`), [PUBSUB_TOPIC]); await http.post(buildURL(`${RELAY}/subscriptions`), SUPPORTED_PUBSUB_TOPICS);
this.subscriptionRoutine = window.setInterval(async () => { this.subscriptionRoutine = window.setInterval(async () => {
await this.fetchMessages(); await this.fetchMessages();
}, 5 * SECOND); }, 5 * SECOND);
} catch (error) { } catch (error) {
console.error(`Failed to subscribe node ${PUBSUB_TOPIC}:`, error); console.error(`Failed to subscribe node any of ${SUPPORTED_PUBSUB_TOPICS}:`, error);
} }
this.subscribing = false; this.subscribing = false;
} }
@ -71,7 +72,7 @@ class Relay {
private async fetchMessages(): Promise<void> { private async fetchMessages(): Promise<void> {
const response = await http.get( const response = await http.get(
buildURL(`${RELAY}/messages/${encodeURIComponent(PUBSUB_TOPIC)}`) buildURL(`${RELAY}/messages/${encodeURIComponent(this.activePubsubTopic)}`)
); );
const body: Message[] = await response.json(); const body: Message[] = await response.json();
@ -102,8 +103,12 @@ class Relay {
}); });
} }
public async send(message: Message): Promise<void> { public changeActivePubsubTopic(pubsubTopic: string) {
await http.post(buildURL(`${RELAY}/messages/${encodeURIComponent(PUBSUB_TOPIC)}`), message); this.activePubsubTopic = pubsubTopic;
}
public async send(pubsubTopic: string, message: Message): Promise<void> {
await http.post(buildURL(`${RELAY}/messages/${encodeURIComponent(pubsubTopic)}`), message);
} }
} }