mirror of
https://github.com/logos-messaging/js-waku.git
synced 2026-01-08 08:43:09 +00:00
217 lines
5.2 KiB
TypeScript
217 lines
5.2 KiB
TypeScript
import PeerId from 'peer-id';
|
|
import { useEffect, useState } from 'react';
|
|
import './App.css';
|
|
import {
|
|
getStatusFleetNodes,
|
|
Environment,
|
|
StoreCodec,
|
|
Waku,
|
|
WakuMessage,
|
|
} 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';
|
|
|
|
const themes = {
|
|
AuthorName: {
|
|
css: {
|
|
fontSize: '1.1em',
|
|
},
|
|
},
|
|
Message: {
|
|
css: {
|
|
margin: '0em',
|
|
padding: '0em',
|
|
fontSize: '0.83em',
|
|
},
|
|
},
|
|
MessageText: {
|
|
css: {
|
|
margin: '0em',
|
|
padding: '0.1em',
|
|
paddingLeft: '1em',
|
|
fontSize: '1.1em',
|
|
},
|
|
},
|
|
MessageGroup: {
|
|
css: {
|
|
margin: '0em',
|
|
padding: '0.2em',
|
|
},
|
|
},
|
|
};
|
|
|
|
export const ChatContentTopic = '/toy-chat/2/huilong/proto';
|
|
|
|
async function retrieveStoreMessages(
|
|
waku: Waku,
|
|
peerId: PeerId,
|
|
setArchivedMessages: (value: Message[]) => void
|
|
): Promise<number> {
|
|
const callback = (wakuMessages: WakuMessage[]): void => {
|
|
const messages: Message[] = [];
|
|
wakuMessages
|
|
.map((wakuMsg) => Message.fromWakuMessage(wakuMsg))
|
|
.forEach((message) => {
|
|
if (message) {
|
|
messages.push(message);
|
|
}
|
|
});
|
|
setArchivedMessages(messages);
|
|
};
|
|
|
|
const res = await waku.store.queryHistory({
|
|
peerId,
|
|
contentTopics: [ChatContentTopic],
|
|
pageSize: 5,
|
|
callback,
|
|
});
|
|
|
|
return res ? res.length : 0;
|
|
}
|
|
|
|
export default function App() {
|
|
const [newMessages, setNewMessages] = useState<Message[]>([]);
|
|
const [archivedMessages, setArchivedMessages] = useState<Message[]>([]);
|
|
const [waku, setWaku] = useState<Waku | undefined>(undefined);
|
|
const [nick, setNick] = useState<string>(() => {
|
|
const persistedNick = window.localStorage.getItem('nick');
|
|
return persistedNick !== null ? persistedNick : generate();
|
|
});
|
|
const [fleetEnv, setFleetEnv] = useState<Environment>(defaultFleetEnv);
|
|
|
|
useEffect(() => {
|
|
localStorage.setItem('nick', nick);
|
|
}, [nick]);
|
|
|
|
useEffect(() => {
|
|
initWaku(fleetEnv, setWaku)
|
|
.then(() => console.log('Waku init done'))
|
|
.catch((e) => console.log('Waku init failed ', e));
|
|
}, [fleetEnv]);
|
|
|
|
useEffect(() => {
|
|
if (!waku) return;
|
|
|
|
const handleRelayMessage = (wakuMsg: WakuMessage) => {
|
|
console.log('Message received: ', wakuMsg);
|
|
const msg = Message.fromWakuMessage(wakuMsg);
|
|
if (msg) {
|
|
setNewMessages([msg]);
|
|
}
|
|
};
|
|
|
|
waku.relay.addObserver(handleRelayMessage, [ChatContentTopic]);
|
|
|
|
return function cleanUp() {
|
|
waku?.relay.deleteObserver(handleRelayMessage, [ChatContentTopic]);
|
|
};
|
|
}, [waku]);
|
|
|
|
useEffect(() => {
|
|
if (!waku) return;
|
|
|
|
const handleProtocolChange = async (
|
|
_waku: Waku,
|
|
{ peerId, protocols }: { peerId: PeerId; protocols: string[] }
|
|
) => {
|
|
if (protocols.includes(StoreCodec)) {
|
|
console.log(`${peerId.toB58String()}: retrieving archived messages}`);
|
|
try {
|
|
const length = await retrieveStoreMessages(
|
|
_waku,
|
|
peerId,
|
|
setArchivedMessages
|
|
);
|
|
console.log(`${peerId.toB58String()}: messages retrieved:`, length);
|
|
} catch (e) {
|
|
console.log(
|
|
`${peerId.toB58String()}: error encountered when retrieving archived messages`,
|
|
e
|
|
);
|
|
}
|
|
}
|
|
};
|
|
|
|
waku.libp2p.peerStore.on(
|
|
'change:protocols',
|
|
handleProtocolChange.bind({}, waku)
|
|
);
|
|
|
|
return function cleanUp() {
|
|
waku?.libp2p.peerStore.removeListener(
|
|
'change:protocols',
|
|
handleProtocolChange.bind({}, waku)
|
|
);
|
|
};
|
|
}, [waku]);
|
|
|
|
return (
|
|
<div
|
|
className="chat-app"
|
|
style={{ height: '100vh', width: '100vw', overflow: 'hidden' }}
|
|
>
|
|
<WakuContext.Provider value={{ waku: waku }}>
|
|
<ThemeProvider theme={themes}>
|
|
<Room
|
|
nick={nick}
|
|
newMessages={newMessages}
|
|
archivedMessages={archivedMessages}
|
|
commandHandler={(input: string) => {
|
|
const { command, response } = handleCommand(
|
|
input,
|
|
waku,
|
|
setNick,
|
|
fleetEnv,
|
|
setFleetEnv
|
|
);
|
|
const commandMessages = response.map((msg) => {
|
|
return Message.fromUtf8String(command, msg);
|
|
});
|
|
setNewMessages(commandMessages);
|
|
}}
|
|
/>
|
|
</ThemeProvider>
|
|
</WakuContext.Provider>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
async function initWaku(fleetEnv: Environment, setter: (waku: Waku) => void) {
|
|
try {
|
|
const waku = await Waku.create({
|
|
libp2p: {
|
|
config: {
|
|
pubsub: {
|
|
enabled: true,
|
|
emitSelf: true,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
setter(waku);
|
|
|
|
const nodes = await getStatusFleetNodes(fleetEnv);
|
|
await Promise.all(
|
|
nodes.map((addr) => {
|
|
return waku.dial(addr);
|
|
})
|
|
);
|
|
} catch (e) {
|
|
console.log('Issue starting waku ', e);
|
|
}
|
|
}
|
|
|
|
function defaultFleetEnv() {
|
|
// Works with react-scripts
|
|
if (process?.env?.NODE_ENV === 'development') {
|
|
return Environment.Test;
|
|
} else {
|
|
return Environment.Prod;
|
|
}
|
|
}
|