refactor: Room logic (#34)

* refactor: move room logic to usePeerRoom hook
* refactor: make peer room hooks private
This commit is contained in:
Jeremy Kahn 2022-10-04 22:00:16 -05:00 committed by GitHub
parent ebb80c3e6c
commit 58326ecbb8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 177 additions and 175 deletions

View File

@ -1,21 +1,13 @@
import { useContext, useEffect, useState } from 'react'
import { v4 as uuid } from 'uuid'
import Box from '@mui/material/Box' import Box from '@mui/material/Box'
import Divider from '@mui/material/Divider' import Divider from '@mui/material/Divider'
import { v4 as uuid } from 'uuid'
import { rtcConfig } from 'config/rtcConfig' import { rtcConfig } from 'config/rtcConfig'
import { trackerUrls } from 'config/trackerUrls' 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 { MessageForm } from 'components/MessageForm'
import { ChatTranscript } from 'components/ChatTranscript' import { ChatTranscript } from 'components/ChatTranscript'
import { funAnimalName } from 'fun-animal-names'
import { getPeerName } from 'components/PeerNameDisplay' import { useRoom } from './useRoom'
import { NotificationService } from 'services/Notification'
import { Audio } from 'services/Audio'
export interface RoomProps { export interface RoomProps {
appId?: string appId?: string
@ -30,156 +22,21 @@ export function Room({
roomId, roomId,
userId, userId,
}: RoomProps) { }: RoomProps) {
const [numberOfPeers, setNumberOfPeers] = useState(1) // Includes this peer const { messageLog, sendMessage, isMessageSending } = useRoom(
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(
{ {
appId, appId,
trackerUrls, trackerUrls,
rtcConfig, 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) => { const handleMessageSubmit = async (message: string) => {
await performMessageSend(message) await sendMessage(message)
} }
return ( return (

View 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,
}
}

View File

@ -1,2 +0,0 @@
export * from './usePeerRoom'
export * from './usePeerRoomAction'

View File

@ -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
}