diff --git a/package-lock.json b/package-lock.json index 4295336..0713359 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "@types/node": "^18.6.5", "@types/react": "^18.0.17", "@types/react-dom": "^18.0.6", + "fast-memoize": "^2.5.2", "react": "^18.2.0", "react-dom": "^18.2.0", "react-markdown": "^8.0.3", @@ -10501,6 +10502,11 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, + "node_modules/fast-memoize": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/fast-memoize/-/fast-memoize-2.5.2.tgz", + "integrity": "sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==" + }, "node_modules/fast-write-atomic": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fast-write-atomic/-/fast-write-atomic-0.2.1.tgz", @@ -31141,6 +31147,11 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, + "fast-memoize": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/fast-memoize/-/fast-memoize-2.5.2.tgz", + "integrity": "sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==" + }, "fast-write-atomic": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fast-write-atomic/-/fast-write-atomic-0.2.1.tgz", @@ -39552,7 +39563,7 @@ }, "trystero": { "version": "git+ssh://git@github.com/jeremyckahn/trystero.git#91e9f722302597e232e96932424f3ed47d0d0171", - "from": "trystero@jeremyckahn/trystero#bugfix/fully-qualified-module-resolution", + "from": "trystero@github:jeremyckahn/trystero#bugfix/fully-qualified-module-resolution", "requires": { "firebase": "^9.6.5", "ipfs-core": "0.9.0", diff --git a/package.json b/package.json index b7dab56..fcb4560 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@types/node": "^18.6.5", "@types/react": "^18.0.17", "@types/react-dom": "^18.0.6", + "fast-memoize": "^2.5.2", "react": "^18.2.0", "react-dom": "^18.2.0", "react-markdown": "^8.0.3", diff --git a/src/hooks/usePeerRoom/usePeerRoom.ts b/src/hooks/usePeerRoom/usePeerRoom.ts index 96728e5..1b02344 100644 --- a/src/hooks/usePeerRoom/usePeerRoom.ts +++ b/src/hooks/usePeerRoom/usePeerRoom.ts @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react' -import { PeerRoom, getPeerRoom } from 'services/PeerRoom' +import { getPeerRoom } from 'services/PeerRoom' interface UsePeerRoomProps { appId: string @@ -8,19 +8,11 @@ interface UsePeerRoomProps { } export function usePeerRoom({ appId, roomId }: UsePeerRoomProps) { - const [peerRoom, setPeerRoom] = useState(null) + const [peerRoom, setPeerRoom] = useState(getPeerRoom({ appId }, roomId)) useEffect(() => { - ;(async () => { - setPeerRoom(await getPeerRoom({ appId }, roomId)) - })() + setPeerRoom(getPeerRoom({ appId }, roomId)) }, [appId, roomId]) - useEffect(() => { - return () => { - peerRoom?.leaveRoom() - } - }, [peerRoom]) - return peerRoom } diff --git a/src/index.tsx b/src/index.tsx index bc2f7e5..c17cec2 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,4 +1,3 @@ -import React from 'react' import ReactDOM from 'react-dom/client' import { BrowserRouter as Router } from 'react-router-dom' import { ThemeProvider, createTheme } from '@mui/material/styles' diff --git a/src/services/PeerRoom/PeerRoom.ts b/src/services/PeerRoom/PeerRoom.ts index bf758c6..d29a1d8 100644 --- a/src/services/PeerRoom/PeerRoom.ts +++ b/src/services/PeerRoom/PeerRoom.ts @@ -1,6 +1,5 @@ import { joinRoom, Room, RoomConfig } from 'trystero' - -import { sleep } from 'utils' +import memoize from 'fast-memoize' export class PeerRoom { private room: Room @@ -23,24 +22,10 @@ export class PeerRoom { } } -// This abstraction is necessary because it takes some time for a PeerRoom to -// be torn down, and there is no way to detect when that happens. If a new -// PeerRoom is instantiated with the same config and roomId before the previous -// one is torn down, an error is thrown. The workaround is to continually -// trying to instantiate a PeerRoom until it succeeds. -export const getPeerRoom = async (config: RoomConfig, roomId: string) => { - const timeout = 1000 - const epoch = Date.now() - - do { - if (Date.now() - epoch > timeout) { - throw new Error('Could not create PeerRoom') - } - - try { - return new PeerRoom(config, roomId) - } catch (e) {} - - await sleep(100) - } while (true) -} +// Memoization isn't just a performance optimization here. It is necessary to +// prevent subsequent calls to getPeerRoom from causing a room collision due to +// the amount of time it takes for Trystero rooms to be torn down (which is an +// asynchronous operation). +export const getPeerRoom = memoize((config: RoomConfig, roomId: string) => { + return new PeerRoom(config, roomId) +})