forked from Shiloh/remnantchat
refactor: Room logic (#34)
* refactor: move room logic to usePeerRoom hook * refactor: make peer room hooks private
This commit is contained in:
parent
ebb80c3e6c
commit
58326ecbb8
@ -1,21 +1,13 @@
|
||||
import { useContext, useEffect, useState } from 'react'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
import Box from '@mui/material/Box'
|
||||
import Divider from '@mui/material/Divider'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
|
||||
import { rtcConfig } from 'config/rtcConfig'
|
||||
import { trackerUrls } from 'config/trackerUrls'
|
||||
import { ShellContext } from 'contexts/ShellContext'
|
||||
import { SettingsContext } from 'contexts/SettingsContext'
|
||||
import { usePeerRoom, usePeerRoomAction } from 'hooks/usePeerRoom'
|
||||
import { PeerActions } from 'models/network'
|
||||
import { Peer, ReceivedMessage, UnsentMessage } from 'models/chat'
|
||||
import { MessageForm } from 'components/MessageForm'
|
||||
import { ChatTranscript } from 'components/ChatTranscript'
|
||||
import { funAnimalName } from 'fun-animal-names'
|
||||
import { getPeerName } from 'components/PeerNameDisplay'
|
||||
import { NotificationService } from 'services/Notification'
|
||||
import { Audio } from 'services/Audio'
|
||||
|
||||
import { useRoom } from './useRoom'
|
||||
|
||||
export interface RoomProps {
|
||||
appId?: string
|
||||
@ -30,156 +22,21 @@ export function Room({
|
||||
roomId,
|
||||
userId,
|
||||
}: RoomProps) {
|
||||
const [numberOfPeers, setNumberOfPeers] = useState(1) // Includes this peer
|
||||
const shellContext = useContext(ShellContext)
|
||||
const settingsContext = useContext(SettingsContext)
|
||||
const [isMessageSending, setIsMessageSending] = useState(false)
|
||||
const [messageLog, setMessageLog] = useState<
|
||||
Array<ReceivedMessage | UnsentMessage>
|
||||
>([])
|
||||
const [newMessageAudio] = useState(
|
||||
() => new Audio(process.env.PUBLIC_URL + '/sounds/new-message.aac')
|
||||
)
|
||||
|
||||
const peerRoom = usePeerRoom(
|
||||
const { messageLog, sendMessage, isMessageSending } = useRoom(
|
||||
{
|
||||
appId,
|
||||
trackerUrls,
|
||||
rtcConfig,
|
||||
},
|
||||
roomId
|
||||
{
|
||||
roomId,
|
||||
userId,
|
||||
getUuid,
|
||||
}
|
||||
)
|
||||
|
||||
const [sendPeerId, receivePeerId] = usePeerRoomAction<string>(
|
||||
peerRoom,
|
||||
PeerActions.PEER_NAME
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
shellContext.setDoShowPeers(true)
|
||||
|
||||
peerRoom.onPeerJoin((peerId: string) => {
|
||||
shellContext.showAlert(`Someone has joined the room`, {
|
||||
severity: 'success',
|
||||
})
|
||||
|
||||
const newNumberOfPeers = numberOfPeers + 1
|
||||
setNumberOfPeers(newNumberOfPeers)
|
||||
shellContext.setNumberOfPeers(newNumberOfPeers)
|
||||
;(async () => {
|
||||
try {
|
||||
await sendPeerId(userId, peerId)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
})()
|
||||
})
|
||||
|
||||
peerRoom.onPeerLeave((peerId: string) => {
|
||||
const peerIndex = shellContext.peerList.findIndex(
|
||||
peer => peer.peerId === peerId
|
||||
)
|
||||
const peerExist = peerIndex !== -1
|
||||
shellContext.showAlert(
|
||||
`${
|
||||
peerExist
|
||||
? funAnimalName(shellContext.peerList[peerIndex].userId)
|
||||
: 'Someone'
|
||||
} has left the room`,
|
||||
{
|
||||
severity: 'warning',
|
||||
}
|
||||
)
|
||||
|
||||
const newNumberOfPeers = numberOfPeers - 1
|
||||
setNumberOfPeers(newNumberOfPeers)
|
||||
shellContext.setNumberOfPeers(newNumberOfPeers)
|
||||
|
||||
if (peerExist) {
|
||||
const peerListClone = [...shellContext.peerList]
|
||||
peerListClone.splice(peerIndex, 1)
|
||||
shellContext.setPeerList(peerListClone)
|
||||
}
|
||||
})
|
||||
|
||||
return () => {
|
||||
shellContext.setDoShowPeers(false)
|
||||
}
|
||||
}, [
|
||||
numberOfPeers,
|
||||
shellContext.peerList,
|
||||
peerRoom,
|
||||
sendPeerId,
|
||||
shellContext,
|
||||
userId,
|
||||
])
|
||||
|
||||
const [sendMessage, receiveMessage] = usePeerRoomAction<UnsentMessage>(
|
||||
peerRoom,
|
||||
PeerActions.MESSAGE
|
||||
)
|
||||
|
||||
const performMessageSend = async (message: string) => {
|
||||
if (isMessageSending) return
|
||||
|
||||
const unsentMessage: UnsentMessage = {
|
||||
authorId: userId,
|
||||
text: message,
|
||||
timeSent: Date.now(),
|
||||
id: getUuid(),
|
||||
}
|
||||
|
||||
setIsMessageSending(true)
|
||||
setMessageLog([...messageLog, unsentMessage])
|
||||
await sendMessage(unsentMessage)
|
||||
|
||||
setMessageLog([
|
||||
...messageLog,
|
||||
{ ...unsentMessage, timeReceived: Date.now() },
|
||||
])
|
||||
setIsMessageSending(false)
|
||||
}
|
||||
|
||||
const upsertToPeerList = (peerToAdd: Peer) => {
|
||||
const peerIndex = shellContext.peerList.findIndex(
|
||||
peer => peer.peerId === peerToAdd.peerId
|
||||
)
|
||||
if (peerIndex === -1) {
|
||||
shellContext.setPeerList([
|
||||
...shellContext.peerList,
|
||||
{ peerId: peerToAdd.peerId, userId: peerToAdd.userId },
|
||||
])
|
||||
} else {
|
||||
const peerListClone = [...shellContext.peerList]
|
||||
peerListClone[peerIndex].userId = peerToAdd.userId
|
||||
shellContext.setPeerList(peerListClone)
|
||||
}
|
||||
}
|
||||
|
||||
receivePeerId((userId: string, peerId: string) => {
|
||||
upsertToPeerList({ peerId, userId })
|
||||
})
|
||||
|
||||
receiveMessage(message => {
|
||||
const userSettings = settingsContext.getUserSettings()
|
||||
|
||||
if (!shellContext.tabHasFocus) {
|
||||
if (userSettings.playSoundOnNewMessage) {
|
||||
newMessageAudio.play()
|
||||
}
|
||||
|
||||
if (userSettings.showNotificationOnNewMessage) {
|
||||
NotificationService.showNotification(
|
||||
`${getPeerName(message.authorId)}: ${message.text}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
setMessageLog([...messageLog, { ...message, timeReceived: Date.now() }])
|
||||
})
|
||||
|
||||
const handleMessageSubmit = async (message: string) => {
|
||||
await performMessageSend(message)
|
||||
await sendMessage(message)
|
||||
}
|
||||
|
||||
return (
|
||||
|
167
src/components/Room/useRoom.ts
Normal file
167
src/components/Room/useRoom.ts
Normal file
@ -0,0 +1,167 @@
|
||||
import { useContext, useEffect, useState } from 'react'
|
||||
import { BaseRoomConfig } from 'trystero'
|
||||
import { TorrentRoomConfig } from 'trystero/torrent'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
|
||||
import { ShellContext } from 'contexts/ShellContext'
|
||||
import { SettingsContext } from 'contexts/SettingsContext'
|
||||
import { PeerActions } from 'models/network'
|
||||
import { ReceivedMessage, UnsentMessage } from 'models/chat'
|
||||
import { funAnimalName } from 'fun-animal-names'
|
||||
import { getPeerName } from 'components/PeerNameDisplay'
|
||||
import { NotificationService } from 'services/Notification'
|
||||
import { Audio } from 'services/Audio'
|
||||
import { PeerRoom } from 'services/PeerRoom'
|
||||
|
||||
import { usePeerRoomAction } from './usePeerRoomAction'
|
||||
|
||||
interface UseRoomConfig {
|
||||
roomId: string
|
||||
userId: string
|
||||
getUuid?: typeof uuid
|
||||
}
|
||||
|
||||
export function useRoom(
|
||||
roomConfig: BaseRoomConfig & TorrentRoomConfig,
|
||||
{ roomId, userId, getUuid = uuid }: UseRoomConfig
|
||||
) {
|
||||
const [peerRoom] = useState(() => new PeerRoom(roomConfig, roomId))
|
||||
const [numberOfPeers, setNumberOfPeers] = useState(1) // Includes this peer
|
||||
const shellContext = useContext(ShellContext)
|
||||
const settingsContext = useContext(SettingsContext)
|
||||
const [isMessageSending, setIsMessageSending] = useState(false)
|
||||
const [messageLog, setMessageLog] = useState<
|
||||
Array<ReceivedMessage | UnsentMessage>
|
||||
>([])
|
||||
const [newMessageAudio] = useState(
|
||||
() => new Audio(process.env.PUBLIC_URL + '/sounds/new-message.aac')
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
peerRoom.leaveRoom()
|
||||
}
|
||||
}, [peerRoom])
|
||||
|
||||
useEffect(() => {
|
||||
shellContext.setDoShowPeers(true)
|
||||
|
||||
return () => {
|
||||
shellContext.setDoShowPeers(false)
|
||||
}
|
||||
}, [shellContext])
|
||||
|
||||
const [sendPeerId, receivePeerId] = usePeerRoomAction<string>(
|
||||
peerRoom,
|
||||
PeerActions.PEER_NAME
|
||||
)
|
||||
|
||||
const [sendPeerMessage, receivePeerMessage] =
|
||||
usePeerRoomAction<UnsentMessage>(peerRoom, PeerActions.MESSAGE)
|
||||
|
||||
const sendMessage = async (message: string) => {
|
||||
if (isMessageSending) return
|
||||
|
||||
const unsentMessage: UnsentMessage = {
|
||||
authorId: userId,
|
||||
text: message,
|
||||
timeSent: Date.now(),
|
||||
id: getUuid(),
|
||||
}
|
||||
|
||||
setIsMessageSending(true)
|
||||
setMessageLog([...messageLog, unsentMessage])
|
||||
await sendPeerMessage(unsentMessage)
|
||||
|
||||
setMessageLog([
|
||||
...messageLog,
|
||||
{ ...unsentMessage, timeReceived: Date.now() },
|
||||
])
|
||||
setIsMessageSending(false)
|
||||
}
|
||||
|
||||
receivePeerId((userId: string, peerId: string) => {
|
||||
const peerIndex = shellContext.peerList.findIndex(
|
||||
peer => peer.peerId === peerId
|
||||
)
|
||||
if (peerIndex === -1) {
|
||||
shellContext.setPeerList([
|
||||
...shellContext.peerList,
|
||||
{ peerId: peerId, userId: userId },
|
||||
])
|
||||
} else {
|
||||
const peerListClone = [...shellContext.peerList]
|
||||
peerListClone[peerIndex].userId = userId
|
||||
shellContext.setPeerList(peerListClone)
|
||||
}
|
||||
})
|
||||
|
||||
receivePeerMessage(message => {
|
||||
const userSettings = settingsContext.getUserSettings()
|
||||
|
||||
if (!shellContext.tabHasFocus) {
|
||||
if (userSettings.playSoundOnNewMessage) {
|
||||
newMessageAudio.play()
|
||||
}
|
||||
|
||||
if (userSettings.showNotificationOnNewMessage) {
|
||||
NotificationService.showNotification(
|
||||
`${getPeerName(message.authorId)}: ${message.text}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
setMessageLog([...messageLog, { ...message, timeReceived: Date.now() }])
|
||||
})
|
||||
|
||||
peerRoom.onPeerJoin((peerId: string) => {
|
||||
shellContext.showAlert(`Someone has joined the room`, {
|
||||
severity: 'success',
|
||||
})
|
||||
|
||||
const newNumberOfPeers = numberOfPeers + 1
|
||||
setNumberOfPeers(newNumberOfPeers)
|
||||
shellContext.setNumberOfPeers(newNumberOfPeers)
|
||||
;(async () => {
|
||||
try {
|
||||
await sendPeerId(userId, peerId)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
})()
|
||||
})
|
||||
|
||||
peerRoom.onPeerLeave((peerId: string) => {
|
||||
const peerIndex = shellContext.peerList.findIndex(
|
||||
peer => peer.peerId === peerId
|
||||
)
|
||||
const peerExist = peerIndex !== -1
|
||||
shellContext.showAlert(
|
||||
`${
|
||||
peerExist
|
||||
? funAnimalName(shellContext.peerList[peerIndex].userId)
|
||||
: 'Someone'
|
||||
} has left the room`,
|
||||
{
|
||||
severity: 'warning',
|
||||
}
|
||||
)
|
||||
|
||||
const newNumberOfPeers = numberOfPeers - 1
|
||||
setNumberOfPeers(newNumberOfPeers)
|
||||
shellContext.setNumberOfPeers(newNumberOfPeers)
|
||||
|
||||
if (peerExist) {
|
||||
const peerListClone = [...shellContext.peerList]
|
||||
peerListClone.splice(peerIndex, 1)
|
||||
shellContext.setPeerList(peerListClone)
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
peerRoom,
|
||||
messageLog,
|
||||
sendMessage,
|
||||
isMessageSending,
|
||||
}
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
export * from './usePeerRoom'
|
||||
export * from './usePeerRoomAction'
|
@ -1,20 +0,0 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { BaseRoomConfig } from 'trystero'
|
||||
import { TorrentRoomConfig } from 'trystero/torrent'
|
||||
|
||||
import { PeerRoom } from 'services/PeerRoom'
|
||||
|
||||
export function usePeerRoom(
|
||||
roomConfig: BaseRoomConfig & TorrentRoomConfig,
|
||||
roomId: string
|
||||
) {
|
||||
const [peerRoom] = useState(() => new PeerRoom(roomConfig, roomId))
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
peerRoom.leaveRoom()
|
||||
}
|
||||
}, [peerRoom])
|
||||
|
||||
return peerRoom
|
||||
}
|
Loading…
Reference in New Issue
Block a user