From 638b43c29ba78f73cd74c7623193eb7c9b04e842 Mon Sep 17 00:00:00 2001 From: Midgard Date: Thu, 16 Sep 2021 16:58:13 +0200 Subject: [PATCH 1/4] Add start of frontend --- frontend/index.html | 109 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 frontend/index.html diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..1100d6b --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,109 @@ + + + + + + LED strip control + + + + +

LED strip control

+ +

This application requires JavaScript.

+
+ + + + + + + From 0aece8b8cab34b5b64be3eb294d20fa00c0ed142 Mon Sep 17 00:00:00 2001 From: Midgard Date: Sun, 19 Sep 2021 03:48:30 +0200 Subject: [PATCH 2/4] Write frontend --- frontend/index.html | 233 ++++++++++++++++++++++++++++++++------------ frontend/main.js | 231 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 402 insertions(+), 62 deletions(-) create mode 100644 frontend/main.js diff --git a/frontend/index.html b/frontend/index.html index 1100d6b..503c1b2 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -3,48 +3,205 @@ - LED strip control + LAP -

LED strip control

+
-

This application requires JavaScript.

-
- +

Zeus WPI – LED-Automaten-Programmatie

- +

Voor deze applicatie is helaas JavaScript vereist.

+ +
+

Configuratie

+ Je schuilnaam: +
+ +
+

LED-strip

+
+ LED-strip wordt geladen... +
+
+ +
+

Segmentcontrole

+
+ Segment + van LED + tot +
+
Toegewezen aan:
+ +
+ +
+

Programma

+

Dit segment is niet van jou. Je kunt de code enkel bekijken.

+ +
+ +

De code wordt niet bestendig bewaard. Sla ze zelf op op je computer. Gebruik dit veld bij voorkeur enkel om naar te kopiëren-en-plakken.

+
+
+

Programmeer je segment in Lua. Voor je code lijkt het alsof je LED 0 tot x hebt. Extra beschikbare functies:

+
+
led(led_nr, r, g, b)
+
Stel LED led_nr in op de kleur met gegeven RGB-waarden (0–255)
+
ledamount(something, probably)
+
Uhh
+
delay(ms)
+
Wacht gedurende ms milliseconden
+
waitframes(frames)
+
Wacht gedurende frames frames
+
print(message)
+
Stuur message naar de console
+
+
+
+ + diff --git a/frontend/main.js b/frontend/main.js new file mode 100644 index 0000000..a4c9779 --- /dev/null +++ b/frontend/main.js @@ -0,0 +1,231 @@ +var ledStripControl = (function() { + "use strict"; + + var HOST = "http://localhost:8080"; + + var segments = null; + var activeSegmentId = null; + var us = null; + + function xhr(url, method, data, callback) { + var oReq = new XMLHttpRequest(); + + if (callback) { + function reqListener() { + var json = null; + try { json = JSON.parse(this.responseText); } catch(e) {} + callback(json); + } + oReq.addEventListener("load", reqListener); + } + + oReq.open(method, url); + oReq.send(data); + } + + function getJson(url, callback) { + xhr(url, "GET", "", callback); + } + function putJson(url, data, callback) { + xhr(url, "PUT", JSON.stringify(data), callback); + } + + function updateUs() { + us = document.getElementById("us").value; + showSegments(); + } + updateUs(); + + function saveAndShowSegments(segs) { + segments = {}; + for (var i in segs) { + segments[segs[i].id] = segs[i]; + } + showSegments(); + } + + function fetchSegments() { + getJson(HOST + "/api/segments.json", saveAndShowSegments); + } + + function activateSegment(segment) { + activeSegmentId = segment.id; + getJson(HOST + "/api/segments.json", saveAndShowSegments); + showSegments(); + document.getElementById("segment-control").style.display = "block"; + } + + function repeatString(text, amount) { + var result = ""; + for (var i = 0; i < amount; i++) { + result += text; + } + return result; + } + + function showSegmentEventListener(e) { + if (e.currentTarget.dataset["segment"] !== "true") return; + + var id = e.currentTarget.dataset["id"]; + activateSegment(segments[id]); + e.stopPropagation(); + } + function showOwnerEventListener(e) { + if (e.currentTarget.dataset["segment"] !== "true") return; + + var owner = e.currentTarget.dataset["owner"]; + if (owner) { + document.getElementById("owner_label").innerText = owner; + } else { + document.getElementById("owner_label").innerHTML = "Vrij"; + } + document.getElementById("owner_label").style.display = "block"; + document.getElementById("owner_label").style.left = (e.currentTarget.clientWidth/2 + e.currentTarget.offsetLeft - document.getElementById("owner_label").clientWidth/2) + "px"; + document.getElementById("owner_label").style.top = (e.currentTarget.offsetTop - document.getElementById("owner_label").clientHeight - 2) + "px"; + e.stopPropagation(); + } + function hideOwnerEventListener(e) { + if (e.currentTarget.dataset["segment"] !== "true") return; + + document.getElementById("owner_label").innerHTML = ""; + document.getElementById("owner_label").style.display = "none"; + } + + function updatePublishButton() { + var activeSegment = activeSegmentId !== null ? segments[activeSegmentId] : null; + if (document.getElementById("lua_editor").value == activeSegment.code) { + document.getElementById("publish-button").innerText = "Gepubliceerd"; + document.getElementById("publish-button").setAttribute("disabled", "disabled"); + } else { + document.getElementById("publish-button").innerText = "Publiceren"; + document.getElementById("publish-button").removeAttribute("disabled"); + } + } + + function showSegments() { + var segmentsContainer = document.getElementById("segments"); + segmentsContainer.innerHTML = ""; + + var prevSegEnd = 0; + if (segments !== null) for (var i in segments) { + if (!segments.hasOwnProperty(i)) continue; + var seg = segments[i]; + var color = seg.owner === "" ? "#555" : seg.owner === us ? "#050" : "#700"; + + var unsegmented = parseFloat(seg.begin) - prevSegEnd; + if (unsegmented > 0) { + var unsegmented_el = document.createElement("span"); + unsegmented_el.className = "unsegmented"; + unsegmented_el.innerHTML = repeatString("", unsegmented); + segmentsContainer.append(unsegmented_el); + } + + var rect = document.createElement("a"); + rect.className = seg.id === activeSegmentId ? "active segment" : "segment"; + rect.style.backgroundColor = color; + rect.id = "segment" + seg.id; + rect.href = "#segment" + seg.id; + rect.dataset["segment"] = "true"; + rect.dataset["owner"] = seg.owner; + rect.dataset["id"] = seg.id; + rect.addEventListener("click", showSegmentEventListener); + rect.addEventListener("focus", showOwnerEventListener); + rect.addEventListener("blur", hideOwnerEventListener); + rect.addEventListener("mouseover", showOwnerEventListener); + rect.addEventListener("mouseout", hideOwnerEventListener); + rect.innerHTML = repeatString("", seg.length); + segmentsContainer.appendChild(rect); + + prevSegEnd = seg.begin + seg.length; + } + + var activeSegment = activeSegmentId !== null ? segments[activeSegmentId] : null; + if (activeSegment !== null) { + document.getElementById("active_segment_id").innerText = activeSegmentId; + document.getElementById("active_segment_begin").innerText = activeSegment.begin; + document.getElementById("active_segment_end").innerText = activeSegment.begin + activeSegment.length - 1; + document.getElementById("active_segment_last_virtual").innerText = activeSegment.length - 1; + + updatePublishButton(); + + document.getElementById("lua_editor").value = activeSegment.code; + + if (activeSegment.owner !== "" && activeSegment.owner === us) { + document.getElementById("release_button").style.display = ""; + document.getElementById("release_button").innerText = "Onteigen"; + document.getElementById("release_button").removeAttribute("disabled"); + + document.getElementById("lua_editor").removeAttribute("disabled"); + document.getElementById("not-your-own").style.display = "none"; + document.getElementById("program-controls").style.display = "block"; + document.getElementById("program-instructions").style.display = "block"; + } else { + document.getElementById("release_button").style.display = "none"; + + document.getElementById("lua_editor").setAttribute("disabled", "disabled"); + document.getElementById("not-your-own").style.display = "block"; + document.getElementById("program-controls").style.display = "none"; + document.getElementById("program-instructions").style.display = "none"; + } + + if (activeSegment.owner !== "") { + document.getElementById("active_segment_owner").innerText = activeSegment.owner; + document.getElementById("claim_button").style.display = "none"; + + document.getElementById("program").style.display = "block"; + } else { + document.getElementById("active_segment_owner").innerText = "nog niemand"; + document.getElementById("claim_button").style.display = ""; + document.getElementById("claim_button").innerText = "Eigen je toe"; + document.getElementById("claim_button").removeAttribute("disabled"); + + document.getElementById("program").style.display = "none"; + } + } + } + + document.getElementById("claim_button").addEventListener("click", function() { + document.getElementById("claim_button").innerText = "Bezig met toe-eigenen..."; + document.getElementById("claim_button").setAttribute("disabled", "disabled"); + var activeSegment = segments[activeSegmentId]; + if (!activeSegment) { throw new Error("Trying to claim segment but no segment active"); } + putJson(HOST + "/api/code.json", { + "id": activeSegmentId, + "owner": us, + "code": activeSegment.code + }, fetchSegments); + }); + + document.getElementById("release_button").addEventListener("click", function() { + document.getElementById("release_button").innerText = "Bezig met onteigenen..."; + document.getElementById("release_button").setAttribute("disabled", "disabled"); + var activeSegment = segments[activeSegmentId]; + if (!activeSegment) { throw new Error("Trying to release segment but no segment active"); } + putJson(HOST + "/api/code.json", { + "id": activeSegmentId, + "owner": "", + "code": activeSegment.code + }, fetchSegments); + }); + + document.getElementById("publish-button").addEventListener("click", function() { + document.getElementById("publish-button").innerText = "Bezig met publiceren..."; + document.getElementById("publish-button").setAttribute("disabled", "disabled"); + var activeSegment = segments[activeSegmentId]; + if (!activeSegment) { throw new Error("Trying to update code of segment but no segment active"); } + putJson(HOST + "/api/code.json", { + "id": activeSegmentId, + "owner": activeSegment.owner, + "code": document.getElementById("lua_editor").value + }, fetchSegments); + }); + + document.getElementById("lua_editor").addEventListener("keyup", updatePublishButton); + document.getElementById("lua_editor").addEventListener("change", updatePublishButton); + + fetchSegments(); + + return { + updateUs: updateUs, + }; +})(); From bc78ac5775f7afc3d44ffdbaf4310317cff405fa Mon Sep 17 00:00:00 2001 From: Midgard Date: Sun, 19 Sep 2021 03:49:00 +0200 Subject: [PATCH 3/4] Improve submit script --- submit.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) mode change 100644 => 100755 submit.py diff --git a/submit.py b/submit.py old mode 100644 new mode 100755 index 1456c6b..7af2969 --- a/submit.py +++ b/submit.py @@ -1,10 +1,12 @@ +#!/usr/bin/env python3 + +import os import json import requests import time - - +SERVER = os.getenv("LEDSTRIP_SERVER", "http://10.1.0.212:8080") for i in range(10): @@ -13,11 +15,12 @@ for i in range(10): c = codefile.read() except: continue - j = { + + payload = { "code": c, "owner": "j", "id": i } - r = requests.put('http://10.1.0.212:8080/api/code.json', json=j) + r = requests.put(SERVER + '/api/code.json', json=payload) print(r) - print(r.text) \ No newline at end of file + print(r.text) From 72e5b663c52d1ed370428ebe466ad0cb2bfaaee1 Mon Sep 17 00:00:00 2001 From: Midgard Date: Sun, 19 Sep 2021 03:50:03 +0200 Subject: [PATCH 4/4] Allow CORS in webserver --- main/main.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/main/main.cpp b/main/main.cpp index 74a5699..2e3ec49 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -277,6 +277,8 @@ int main(int argc, char** argv) } svr.Get("/api/segments.json", [](const httplib::Request &, httplib::Response &res) { + res.set_header("Access-Control-Allow-Origin", "*"); + res.set_header("Access-Control-Allow-Methods", "GET"); json j; int i = 0; for (LedSegment* ledsegment : ledsegments) { @@ -293,6 +295,8 @@ int main(int argc, char** argv) }); svr.Put("/api/code.json", [](const httplib::Request &req, httplib::Response &res, const httplib::ContentReader &content_reader) { + res.set_header("Access-Control-Allow-Origin", "*"); + res.set_header("Access-Control-Allow-Methods", "PUT"); if (req.is_multipart_form_data()) { res.set_content("No multipart forms allowed", "text/plain"); return true; @@ -316,6 +320,12 @@ int main(int argc, char** argv) return true; }); + svr.Options("/api/code.json", [](const httplib::Request &req, httplib::Response &res) { + res.set_header("Access-Control-Allow-Origin", "*"); + res.set_header("Access-Control-Allow-Methods", "PUT"); + return true; + }); + std::thread httpserverthread(starthttpserver); ws2811_return_t ret; @@ -336,4 +346,4 @@ int main(int argc, char** argv) ws2811_render(&ledstring); std::this_thread::sleep_for(std::chrono::milliseconds(frametime)); } -} \ No newline at end of file +}