diff --git a/web-chat/README.md b/web-chat/README.md index 63cf102..6011a69 100644 --- a/web-chat/README.md +++ b/web-chat/README.md @@ -4,7 +4,8 @@ - Group chat - React/TypeScript -- Waku Relay +- Waku Filter +- Waku Light Push - Waku Store A ReactJS chat app is provided as a showcase of the library used in the browser. diff --git a/web-chat/src/App.tsx b/web-chat/src/App.tsx index 1edf749..802e582 100644 --- a/web-chat/src/App.tsx +++ b/web-chat/src/App.tsx @@ -121,7 +121,7 @@ export default function App() { // Let's retrieve previous messages before listening to new messages if (!historicalMessagesRetrieved) return; - const handleRelayMessage = (wakuMsg: WakuMessage) => { + const handleIncomingMessage = (wakuMsg: WakuMessage) => { console.log("Message received: ", wakuMsg); const msg = Message.fromWakuMessage(wakuMsg); if (msg) { @@ -129,10 +129,26 @@ export default function App() { } }; - waku.relay.addObserver(handleRelayMessage, [ChatContentTopic]); + let unsubscribe: undefined | (() => Promise); + waku.filter.subscribe(handleIncomingMessage, [ChatContentTopic]).then( + (_unsubscribe) => { + console.log("subscribed to ", ChatContentTopic); + unsubscribe = _unsubscribe; + }, + (e) => { + console.error("Failed to subscribe", e); + } + ); return function cleanUp() { - waku?.relay.deleteObserver(handleRelayMessage, [ChatContentTopic]); + if (!waku) return; + if (typeof unsubscribe === "undefined") return; + unsubscribe().then( + () => { + console.log("unsubscribed to ", ChatContentTopic); + }, + (e) => console.error("Failed to unsubscribe", e) + ); }; }, [waku, historicalMessagesRetrieved]); @@ -141,7 +157,11 @@ export default function App() { if (historicalMessagesRetrieved) return; const retrieveMessages = async () => { - await waitForRemotePeer(waku, [Protocols.Relay, Protocols.Store]); + await waitForRemotePeer(waku, [ + Protocols.Store, + Protocols.Filter, + Protocols.LightPush, + ]); console.log(`Retrieving archived messages`); try { @@ -186,7 +206,9 @@ export default function App() { async function initWaku(setter: (waku: Waku) => void) { try { + // TODO: Remove this declaration once there are optional in js-waku const wakuRelay = new WakuRelay({ emitSelf: true }); + const libp2p = await defaultLibp2p(wakuRelay, { peerDiscovery: [ new PeerDiscoveryStaticPeers( @@ -196,7 +218,6 @@ async function initWaku(setter: (waku: Waku) => void) { }); const wakuStore = new WakuStore(libp2p); - // TODO: Remove these two declarations once there are optional in js-waku const wakuLightPush = new WakuLightPush(libp2p); const wakuFilter = new WakuFilter(libp2p); @@ -211,7 +232,8 @@ async function initWaku(setter: (waku: Waku) => void) { function selectFleetEnv() { // Works with react-scripts - if (process?.env?.NODE_ENV === "development") { + // TODO: Re-enable the switch once nwaku v0.12 is deployed + if (true || process?.env?.NODE_ENV === "development") { return Fleet.Test; } else { return Fleet.Prod; diff --git a/web-chat/src/MessageInput.tsx b/web-chat/src/MessageInput.tsx index 72c2c53..386bab3 100644 --- a/web-chat/src/MessageInput.tsx +++ b/web-chat/src/MessageInput.tsx @@ -1,4 +1,4 @@ -import { ChangeEvent, KeyboardEvent, useState } from "react"; +import { ChangeEvent, KeyboardEvent, useEffect, useState } from "react"; import { useWaku } from "./WakuContext"; import { TextInput, @@ -15,6 +15,7 @@ interface Props { export default function MessageInput(props: Props) { const [inputText, setInputText] = useState(""); + const [activeButton, setActiveButton] = useState(false); const { waku } = useWaku(); const sendMessage = async () => { @@ -39,10 +40,21 @@ export default function MessageInput(props: Props) { } }; - // Enable the button if there are relay peers available or the user is sending a command - const activeButton = - (waku && waku.relay.getMeshPeers().length !== 0) || - inputText.startsWith("/"); + // Enable the button if there are peers available or the user is sending a command + useEffect(() => { + if (inputText.startsWith("/")) { + setActiveButton(true); + } else if (waku) { + (async () => { + const peers = await waku.lightPush.peers(); + if (!!peers) { + setActiveButton(true); + } else { + setActiveButton(false); + } + })(); + } + }, [activeButton, inputText, waku]); return ( { - if (!waku) return; - - // Update relay peer count on heartbeat - waku.relay.addEventListener("gossipsub:heartbeat", () => { - setRelayPeers(waku.relay.getMeshPeers().length); - }); - }, [waku]); + const [filterPeers, setFilterPeers] = useState(0); + const [lightPushPeers, setLightPushPeers] = useState(0); useEffect(() => { if (!waku) return; // Update store peer when new peer connected & identified waku.libp2p.peerStore.addEventListener("change:protocols", async () => { - const peers = await waku.store.peers(); - setStorePeers(peers.length); + const storePeers = await waku.store.peers(); + setStorePeers(storePeers.length); + + const filterPeers = await waku.filter.peers(); + setFilterPeers(filterPeers.length); + + const lightPushPeers = await waku.lightPush.peers(); + setLightPushPeers(lightPushPeers.length); }); }, [waku]); @@ -45,7 +43,9 @@ export default function Room(props: Props) { style={{ height: "98vh", display: "flex", flexDirection: "column" }} > @@ -57,7 +57,7 @@ export default function Room(props: Props) { messageToSend, props.nick, props.commandHandler, - waku.relay.send.bind(waku.relay) + waku.lightPush.push.bind(waku.lightPush) ); } : undefined @@ -71,7 +71,7 @@ async function handleMessage( message: string, nick: string, commandHandler: (cmd: string) => void, - messageSender: (msg: WakuMessage) => Promise + messageSender: (msg: WakuMessage) => Promise ) { if (message.startsWith("/")) { commandHandler(message); @@ -83,6 +83,6 @@ async function handleMessage( ChatContentTopic, { timestamp } ); - return messageSender(wakuMsg); + await messageSender(wakuMsg); } } diff --git a/web-chat/src/chat_message.ts b/web-chat/src/chat_message.ts index 82bba96..7250c71 100644 --- a/web-chat/src/chat_message.ts +++ b/web-chat/src/chat_message.ts @@ -59,6 +59,6 @@ export class ChatMessage { return ""; } - return Buffer.from(this.proto.payload).toString("utf-8"); + return utils.bytesToUtf8(this.proto.payload); } }