js-waku-examples/eth-pm/src/App.tsx

276 lines
7.3 KiB
TypeScript
Raw Normal View History

2022-06-17 00:48:15 +00:00
import "@ethersproject/shims";
import React, { useEffect, useState } from "react";
import "./App.css";
2022-09-13 02:23:56 +00:00
import type { WakuLight } from "js-waku/lib/interfaces";
2022-06-17 00:48:15 +00:00
import { KeyPair, PublicKeyMessageEncryptionKey } from "./crypto";
import { Message } from "./messaging/Messages";
import "fontsource-roboto";
import { AppBar, IconButton, Toolbar, Typography } from "@material-ui/core";
import KeyPairHandling from "./key_pair_handling/KeyPairHandling";
import {
createMuiTheme,
ThemeProvider,
makeStyles,
} from "@material-ui/core/styles";
import { teal, purple, green } from "@material-ui/core/colors";
import WifiIcon from "@material-ui/icons/Wifi";
import BroadcastPublicKey from "./BroadcastPublicKey";
import Messaging from "./messaging/Messaging";
import {
PrivateMessageContentTopic,
handlePrivateMessage,
handlePublicKeyMessage,
initWaku,
PublicKeyContentTopic,
} from "./waku";
import { Web3Provider } from "@ethersproject/providers/src.ts/web3-provider";
import ConnectWallet from "./ConnectWallet";
import { waku_message } from "js-waku";
2022-06-17 00:48:15 +00:00
const theme = createMuiTheme({
palette: {
primary: {
main: purple[500],
},
secondary: {
main: teal[600],
},
},
});
const useStyles = makeStyles({
root: {
textAlign: "center",
display: "flex",
flexDirection: "column",
minHeight: "100vh",
},
appBar: {
// height: '200p',
},
container: {
display: "flex",
flex: 1,
},
main: {
flex: 1,
margin: "10px",
},
wakuStatus: {
marginRight: theme.spacing(2),
},
title: {
flexGrow: 1,
},
peers: {},
});
function App() {
2022-09-13 02:23:56 +00:00
const [waku, setWaku] = useState<WakuLight>();
2022-06-17 00:48:15 +00:00
const [provider, setProvider] = useState<Web3Provider>();
const [encryptionKeyPair, setEncryptionKeyPair] = useState<
KeyPair | undefined
>();
const [publicKeys, setPublicKeys] = useState<Map<string, Uint8Array>>(
new Map()
);
const [messages, setMessages] = useState<Message[]>([]);
const [address, setAddress] = useState<string>();
const [peerStats, setPeerStats] = useState<{
filterPeers: number;
2022-06-17 00:48:15 +00:00
lightPushPeers: number;
}>({
filterPeers: 0,
2022-06-17 00:48:15 +00:00
lightPushPeers: 0,
});
const classes = useStyles();
// Waku initialization
useEffect(() => {
(async () => {
if (waku) return;
const _waku = await initWaku();
console.log("waku: ready");
setWaku(_waku);
})().catch((e) => {
console.error("Failed to initiate Waku", e);
});
2022-06-17 00:48:15 +00:00
}, [waku]);
useEffect(() => {
if (!waku) return;
const observerPublicKeyMessage = handlePublicKeyMessage.bind(
{},
address,
setPublicKeys
);
2022-08-20 08:49:48 +00:00
let unsubscribe: undefined | (() => Promise<void>);
waku.filter.addDecryptionKey(PublicKeyMessageEncryptionKey, {
method: waku_message.DecryptionMethod.Symmetric,
contentTopics: [PublicKeyContentTopic],
});
waku.filter
.subscribe(observerPublicKeyMessage, [PublicKeyContentTopic])
.then(
2022-08-20 08:49:48 +00:00
(_unsubscribe) => {
console.log("subscribed to ", PublicKeyContentTopic);
unsubscribe = _unsubscribe;
},
(e) => {
console.error("Failed to subscribe", e);
}
);
2022-06-17 00:48:15 +00:00
return function cleanUp() {
if (!waku) return;
waku.filter.deleteDecryptionKey(PublicKeyMessageEncryptionKey);
2022-08-20 08:49:48 +00:00
if (typeof unsubscribe === "undefined") return;
unsubscribe().then(
() => {
console.log("unsubscribed to ", PublicKeyContentTopic);
},
(e) => console.error("Failed to unsubscribe", e)
);
2022-06-17 00:48:15 +00:00
};
2022-08-20 08:49:48 +00:00
}, [waku, address]);
2022-06-17 00:48:15 +00:00
useEffect(() => {
if (!waku) return;
if (!encryptionKeyPair) return;
waku.filter.addDecryptionKey(encryptionKeyPair.privateKey, {
method: waku_message.DecryptionMethod.Asymmetric,
contentTopics: [PrivateMessageContentTopic],
});
2022-06-17 00:48:15 +00:00
return function cleanUp() {
if (!waku) return;
if (!encryptionKeyPair) return;
waku.filter.deleteDecryptionKey(encryptionKeyPair.privateKey);
2022-06-17 00:48:15 +00:00
};
}, [waku, encryptionKeyPair]);
useEffect(() => {
if (!waku) return;
if (!encryptionKeyPair) return;
if (!address) return;
const observerPrivateMessage = handlePrivateMessage.bind(
{},
setMessages,
address
);
2022-08-20 08:49:48 +00:00
let unsubscribe: undefined | (() => Promise<void>);
waku.filter
.subscribe(observerPrivateMessage, [PrivateMessageContentTopic])
.then(
2022-08-20 08:49:48 +00:00
(_unsubscribe) => {
unsubscribe = _unsubscribe;
},
(e) => {
console.error("Failed to subscribe", e);
}
);
2022-06-17 00:48:15 +00:00
return function cleanUp() {
if (!waku) return;
2022-08-20 08:49:48 +00:00
if (typeof unsubscribe === "undefined") return;
unsubscribe().catch((e) => console.error("Failed to unsubscribe", e));
2022-06-17 00:48:15 +00:00
};
2022-08-20 08:49:48 +00:00
}, [waku, address, encryptionKeyPair]);
2022-06-17 00:48:15 +00:00
useEffect(() => {
if (!waku) return;
const interval = setInterval(async () => {
2022-08-20 03:32:47 +00:00
const lightPushPeers = await waku.store.peers();
const filterPeers = await waku.filter.peers();
2022-06-17 00:48:15 +00:00
setPeerStats({
filterPeers: filterPeers.length,
2022-08-20 03:32:47 +00:00
lightPushPeers: lightPushPeers.length,
2022-06-17 00:48:15 +00:00
});
}, 1000);
return () => clearInterval(interval);
}, [waku]);
let addressDisplay = "";
if (address) {
addressDisplay =
address.substr(0, 6) + "..." + address.substr(address.length - 4, 4);
}
return (
<ThemeProvider theme={theme}>
<div className={classes.root}>
<AppBar className={classes.appBar} position="static">
<Toolbar>
<IconButton
edge="start"
className={classes.wakuStatus}
aria-label="waku-status"
>
<WifiIcon
color={waku ? undefined : "disabled"}
style={waku ? { color: green[500] } : {}}
/>
</IconButton>
<Typography className={classes.peers} aria-label="connected-peers">
Peers: {peerStats.filterPeers} filter, {peerStats.lightPushPeers}{" "}
2022-06-17 00:48:15 +00:00
light push
</Typography>
<Typography variant="h6" className={classes.title}>
Ethereum Private Message
</Typography>
<Typography>{addressDisplay}</Typography>
</Toolbar>
</AppBar>
<div className={classes.container}>
<main className={classes.main}>
<fieldset>
<legend>Wallet</legend>
<ConnectWallet
setAddress={setAddress}
setProvider={setProvider}
/>
</fieldset>
<fieldset>
<legend>Encryption Key Pair</legend>
<KeyPairHandling
encryptionKeyPair={encryptionKeyPair}
setEncryptionKeyPair={setEncryptionKeyPair}
/>
<BroadcastPublicKey
address={address}
EncryptionKeyPair={encryptionKeyPair}
waku={waku}
signer={provider?.getSigner()}
2022-06-17 00:48:15 +00:00
/>
</fieldset>
<fieldset>
<legend>Messaging</legend>
<Messaging
recipients={publicKeys}
waku={waku}
messages={messages}
/>
</fieldset>
</main>
</div>
</div>
</ThemeProvider>
);
}
export default App;