From ea49955412e1b6b3b1d7ee8c2161cd6f3bc01551 Mon Sep 17 00:00:00 2001 From: Szymon Szlachtowicz <38212223+Szymx95@users.noreply.github.com> Date: Tue, 5 Oct 2021 14:47:18 +0200 Subject: [PATCH] Use retrieve previous messages (#39) --- .../src/components/Chat/ChatMessages.tsx | 2 +- packages/react-chat/src/hooks/useMessenger.ts | 145 ++++++++---------- packages/status-communities/src/index.ts | 4 +- 3 files changed, 67 insertions(+), 84 deletions(-) diff --git a/packages/react-chat/src/components/Chat/ChatMessages.tsx b/packages/react-chat/src/components/Chat/ChatMessages.tsx index 9a78790..fb3eac3 100644 --- a/packages/react-chat/src/components/Chat/ChatMessages.tsx +++ b/packages/react-chat/src/components/Chat/ChatMessages.tsx @@ -20,7 +20,7 @@ export function ChatMessages({ messages, theme }: ChatMessagesProps) { if (ref && ref.current) { ref.current.scrollTop = ref.current.scrollHeight; } - }, [messages]); + }, [messages, messages.length]); return ( {messages.map((message, idx) => { diff --git a/packages/react-chat/src/hooks/useMessenger.ts b/packages/react-chat/src/hooks/useMessenger.ts index f90e934..f6c17b0 100644 --- a/packages/react-chat/src/hooks/useMessenger.ts +++ b/packages/react-chat/src/hooks/useMessenger.ts @@ -1,15 +1,33 @@ // import { StoreCodec } from "js-waku"; import { getBootstrapNodes, StoreCodec } from "js-waku"; import { useCallback, useEffect, useState } from "react"; -import { - ChatMessage as ApiChatMessage, - ApplicationMetadataMessage, - Identity, - Messenger, -} from "status-communities/dist/cjs"; +import { Identity, Messenger } from "status-communities/dist/cjs"; +import { ApplicationMetadataMessage } from "status-communities/dist/cjs/application_metadata_message"; import { ChatMessage } from "../models/ChatMessage"; +function binarySetInsert( + arr: T[], + val: T, + compFunc: (a: T, b: T) => boolean, + eqFunc: (a: T, b: T) => boolean +) { + let low = 0; + let high = arr.length; + while (low < high) { + const mid = (low + high) >> 1; + if (compFunc(arr[mid], val)) { + low = mid + 1; + } else { + high = mid; + } + } + if (arr.length === low || !eqFunc(arr[low], val)) { + arr.splice(low, 0, val); + } + return arr; +} + export function useMessenger(chatId: string, chatIdList: string[]) { const [messenger, setMessenger] = useState(undefined); const [activeMessages, setActiveMessages] = useState([]); @@ -29,40 +47,42 @@ export function useMessenger(chatId: string, chatIdList: string[]) { }); }, []); - const addNewMessage = useCallback( - (sender: Uint8Array, content: string, date: Date, id: string) => { - let signer = "0x"; - sender.forEach((e) => { - signer = signer + e.toString(16); - }); - setMessages((prevMessages) => { - const newMessage = { - sender: signer, - content: content, - date: date, - }; - if (prevMessages?.[id]) { - return { - ...prevMessages, - [id]: [...prevMessages[id], newMessage], - }; - } else { - return { - ...prevMessages, - [id]: [newMessage], - }; - } - }); - setNotifications((prevNotifications) => { + const addNewMessageRaw = useCallback( + (signer: Uint8Array, content: string, date: Date, id: string) => { + const sender = signer.reduce((p, c) => p + c.toString(16), "0x"); + const newMessage = { sender, content, date }; + setMessages((prev) => { return { - ...prevNotifications, - [id]: prevNotifications[id] + 1, + ...prev, + [id]: binarySetInsert( + prev?.[id] ?? [], + newMessage, + (a, b) => a.date < b.date, + (a, b) => a.date.getTime() === b.date.getTime() + ), + }; + }); + setNotifications((prev) => { + return { + ...prev, + [id]: prev[id] + 1, }; }); }, [] ); + const addNewMessage = useCallback( + (msg: ApplicationMetadataMessage, id: string) => { + if (msg.signer && msg.chatMessage?.text) { + const content = msg.chatMessage.text; + const date = new Date(msg.chatMessage.clock); + addNewMessageRaw(msg.signer, content, date, id); + } + }, + [addNewMessageRaw] + ); + useEffect(() => { const createMessenger = async () => { const identity = Identity.generate(); @@ -86,54 +106,19 @@ export function useMessenger(chatId: string, chatIdList: string[]) { }); await Promise.all( + chatIdList.map(async (id) => await messenger.joinChat(id)) + ); + + Promise.all( chatIdList.map(async (id) => { - await messenger.joinChat(id); - const chat = messenger.chatsById.get(id); - if (chat) { - const messages = await messenger.waku.store.queryHistory( - [chat.contentTopic], - { - decryptionKeys: [chat.symKey], - } - ); - messages.sort((a, b) => - (a?.timestamp?.getTime() ?? 0) > (b?.timestamp?.getTime() ?? 0) - ? 1 - : -1 - ); - messages.forEach((message) => { - if (message.payload) { - const metadata = ApplicationMetadataMessage.decode( - message.payload - ); - if (metadata.payload) { - const chatMessage = ApiChatMessage.decode(metadata.payload); - if ( - metadata.signer && - chatMessage.text && - chatMessage.proto.timestamp - ) { - addNewMessage( - metadata.signer, - chatMessage.text, - new Date(chatMessage.proto.timestamp ?? 0), - id - ); - } - } - } - return undefined; - }); - } + await messenger.retrievePreviousMessages( + id, + new Date(0), + new Date(), + (messages) => messages.forEach((msg) => addNewMessage(msg, id)) + ); clearNotifications(id); - messenger.addObserver((message) => { - addNewMessage( - message.signer ?? new Uint8Array(), - message.chatMessage?.text ?? "", - new Date(message.chatMessage?.proto.timestamp ?? 0), - id - ); - }, id); + messenger.addObserver((msg) => addNewMessage(msg, id), id); }) ); setMessenger(messenger); @@ -144,7 +129,7 @@ export function useMessenger(chatId: string, chatIdList: string[]) { const sendMessage = useCallback( async (messageText: string) => { await messenger?.sendMessage(messageText, chatId); - addNewMessage( + addNewMessageRaw( messenger?.identity.publicKey ?? new Uint8Array(), messageText, new Date(), diff --git a/packages/status-communities/src/index.ts b/packages/status-communities/src/index.ts index 7e9747a..4350c11 100644 --- a/packages/status-communities/src/index.ts +++ b/packages/status-communities/src/index.ts @@ -1,5 +1,3 @@ -import { ApplicationMetadataMessage } from "./application_metadata_message"; -import { ChatMessage } from "./chat_message"; import { Identity } from "./identity"; import { Messenger } from "./messenger"; -export { Messenger, Identity, ApplicationMetadataMessage, ChatMessage }; +export { Messenger, Identity };