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({});
// 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 };
}

View File

@ -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);
}
}
}