diff --git a/examples/eth-dm/src/App.tsx b/examples/eth-dm/src/App.tsx index 516b5b055f..c57df3e3c5 100644 --- a/examples/eth-dm/src/App.tsx +++ b/examples/eth-dm/src/App.tsx @@ -12,13 +12,14 @@ import { validatePublicKeyMessage, } from './crypto'; import * as EthCrypto from 'eth-crypto'; -import { DirectMessage, PublicKeyMessage } from './messages'; +import { decode, DirectMessage, encode, PublicKeyMessage } from './messages'; import { Message, Messages } from './Messages'; import 'fontsource-roboto'; import { Button } from '@material-ui/core'; +import { SendMessage } from './SendMessage'; -const PublicKeyContentTopic = '/eth-dm/1/public-key/json'; -const DirectMessageContentTopic = '/eth-dm/1/direct-message/json'; +export const PublicKeyContentTopic = '/eth-dm/1/public-key/json'; +export const DirectMessageContentTopic = '/eth-dm/1/direct-message/json'; declare let window: any; @@ -126,54 +127,38 @@ function App() { } }; - const sendDummyMessage = () => { - if (!waku) return; - - console.log(`Sending messages to ${publicKeys.size} peers`); - publicKeys.forEach(async (publicKey, address) => { - const msg = await encodeEncryptedWakuMessage( - 'Here is a secret message', - publicKey, - address - ); - await waku?.lightPush.push(msg); - }); - }; - const wakuReady = !!waku ? 'Waku is ready' : 'Waku is loading'; return (
{wakuReady} - - - -
+ -
+ +
); @@ -208,22 +193,6 @@ function encodePublicKeyWakuMessage(ethDmMsg: PublicKeyMessage): WakuMessage { return WakuMessage.fromBytes(payload, PublicKeyContentTopic); } -async function encodeEncryptedWakuMessage( - message: string, - publicKey: string, - address: string -): Promise { - const encryptedMsg = await EthCrypto.encryptWithPublicKey(publicKey, message); - - const directMsg: DirectMessage = { - toAddress: address, - encMessage: encryptedMsg, - }; - - const payload = encode(directMsg); - return WakuMessage.fromBytes(payload, DirectMessageContentTopic); -} - function handlePublicKeyMessage( setter: Dispatch>>, msg: WakuMessage @@ -264,14 +233,3 @@ async function handleDirectMessage( return copy; }); } - -function encode(msg: T): Buffer { - const jsonStr = JSON.stringify(msg); - return Buffer.from(jsonStr, 'utf-8'); -} - -function decode(bytes: Uint8Array): T { - const buf = Buffer.from(bytes); - const str = buf.toString('utf-8'); - return JSON.parse(str); -} diff --git a/examples/eth-dm/src/SendMessage.tsx b/examples/eth-dm/src/SendMessage.tsx new file mode 100644 index 0000000000..723c00d773 --- /dev/null +++ b/examples/eth-dm/src/SendMessage.tsx @@ -0,0 +1,146 @@ +import { + FormControl, + InputLabel, + makeStyles, + MenuItem, + Select, + TextField, +} from '@material-ui/core'; +import React, { ChangeEvent, useState, KeyboardEvent } from 'react'; +import { Waku, WakuMessage } from 'js-waku'; +import * as EthCrypto from 'eth-crypto'; +import { DirectMessage, encode } from './messages'; +import { DirectMessageContentTopic } from './App'; + +const useStyles = makeStyles((theme) => ({ + formControl: { + margin: theme.spacing(1), + minWidth: 120, + }, + selectEmpty: { + marginTop: theme.spacing(2), + }, +})); + +export interface Props { + waku: Waku | undefined; + // address, public key + recipients: Map; +} + +export function SendMessage(props: Props) { + const classes = useStyles(); + const [recipient, setRecipient] = useState(''); + const [message, setMessage] = useState(); + + const waku = props.waku; + + const handleRecipientChange = ( + event: ChangeEvent<{ name?: string; value: unknown }> + ) => { + setRecipient(event.target.value as string); + }; + + const handleMessageChange = (event: ChangeEvent) => { + setMessage(event.target.value); + }; + + const items = Array.from(props.recipients.keys()).map((recipient) => { + return {recipient}; + }); + + const keyDownHandler = async (event: KeyboardEvent) => { + if ( + event.key === 'Enter' && + !event.altKey && + !event.ctrlKey && + !event.shiftKey + ) { + if (!waku) return; + if (!recipient) return; + if (!message) return; + const publicKey = props.recipients.get(recipient); + if (!publicKey) return; + + sendMessage(waku, recipient, publicKey, message, (res) => { + if (res) { + console.log('callback called with', res); + setMessage(''); + } + }); + } + }; + + return ( +
+ + Recipient + + + +
+ ); +} + +async function encodeEncryptedWakuMessage( + message: string, + publicKey: string, + address: string +): Promise { + const encryptedMsg = await EthCrypto.encryptWithPublicKey(publicKey, message); + + const directMsg: DirectMessage = { + toAddress: address, + encMessage: encryptedMsg, + }; + + const payload = encode(directMsg); + return WakuMessage.fromBytes(payload, DirectMessageContentTopic); +} + +function sendMessage( + waku: Waku, + recipientAddress: string, + recipientPublicKey: string, + message: string, + callback: (res: boolean) => void +) { + encodeEncryptedWakuMessage(message, recipientPublicKey, recipientAddress) + .then((msg) => { + console.log('pushing'); + waku.lightPush + .push(msg) + .then((res) => { + console.log('Message sent', res); + callback(res ? res.isSuccess : false); + }) + .catch((e) => { + console.error('Failed to send message', e); + callback(false); + }); + }) + .catch((e) => { + console.error('Cannot encode & encrypt message', e); + callback(false); + }); +} diff --git a/examples/eth-dm/src/messages.ts b/examples/eth-dm/src/messages.ts index 05d771387b..e76cbc8a89 100644 --- a/examples/eth-dm/src/messages.ts +++ b/examples/eth-dm/src/messages.ts @@ -16,3 +16,14 @@ export interface DirectMessage { toAddress: string; encMessage: EthCrypto.Encrypted; } + +export function encode(msg: T): Buffer { + const jsonStr = JSON.stringify(msg); + return Buffer.from(jsonStr, 'utf-8'); +} + +export function decode(bytes: Uint8Array): T { + const buf = Buffer.from(bytes); + const str = buf.toString('utf-8'); + return JSON.parse(str); +}