feat(connection-test): display failed tracker connections (#129)

This commit is contained in:
Jeremy Kahn 2023-07-14 17:21:25 -05:00 committed by GitHub
parent 291ed0c2b9
commit f67dbb60d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 71 additions and 14 deletions

View File

@ -3,6 +3,9 @@ import Tooltip from '@mui/material/Tooltip'
import Typography from '@mui/material/Typography'
import Circle from '@mui/icons-material/FiberManualRecord'
import { Box } from '@mui/system'
import ReportIcon from '@mui/icons-material/Report'
import { TrackerConnection } from 'services/ConnectionTest/ConnectionTest'
import { ConnectionTestResults as IConnectionTestResults } from './useConnectionTest'
@ -10,9 +13,22 @@ interface ConnectionTestResultsProps {
connectionTestResults: IConnectionTestResults
}
export const ConnectionTestResults = ({
connectionTestResults: { hasHost, hasRelay, hasTracker },
connectionTestResults: { hasHost, hasRelay, trackerConnection },
}: ConnectionTestResultsProps) => {
if (!hasTracker) {
if (trackerConnection === TrackerConnection.FAILED) {
return (
<Typography variant="subtitle2">
<Box
sx={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}
>
<ReportIcon color="error" sx={{ mr: 1 }} />
<span>Server connection failed</span>
</Box>
</Typography>
)
}
if (trackerConnection !== TrackerConnection.CONNECTED) {
return (
<Typography variant="subtitle2">
<Box

View File

@ -16,6 +16,7 @@ import { PeerListHeader } from 'components/Shell/PeerListHeader'
import { Username } from 'components/Username/Username'
import { AudioState, Peer } from 'models/chat'
import { PeerConnectionType } from 'services/PeerRoom/PeerRoom'
import { TrackerConnection } from 'services/ConnectionTest/ConnectionTest'
import { routes } from 'config/routes'
import { PeerListItem } from './PeerListItem'
@ -113,7 +114,8 @@ export const PeerList = ({
))}
{peerList.length === 0 &&
typeof roomId === 'string' &&
connectionTestResults.hasTracker &&
connectionTestResults.trackerConnection ===
TrackerConnection.CONNECTED &&
connectionTestResults.hasHost ? (
<>
<Box

View File

@ -4,12 +4,13 @@ import {
ConnectionTest,
ConnectionTestEvent,
ConnectionTestEvents,
TrackerConnection,
} from 'services/ConnectionTest/ConnectionTest'
export interface ConnectionTestResults {
hasHost: boolean
hasRelay: boolean
hasTracker: boolean
trackerConnection: TrackerConnection
}
const rtcPollInterval = 20 * 1000
@ -18,7 +19,9 @@ const trackerPollInterval = 5 * 1000
export const useConnectionTest = () => {
const [hasHost, setHasHost] = useState(false)
const [hasRelay, setHasRelay] = useState(false)
const [hasTracker, setHasTracker] = useState(false)
const [trackerConnection, setTrackerConnection] = useState(
TrackerConnection.SEARCHING
)
useEffect(() => {
const checkRtcConnection = async () => {
@ -83,14 +86,22 @@ export const useConnectionTest = () => {
})()
;(async () => {
while (true) {
const connectionTest = new ConnectionTest()
setHasTracker(connectionTest.testTrackerConnection())
try {
const connectionTest = new ConnectionTest()
const trackerConnectionTestResult =
connectionTest.testTrackerConnection()
setTrackerConnection(trackerConnectionTestResult)
} catch (e) {
setTrackerConnection(TrackerConnection.FAILED)
}
await sleep(trackerPollInterval)
}
})()
}, [])
return {
connectionTestResults: { hasHost, hasRelay, hasTracker },
connectionTestResults: { hasHost, hasRelay, trackerConnection },
}
}

View File

@ -4,6 +4,7 @@ import { AlertOptions } from 'models/shell'
import { AudioState, ScreenShareState, VideoState, Peer } from 'models/chat'
import { PeerConnectionType } from 'services/PeerRoom/PeerRoom'
import { ConnectionTestResults } from 'components/Shell/useConnectionTest'
import { TrackerConnection } from 'services/ConnectionTest/ConnectionTest'
interface ShellContextProps {
tabHasFocus: boolean
@ -62,5 +63,9 @@ export const ShellContext = createContext<ShellContextProps>({
setPeerAudios: () => {},
customUsername: '',
setCustomUsername: () => {},
connectionTestResults: { hasHost: false, hasRelay: false, hasTracker: false },
connectionTestResults: {
hasHost: false,
hasRelay: false,
trackerConnection: TrackerConnection.SEARCHING,
},
})

View File

@ -8,12 +8,18 @@ export enum ConnectionTestEvents {
HAS_RELAY_CHANGED = 'HAS_RELAY_CHANGED',
}
export enum TrackerConnection {
SEARCHING = 'SEARCHING',
CONNECTED = 'CONNECTED',
FAILED = 'FAILED',
}
export type ConnectionTestEvent = CustomEvent<ConnectionTest>
const checkExperationTime = 10 * 1000
export class ConnectionTest extends EventTarget {
hasTracker = false
trackerConnection = TrackerConnection.SEARCHING
hasHost = false
hasRelay = false
hasPeerReflexive = false
@ -100,17 +106,34 @@ export class ConnectionTest extends EventTarget {
testTrackerConnection() {
const trackers = getTrackers()
const readyStates = Object.values(trackers).map(
({ readyState }) => readyState
const trackerSockets = Object.values(trackers)
if (trackerSockets.length === 0) {
// Trystero has not yet initialized tracker sockets
this.trackerConnection = TrackerConnection.SEARCHING
return this.trackerConnection
}
const readyStates = trackerSockets.map(({ readyState }) => readyState)
const haveAllTrackerConnectionsFailed = readyStates.every(
readyState => readyState === WebSocket.CLOSED
)
if (haveAllTrackerConnectionsFailed) {
this.trackerConnection = TrackerConnection.FAILED
throw new Error('Could not connect to a WebTorrent tracker')
}
const areAnyTrackersConnected = readyStates.some(
readyState => readyState === WebSocket.OPEN
)
this.hasTracker = areAnyTrackersConnected
this.trackerConnection = areAnyTrackersConnected
? TrackerConnection.CONNECTED
: TrackerConnection.SEARCHING
return this.hasTracker
return this.trackerConnection
}
}