221 lines
6.9 KiB
JavaScript
Executable File
221 lines
6.9 KiB
JavaScript
Executable File
// ==== FRONTEND app.js ====
|
||
|
||
// Service-Liste
|
||
const services = [
|
||
{ id: "abc", name: "Control GamePad", url: "https://tccontrol.server.schooltech.ch/" },
|
||
{ id: "xyz", name: "Guacamole", url: "https://rp5guac.server.schooltech.ch/" },
|
||
{ id: "sim", name: "Simulation", url: "https://tcSimulation.server.schooltech.ch/" },
|
||
{ id: "video", name: "Video", url: "https://robotVideo.server.schooltech.ch/" },
|
||
{ id: "homing", name: "Homing", url:"https://robotHoming.server.schooltech.ch/"},
|
||
{ id: "base", name:"RobotBase", url:"https://robotBase.server.schooltech.ch/"},
|
||
{ id: "ellbow", name:"RobotEllbow", url:"https://robotEllbow.server.schooltech.ch/"},
|
||
{ id: "hand", name:"RobotHand", url:"https://robotHand.server.schooltech.ch/"},
|
||
{ id: "driver", name:"RobotDriver", url:"https://robotdriver.server.schooltech.ch/"},
|
||
{ id: "code", name:"VSCode", url:"https://robotVSCode.server.schooltech.ch/"}
|
||
];
|
||
|
||
// DOM-Elemente
|
||
const iframe = document.getElementById("service-frame");
|
||
const loginModal = document.getElementById("login-modal");
|
||
const loginBtn = document.getElementById("login-btn");
|
||
const loginSubmit = document.getElementById("login-submit");
|
||
const loginMsg = document.getElementById("login-msg");
|
||
const nav = document.getElementById("services");
|
||
const estopBtn = document.getElementById("emergency-stop");
|
||
|
||
const usernameInput = document.getElementById("username");
|
||
const passwordInput = document.getElementById("password");
|
||
|
||
let loggedIn = false;
|
||
let armedPollInterval = null;
|
||
|
||
// ===========================
|
||
// Login anzeigen
|
||
// ===========================
|
||
function switchToLogin() {
|
||
loginBtn.textContent = "Login";
|
||
loginBtn.onclick = () => {
|
||
loginModal.style.display = "block";
|
||
};
|
||
}
|
||
|
||
// ===========================
|
||
// Logout anzeigen
|
||
// ===========================
|
||
function switchToLogout() {
|
||
loginBtn.textContent = "Logout";
|
||
loginBtn.onclick = async () => {
|
||
try {
|
||
await fetch("/api/logout", { method: "POST" });
|
||
} catch (e) {
|
||
console.warn("Logout request failed:", e);
|
||
}
|
||
performLocalLogout();
|
||
};
|
||
}
|
||
|
||
// ===========================
|
||
// Lokales Logout
|
||
// ===========================
|
||
function performLocalLogout() {
|
||
loggedIn = false;
|
||
stopArmedPolling();
|
||
estopBtn.style.display = "none";
|
||
iframe.src = "";
|
||
iframe.style.display = "none";
|
||
nav.innerHTML = "";
|
||
loginModal.style.display = "block";
|
||
switchToLogin();
|
||
}
|
||
|
||
// ===========================
|
||
// Armed-Status prüfen
|
||
// ===========================
|
||
const POWER_STATUS_URL = 'https://robotdriver.server.schooltech.ch/api/power-status';
|
||
const ESTOP_URL = 'https://robotdriver.server.schooltech.ch/api/emergency-stop';
|
||
|
||
async function updateArmedStatus() {
|
||
console.log('[armed-check] GET', POWER_STATUS_URL);
|
||
try {
|
||
const r = await fetch(POWER_STATUS_URL);
|
||
if (r.ok) {
|
||
const data = await r.json();
|
||
console.log('[armed-check] response:', data);
|
||
estopBtn.style.display = data.armed ? "block" : "none";
|
||
} else {
|
||
console.warn('[armed-check] HTTP', r.status, '– Button versteckt');
|
||
estopBtn.style.display = "none";
|
||
}
|
||
} catch (e) {
|
||
console.error('[armed-check] Fehler bei', POWER_STATUS_URL, '–', e.message);
|
||
estopBtn.style.display = "none";
|
||
}
|
||
}
|
||
|
||
function startArmedPolling() {
|
||
updateArmedStatus();
|
||
armedPollInterval = setInterval(updateArmedStatus, 5000);
|
||
}
|
||
|
||
function stopArmedPolling() {
|
||
if (armedPollInterval) {
|
||
clearInterval(armedPollInterval);
|
||
armedPollInterval = null;
|
||
}
|
||
}
|
||
|
||
// ===========================
|
||
// Emergency Stop
|
||
// ===========================
|
||
estopBtn.addEventListener("click", async () => {
|
||
console.log('[estop] POST', ESTOP_URL);
|
||
try {
|
||
const r = await fetch(ESTOP_URL, { method: 'POST' });
|
||
console.log('[estop] response HTTP', r.status);
|
||
} catch (e) {
|
||
console.error('[estop] Fehler bei', ESTOP_URL, '–', e.message);
|
||
}
|
||
});
|
||
|
||
// ===========================
|
||
// Login-Logik
|
||
// ===========================
|
||
async function doLogin() {
|
||
const user = usernameInput.value;
|
||
const pass = passwordInput.value;
|
||
|
||
try {
|
||
const res = await fetch("/api/login", {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify({ user, pass })
|
||
});
|
||
|
||
if (res.ok) {
|
||
loggedIn = true;
|
||
loginModal.style.display = "none";
|
||
loginMsg.textContent = "";
|
||
setupServiceButtons();
|
||
switchToLogout();
|
||
startArmedPolling();
|
||
} else {
|
||
loginMsg.textContent = "Login fehlgeschlagen";
|
||
}
|
||
} catch (e) {
|
||
loginMsg.textContent = "Fehler: " + e.message;
|
||
}
|
||
}
|
||
|
||
loginSubmit.onclick = doLogin;
|
||
|
||
// Enter-Taste Login
|
||
[usernameInput, passwordInput].forEach(input => {
|
||
input.addEventListener('keydown', (e) => {
|
||
if (e.key === 'Enter') {
|
||
e.preventDefault();
|
||
doLogin();
|
||
}
|
||
});
|
||
});
|
||
|
||
// ===========================
|
||
// Buttons erzeugen
|
||
// ===========================
|
||
function setupServiceButtons() {
|
||
nav.innerHTML = "";
|
||
services.forEach(svc => {
|
||
console.log("Service " + svc.name + " wird als Button angefuegt");
|
||
const btn = document.createElement("button");
|
||
btn.textContent = svc.name;
|
||
btn.onclick = async () => {
|
||
try {
|
||
await fetch('/api/event', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
event: 'open',
|
||
service: svc.id,
|
||
url: svc.url
|
||
})
|
||
});
|
||
} catch(e) {
|
||
console.error('Event log failed', e);
|
||
}
|
||
|
||
document.querySelectorAll("nav button").forEach(b => b.classList.remove("active"));
|
||
btn.classList.add("active");
|
||
|
||
openService(svc);
|
||
};
|
||
nav.appendChild(btn);
|
||
});
|
||
}
|
||
|
||
// ===========================
|
||
// Service öffnen
|
||
// ===========================
|
||
function openService(svc) {
|
||
iframe.src = svc.url;
|
||
iframe.style.display = "block";
|
||
window.scrollTo(0,0);
|
||
}
|
||
|
||
// ===========================
|
||
// Session Status beim Laden prüfen
|
||
// ===========================
|
||
(async function checkStatus() {
|
||
try {
|
||
const r = await fetch('/api/status');
|
||
if (r.ok) {
|
||
loggedIn = true;
|
||
setupServiceButtons();
|
||
switchToLogout();
|
||
startArmedPolling();
|
||
} else {
|
||
switchToLogin();
|
||
}
|
||
} catch (e) {
|
||
switchToLogin();
|
||
}
|
||
})();
|