mirror of https://github.com/waku-org/js-waku.git
Enable recipient selection and message input
This commit is contained in:
parent
0c825fe391
commit
66fcb2e48b
|
@ -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,27 +127,19 @@ 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 (
|
||||
<div className="App">
|
||||
<header className="App-header">
|
||||
{wakuReady}
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
flexWrap: 'wrap',
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
|
@ -163,17 +156,9 @@ function App() {
|
|||
>
|
||||
Broadcast Eth-DM Public Key
|
||||
</Button>
|
||||
<div>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={sendDummyMessage}
|
||||
disabled={!waku || publicKeys.size === 0}
|
||||
>
|
||||
Send Direct Message
|
||||
</Button>
|
||||
<Messages messages={messages} />
|
||||
</div>
|
||||
<SendMessage recipients={publicKeys} waku={waku} />
|
||||
<Messages messages={messages} />
|
||||
</header>
|
||||
</div>
|
||||
);
|
||||
|
@ -208,22 +193,6 @@ function encodePublicKeyWakuMessage(ethDmMsg: PublicKeyMessage): WakuMessage {
|
|||
return WakuMessage.fromBytes(payload, PublicKeyContentTopic);
|
||||
}
|
||||
|
||||
async function encodeEncryptedWakuMessage(
|
||||
message: string,
|
||||
publicKey: string,
|
||||
address: string
|
||||
): Promise<WakuMessage> {
|
||||
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<SetStateAction<Map<string, string>>>,
|
||||
msg: WakuMessage
|
||||
|
@ -264,14 +233,3 @@ async function handleDirectMessage(
|
|||
return copy;
|
||||
});
|
||||
}
|
||||
|
||||
function encode<T>(msg: T): Buffer {
|
||||
const jsonStr = JSON.stringify(msg);
|
||||
return Buffer.from(jsonStr, 'utf-8');
|
||||
}
|
||||
|
||||
function decode<T>(bytes: Uint8Array): T {
|
||||
const buf = Buffer.from(bytes);
|
||||
const str = buf.toString('utf-8');
|
||||
return JSON.parse(str);
|
||||
}
|
||||
|
|
|
@ -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<string, string>;
|
||||
}
|
||||
|
||||
export function SendMessage(props: Props) {
|
||||
const classes = useStyles();
|
||||
const [recipient, setRecipient] = useState<string>('');
|
||||
const [message, setMessage] = useState<string>();
|
||||
|
||||
const waku = props.waku;
|
||||
|
||||
const handleRecipientChange = (
|
||||
event: ChangeEvent<{ name?: string; value: unknown }>
|
||||
) => {
|
||||
setRecipient(event.target.value as string);
|
||||
};
|
||||
|
||||
const handleMessageChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
setMessage(event.target.value);
|
||||
};
|
||||
|
||||
const items = Array.from(props.recipients.keys()).map((recipient) => {
|
||||
return <MenuItem value={recipient}>{recipient}</MenuItem>;
|
||||
});
|
||||
|
||||
const keyDownHandler = async (event: KeyboardEvent<HTMLInputElement>) => {
|
||||
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 (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
flexWrap: 'wrap',
|
||||
}}
|
||||
>
|
||||
<FormControl className={classes.formControl}>
|
||||
<InputLabel id="select-recipient-label">Recipient</InputLabel>
|
||||
<Select
|
||||
labelId="select-recipient"
|
||||
id="select-recipient"
|
||||
value={recipient}
|
||||
onChange={handleRecipientChange}
|
||||
>
|
||||
{items}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<TextField
|
||||
id="message-input"
|
||||
label="Message"
|
||||
variant="filled"
|
||||
onChange={handleMessageChange}
|
||||
onKeyDown={keyDownHandler}
|
||||
value={message}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
async function encodeEncryptedWakuMessage(
|
||||
message: string,
|
||||
publicKey: string,
|
||||
address: string
|
||||
): Promise<WakuMessage> {
|
||||
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);
|
||||
});
|
||||
}
|
|
@ -16,3 +16,14 @@ export interface DirectMessage {
|
|||
toAddress: string;
|
||||
encMessage: EthCrypto.Encrypted;
|
||||
}
|
||||
|
||||
export function encode<T>(msg: T): Buffer {
|
||||
const jsonStr = JSON.stringify(msg);
|
||||
return Buffer.from(jsonStr, 'utf-8');
|
||||
}
|
||||
|
||||
export function decode<T>(bytes: Uint8Array): T {
|
||||
const buf = Buffer.from(bytes);
|
||||
const str = buf.toString('utf-8');
|
||||
return JSON.parse(str);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue