Refactored useSession to properly handle peer events

Added indicator of what connection errored
This commit is contained in:
Mitchell McCaffrey 2020-04-11 20:42:13 +10:00
parent aed9c06dc6
commit da0f80316c
2 changed files with 112 additions and 65 deletions

View File

@ -21,45 +21,96 @@ function useSession(
const [peers, setPeers] = useState({}); const [peers, setPeers] = useState({});
// Setup event listeners for peers
useEffect(() => {
let peerEvents = [];
for (let peer of Object.values(peers)) {
function handleSignal(signal) {
socket.emit("signal", JSON.stringify({ to: peer.id, signal }));
}
function handleConnect() {
onPeerConnected && onPeerConnected(peer);
if (peer.sync) {
peer.connection.send({ id: "sync" });
}
}
function handleDataComplete(data) {
onPeerData && onPeerData({ peer, data });
}
function handleTrack(track, stream) {
onPeerTrackAdded && onPeerTrackAdded({ peer, track, stream });
track.addEventListener("mute", () => {
onPeerTrackRemoved && onPeerTrackRemoved({ peer, track, stream });
});
}
function handleClose() {
onPeerDisconnected && onPeerDisconnected(peer);
}
function handleError(error) {
onPeerError && onPeerError({ peer, error });
console.error(error);
}
peer.connection.on("signal", handleSignal);
peer.connection.on("connect", handleConnect);
peer.connection.on("dataComplete", handleDataComplete);
peer.connection.on("track", handleTrack);
peer.connection.on("close", handleClose);
peer.connection.on("error", handleError);
// Save events for cleanup
peerEvents.push({
peer,
handleSignal,
handleConnect,
handleDataComplete,
handleTrack,
handleClose,
handleError,
});
}
// Cleanup events
return () => {
for (let {
peer,
handleSignal,
handleConnect,
handleDataComplete,
handleTrack,
handleClose,
handleError,
} of peerEvents) {
peer.connection.off("signal", handleSignal);
peer.connection.off("connect", handleConnect);
peer.connection.off("dataComplete", handleDataComplete);
peer.connection.off("track", handleTrack);
peer.connection.off("close", handleClose);
peer.connection.off("error", handleError);
}
};
}, [
peers,
onPeerConnected,
onPeerDisconnected,
onPeerData,
onPeerTrackAdded,
onPeerTrackRemoved,
onPeerError,
]);
// Setup event listeners for the socket
useEffect(() => { useEffect(() => {
function addPeer(id, initiator, sync) { function addPeer(id, initiator, sync) {
const peer = new Peer({ initiator, trickle: false }); const connection = new Peer({ initiator, trickle: false });
peer.on("signal", (signal) => {
socket.emit("signal", JSON.stringify({ to: id, signal }));
});
peer.on("connect", () => {
onPeerConnected && onPeerConnected({ id, peer, initiator });
if (sync) {
peer.send({ id: "sync" });
}
});
peer.on("dataComplete", (data) => {
onPeerData && onPeerData({ id, peer, data });
});
peer.on("track", (track, stream) => {
onPeerTrackAdded && onPeerTrackAdded({ id, peer, track, stream });
track.addEventListener("mute", () => {
onPeerTrackRemoved && onPeerTrackRemoved({ id, peer, track, stream });
});
});
peer.on("close", () => {
onPeerDisconnected && onPeerDisconnected(id);
});
peer.on("error", (error) => {
onPeerDisconnected && onPeerDisconnected(id);
onPeerError && onPeerError(error);
console.error(error);
});
setPeers((prevPeers) => ({ setPeers((prevPeers) => ({
...prevPeers, ...prevPeers,
[id]: peer, [id]: { id, connection, initiator, sync },
})); }));
} }
@ -69,7 +120,7 @@ function useSession(
function handlePartyMemberLeft(id) { function handlePartyMemberLeft(id) {
if (id in peers) { if (id in peers) {
peers[id].destroy(); peers[id].connection.destroy();
} }
setPeers((prevPeers) => omit(prevPeers, [id])); setPeers((prevPeers) => omit(prevPeers, [id]));
} }
@ -85,7 +136,7 @@ function useSession(
function handleSignal(data) { function handleSignal(data) {
const { from, signal } = JSON.parse(data); const { from, signal } = JSON.parse(data);
if (from in peers) { if (from in peers) {
peers[from].signal(signal); peers[from].connection.signal(signal);
} }
} }
@ -99,15 +150,7 @@ function useSession(
socket.removeListener("joined party", handleJoinedParty); socket.removeListener("joined party", handleJoinedParty);
socket.removeListener("signal", handleSignal); socket.removeListener("signal", handleSignal);
}; };
}, [ }, [peers]);
peers,
onPeerConnected,
onPeerDisconnected,
onPeerData,
onPeerTrackAdded,
onPeerTrackRemoved,
onPeerError,
]);
return { peers, socket }; return { peers, socket };
} }

View File

