mirror of https://github.com/waku-org/js-waku.git
Extract waku initialisation in separate component
This commit is contained in:
parent
5de030d3ca
commit
6921242877
|
@ -1,22 +1,18 @@
|
||||||
import '@ethersproject/shims';
|
import '@ethersproject/shims';
|
||||||
|
|
||||||
import React, { Dispatch, SetStateAction, useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import './App.css';
|
import './App.css';
|
||||||
import { Environment, getStatusFleetNodes, Waku, WakuMessage } from 'js-waku';
|
import { Waku, WakuMessage } from 'js-waku';
|
||||||
import { ethers } from 'ethers';
|
import { ethers } from 'ethers';
|
||||||
import { Web3Provider } from '@ethersproject/providers';
|
import { Web3Provider } from '@ethersproject/providers';
|
||||||
import {
|
import { createPublicKeyMessage, KeyPair } from './crypto';
|
||||||
createPublicKeyMessage,
|
import { encode, PublicKeyMessage } from './messages';
|
||||||
decryptMessage,
|
import Messages, { Message } from './Messages';
|
||||||
KeyPair,
|
|
||||||
validatePublicKeyMessage,
|
|
||||||
} from './crypto';
|
|
||||||
import { decode, DirectMessage, encode, PublicKeyMessage } from './messages';
|
|
||||||
import { Message, Messages } from './Messages';
|
|
||||||
import 'fontsource-roboto';
|
import 'fontsource-roboto';
|
||||||
import { Button } from '@material-ui/core';
|
import { Button } from '@material-ui/core';
|
||||||
import { SendMessage } from './SendMessage';
|
import SendMessage from './SendMessage';
|
||||||
import { KeyPairHandling } from './key_pair_handling/KeyPairHandling';
|
import KeyPairHandling from './key_pair_handling/KeyPairHandling';
|
||||||
|
import InitWaku from './InitWaku';
|
||||||
|
|
||||||
export const PublicKeyContentTopic = '/eth-dm/1/public-key/json';
|
export const PublicKeyContentTopic = '/eth-dm/1/public-key/json';
|
||||||
export const DirectMessageContentTopic = '/eth-dm/1/direct-message/json';
|
export const DirectMessageContentTopic = '/eth-dm/1/direct-message/json';
|
||||||
|
@ -42,54 +38,6 @@ function App() {
|
||||||
}
|
}
|
||||||
}, [provider]);
|
}, [provider]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (waku) return;
|
|
||||||
initWaku()
|
|
||||||
.then((wakuNode) => {
|
|
||||||
console.log('waku: ready');
|
|
||||||
setWaku(wakuNode);
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.error('Failed to initiate Waku', e);
|
|
||||||
});
|
|
||||||
}, [waku]);
|
|
||||||
|
|
||||||
const observerPublicKeyMessage = handlePublicKeyMessage.bind(
|
|
||||||
{},
|
|
||||||
ethDmKeyPair?.publicKey,
|
|
||||||
setPublicKeys
|
|
||||||
);
|
|
||||||
|
|
||||||
const observerDirectMessage = ethDmKeyPair
|
|
||||||
? handleDirectMessage.bind({}, setMessages, ethDmKeyPair.privateKey)
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!waku) return;
|
|
||||||
waku.relay.addObserver(observerPublicKeyMessage, [PublicKeyContentTopic]);
|
|
||||||
|
|
||||||
return function cleanUp() {
|
|
||||||
if (!waku) return;
|
|
||||||
waku.relay.deleteObserver(observerPublicKeyMessage, [
|
|
||||||
PublicKeyContentTopic,
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!waku) return;
|
|
||||||
if (!observerDirectMessage) return;
|
|
||||||
waku.relay.addObserver(observerDirectMessage, [DirectMessageContentTopic]);
|
|
||||||
|
|
||||||
return function cleanUp() {
|
|
||||||
if (!waku) return;
|
|
||||||
if (!observerDirectMessage) return;
|
|
||||||
waku.relay.deleteObserver(observerDirectMessage, [
|
|
||||||
DirectMessageContentTopic,
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const broadcastPublicKey = () => {
|
const broadcastPublicKey = () => {
|
||||||
if (!ethDmKeyPair) return;
|
if (!ethDmKeyPair) return;
|
||||||
if (!provider) return;
|
if (!provider) return;
|
||||||
|
@ -115,12 +63,16 @@ function App() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const wakuReady = !!waku ? 'Waku is ready' : 'Waku is loading';
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<div className="App">
|
||||||
<header className="App-header">
|
<header className="App-header">
|
||||||
{wakuReady}
|
<InitWaku
|
||||||
|
ethDmKeyPair={ethDmKeyPair}
|
||||||
|
setMessages={setMessages}
|
||||||
|
setPublicKeys={setPublicKeys}
|
||||||
|
setWaku={setWaku}
|
||||||
|
waku={waku}
|
||||||
|
/>
|
||||||
<KeyPairHandling
|
<KeyPairHandling
|
||||||
ethDmKeyPair={ethDmKeyPair}
|
ethDmKeyPair={ethDmKeyPair}
|
||||||
setEthDmKeyPair={(keyPair) => setEthDmKeyPair(keyPair)}
|
setEthDmKeyPair={(keyPair) => setEthDmKeyPair(keyPair)}
|
||||||
|
@ -144,69 +96,7 @@ function App() {
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|
||||||
async function initWaku(): Promise<Waku> {
|
|
||||||
const waku = await Waku.create({});
|
|
||||||
|
|
||||||
const nodes = await getNodes();
|
|
||||||
await Promise.all(
|
|
||||||
nodes.map((addr) => {
|
|
||||||
return waku.dial(addr);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return waku;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getNodes() {
|
|
||||||
// Works with react-scripts
|
|
||||||
if (process?.env?.NODE_ENV === 'development') {
|
|
||||||
return getStatusFleetNodes(Environment.Test);
|
|
||||||
} else {
|
|
||||||
return getStatusFleetNodes(Environment.Prod);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function encodePublicKeyWakuMessage(ethDmMsg: PublicKeyMessage): WakuMessage {
|
function encodePublicKeyWakuMessage(ethDmMsg: PublicKeyMessage): WakuMessage {
|
||||||
const payload = encode(ethDmMsg);
|
const payload = encode(ethDmMsg);
|
||||||
return WakuMessage.fromBytes(payload, PublicKeyContentTopic);
|
return WakuMessage.fromBytes(payload, PublicKeyContentTopic);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handlePublicKeyMessage(
|
|
||||||
myPublicKey: string | undefined,
|
|
||||||
setter: Dispatch<SetStateAction<Map<string, string>>>,
|
|
||||||
msg: WakuMessage
|
|
||||||
) {
|
|
||||||
if (!msg.payload) return;
|
|
||||||
const publicKeyMsg: PublicKeyMessage = decode(msg.payload);
|
|
||||||
if (publicKeyMsg.ethDmPublicKey === myPublicKey) return;
|
|
||||||
const res = validatePublicKeyMessage(publicKeyMsg);
|
|
||||||
console.log(`Public Key Message Received, valid: ${res}`, publicKeyMsg);
|
|
||||||
|
|
||||||
setter((prevPks: Map<string, string>) => {
|
|
||||||
prevPks.set(publicKeyMsg.ethAddress, publicKeyMsg.ethDmPublicKey);
|
|
||||||
return new Map(prevPks);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleDirectMessage(
|
|
||||||
setter: Dispatch<SetStateAction<Message[]>>,
|
|
||||||
privateKey: string,
|
|
||||||
wakuMsg: WakuMessage
|
|
||||||
) {
|
|
||||||
console.log('Waku Message received:', wakuMsg);
|
|
||||||
if (!wakuMsg.payload) return;
|
|
||||||
const directMessage: DirectMessage = decode(wakuMsg.payload);
|
|
||||||
const text = await decryptMessage(privateKey, directMessage);
|
|
||||||
|
|
||||||
const timestamp = wakuMsg.timestamp ? wakuMsg.timestamp : new Date();
|
|
||||||
|
|
||||||
console.log('Message decrypted:', text);
|
|
||||||
setter((prevMsgs: Message[]) => {
|
|
||||||
const copy = prevMsgs.slice();
|
|
||||||
copy.push({
|
|
||||||
text: text,
|
|
||||||
timestamp: timestamp,
|
|
||||||
});
|
|
||||||
return copy;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,137 @@
|
||||||
|
import { Dispatch, SetStateAction, useEffect } from 'react';
|
||||||
|
import { Environment, getStatusFleetNodes, Waku, WakuMessage } from 'js-waku';
|
||||||
|
import { decode, DirectMessage, PublicKeyMessage } from './messages';
|
||||||
|
import { decryptMessage, KeyPair, validatePublicKeyMessage } from './crypto';
|
||||||
|
import { Message } from './Messages';
|
||||||
|
import { DirectMessageContentTopic, PublicKeyContentTopic } from './App';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
waku: Waku | undefined;
|
||||||
|
setWaku: (waku: Waku) => void;
|
||||||
|
ethDmKeyPair: KeyPair | undefined;
|
||||||
|
setPublicKeys: Dispatch<SetStateAction<Map<string, string>>>;
|
||||||
|
setMessages: Dispatch<SetStateAction<Message[]>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does all the waku initialisation
|
||||||
|
*/
|
||||||
|
export default function InitWaku({
|
||||||
|
waku,
|
||||||
|
setWaku,
|
||||||
|
ethDmKeyPair,
|
||||||
|
setPublicKeys,
|
||||||
|
setMessages,
|
||||||
|
}: Props) {
|
||||||
|
useEffect(() => {
|
||||||
|
if (waku) return;
|
||||||
|
initWaku()
|
||||||
|
.then((wakuNode) => {
|
||||||
|
console.log('waku: ready');
|
||||||
|
setWaku(wakuNode);
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.error('Failed to initiate Waku', e);
|
||||||
|
});
|
||||||
|
}, [waku, setWaku]);
|
||||||
|
|
||||||
|
const observerPublicKeyMessage = handlePublicKeyMessage.bind(
|
||||||
|
{},
|
||||||
|
ethDmKeyPair?.publicKey,
|
||||||
|
setPublicKeys
|
||||||
|
);
|
||||||
|
|
||||||
|
const observerDirectMessage = ethDmKeyPair
|
||||||
|
? handleDirectMessage.bind({}, setMessages, ethDmKeyPair.privateKey)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!waku) return;
|
||||||
|
waku.relay.addObserver(observerPublicKeyMessage, [PublicKeyContentTopic]);
|
||||||
|
|
||||||
|
return function cleanUp() {
|
||||||
|
if (!waku) return;
|
||||||
|
waku.relay.deleteObserver(observerPublicKeyMessage, [
|
||||||
|
PublicKeyContentTopic,
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!waku) return;
|
||||||
|
if (!observerDirectMessage) return;
|
||||||
|
waku.relay.addObserver(observerDirectMessage, [DirectMessageContentTopic]);
|
||||||
|
|
||||||
|
return function cleanUp() {
|
||||||
|
if (!waku) return;
|
||||||
|
if (!observerDirectMessage) return;
|
||||||
|
waku.relay.deleteObserver(observerDirectMessage, [
|
||||||
|
DirectMessageContentTopic,
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return <p>{!!waku ? 'Waku is ready' : 'Waku is loading'}</p>;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function initWaku(): Promise<Waku> {
|
||||||
|
const waku = await Waku.create({});
|
||||||
|
|
||||||
|
const nodes = await getNodes();
|
||||||
|
await Promise.all(
|
||||||
|
nodes.map((addr) => {
|
||||||
|
return waku.dial(addr);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return waku;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNodes() {
|
||||||
|
// Works with react-scripts
|
||||||
|
if (process?.env?.NODE_ENV === 'development') {
|
||||||
|
return getStatusFleetNodes(Environment.Test);
|
||||||
|
} else {
|
||||||
|
return getStatusFleetNodes(Environment.Prod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePublicKeyMessage(
|
||||||
|
myPublicKey: string | undefined,
|
||||||
|
setter: Dispatch<SetStateAction<Map<string, string>>>,
|
||||||
|
msg: WakuMessage
|
||||||
|
) {
|
||||||
|
if (!msg.payload) return;
|
||||||
|
const publicKeyMsg: PublicKeyMessage = decode(msg.payload);
|
||||||
|
if (publicKeyMsg.ethDmPublicKey === myPublicKey) return;
|
||||||
|
const res = validatePublicKeyMessage(publicKeyMsg);
|
||||||
|
console.log(`Public Key Message Received, valid: ${res}`, publicKeyMsg);
|
||||||
|
|
||||||
|
setter((prevPks: Map<string, string>) => {
|
||||||
|
prevPks.set(publicKeyMsg.ethAddress, publicKeyMsg.ethDmPublicKey);
|
||||||
|
return new Map(prevPks);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleDirectMessage(
|
||||||
|
setter: Dispatch<SetStateAction<Message[]>>,
|
||||||
|
privateKey: string,
|
||||||
|
wakuMsg: WakuMessage
|
||||||
|
) {
|
||||||
|
console.log('Waku Message received:', wakuMsg);
|
||||||
|
if (!wakuMsg.payload) return;
|
||||||
|
const directMessage: DirectMessage = decode(wakuMsg.payload);
|
||||||
|
const text = await decryptMessage(privateKey, directMessage);
|
||||||
|
|
||||||
|
const timestamp = wakuMsg.timestamp ? wakuMsg.timestamp : new Date();
|
||||||
|
|
||||||
|
console.log('Message decrypted:', text);
|
||||||
|
setter((prevMsgs: Message[]) => {
|
||||||
|
const copy = prevMsgs.slice();
|
||||||
|
copy.push({
|
||||||
|
text: text,
|
||||||
|
timestamp: timestamp,
|
||||||
|
});
|
||||||
|
return copy;
|
||||||
|
});
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ export interface Props {
|
||||||
messages: Message[];
|
messages: Message[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Messages(props: Props) {
|
export default function Messages(props: Props) {
|
||||||
const messages = props.messages.map((msg) => {
|
const messages = props.messages.map((msg) => {
|
||||||
return (
|
return (
|
||||||
<li>
|
<li>
|
||||||
|
|
|
@ -28,7 +28,7 @@ export interface Props {
|
||||||
recipients: Map<string, string>;
|
recipients: Map<string, string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SendMessage({ waku, recipients }: Props) {
|
export default function SendMessage({ waku, recipients }: Props) {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const [recipient, setRecipient] = useState<string>('');
|
const [recipient, setRecipient] = useState<string>('');
|
||||||
const [message, setMessage] = useState<string>();
|
const [message, setMessage] = useState<string>();
|
||||||
|
|
|
@ -9,7 +9,10 @@ export interface Props {
|
||||||
setEthDmKeyPair: (keyPair: KeyPair) => void;
|
setEthDmKeyPair: (keyPair: KeyPair) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function KeyPairHandling({ ethDmKeyPair, setEthDmKeyPair }: Props) {
|
export default function KeyPairHandling({
|
||||||
|
ethDmKeyPair,
|
||||||
|
setEthDmKeyPair,
|
||||||
|
}: Props) {
|
||||||
const generateKeyPair = () => {
|
const generateKeyPair = () => {
|
||||||
if (ethDmKeyPair) return;
|
if (ethDmKeyPair) return;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue