commit 3872d32efdac5e2ff97a8f6867ec86f4056bae0a
parent 78dd7a5bc4e8cdc7025dfb93eedfbd02358e866e
Author: Andreas Gruhler <andreas.gruhler@adfinis.com>
Date: Wed, 25 Sep 2024 23:07:38 +0200
feat: real-time scores with ws
Diffstat:
3 files changed, 30 insertions(+), 48 deletions(-)
diff --git a/src/api/db.cjs b/src/api/db.cjs
@@ -17,7 +17,7 @@ require('dotenv').config({
// https://github.com/porsager/postgres?tab=readme-ov-file#environmental-variables
const sql = pg({
publications: [
- 'scores',
+ 'myheats_realtime',
]
})
@@ -392,22 +392,27 @@ async function setScore(heat, athlete, judge, score) {
}
}
-async function getScores() {
+async function watchScores(clients) {
try {
const { unsubscribe } = await sql.subscribe(
'*:scores',
(row, { command, relation, key, old }) => {
- // Callback function for each row change
- // tell about new event row over eg. websockets or do something else
- console.log("!! SCORES CHANGED:", row)
- return row
+ // distributed score updates to all connected clients
+ for(let c of clients) {
+ c.send(JSON.stringify({
+ "message": "Received new scores",
+ "data": row,
+ }))
+ }
},
() => {
- // Callback on initial connect and potential reconnects
+ // callback on initial connect and potential reconnects
+ console.log("Watching scores")
}
)
+ return unsubscribe
} catch (error) {
- console.log('Error occurred in getScores:', error);
+ console.log('Error occurred in watchScores:', error);
throw error
}
}
@@ -429,7 +434,7 @@ module.exports = {
scoreSummaryForHeatAndAthlete,
getScore,
setScore,
- getScores,
+ watchScores,
addAthleteToHeat,
addAthlete,
removeAthlete,
diff --git a/src/api/server.cjs b/src/api/server.cjs
@@ -685,26 +685,8 @@ wss1.on('connection', function connection(sock) {
msg = JSON.parse(m)
console.log(' Uncle roger hears: %s', msg);
- if (msg.method === 'getStartListForHeats') {
- const startlist = await db.getStartlistForHeats(msg.data.heatIds)
- sock.send(JSON.stringify({
- "data": startlist,
- }));
- } else if (msg.method === 'getScoreForHeatAndAthlete') {
- const score = await db.getScoreForHeatAndAthlete(msg.data.heatId, msg.data.athleteId)
- sock.send(JSON.stringify({
- "data": score,
- }));
- } else if (msg.method === 'getHeats') {
- const heats = await db.getHeats()
- sock.send(JSON.stringify({
- "data": heats,
- }));
- } else if (msg.method === 'getScores') {
- const scores = await db.getScores()
- sock.send(JSON.stringify({
- "data": scores,
- }));
+ if (msg.method === 'watchScores') {
+ db.watchScores(clients)
}
} catch (error) {
console.log('x Error: %s', error.message);
diff --git a/src/frontend/Leaderboard.jsx b/src/frontend/Leaderboard.jsx
@@ -307,25 +307,20 @@ function Leaderboard({session}) {
})();
}, [heatSelection]);
-// useEffect(() => {
-// (async() => {
-// // subscribe to scoring from judges and
-// const scores = await socket.send(JSON.stringify({
-// method: "getScores",
-// }))
-// console.log("DEBUG: Scores", scores)
-// // todo: reload only required scores
-// const scoreSummary = await getScoreSummary(heatSelection.map(h => h.value))
-// setLeaderboard(scoreSummary)
-// setLoading(false)
-//
-// // remove subscription
-// return function cleanup() {
-// // todo: remove subscription on API server
-// //supabase.removeChannel(channel)
-// }
-// })();
-// }, [heatSelection]);
+ useEffect(() => {
+ (async() => {
+ // subscribe to scoring from judges
+ socket.send(JSON.stringify({
+ method: "watchScores",
+ }))
+ socket.onmessage = async function(event) {
+ // todo: reload only required scores
+ const scoreSummary = await getScoreSummary(heatSelection.map(h => h.value))
+ setLeaderboard(scoreSummary)
+ }
+ setLoading(false)
+ })();
+ }, [heatSelection]);
return (
<div>