diff --git a/scoreboard/controllers/socketio.js b/scoreboard/controllers/socketio.js
index ae048c3..f02ec39 100644
--- a/scoreboard/controllers/socketio.js
+++ b/scoreboard/controllers/socketio.js
@@ -9,4 +9,15 @@ const io = new Server(3001, {
cors: { origin: "*" }
});
+// Verbindungs-Handling: der Client meldet sich beim Verbinden selbst mit dem
+// Socket.IO-eigenen 'connect'-Event und holt sich den aktuellen Stand ueber die
+// REST-Endpunkte. Serverseitig wird die Verbindung nur protokolliert.
+io.on('connection', (socket) => {
+ console.log("A user connected");
+
+ socket.on('disconnect', (reason) => {
+ console.log("A user disconnected: ", reason);
+ });
+});
+
module.exports = io
\ No newline at end of file
diff --git a/scoreboard/public/javascripts/admin.js b/scoreboard/public/javascripts/admin.js
index 1036eec..67d4ec2 100644
--- a/scoreboard/public/javascripts/admin.js
+++ b/scoreboard/public/javascripts/admin.js
@@ -5,8 +5,12 @@ const socket = io(wss); // Conne
// Websockets event handler
// ######################################################################################################################################################
-socket.on('connected', (message) => { // Once client is connected to websocket
- console.log("Connected");
+// 'connect' feuert bei jeder Verbindung, auch nach einem Reconnect. Da der Pi das
+// WLAN selbst aufspannt, sind kurze Abbrueche normal: danach werden die Werte neu
+// geholt, damit das Panel nicht auf einem veralteten Stand stehen bleibt.
+socket.on('connect', () => {
+ console.log("Verbunden");
+ initialUpdate();
});
socket.on('timerDurationLeft', (message) => {
@@ -28,6 +32,22 @@ socket.on('score', (message) => {
// General functions
// ######################################################################################################################################################
+// Holt JSON von einem Endpunkt. Liefert null statt zu werfen, wenn der Server nicht
+// erreichbar ist oder mit einem Fehler antwortet — sonst bricht der Aufrufer still ab.
+async function fetchJson(url, options) {
+ try {
+ const response = await fetch(url, options);
+ if(!response.ok) {
+ console.error("Anfrage fehlgeschlagen:", url, response.status);
+ return null;
+ }
+ return await response.json();
+ } catch (err) {
+ console.error("Server nicht erreichbar:", url, err);
+ return null;
+ }
+}
+
// Initial update gets called whenever page has been loaded
async function initialUpdate() {
etcGetValues(); // Request new values for etc stuff
@@ -104,6 +124,19 @@ function updateScoreFrontend(values) {
}
+// Erzeugt einen Dropdown-Eintrag, der den Teamnamen in das angegebene Feld uebernimmt.
+// Der Name wird als Text gesetzt und per Closure an den Handler gegeben, statt ihn in
+// einen onclick-String zu schreiben: Namen mit Apostroph zerlegten sonst den Handler.
+function createTeamDropdownItem(field, team) {
+ const li = document.createElement("li");
+ const a = document.createElement("a");
+ a.className = "dropdown-item";
+ a.textContent = team;
+ a.addEventListener("click", () => scoreInsertChosenName(field, team));
+ li.appendChild(a);
+ return li;
+}
+
// Update DOM for all db contents with the passed values
function updateDbFrontend(values) {
console.log(values);
@@ -122,27 +155,17 @@ function updateDbFrontend(values) {
let selectDelete = document.getElementById("dbTeamToDelete"); // Select for team deletion from db
selectDelete.innerHTML = "" // Clears all existing options from select
- //
Action
-
- for(team of values.teams) {
+ for(const team of values.teams) {
// Create custom Dropdowns with different function arguments for team configuration
- var li = document.createElement("li");
- li.innerHTML = ` `+ team +``;
- teamAnameDropdown.appendChild(li);
- var li = document.createElement("li");
- li.innerHTML = ` `+ team +``;
- teamAname2Dropdown.appendChild(li);
- var li = document.createElement("li");
- li.innerHTML = ` `+ team +``;
- teamBnameDropdown.appendChild(li);
- var li = document.createElement("li");
- li.innerHTML = ` `+ team +``;
- teamBname2Dropdown.appendChild(li);
+ teamAnameDropdown.appendChild(createTeamDropdownItem("teamAname", team));
+ teamAname2Dropdown.appendChild(createTeamDropdownItem("teamAname2", team));
+ teamBnameDropdown.appendChild(createTeamDropdownItem("teamBname", team));
+ teamBname2Dropdown.appendChild(createTeamDropdownItem("teamBname2", team));
// Create select options for deletion in debugwindow
let opt = document.createElement("option");
opt.value = team;
- opt.innerHTML = team;
+ opt.textContent = team;
selectDelete.appendChild(opt);
}
}
@@ -184,16 +207,14 @@ async function killBrowser() {
// Request important values for etc stuff
async function etcGetValues() {
- const response = await fetch("/admin/etcGetValues"); // Call API Endpoint /admin/etcGetValues
- const data = await response.json(); // Wait for asynchronous transfer to complete
- updateEtcFrontend(data); // Update admin frontend
+ const data = await fetchJson("/admin/etcGetValues"); // Call API Endpoint /admin/etcGetValues
+ if(data) updateEtcFrontend(data); // Update admin frontend
}
// Toggle index page to also show scoreboard
async function etcToggleSplashscreen() {
- const response = await fetch("/admin/etcToggleSplashscreen");// Call API Endpoint /admin/etcToggleSplashscreen
- const data = await response.json(); // Wait for asyncronous transfer to complete
- updateEtcFrontend(data); // Update admin frontend
+ const data = await fetchJson("/admin/etcToggleSplashscreen");// Call API Endpoint /admin/etcToggleSplashscreen
+ if(data) updateEtcFrontend(data); // Update admin frontend
refreshMonitor(); // Refresh main monitor to display new frontend
}
@@ -203,9 +224,8 @@ async function etcToggleSplashscreen() {
// Request important timer values
async function timerGetValues() {
- const response = await fetch("/admin/timerGetValues"); // Call API Endpoint /admin/timerGetValues
- const data = await response.json(); // Wait for asynchronous transfer to complete
- updateTimerFrontend(data); // Update admin frontend
+ const data = await fetchJson("/admin/timerGetValues"); // Call API Endpoint /admin/timerGetValues
+ if(data) updateTimerFrontend(data); // Update admin frontend
}
// Request to start the timer
@@ -235,24 +255,22 @@ async function timerPause() {
// Request to reset the timer with the specified time
async function timerReset() {
let newDuration = document.getElementById("timerSelectDuration").value;
- const response = await fetch("/admin/timerReset", { // Call API Endpoint /admin/timerStart with selected new duration in seconds
+ const data = await fetchJson("/admin/timerReset", { // Call API Endpoint /admin/timerStart with selected new duration in seconds
method: 'POST',
headers: { "Content-Type": "application/json" },
body: JSON.stringify({duration: newDuration})
});
- const data = await response.json(); // Wait for asyncronous transfer to complete
- updateTimerFrontend(data); // Update admin frontend
+ if(data) updateTimerFrontend(data); // Update admin frontend
}
// Request to increase or decrease the timer depending on passed value in seconds
async function timerIncDec(value) {
- const response = await fetch("/admin/timerIncDec", { // Call API Endpoint /admin/timerIncDec with value in seconds to increase or decrease the timer
+ const data = await fetchJson("/admin/timerIncDec", { // Call API Endpoint /admin/timerIncDec with value in seconds to increase or decrease the timer
method: 'POST',
headers: { "Content-Type": "application/json" },
body: JSON.stringify({value: value})
});
- const data = await response.json(); // Wait for asyncronous transfer to complete
- updateTimerFrontend(data); // Update admin frontend
+ if(data) updateTimerFrontend(data); // Update admin frontend
}
// ######################################################################################################################################################
@@ -261,49 +279,43 @@ async function timerIncDec(value) {
// Request important values for score
async function scoreGetValues() {
- const response = await fetch("/admin/scoreGetValues"); // Call API Endpoint /admin/scoreGetValues
- const data = await response.json(); // Wait for asynchronous transfer to complete
- updateScoreFrontend(data); // Update admin frontend
+ const data = await fetchJson("/admin/scoreGetValues"); // Call API Endpoint /admin/scoreGetValues
+ if(data) updateScoreFrontend(data); // Update admin frontend
}
// Toggle index page to also show scoreboard
async function scoreToggle() {
- const response = await fetch("/admin/scoreToggle"); // Call API Endpoint /admin/scoreToggle
- const data = await response.json(); // Wait for asyncronous transfer to complete
- updateScoreFrontend(data); // Update admin frontend
+ const data = await fetchJson("/admin/scoreToggle"); // Call API Endpoint /admin/scoreToggle
+ if(data) updateScoreFrontend(data); // Update admin frontend
refreshMonitor(); // Refresh main monitor to display new frontend
}
// Alter the score of passed team in the specified direction
async function scoreAlterScore(team, dir) {
- const response = await fetch("/admin/scoreAlterScore", { // Call API Endpoint /admin/scoreAlterScore with the teamname to alter the score in the specified direction
+ const data = await fetchJson("/admin/scoreAlterScore", { // Call API Endpoint /admin/scoreAlterScore with the teamname to alter the score in the specified direction
method: 'POST',
headers: { "Content-Type": "application/json" },
body: JSON.stringify({team: team, dir: dir})
});
- const data = await response.json(); // Wait for asyncronous transfer to complete
- updateScoreFrontend(data); // Update admin frontend
+ if(data) updateScoreFrontend(data); // Update admin frontend
}
// Switch sides
async function scoreToggleSideswitch() {
- const response = await fetch("/admin/scoreToggleSideswitch");// Call API Endpoint /admin/scoreSwitch
- const data = await response.json(); // Wait for asyncronous transfer to complete
- updateScoreFrontend(data); // Update admin frontend
+ const data = await fetchJson("/admin/scoreToggleSideswitch");// Call API Endpoint /admin/scoreSwitch
+ if(data) updateScoreFrontend(data); // Update admin frontend
}
// Switch sides to mirror admin panel when sitting behind main monitor
async function scoreToggleReferenceMirrored() {
- const response = await fetch("/admin/scoreToggleReferenceMirrored");// Call API Endpoint /admin/scoreSwitch
- const data = await response.json(); // Wait for asyncronous transfer to complete
- updateScoreFrontend(data); // Update admin frontend
+ const data = await fetchJson("/admin/scoreToggleReferenceMirrored");// Call API Endpoint /admin/scoreSwitch
+ if(data) updateScoreFrontend(data); // Update admin frontend
}
// Clear score
async function scoreClearScore() {
- const response = await fetch("/admin/scoreClearScore"); // Call API Endpoint /admin/scoreClearScore
- const data = await response.json(); // Wait for asynchronous transfer to complete
- updateScoreFrontend(data); // Update admin frontend
+ const data = await fetchJson("/admin/scoreClearScore"); // Call API Endpoint /admin/scoreClearScore
+ if(data) updateScoreFrontend(data); // Update admin frontend
}
// Configure Teams
@@ -320,13 +332,12 @@ async function scoreConfigTeams() {
}
console.log(teamA, teamB)
- const response = await fetch("/admin/scoreConfigTeams", { // Call API Endpoint /admin/scoreAlterScore with the teamname to alter the score in the specified direction
+ const data = await fetchJson("/admin/scoreConfigTeams", { // Call API Endpoint /admin/scoreAlterScore with the teamname to alter the score in the specified direction
method: 'POST',
headers: { "Content-Type": "application/json" },
body: JSON.stringify({teamA: teamA, teamB: teamB})
});
- const data = await response.json(); // Wait for asyncronous transfer to complete
- updateScoreFrontend(data); // Update admin frontend
+ if(data) updateScoreFrontend(data); // Update admin frontend
refreshMonitor();
}
@@ -336,31 +347,28 @@ async function scoreConfigTeams() {
// Request important values for db contents
async function dbGetValues() {
- const response = await fetch("/admin/dbGetValues"); // Call API Endpoint /admin/dbGetValues
- const data = await response.json(); // Wait for asynchronous transfer to complete
- updateDbFrontend(data); // Update admin frontend
+ const data = await fetchJson("/admin/dbGetValues"); // Call API Endpoint /admin/dbGetValues
+ if(data) updateDbFrontend(data); // Update admin frontend
}
// Add team to DB
async function dbAddTeam() {
- const response = await fetch("/admin/dbAddTeam", { // Call API Endpoint /admin/scoreAlterScore with the teamname to alter the score in the specified direction
+ const data = await fetchJson("/admin/dbAddTeam", { // Call API Endpoint /admin/scoreAlterScore with the teamname to alter the score in the specified direction
method: 'POST',
headers: { "Content-Type": "application/json" },
body: JSON.stringify({teamName: document.getElementById("dbTeamToAdd").value})
});
document.getElementById("dbTeamToAdd").value = ""; // Empty the text field after sending
- const data = await response.json(); // Wait for asyncronous transfer to complete
- updateDbFrontend(data);
+ if(data) updateDbFrontend(data);
}
// Delete team from DB
async function dbDeleteTeam() {
let teamName = document.getElementById("dbTeamToDelete").value;
- const response = await fetch("/admin/dbDeleteTeam", { // Call API Endpoint /admin/scoreAlterScore with the teamname to alter the score in the specified direction
+ const data = await fetchJson("/admin/dbDeleteTeam", { // Call API Endpoint /admin/scoreAlterScore with the teamname to alter the score in the specified direction
method: 'POST',
headers: { "Content-Type": "application/json" },
body: JSON.stringify({teamName: teamName})
});
- const data = await response.json(); // Wait for asyncronous transfer to complete
- updateDbFrontend(data);
+ if(data) updateDbFrontend(data);
}
\ No newline at end of file
diff --git a/scoreboard/public/javascripts/index.js b/scoreboard/public/javascripts/index.js
index 1e52645..4410c9b 100644
--- a/scoreboard/public/javascripts/index.js
+++ b/scoreboard/public/javascripts/index.js
@@ -5,8 +5,12 @@ const socket = io(wss); // Connect to socketio s
// Websockets event handler
// ######################################################################################################################################################
-socket.on('connected', (message) => {
- console.log("Connected");
+// 'connect' feuert bei jeder Verbindung, auch nach einem Reconnect. Da der Pi das WLAN
+// selbst aufspannt, sind kurze Abbrueche normal: danach werden Timer und Spielstand neu
+// geholt, damit die Anzeige nicht auf einem veralteten Stand haengen bleibt.
+socket.on('connect', () => {
+ console.log("Verbunden");
+ initialUpdate();
});
socket.on('timerDurationLeft', (message) => {
@@ -26,6 +30,22 @@ socket.on('refresh', (message) => {
// General functions
// ######################################################################################################################################################
+// Holt JSON von einem Endpunkt. Liefert null statt zu werfen, wenn der Server nicht
+// erreichbar ist oder mit einem Fehler antwortet.
+async function fetchJson(url) {
+ try {
+ const response = await fetch(url);
+ if(!response.ok) {
+ console.error("Anfrage fehlgeschlagen:", url, response.status);
+ return null;
+ }
+ return await response.json();
+ } catch (err) {
+ console.error("Server nicht erreichbar:", url, err);
+ return null;
+ }
+}
+
// Update DOM timer elements from passed values
function updateTimerFrontend(values) {
document.getElementById("durationLeft").innerHTML = values.print; // Display durationLeft as prettyfied string
@@ -42,7 +62,6 @@ async function initialUpdate() {
// Request important timer values
async function timerGetValues() {
- const response = await fetch("/admin/timerGetValues"); // Call API Endpoint /admin/timerGetValues
- const data = await response.json(); // Wait for asynchronous transfer to complete
- updateTimerFrontend(data); // Update admin frontend
+ const data = await fetchJson("/admin/timerGetValues"); // Call API Endpoint /admin/timerGetValues
+ if(data) updateTimerFrontend(data); // Update admin frontend
}
\ No newline at end of file
diff --git a/scoreboard/public/javascripts/indexScore.js b/scoreboard/public/javascripts/indexScore.js
index 476cec9..db99789 100644
--- a/scoreboard/public/javascripts/indexScore.js
+++ b/scoreboard/public/javascripts/indexScore.js
@@ -5,8 +5,12 @@ const socket = io(wss); // Connect to socketio s
// Websockets event handler
// ######################################################################################################################################################
-socket.on('connected', (message) => {
- console.log("Connected");
+// 'connect' feuert bei jeder Verbindung, auch nach einem Reconnect. Da der Pi das WLAN
+// selbst aufspannt, sind kurze Abbrueche normal: danach werden Timer und Spielstand neu
+// geholt, damit die Anzeige nicht auf einem veralteten Stand haengen bleibt.
+socket.on('connect', () => {
+ console.log("Verbunden");
+ initialUpdate();
});
socket.on('timerDurationLeft', (message) => {
@@ -35,6 +39,22 @@ socket.on('scoreSideswitch', (message) => {
// General functions
// ######################################################################################################################################################
+// Holt JSON von einem Endpunkt. Liefert null statt zu werfen, wenn der Server nicht
+// erreichbar ist oder mit einem Fehler antwortet.
+async function fetchJson(url) {
+ try {
+ const response = await fetch(url);
+ if(!response.ok) {
+ console.error("Anfrage fehlgeschlagen:", url, response.status);
+ return null;
+ }
+ return await response.json();
+ } catch (err) {
+ console.error("Server nicht erreichbar:", url, err);
+ return null;
+ }
+}
+
// Update DOM timer elements from passed values
function updateTimerFrontend(values) {
document.getElementById("durationLeft").innerHTML = values.print; // Display durationLeft as prettyfied string
@@ -87,9 +107,8 @@ async function initialUpdate() {
// Request important timer values
async function timerGetValues() {
- const response = await fetch("/admin/timerGetValues"); // Call API Endpoint /admin/timerGetValues
- const data = await response.json(); // Wait for asynchronous transfer to complete
- updateTimerFrontend(data); // Update admin frontend
+ const data = await fetchJson("/admin/timerGetValues"); // Call API Endpoint /admin/timerGetValues
+ if(data) updateTimerFrontend(data); // Update admin frontend
}
// ######################################################################################################################################################
@@ -98,8 +117,7 @@ async function timerGetValues() {
// Request important values for score
async function scoreGetValues() {
- const response = await fetch("/admin/scoreGetValues"); // Call API Endpoint /admin/scoreGetValues
- const data = await response.json(); // Wait for asynchronous transfer to complete and parse json (which got received by backend)
+ const data = await fetchJson("/admin/scoreGetValues"); // Call API Endpoint /admin/scoreGetValues
console.log(data); // Print received data
- updateScoreFrontend(data); // Update admin frontend with received values for scoreboard
+ if(data) updateScoreFrontend(data); // Update admin frontend with received values for scoreboard
}
\ No newline at end of file
diff --git a/scoreboard/public/javascripts/splashscreen.js b/scoreboard/public/javascripts/splashscreen.js
index 3053f07..a46f235 100644
--- a/scoreboard/public/javascripts/splashscreen.js
+++ b/scoreboard/public/javascripts/splashscreen.js
@@ -5,10 +5,6 @@ const socket = io(wss); // Connect to socketio s
// Websockets event handler
// ######################################################################################################################################################
-socket.on('connected', (message) => {
- console.log("Connected");
-});
-
socket.on('refresh', (message) => {
document.location.reload() // Reload page on received 'refresh' messagen
});
\ No newline at end of file
diff --git a/scoreboard/routes/index.js b/scoreboard/routes/index.js
index 70d56ab..059748a 100644
--- a/scoreboard/routes/index.js
+++ b/scoreboard/routes/index.js
@@ -1,6 +1,5 @@
var express = require('express');
var router = express.Router();
-let io = require('../controllers/socketio');
const score = require('../controllers/score');
const etc = require('../controllers/etc');
@@ -18,15 +17,4 @@ router.get('/', function(req, res, next) {
}
});
-// Websocket-Verbindungshandler: wird ausgelöst, sobald ein Client (Monitor) sich verbindet
-io.on('connection', (socket) => {
- console.log("A user connected");
- socket.emit("Hello user from server"); // Begrüßungsnachricht an den neuen Client
-
- // Eingehende Nachrichten vom Client loggen (aktuell nur für Debugging)
- socket.on('message', (message) => {
- console.log(message)
- })
-})
-
module.exports = router;