@ -32,7 +32,7 @@ function Game() {
mapDataRef.current = mapData; mapDataRef.current = mapData;
setMapSource(mapSource); setMapSource(mapSource);
for (let peer of Object.values(peers)) { for (let peer of Object.values(peers)) {
peer.send({ id: "map", data: mapDataRef.current }); peer.connection.send({ id: "map", data: mapDataRef.current });
} }
} }
@ -48,7 +48,7 @@ function Game() {
})); }));
for (let peer of Object.values(peers)) { for (let peer of Object.values(peers)) {
const data = { [token.id]: token }; const data = { [token.id]: token };
peer.send({ id: "tokenEdit", data }); peer.connection.send({ id: "tokenEdit", data });
} }
} }
@ -59,7 +59,7 @@ function Game() {
}); });
for (let peer of Object.values(peers)) { for (let peer of Object.values(peers)) {
const data = { [token.id]: token }; const data = { [token.id]: token };
peer.send({ id: "tokenRemove", data }); peer.connection.send({ id: "tokenRemove", data });
} }
} }
@ -70,26 +70,26 @@ function Game() {
setNickname(nickname); setNickname(nickname);
for (let peer of Object.values(peers)) { for (let peer of Object.values(peers)) {
const data = { [socket.id]: nickname }; const data = { [socket.id]: nickname };
peer.send({ id: "nickname", data }); peer.connection.send({ id: "nickname", data });
} }
} }
const [stream, setStream] = useState(null); const [stream, setStream] = useState(null);
const [partyStreams, setPartyStreams] = useState({}); const [partyStreams, setPartyStreams] = useState({});
function handlePeerConnected({ peer }) { function handlePeerConnected(peer) {
peer.send({ id: "nickname", data: { [socket.id]: nickname } }); peer.connection.send({ id: "nickname", data: { [socket.id]: nickname } });
if (stream) { if (stream) {
peer.addStream(stream); peer.connection.addStream(stream);
} }
} }
function handlePeerData({ data, peer }) { function handlePeerData({ data, peer }) {
if (data.id === "sync") { if (data.id === "sync") {
if (mapSource) { if (mapSource) {
peer.send({ id: "map", data: mapDataRef.current }); peer.connection.send({ id: "map", data: mapDataRef.current });
} }
if (mapTokens) { if (mapTokens) {
peer.send({ id: "tokenEdit", data: mapTokens }); peer.connection.send({ id: "tokenEdit", data: mapTokens });
} }
} }
if (data.id === "map") { if (data.id === "map") {
@ -116,29 +116,33 @@ function Game() {
} }
} }
function handlePeerDisconnected(disconnectedId) { function handlePeerDisconnected(peer) {
setPartyNicknames((prevNicknames) => omit(prevNicknames, [disconnectedId])); setPartyNicknames((prevNicknames) => omit(prevNicknames, [peer.id]));
} }
const [peerError, setPeerError] = useState(null); const [peerError, setPeerError] = useState(null);
function handlePeerError(error) { function handlePeerError({ error, peer }) {
setPeerError(error.message || "Unknown Error Occurred."); setPeerError(
`${
peer.id === socket.id ? "" : `(${partyNicknames[peer.id] || "Unknown"})`
} ${error.message || "Unknown Error Occurred."}`
);
} }
function handlePeerTrackAdded({ id, stream: remoteStream }) { function handlePeerTrackAdded({ peer, stream: remoteStream }) {
setPartyStreams((prevStreams) => ({ setPartyStreams((prevStreams) => ({
...prevStreams, ...prevStreams,
[id]: remoteStream, [peer.id]: remoteStream,
})); }));
} }
function handlePeerTrackRemoved({ id, stream: remoteStream }) { function handlePeerTrackRemoved({ peer, stream: remoteStream }) {
if (isStreamStopped(remoteStream)) { if (isStreamStopped(remoteStream)) {
setPartyStreams((prevStreams) => omit(prevStreams, [id])); setPartyStreams((prevStreams) => omit(prevStreams, [peer.id]));
} else { } else {
setPartyStreams((prevStreams) => ({ setPartyStreams((prevStreams) => ({
...prevStreams, ...prevStreams,
[id]: remoteStream, [peer.id]: remoteStream,
})); }));
} }
} }
@ -150,7 +154,7 @@ function Game() {
// Only add the audio track of the stream to the remote peer // Only add the audio track of the stream to the remote peer
if (track.kind === "audio") { if (track.kind === "audio") {
for (let peer of Object.values(peers)) { for (let peer of Object.values(peers)) {
peer.addTrack(track, localStream); peer.connection.addTrack(track, localStream);
} }
} }
} }
@ -165,7 +169,7 @@ function Game() {
// Only sending audio so only remove the audio track // Only sending audio so only remove the audio track
if (track.kind === "audio") { if (track.kind === "audio") {
for (let peer of Object.values(peers)) { for (let peer of Object.values(peers)) {
peer.removeTrack(track, localStream); peer.connection.removeTrack(track, localStream);
} }
} }
} }