diff --git a/src/helpers/useSession.js b/src/helpers/useSession.js new file mode 100644 index 0000000..25f1517 --- /dev/null +++ b/src/helpers/useSession.js @@ -0,0 +1,92 @@ +import { useEffect, useState } from "react"; +import Peer from "peerjs"; + +function useSession(onConnectionOpen) { + const [peerId, setPeerId] = useState(null); + const [peer, setPeer] = useState(null); + const [connections, setConnections] = useState({}); + function addConnection(connection) { + setConnections(prevConnnections => ({ + ...prevConnnections, + [connection.peer]: connection + })); + } + + useEffect(() => { + setPeer(new Peer()); + }, []); + + useEffect(() => { + function handleOpen(id) { + setPeerId(id); + } + + function handleConnection(connection) { + connection.on("open", () => { + connection.send( + JSON.stringify({ + id: "sync", + data: Object.keys(connections) + }) + ); + + addConnection(connection); + + if (onConnectionOpen) { + onConnectionOpen(); + } + }); + + function removeConnection() { + setConnections(prevConnections => { + const { [connection.peer]: old, ...rest } = prevConnections; + return rest; + }); + } + + connection.on("close", removeConnection); + connection.on("error", removeConnection); + } + + if (!peer) { + return; + } + + peer.on("open", handleOpen); + peer.on("connection", handleConnection); + return () => { + peer.removeListener("open", handleOpen); + peer.removeListener("connection", handleConnection); + }; + }, [peer, peerId, connections]); + + function sync(connectionIds) { + for (let connectionId of connectionIds) { + if (connectionId in connections) { + continue; + } + const connection = peer.connect(connectionId); + addConnection(connection); + } + } + + function connectTo(connectionId) { + if (connectionId in connections) { + return; + } + const connection = peer.connect(connectionId); + connection.on("open", () => { + connection.on("data", json => { + const data = JSON.parse(json); + if (data.id === "sync") { + sync(data.data); + } + }); + }); + addConnection(connection); + } + + return [peer, peerId, connections, connectTo]; +} + +export default useSession; diff --git a/src/routes/Game.js b/src/routes/Game.js index 6de3741..c37cf09 100644 --- a/src/routes/Game.js +++ b/src/routes/Game.js @@ -1,10 +1,18 @@ -import React, { useContext } from "react"; +import React, { useContext, useEffect } from "react"; import { A } from "hookrouter"; import GameContext from "../contexts/GameContext"; +import useSession from "../helpers/useSession"; function Game() { const [gameId, setGameId] = useContext(GameContext); + const [peer, peerId, connections, connectTo] = useSession(); + + useEffect(() => { + if (gameId !== null && peerId !== null) { + connectTo(gameId); + } + }, [gameId, peerId]); return (