mirror of https://github.com/waku-org/js-waku.git
Use waku message timestamp as better unique key
This commit is contained in:
parent
9e64eec2a6
commit
553c0154d9
|
@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
### Added
|
||||
- Enable access to `WakuMessage.timestamp`.
|
||||
- Examples (web chat): Use `WakuMessage.timestamp` as unique key for list items.
|
||||
|
||||
## [0.5.0] - 2021-05-21
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ import PeerId from 'peer-id';
|
|||
import { useEffect, useState } from 'react';
|
||||
import './App.css';
|
||||
import {
|
||||
ChatMessage,
|
||||
getStatusFleetNodes,
|
||||
Environment,
|
||||
StoreCodec,
|
||||
|
@ -14,6 +13,7 @@ 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: {
|
||||
|
@ -49,13 +49,17 @@ export const ChatContentTopic = '/waku/2/huilong/proto';
|
|||
async function retrieveStoreMessages(
|
||||
waku: Waku,
|
||||
peerId: PeerId,
|
||||
setArchivedMessages: (value: ChatMessage[]) => void
|
||||
setArchivedMessages: (value: Message[]) => void
|
||||
): Promise<number> {
|
||||
const callback = (wakuMessages: WakuMessage[]): void => {
|
||||
const messages = wakuMessages
|
||||
.map((wakuMsg) => wakuMsg.payload)
|
||||
.filter((payload) => !!payload)
|
||||
.map((payload) => ChatMessage.decode(payload as Uint8Array));
|
||||
const messages: Message[] = [];
|
||||
wakuMessages
|
||||
.map((wakuMsg) => Message.fromWakuMessage(wakuMsg))
|
||||
.forEach((message) => {
|
||||
if (message) {
|
||||
messages.push(message);
|
||||
}
|
||||
});
|
||||
setArchivedMessages(messages);
|
||||
};
|
||||
|
||||
|
@ -70,18 +74,17 @@ async function retrieveStoreMessages(
|
|||
}
|
||||
|
||||
export default function App() {
|
||||
let [newMessages, setNewMessages] = useState<ChatMessage[]>([]);
|
||||
let [archivedMessages, setArchivedMessages] = useState<ChatMessage[]>([]);
|
||||
let [newMessages, setNewMessages] = useState<Message[]>([]);
|
||||
let [archivedMessages, setArchivedMessages] = useState<Message[]>([]);
|
||||
let [stateWaku, setWaku] = useState<Waku | undefined>(undefined);
|
||||
let [nick, setNick] = useState<string>(generate());
|
||||
|
||||
useEffect(() => {
|
||||
const handleRelayMessage = (wakuMsg: WakuMessage) => {
|
||||
if (wakuMsg.payload) {
|
||||
const chatMsg = ChatMessage.decode(wakuMsg.payload);
|
||||
if (chatMsg) {
|
||||
setNewMessages([chatMsg]);
|
||||
}
|
||||
console.log('Message received: ', wakuMsg);
|
||||
const msg = Message.fromWakuMessage(wakuMsg);
|
||||
if (msg) {
|
||||
setNewMessages([msg]);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -147,7 +150,7 @@ export default function App() {
|
|||
setNick
|
||||
);
|
||||
const commandMessages = response.map((msg) => {
|
||||
return ChatMessage.fromUtf8String(new Date(), command, msg);
|
||||
return Message.fromUtf8String(command, msg);
|
||||
});
|
||||
setNewMessages(commandMessages);
|
||||
}}
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
import { useEffect, useRef, useState } from 'react';
|
||||
import { ChatMessage } from 'js-waku';
|
||||
import {
|
||||
Message,
|
||||
Message as LiveMessage,
|
||||
MessageText,
|
||||
MessageGroup,
|
||||
MessageList,
|
||||
} from '@livechat/ui-kit';
|
||||
import { Message } from './Message';
|
||||
|
||||
interface Props {
|
||||
archivedMessages: ChatMessage[];
|
||||
newMessages: ChatMessage[];
|
||||
archivedMessages: Message[];
|
||||
newMessages: Message[];
|
||||
}
|
||||
|
||||
export default function ChatList(props: Props) {
|
||||
const [messages, setMessages] = useState<ChatMessage[]>([]);
|
||||
const [groupedMessages, setGroupedMessages] = useState<ChatMessage[][]>([]);
|
||||
const [messages, setMessages] = useState<Message[]>([]);
|
||||
const [groupedMessages, setGroupedMessages] = useState<Message[][]>([]);
|
||||
let updatedMessages;
|
||||
|
||||
if (IsThereNewMessages(props.newMessages, messages)) {
|
||||
|
@ -42,17 +42,20 @@ export default function ChatList(props: Props) {
|
|||
const renderedGroupedMessages = groupedMessages.map((currentMessageGroup) => (
|
||||
<MessageGroup onlyFirstWithMeta>
|
||||
{currentMessageGroup.map((currentMessage) => (
|
||||
<Message
|
||||
<LiveMessage
|
||||
key={
|
||||
currentMessage.timestamp.valueOf() +
|
||||
currentMessage.nick +
|
||||
currentMessage.payloadAsUtf8
|
||||
currentMessage.sentTimestamp
|
||||
? currentMessage.sentTimestamp.valueOf()
|
||||
: '' +
|
||||
currentMessage.timestamp.valueOf() +
|
||||
currentMessage.nick +
|
||||
currentMessage.payloadAsUtf8
|
||||
}
|
||||
authorName={currentMessage.nick}
|
||||
date={formatDisplayDate(currentMessage)}
|
||||
>
|
||||
<MessageText>{currentMessage.payloadAsUtf8}</MessageText>
|
||||
</Message>
|
||||
</LiveMessage>
|
||||
))}
|
||||
</MessageGroup>
|
||||
));
|
||||
|
@ -65,10 +68,10 @@ export default function ChatList(props: Props) {
|
|||
);
|
||||
}
|
||||
|
||||
function groupMessagesBySender(messageArray: ChatMessage[]): ChatMessage[][] {
|
||||
function groupMessagesBySender(messageArray: Message[]): Message[][] {
|
||||
let currentSender = -1;
|
||||
let lastNick = '';
|
||||
let messagesBySender: ChatMessage[][] = [];
|
||||
let messagesBySender: Message[][] = [];
|
||||
let currentSenderMessage = 0;
|
||||
|
||||
for (let currentMessage of messageArray) {
|
||||
|
@ -83,7 +86,7 @@ function groupMessagesBySender(messageArray: ChatMessage[]): ChatMessage[][] {
|
|||
return messagesBySender;
|
||||
}
|
||||
|
||||
function formatDisplayDate(message: ChatMessage): string {
|
||||
function formatDisplayDate(message: Message): string {
|
||||
return message.timestamp.toLocaleString([], {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
|
@ -93,7 +96,7 @@ function formatDisplayDate(message: ChatMessage): string {
|
|||
});
|
||||
}
|
||||
|
||||
const AlwaysScrollToBottom = (props: { newMessages: ChatMessage[] }) => {
|
||||
const AlwaysScrollToBottom = (props: { newMessages: Message[] }) => {
|
||||
const elementRef = useRef<HTMLDivElement>();
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -106,8 +109,8 @@ const AlwaysScrollToBottom = (props: { newMessages: ChatMessage[] }) => {
|
|||
};
|
||||
|
||||
function IsThereNewMessages(
|
||||
newValues: ChatMessage[],
|
||||
currentValues: ChatMessage[]
|
||||
newValues: Message[],
|
||||
currentValues: Message[]
|
||||
): boolean {
|
||||
if (newValues.length === 0) return false;
|
||||
if (currentValues.length === 0) return true;
|
||||
|
@ -118,8 +121,8 @@ function IsThereNewMessages(
|
|||
}
|
||||
|
||||
function copyMergeUniqueReplace(
|
||||
newValues: ChatMessage[],
|
||||
currentValues: ChatMessage[]
|
||||
newValues: Message[],
|
||||
currentValues: Message[]
|
||||
) {
|
||||
const copy = currentValues.slice();
|
||||
newValues.forEach((msg) => {
|
||||
|
@ -131,10 +134,11 @@ function copyMergeUniqueReplace(
|
|||
return copy;
|
||||
}
|
||||
|
||||
function isEqual(lhs: ChatMessage, rhs: ChatMessage): boolean {
|
||||
function isEqual(lhs: Message, rhs: Message): boolean {
|
||||
return (
|
||||
lhs.nick === rhs.nick &&
|
||||
lhs.payloadAsUtf8 === rhs.payloadAsUtf8 &&
|
||||
lhs.timestamp.toString() === rhs.timestamp.toString()
|
||||
lhs.timestamp.valueOf() === rhs.timestamp.valueOf() &&
|
||||
lhs.sentTimestamp?.valueOf() === rhs.sentTimestamp?.valueOf()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
import { ChatMessage, WakuMessage } from 'js-waku';
|
||||
|
||||
export class Message {
|
||||
public chatMessage: ChatMessage;
|
||||
// WakuMessage timestamp
|
||||
public sentTimestamp: Date | undefined;
|
||||
|
||||
constructor(chatMessage: ChatMessage, sentTimestamp: Date | undefined) {
|
||||
this.chatMessage = chatMessage;
|
||||
this.sentTimestamp = sentTimestamp;
|
||||
}
|
||||
|
||||
static fromWakuMessage(wakuMsg: WakuMessage): Message | undefined {
|
||||
if (wakuMsg.payload) {
|
||||
const chatMsg = ChatMessage.decode(wakuMsg.payload);
|
||||
if (chatMsg) {
|
||||
return new Message(chatMsg, wakuMsg.timestamp);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static fromUtf8String(nick: string, text: string): Message {
|
||||
const now = new Date();
|
||||
return new Message(ChatMessage.fromUtf8String(now, nick, text), now);
|
||||
}
|
||||
|
||||
get nick() {
|
||||
return this.chatMessage.nick;
|
||||
}
|
||||
|
||||
get timestamp() {
|
||||
return this.chatMessage.timestamp;
|
||||
}
|
||||
|
||||
get payloadAsUtf8() {
|
||||
return this.chatMessage.payloadAsUtf8;
|
||||
}
|
||||
}
|
|
@ -4,10 +4,11 @@ import ChatList from './ChatList';
|
|||
import MessageInput from './MessageInput';
|
||||
import { useWaku } from './WakuContext';
|
||||
import { TitleBar } from '@livechat/ui-kit';
|
||||
import { Message } from './Message';
|
||||
|
||||
interface Props {
|
||||
newMessages: ChatMessage[];
|
||||
archivedMessages: ChatMessage[];
|
||||
newMessages: Message[];
|
||||
archivedMessages: Message[];
|
||||
commandHandler: (cmd: string) => void;
|
||||
nick: string;
|
||||
}
|
||||
|
@ -52,10 +53,12 @@ async function handleMessage(
|
|||
if (message.startsWith('/')) {
|
||||
commandHandler(message);
|
||||
} else {
|
||||
const chatMessage = ChatMessage.fromUtf8String(new Date(), nick, message);
|
||||
const timestamp = new Date();
|
||||
const chatMessage = ChatMessage.fromUtf8String(timestamp, nick, message);
|
||||
const wakuMsg = WakuMessage.fromBytes(
|
||||
chatMessage.encode(),
|
||||
ChatContentTopic
|
||||
ChatContentTopic,
|
||||
timestamp
|
||||
);
|
||||
return messageSender(wakuMsg);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue