Files
grungnet/src/helpers/useSession.js
Mitchell McCaffrey da0f80316c Refactored useSession to properly handle peer events
Added indicator of what connection errored
2020-04-11 20:42:13 +10:00

159 lines
4.2 KiB
JavaScript

import { useEffect, useState } from "react";
import io from "socket.io-client";
import { omit } from "../helpers/shared";
import Peer from "../helpers/Peer";
const socket = io("https://broker.owlbear.rodeo");
function useSession(
partyId,
onPeerConnected,
onPeerDisconnected,
onPeerData,
onPeerTrackAdded,
onPeerTrackRemoved,
onPeerError
) {
useEffect(() => {
socket.emit("join party", partyId);
}, [partyId]);
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 connection = new Peer({ initiator, trickle: false });
setPeers((prevPeers) => ({
...prevPeers,
[id]: { id, connection, initiator, sync },
}));
}
function handlePartyMemberJoined(id) {
addPeer(id, false, false);
}
function handlePartyMemberLeft(id) {
if (id in peers) {
peers[id].connection.destroy();
}
setPeers((prevPeers) => omit(prevPeers, [id]));
}
function handleJoinedParty(otherIds) {
for (let [index, id] of otherIds.entries()) {
// Send a sync request to the first member of the party
const sync = index === 0;
addPeer(id, true, sync);
}
}
function handleSignal(data) {
const { from, signal } = JSON.parse(data);
if (from in peers) {
peers[from].connection.signal(signal);
}
}
socket.on("party member joined", handlePartyMemberJoined);
socket.on("party member left", handlePartyMemberLeft);
socket.on("joined party", handleJoinedParty);
socket.on("signal", handleSignal);
return () => {
socket.removeListener("party member joined", handlePartyMemberJoined);
socket.removeListener("party member left", handlePartyMemberLeft);
socket.removeListener("joined party", handleJoinedParty);
socket.removeListener("signal", handleSignal);
};
}, [peers]);
return { peers, socket };
}
export default useSession;