feat: [closes #22] implement message backfilling (#45)

* feat: [#22] implement message backfilling
* feat: scroll to latest backfilled message
* feat: document transcript backfilling
This commit is contained in:
Jeremy Kahn 2022-10-25 21:00:28 -05:00 committed by GitHub
parent bd6f1d5090
commit 10b061e36a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 35 additions and 5 deletions

View File

@ -30,6 +30,7 @@ Open https://chitchatter.im/ and join a room to start chatting with anyone else
- The number displayed at the top-right of the screen shows how many peers you are connected to. Your peers are the only ones who can see your message.
- Markdown support via [`react-markdown`](https://github.com/remarkjs/react-markdown).
- Includes support for syntax highlighting of code.
- Conversation backfilling from peers when a new participant joins
- Multiline message support (hold Shift and press Enter).
- Dark and light themes

View File

@ -1,4 +1,4 @@
import { HTMLAttributes, useRef, useEffect } from 'react'
import { HTMLAttributes, useRef, useEffect, useState } from 'react'
import cx from 'classnames'
import Box from '@mui/material/Box'
@ -16,6 +16,7 @@ export const ChatTranscript = ({
userId,
}: ChatTranscriptProps) => {
const boxRef = useRef<HTMLDivElement>(null)
const [previousMessageLogLength, setPreviousMessageLogLength] = useState(0)
useEffect(() => {
const { current: boxEl } = boxRef
@ -29,14 +30,23 @@ export const ChatTranscript = ({
const lastChild = children[children.length - 1]
const lastChildHeight = lastChild.clientHeight
const previousScrollTopMax = scrollTopMax - lastChildHeight
const wasPreviouslyScrolledToBottom =
Math.ceil(scrollTop) >= Math.ceil(previousScrollTopMax)
const wasMessageLogPreviouslyEmpty = previousMessageLogLength === 0
const shouldScrollToLatestMessage =
wasPreviouslyScrolledToBottom || wasMessageLogPreviouslyEmpty
if (
Math.ceil(scrollTop) >= Math.ceil(previousScrollTopMax) &&
shouldScrollToLatestMessage &&
// scrollTo is not defined in the unit test environment
'scrollTo' in boxEl
) {
boxEl.scrollTo({ top: scrollTopMax })
}
}, [messageLog.length, previousMessageLogLength])
useEffect(() => {
setPreviousMessageLogLength(messageLog.length)
}, [messageLog.length])
return (

View File

@ -6,7 +6,7 @@ import { v4 as uuid } from 'uuid'
import { ShellContext } from 'contexts/ShellContext'
import { SettingsContext } from 'contexts/SettingsContext'
import { PeerActions } from 'models/network'
import { ReceivedMessage, UnsentMessage, Message } from 'models/chat'
import { Message, ReceivedMessage, UnsentMessage, isMessageReceived } from 'models/chat'
import { funAnimalName } from 'fun-animal-names'
import { getPeerName } from 'components/PeerNameDisplay'
import { NotificationService } from 'services/Notification'
@ -62,6 +62,10 @@ export function useRoom(
PeerActions.PEER_NAME
)
const [sendMessageTranscript, receiveMessageTranscript] = usePeerRoomAction<
ReceivedMessage[]
>(peerRoom, PeerActions.MESSAGE_TRANSCRIPT)
const [sendPeerMessage, receivePeerMessage] =
usePeerRoomAction<UnsentMessage>(peerRoom, PeerActions.MESSAGE)
@ -102,6 +106,12 @@ export function useRoom(
}
})
receiveMessageTranscript(transcript => {
if (messageLog.length) return
setMessageLog(transcript)
})
receivePeerMessage(message => {
const userSettings = settingsContext.getUserSettings()
@ -130,7 +140,10 @@ export function useRoom(
shellContext.setNumberOfPeers(newNumberOfPeers)
;(async () => {
try {
await sendPeerId(userId, peerId)
await Promise.all([
sendPeerId(userId, peerId),
sendMessageTranscript(messageLog.filter(isMessageReceived), peerId),
])
} catch (e) {
console.error(e)
}

View File

@ -1,4 +1,6 @@
// NOTE: Action names are limited to 12 characters, otherwise Trystero breaks.
export enum PeerActions {
MESSAGE = 'MESSAGE',
MESSAGE_TRANSCRIPT = 'MSG_XSCRIPT',
PEER_NAME = 'PEER_NAME',
}

View File

@ -28,7 +28,11 @@ Public rooms can be joined by **anyone** with the room URL. By default, rooms ar
To connect to others, share the room URL with a secure tool such as [Burner Note](https://burnernote.com/) or [Yopass](https://yopass.se/). You will be notified when others join the room.
Chat message transcripts are erased as soon as you close the page or navigate away from the room.
##### Conversation backfilling
Conversation transcripts are erased from local memory as soon as you close the page or navigate away from the room. Conversations are only ever held in volatile memory and never persisted to any disk by Chitchatter.
When a peer joins a public room with participants already in it, the new peer will automatically request the transcript of the conversation that has already taken place from the other peers. Once all peers leave the room, the conversation is completely erased.
#### Message Authoring