Added on screen error banner and FAQ section for connection issues

This commit is contained in:
Mitchell McCaffrey 2020-04-10 10:55:44 +10:00
parent f3426e33ef
commit a0e6235f72
3 changed files with 93 additions and 29 deletions

View File

@ -12,7 +12,8 @@ function useSession(
onPeerDisconnected,
onPeerData,
onPeerTrackAdded,
onPeerTrackRemoved
onPeerTrackRemoved,
onPeerError
) {
useEffect(() => {
socket.emit("join party", partyId);
@ -50,9 +51,10 @@ function useSession(
onPeerDisconnected && onPeerDisconnected(id);
});
peer.on("error", (err) => {
peer.on("error", (error) => {
onPeerDisconnected && onPeerDisconnected(id);
console.error("error", err);
onPeerError && onPeerError(error);
console.error(error);
});
setPeers((prevPeers) => ({
@ -104,6 +106,7 @@ function useSession(
onPeerData,
onPeerTrackAdded,
onPeerTrackRemoved,
onPeerError,
]);
return { peers, socket };

View File

@ -61,6 +61,51 @@ function FAQ() {
</Link>{" "}
on the Mozilla Developer Network.
</Text>
<Text my={1} variant="heading" as="h2" sx={{ fontSize: 3 }}>
Connection Failed
</Text>
<Text my={1} variant="heading" as="h3">
Ice connection failed / Connection failed.
</Text>
<Text mb={2} variant="body2" as="p">
Owlbear Rodeo uses peer to peer connections to send data between the
players. Specifically the{" "}
<Link href="https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API">
WebRTC API
</Link>{" "}
is used. WebRTC allows the sending of two types of data, the first is
media such as a camera or microphone and the second is raw data such
as chat messages or in this case the state of the game map. <br /> As
at this time we don't support voice or video chat as such we only use
the raw data feature of WebRTC. This however can lead to connection
issues, specifically with the Safari web browser and connecting
between two devices on the same network. This is due a decision made
by the Safari team to only allow fully peer to peer connections when
the user grants camera permission to the website. Unfortunately that
means in order to fully support Safari we would need to ask for camera
permission even though we wouldn't be using it. To us that is a bad
user experience so we have decided against it at this time. <br />
The good news is that Safari will still work if the two devices are
connected to a seperate network as we make use of{" "}
<Link href="https://en.wikipedia.org/wiki/Traversal_Using_Relays_around_NAT">
TURN
</Link>{" "}
servers which will handle the IP sharing and are not blocked by
Safari.{" "}
<strong>
So if you're seeing errors and are on the same network as the other
person if possible switch to seperate networks and try again.
</strong>
. For more information about Safari's restrictions on WebRTC see this{" "}
<Link href="https://bugs.webkit.org/show_bug.cgi?id=173052">
bug report
</Link>{" "}
on the Webkit site or this{" "}
<Link href="https://webkit.org/blog/7763/a-closer-look-into-webrtc/">
blog post
</Link>
.
</Text>
</Flex>
<Footer />
</Flex>

View File

@ -1,5 +1,5 @@
import React, { useState, useRef, useEffect, useCallback } from "react";
import { Flex } from "theme-ui";
import { Flex, Box, Text, Link } from "theme-ui";
import { useParams } from "react-router-dom";
import { omit, isStreamStopped } from "../helpers/shared";
@ -10,6 +10,7 @@ import { getRandomMonster } from "../helpers/monsters";
import Party from "../components/Party";
import Tokens from "../components/Tokens";
import Map from "../components/Map";
import Banner from "../components/Banner";
function Game() {
const { id: gameId } = useParams();
@ -20,7 +21,8 @@ function Game() {
handlePeerDisconnected,
handlePeerData,
handlePeerTrackAdded,
handlePeerTrackRemoved
handlePeerTrackRemoved,
handlePeerError
);
const [mapSource, setMapSource] = useState(null);
@ -118,6 +120,11 @@ function Game() {
setPartyNicknames((prevNicknames) => omit(prevNicknames, [disconnectedId]));
}
const [peerError, setPeerError] = useState(null);
function handlePeerError(error) {
setPeerError(error.message || "Unknown Error Occurred.");
}
function handlePeerTrackAdded({ id, stream: remoteStream }) {
setPartyStreams((prevStreams) => ({
...prevStreams,
@ -183,31 +190,40 @@ function Game() {
}, [stream, peers, handleStreamEnd]);
return (
<Flex sx={{ flexDirection: "column", height: "100%" }}>
<Flex
sx={{ justifyContent: "space-between", flexGrow: 1, height: "100%" }}
>
<Party
nickname={nickname}
partyNicknames={partyNicknames}
gameId={gameId}
onNicknameChange={handleNicknameChange}
stream={stream}
partyStreams={partyStreams}
onStreamStart={handleStreamStart}
onStreamEnd={handleStreamEnd}
/>
<Map
mapSource={mapSource}
mapData={mapDataRef.current}
tokens={mapTokens}
onMapTokenMove={handleEditMapToken}
onMapTokenRemove={handleRemoveMapToken}
onMapChanged={handleMapChanged}
/>
<Tokens onCreateMapToken={handleEditMapToken} />
<>
<Flex sx={{ flexDirection: "column", height: "100%" }}>
<Flex
sx={{ justifyContent: "space-between", flexGrow: 1, height: "100%" }}
>
<Party
nickname={nickname}
partyNicknames={partyNicknames}
gameId={gameId}
onNicknameChange={handleNicknameChange}
stream={stream}
partyStreams={partyStreams}
onStreamStart={handleStreamStart}
onStreamEnd={handleStreamEnd}
/>
<Map
mapSource={mapSource}
mapData={mapDataRef.current}
tokens={mapTokens}
onMapTokenMove={handleEditMapToken}
onMapTokenRemove={handleRemoveMapToken}
onMapChanged={handleMapChanged}
/>
<Tokens onCreateMapToken={handleEditMapToken} />
</Flex>
</Flex>
</Flex>
<Banner isOpen={!!peerError} onRequestClose={() => setPeerError(null)}>
<Box p={1}>
<Text as="p" variant="body2">
{peerError} See <Link href="#/faq">FAQ</Link> for more information.
</Text>
</Box>
</Banner>
</>
);
}