js-waku/examples/web-chat/src/App.tsx

210 lines
5.2 KiB
TypeScript
Raw Normal View History

2022-02-04 03:12:00 +00:00
import { useEffect, useReducer, useState } from "react";
import "./App.css";
2022-01-13 03:28:45 +00:00
import {
discovery,
2022-02-16 00:43:57 +00:00
getPredefinedBootstrapNodes,
PageDirection,
2022-01-13 03:28:45 +00:00
Waku,
WakuMessage,
2022-02-04 03:12:00 +00:00
} from "js-waku";
import handleCommand from "./command";
import Room from "./Room";
import { WakuContext } from "./WakuContext";
import { ThemeProvider } from "@livechat/ui-kit";
import { generate } from "server-name-generator";
import { Message } from "./Message";
2021-04-14 04:44:12 +00:00
const themes = {
AuthorName: {
css: {
2022-02-04 03:12:00 +00:00
fontSize: "1.1em",
},
},
Message: {
css: {
2022-02-04 03:12:00 +00:00
margin: "0em",
padding: "0em",
fontSize: "0.83em",
},
},
MessageText: {
css: {
2022-02-04 03:12:00 +00:00
margin: "0em",
padding: "0.1em",
paddingLeft: "1em",
fontSize: "1.1em",
},
},
MessageGroup: {
css: {
2022-02-04 03:12:00 +00:00
margin: "0em",
padding: "0.2em",
},
},
};
2022-02-04 03:12:00 +00:00
export const ChatContentTopic = "/toy-chat/2/huilong/proto";
2021-04-21 05:51:52 +00:00
2021-05-17 06:19:50 +00:00
async function retrieveStoreMessages(
waku: Waku,
setArchivedMessages: (value: Message[]) => void
2021-05-17 06:19:50 +00:00
): Promise<number> {
const callback = (wakuMessages: WakuMessage[]): void => {
const messages: Message[] = [];
wakuMessages
.map((wakuMsg) => Message.fromWakuMessage(wakuMsg))
.forEach((message) => {
if (message) {
messages.push(message);
}
});
2021-05-17 06:19:50 +00:00
setArchivedMessages(messages);
};
const startTime = new Date();
// Only retrieve a week of history
startTime.setTime(Date.now() - 1000 * 60 * 60 * 24 * 7);
const endTime = new Date();
try {
const res = await waku.store.queryHistory([ChatContentTopic], {
pageSize: 5,
pageDirection: PageDirection.FORWARD,
timeFilter: {
startTime,
endTime,
},
callback,
});
2021-05-17 06:19:50 +00:00
return res.length;
} catch (e) {
2022-02-04 03:12:00 +00:00
console.log("Failed to retrieve messages", e);
return 0;
}
2021-05-17 06:19:50 +00:00
}
export default function App() {
const [messages, dispatchMessages] = useReducer(reduceMessages, []);
const [waku, setWaku] = useState<Waku | undefined>(undefined);
const [nick, setNick] = useState<string>(() => {
2022-02-04 03:12:00 +00:00
const persistedNick = window.localStorage.getItem("nick");
2021-06-04 05:15:07 +00:00
return persistedNick !== null ? persistedNick : generate();
});
2022-01-06 06:40:40 +00:00
const [historicalMessagesRetrieved, setHistoricalMessagesRetrieved] =
useState(false);
2021-06-04 05:15:07 +00:00
useEffect(() => {
2022-02-04 03:12:00 +00:00
localStorage.setItem("nick", nick);
2021-06-04 05:15:07 +00:00
}, [nick]);
2021-04-19 01:34:13 +00:00
2021-04-21 06:11:07 +00:00
useEffect(() => {
initWaku(setWaku)
2022-02-04 03:12:00 +00:00
.then(() => console.log("Waku init done"))
.catch((e) => console.log("Waku init failed ", e));
}, []);
useEffect(() => {
if (!waku) return;
// Let's retrieve previous messages before listening to new messages
if (!historicalMessagesRetrieved) return;
2021-05-10 02:38:27 +00:00
const handleRelayMessage = (wakuMsg: WakuMessage) => {
2022-02-04 03:12:00 +00:00
console.log("Message received: ", wakuMsg);
const msg = Message.fromWakuMessage(wakuMsg);
if (msg) {
dispatchMessages([msg]);
}
};
waku.relay.addObserver(handleRelayMessage, [ChatContentTopic]);
return function cleanUp() {
waku?.relay.deleteObserver(handleRelayMessage, [ChatContentTopic]);
};
}, [waku, historicalMessagesRetrieved]);
useEffect(() => {
if (!waku) return;
if (historicalMessagesRetrieved) return;
const retrieveMessages = async () => {
await waku.waitForRemotePeer();
console.log(`Retrieving archived messages`);
try {
retrieveStoreMessages(waku, dispatchMessages).then((length) => {
console.log(`Messages retrieved:`, length);
setHistoricalMessagesRetrieved(true);
});
} catch (e) {
console.log(`Error encountered when retrieving archived messages`, e);
}
};
retrieveMessages();
}, [waku, historicalMessagesRetrieved]);
2021-04-21 05:51:52 +00:00
2021-04-21 06:11:07 +00:00
return (
2021-04-27 04:39:34 +00:00
<div
className="chat-app"
2022-02-04 03:12:00 +00:00
style={{ height: "100vh", width: "100vw", overflow: "hidden" }}
2021-04-27 04:39:34 +00:00
>
<WakuContext.Provider value={{ waku: waku }}>
<ThemeProvider theme={themes}>
<Room
nick={nick}
messages={messages}
commandHandler={(input: string) => {
handleCommand(input, waku, setNick).then(
({ command, response }) => {
const commandMessages = response.map((msg) => {
return Message.fromUtf8String(command, msg);
});
dispatchMessages(commandMessages);
}
);
}}
/>
</ThemeProvider>
</WakuContext.Provider>
2021-04-21 06:11:07 +00:00
</div>
);
2021-04-14 04:44:12 +00:00
}
async function initWaku(setter: (waku: Waku) => void) {
2021-04-27 01:05:35 +00:00
try {
const waku = await Waku.create({
libp2p: {
config: {
pubsub: {
enabled: true,
emitSelf: true,
},
2021-04-27 01:05:35 +00:00
},
},
2022-01-13 03:28:45 +00:00
bootstrap: {
peers: getPredefinedBootstrapNodes(selectFleetEnv()),
2022-01-13 03:28:45 +00:00
},
2021-04-27 01:05:35 +00:00
});
setter(waku);
} catch (e) {
2022-02-04 03:12:00 +00:00
console.log("Issue starting waku ", e);
2021-04-27 01:05:35 +00:00
}
}
function selectFleetEnv() {
// Works with react-scripts
2022-02-04 03:12:00 +00:00
if (process?.env?.NODE_ENV === "development") {
return discovery.predefined.Fleet.Test;
} else {
return discovery.predefined.Fleet.Prod;
}
}
function reduceMessages(state: Message[], newMessages: Message[]) {
return state.concat(newMessages);
}