From da0f80316c181f0c6b49cab2d3241b556a893279 Mon Sep 17 00:00:00 2001 From: Mitchell McCaffrey Date: Sat, 11 Apr 2020 20:42:13 +1000 Subject: [PATCH] Refactored useSession to properly handle peer events Added indicator of what connection errored --- src/helpers/useSession.js | 133 +++++++++++++++++++++++++------------- src/routes/Game.js | 44 +++++++------ 2 files changed, 112 insertions(+), 65 deletions(-) diff --git a/src/helpers/useSession.js b/src/helpers/useSession.js index 4676fb9..0030af7 100644 --- a/src/helpers/useSession.js +++ b/src/helpers/useSession.js @@ -21,45 +21,96 @@ function useSession( 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(() => { function addPeer(id, initiator, sync) { - const peer = 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); - }); + const connection = new Peer({ initiator, trickle: false }); setPeers((prevPeers) => ({ ...prevPeers, - [id]: peer, + [id]: { id, connection, initiator, sync }, })); } @@ -69,7 +120,7 @@ function useSession( function handlePartyMemberLeft(id) { if (id in peers) { - peers[id].destroy(); + peers[id].connection.destroy(); } setPeers((prevPeers) => omit(prevPeers, [id])); } @@ -85,7 +136,7 @@ function useSession( function handleSignal(data) { const { from, signal } = JSON.parse(data); 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("signal", handleSignal); }; - }, [ - peers, - onPeerConnected, - onPeerDisconnected, - onPeerData, - onPeerTrackAdded, - onPeerTrackRemoved, - onPeerError, - ]); + }, [peers]); return { peers, socket }; } diff --git a/src/routes/Game.js b/src/routes/Game.js index 8c98529..8d4522c 100644 --- a/src/routes/Game.js +++ b/src/routes/Game.js @@ -32,7 +32,7 @@ function Game() { mapDataRef.current = mapData; setMapSource(mapSource); 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)) { 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)) { const data = { [token.id]: token }; - peer.send({ id: "tokenRemove", data }); + peer.connection.send({ id: "tokenRemove", data }); } } @@ -70,26 +70,26 @@ function Game() { setNickname(nickname); for (let peer of Object.values(peers)) { const data = { [socket.id]: nickname }; - peer.send({ id: "nickname", data }); + peer.connection.send({ id: "nickname", data }); } } const [stream, setStream] = useState(null); const [partyStreams, setPartyStreams] = useState({}); - function handlePeerConnected({ peer }) { - peer.send({ id: "nickname", data: { [socket.id]: nickname } }); + function handlePeerConnected(peer) { + peer.connection.send({ id: "nickname", data: { [socket.id]: nickname } }); if (stream) { - peer.addStream(stream); + peer.connection.addStream(stream); } } function handlePeerData({ data, peer }) { if (data.id === "sync") { if (mapSource) { - peer.send({ id: "map", data: mapDataRef.current }); + peer.connection.send({ id: "map", data: mapDataRef.current }); } if (mapTokens) { - peer.send({ id: "tokenEdit", data: mapTokens }); + peer.connection.send({ id: "tokenEdit", data: mapTokens }); } } if (data.id === "map") { @@ -116,29 +116,33 @@ function Game() { } } - function handlePeerDisconnected(disconnectedId) { - setPartyNicknames((prevNicknames) => omit(prevNicknames, [disconnectedId])); + function handlePeerDisconnected(peer) { + setPartyNicknames((prevNicknames) => omit(prevNicknames, [peer.id])); } const [peerError, setPeerError] = useState(null); - function handlePeerError(error) { - setPeerError(error.message || "Unknown Error Occurred."); + function handlePeerError({ error, peer }) { + 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) => ({ ...prevStreams, - [id]: remoteStream, + [peer.id]: remoteStream, })); } - function handlePeerTrackRemoved({ id, stream: remoteStream }) { + function handlePeerTrackRemoved({ peer, stream: remoteStream }) { if (isStreamStopped(remoteStream)) { - setPartyStreams((prevStreams) => omit(prevStreams, [id])); + setPartyStreams((prevStreams) => omit(prevStreams, [peer.id])); } else { setPartyStreams((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 if (track.kind === "audio") { 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 if (track.kind === "audio") { for (let peer of Object.values(peers)) { - peer.removeTrack(track, localStream); + peer.connection.removeTrack(track, localStream); } } }