SocketIOWrapper

master
Wilco Kruijer 4 years ago
parent 509b1cfdc5
commit 8482deb7e5
  1. 4
      backend/src/Lobby.js
  2. 4
      backend/src/index.js
  3. 67
      frontend/src/App.tsx
  4. 79
      frontend/src/Wrapper.tsx
  5. 40
      frontend/src/components/Feed.tsx
  6. 59
      frontend/src/components/Lobby.tsx
  7. 42
      frontend/src/components/NextShot.tsx
  8. 23
      frontend/src/components/ShotsTaken.tsx
  9. 19
      frontend/src/util/socket.ts

@ -67,10 +67,6 @@ module.exports = class Lobby {
setTimeout(doTick, Math.floor(waitTime / this.speedFactor)); setTimeout(doTick, Math.floor(waitTime / this.speedFactor));
}; };
if (false) {
this.seek(ioLobby, 500);
}
doTick(); doTick();
} }

@ -40,10 +40,6 @@ io.on('connection', socket => {
socket.join(lobby.name); socket.join(lobby.name);
if (lobby.running) {
socket.emit('seek', lobby.currentSeconds);
}
callback(null, { callback(null, {
status: 'ok', status: 'ok',
lobby: lobby lobby: lobby

@ -1,68 +1,13 @@
import React, {useEffect, useRef, useState} from 'react'; import React from 'react';
import './App.sass'; import './App.sass';
import logo from "./via-logo.svg" import {SocketIOProvider} from "use-socketio/lib";
import {Row} from "antd" import Wrapper from "./Wrapper";
import socket from "./util/socket";
import NextShot from "./components/NextShot";
import ShotsTaken from "./components/ShotsTaken";
import Feed from "./components/Feed";
import Lobby from "./components/Lobby";
import {Tick} from "./types/types";
const App = () => { const App = () => {
const [started, setStarted] = useState(false);
const player = useRef(new Audio("centurion.m4a"));
useEffect(() => {
socket.on('started', async () => {
setStarted(true);
await player.current.play();
// player.current.volume = 0;
});
socket.on('seek', async (sec: number) => {
if (player.current.paused) {
await player.current.play();
}
socket.once("tick_event", (tick: Tick) => {
// Wait till the next tick to actually start so we more closely match the leader's sound
setStarted(true);
player.current.currentTime = tick.current
});
});
return () => {
socket.off("started");
socket.off("seek");
}
});
const feedContent = (
<Row>
<NextShot/>
<Feed/>
<ShotsTaken/>
</Row>
);
const lobbyContent = (
<Lobby/>
);
const content = started ? feedContent : lobbyContent;
return ( return (
<> <SocketIOProvider url={window.location.protocol + "//" + window.location.hostname}>
<section className="content"> <Wrapper/>
{content} </SocketIOProvider>
</section>
<footer>
<img src={logo} className="via-logo" alt="logo"/>
</footer>
</>
); );
}; };

@ -0,0 +1,79 @@
import React, {useEffect, useRef, useState} from "react";
import {Row} from "antd";
import NextShot from "./components/NextShot";
import Feed from "./components/Feed";
import ShotsTaken from "./components/ShotsTaken";
import Lobby from "./components/Lobby";
import {useSocket} from "use-socketio";
import logo from "./via-logo.svg";
import {Tick} from "./types/types";
import {NumberParam, useQueryParam} from "use-query-params";
const Wrapper = () => {
const [started, setStarted] = useState(false);
const [wantsToStart, setWantsToStart] = useState(false);
const player = useRef(new Audio("centurion.m4a"));
const [noSound] = useQueryParam('noSound', NumberParam);
function goStart() {
console.log("Starting from wrapper..");
setWantsToStart(true);
}
const {socket} = useSocket("started", async (obj: any) => {
console.log("got started");
setStarted(true);
if (typeof noSound === 'undefined') {
await player.current.play();
}
});
useEffect(() => {
if (noSound === 1) {
// Won't play sound so we don't get DOM Interaction errors.
setWantsToStart(true);
}
}, []);
useSocket("tick_event", async (tick: Tick) => {
if (!started && wantsToStart) {
if (player.current.paused) {
if (typeof noSound === 'undefined') {
await player.current.play();
}
}
setStarted(true);
player.current.currentTime = tick.current;
}
});
const feedContent = (
<Row>
<NextShot/>
<Feed/>
<ShotsTaken/>
</Row>
);
const lobbyContent = (
<Lobby start={goStart}/>
);
const content = started ? feedContent : lobbyContent;
return (
<>
<section className="content">
{content}
</section>
<footer>
<img src={logo} className="via-logo" alt="logo"/>
</footer>
</>
);
};
export default Wrapper;

@ -1,11 +1,11 @@
import React, {useEffect, useState} from 'react'; import React, {useState} from 'react';
import {Col, Timeline} from "antd" import {Col, Timeline} from "antd"
import socket from "../util/socket";
import {Tick, TimestampEvent} from "../types/types"; import {Tick, TimestampEvent} from "../types/types";
import shot from "../img/shot.png"; import shot from "../img/shot.png";
import song from "../img/song.png"; import song from "../img/song.png";
import talk from "../img/talk.png"; import talk from "../img/talk.png";
import time from "../img/time.png"; import time from "../img/time.png";
import {useSocket} from "use-socketio/lib";
const images = { const images = {
shot, song, talk, time shot, song, talk, time
@ -18,32 +18,26 @@ interface Event extends TimestampEvent {
const Feed = () => { const Feed = () => {
const [feedItems, setFeedItems] = useState<Event[]>([]); const [feedItems, setFeedItems] = useState<Event[]>([]);
useEffect(() => { useSocket("tick_event", async (tick: Tick) => {
socket.on("tick_event", (tick: Tick) => { if (!tick.next) {
if (!tick.next) { return;
return; }
}
if (tick.current === tick.next.timestamp) {
// Current tick is a new event.
const newItems: any[] = []; if (tick.current === tick.next.timestamp) {
for (let i = 0; i < feedItems.length; i++) { // Current tick is a new event.
newItems.push(feedItems[i]);
}
for (let j = 0; j < tick.next.events.length; j++) {
newItems.push(tick.next.events[j]);
}
// @ts-ignore const newItems: any[] = [];
// setFeedItems(newItems); for (let i = 0; i < feedItems.length; i++) {
newItems.push(feedItems[i]);
}
for (let j = 0; j < tick.next.events.length; j++) {
newItems.push(tick.next.events[j]);
} }
});
return () => { // @ts-ignore
socket.off("tick_event"); // setFeedItems(newItems);
} }
}, [feedItems]); });
return ( return (
// <Col className="feed" span={16}> // <Col className="feed" span={16}>

@ -1,47 +1,50 @@
import React, {useEffect, useState} from 'react'; import React, {useEffect, useRef, useState} from 'react';
import {Card, Col, InputNumber, Row} from "antd" import {Card, Col, InputNumber, Row} from "antd"
import socket, {emit} from "../util/socket"; import {emit} from "../util/socket";
import "../css/lobby.sass"; import "../css/lobby.sass";
import beer from "../img/beer.png" import beer from "../img/beer.png"
import {NumberParam, useQueryParam} from 'use-query-params'; import {NumberParam, useQueryParam} from 'use-query-params';
import {useSocket} from "use-socketio/lib";
const Lobby = () => { const Lobby = (props: any) => {
const [lobbyId, setLobbyId] = useQueryParam('lobby', NumberParam); const [lobbyId, setLobbyId] = useQueryParam('lobby', NumberParam);
const [isLeader, setIsLeader] = useState(false); const [isLeader, setIsLeader] = useState(false);
const [isRunning, setIsRunning] = useState(false);
const [seekTime, setSeekTime] = useState(0); const [seekTime, setSeekTime] = useState(0);
const [userCount, setUserCount] = useState(0); const [userCount, setUserCount] = useState(0);
const {socket} = useSocket("welcome", async (obj: any) => {
if (lobbyId) {
// lobbyId is already defined, this means we have a queryparam set.
await onChangeLobbyInput(lobbyId);
return;
}
console.log("Got welcome", lobbyId);
setLobbyId(obj.lobby.name);
setIsLeader(socket.id === obj.lobby.leaderId);
setUserCount(obj.lobby.users?.length || 0);
});
const socketRef = useRef<SocketIOClient.Socket>(socket);
async function onChangeLobbyInput(i: any) { async function onChangeLobbyInput(i: any) {
setLobbyId(i); setLobbyId(i);
const result: any = await emit('join_lobby', i); const result: any = await emit(socket,'join_lobby', i);
setIsLeader(socket.id === result.lobby.leaderId); setIsLeader(socket.id === result.lobby.leaderId);
setUserCount(result.lobby.users?.length || 0); setUserCount(result.lobby.users?.length || 0);
setIsRunning(result.lobby.running);
} }
useEffect(() => {
socket.on('welcome', async (obj: any) => {
if (lobbyId) {
// lobbyId is already defined, this means we have a queryparam set.
await onChangeLobbyInput(lobbyId);
return;
}
console.log("Got welcome", lobbyId);
setLobbyId(obj.lobby.name);
setIsLeader(socket.id === obj.lobby.leaderId);
setUserCount(obj.lobby.users?.length || 0);
});
return () => {
socket.off("welcome");
}
});
useEffect(() => { useEffect(() => {
async function wrapper() { async function wrapper() {
const result: any = await emit('lobby_info'); const result: any = await emit(socketRef.current,'lobby_info');
setIsLeader(socket.id === result.lobby.leaderId); setIsLeader(socketRef.current.id === result.lobby.leaderId);
setUserCount(result.lobby.users?.length || 0); setUserCount(result.lobby.users?.length || 0);
setIsRunning(result.lobby.running);
console.log("Got lobby_info");
} }
wrapper(); wrapper();
@ -59,7 +62,9 @@ const Lobby = () => {
<div className="lobby"> <div className="lobby">
<Row> <Row>
<Col span={24}> <Col span={24}>
<h1 id="centurion-title">Centurion! <img src={beer} className="beer" alt="beer"/></h1> <h1 id="centurion-title">
<img src={beer} className="beer" alt="beer"/>Centurion!
<img src={beer} className="beer" alt="beer"/></h1>
</Col> </Col>
</Row> </Row>
<Row> <Row>
@ -73,9 +78,9 @@ const Lobby = () => {
<Col className="control" span={8} offset={8}> <Col className="control" span={8} offset={8}>
<Card title={`Lobby setup (${lobbyId}):`} actions={isLeader ? [ <Card title={`Lobby setup (${lobbyId}):`} actions={isLeader ? [
<span onClick={async () => { <span onClick={async () => {
await emit('request_start', seekTime) await emit(socket,'request_start', seekTime)
}}>Start</span>, }}>Start</span>,
] : []}> ] : [<span onClick={props.start}>Join</span>]}>
<span> <span>
Huidige lobby <InputNumber size="small" min={100} max={100000} value={lobbyId} Huidige lobby <InputNumber size="small" min={100} max={100000} value={lobbyId}
onChange={onChangeLobbyInput}/> onChange={onChangeLobbyInput}/>

@ -1,7 +1,7 @@
import React, {useEffect, useRef, useState} from 'react'; import React, {useEffect, useRef, useState} from 'react';
import {Col, Progress} from "antd" import {Col, Progress} from "antd"
import socket from "../util/socket";
import {Tick} from "../types/types"; import {Tick} from "../types/types";
import {useSocket} from "use-socketio/lib";
const NextShot = () => { const NextShot = () => {
@ -9,34 +9,28 @@ const NextShot = () => {
const [remainingPercentage, setRemainingPercentage] = useState(100); const [remainingPercentage, setRemainingPercentage] = useState(100);
const fullTime = useRef(0); const fullTime = useRef(0);
useEffect(() => { useSocket("tick_event", async (tick: Tick) => {
socket.on("tick_event", (tick: Tick) => { if (!tick.nextShot || !tick.next) {
if (!tick.nextShot || !tick.next) { setRemaining(0);
setRemaining(0); return;
return; }
}
if (fullTime.current === 0) {
fullTime.current = tick.nextShot.timestamp - tick.current;
}
const shotEvent = tick.next.events.find(e => e.type === 'shot'); if (fullTime.current === 0) {
fullTime.current = tick.nextShot.timestamp - tick.current;
}
if (shotEvent && tick.current === tick.next.timestamp) { const shotEvent = tick.next.events.find(e => e.type === 'shot');
fullTime.current = 0;
}
const timeRemaining = tick.nextShot.timestamp - tick.current; if (shotEvent && tick.current === tick.next.timestamp) {
fullTime.current = 0;
}
setRemaining(timeRemaining); const timeRemaining = tick.nextShot.timestamp - tick.current;
// Fix divide by zero (.. || 1)
setRemainingPercentage(Math.ceil(timeRemaining / (fullTime.current || 1) * 100));
});
return () => { setRemaining(timeRemaining);
socket.off("tick_event"); // Fix divide by zero (.. || 1)
} setRemainingPercentage(Math.ceil(timeRemaining / (fullTime.current || 1) * 100));
}, []); });
return ( return (
<Col className="sider" span={4}> <Col className="sider" span={4}>

@ -1,26 +1,21 @@
import React, {useEffect, useRef, useState} from 'react'; import React, {useState} from 'react';
import {Col, Progress} from "antd" import {Col, Progress} from "antd"
import socket from "../util/socket";
import {Tick} from "../types/types"; import {Tick} from "../types/types";
import {useSocket} from "use-socketio/lib";
const ShotsTaken = () => { const ShotsTaken = () => {
const [taken, setTaken] = useState(100); const [taken, setTaken] = useState(100);
useEffect(() => { useSocket("tick_event", async (tick: Tick) => {
socket.on("tick_event", (tick: Tick) => { if (!tick.nextShot) {
if (!tick.nextShot) { setTaken(100);
setTaken(100); return;
return; }
}
setTaken(tick.nextShot.count - 1); setTaken(tick.nextShot.count - 1);
}); });
return () => {
socket.off("tick_event");
}
}, []);
return ( return (
<Col className="sider" span={4}> <Col className="sider" span={4}>

@ -1,7 +1,20 @@
import io from "socket.io-client"; // const socket = io(window.location.protocol + "//" + window.location.hostname + ":3001");
const socket = {
on: (...args: any[]) => {
},
once: (...args: any[]) => {
},
off: (...args: any[]) => {
},
id: '1'
};
const socket = io(window.location.protocol + "//" + window.location.hostname);
export default socket; export default socket;
/** /**
@ -9,7 +22,7 @@ export default socket;
* @param event * @param event
* @param arg * @param arg
*/ */
export function emit(event: string, arg: any = null) { export function emit(socket: SocketIOClient.Socket, event: string, arg: any = null) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const cb = (err: any, res: any) => { const cb = (err: any, res: any) => {
if (err) { if (err) {

Loading…
Cancel
Save