Skip to content

Commit 96b0c7b

Browse files
committed
better packet queuing & pacing for custom palette live preview (#5515)
* better packet queuing / pacing for custom palette live preview * fix leak * remove window prefix from variables
1 parent 6394bec commit 96b0c7b

1 file changed

Lines changed: 12 additions & 10 deletions

File tree

wled00/data/cpal/cpal.htm

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@
7171
let copyColor = '#000';
7272
let ws = null;
7373
let maxCol; // max colors to send out in one chunk, ESP8266 is limited to ~50 (500 bytes), ESP32 can do ~128 (1340 bytes)
74+
let _applySeq = 0; // incremented each time applyLED fires; used to cancel stale in-flight previews
75+
let _httpQueue = [], _httpRun = 0;
7476

7577
// load external resources in sequence to avoid 503 errors if heap is low, repeats indefinitely until loaded
7678
(function loadFiles() {
@@ -621,21 +623,16 @@
621623

622624
async function requestJson(cmd)
623625
{
624-
if (ws && ws.readyState == 1) {
626+
if (ws && ws.readyState == 1 && ws.bufferedAmount < 32768) {
625627
try {
626628
ws.send(JSON.stringify(cmd));
629+
await new Promise(r => setTimeout(r, 15)); // short delay to give ESP time to process (fewer packets dropped)
627630
return 1;
628631
} catch (e) {}
629632
}
630633

631-
if (!window._httpQueue) {
632-
window._httpQueue = [];
633-
window._httpRun = 0;
634-
}
635-
if (_httpQueue.length >= 5) {
636-
return Promise.resolve(-1); // reject if too many queued requests
637-
}
638-
634+
// HTTP fallback
635+
if (_httpQueue.length >= 5) return -1; // queue full; applyLED cancels stale queues before sending
639636
return new Promise(resolve => {
640637
_httpQueue.push({ cmd, resolve });
641638
(async function run() {
@@ -650,7 +647,7 @@
650647
cache: 'no-store'
651648
});
652649
} catch (e) {}
653-
await new Promise(r => setTimeout(r, 120));
650+
await new Promise(r => setTimeout(r, 120)); // delay between requests (go slow, this is the http fallback if WS fails)
654651
q.resolve(0);
655652
}
656653
_httpRun = 0;
@@ -662,8 +659,12 @@
662659
async function applyLED()
663660
{
664661
if (!palCache.length) return;
662+
const seq = ++_applySeq;
663+
// discard pending HTTP chunks from any previous preview so stale data doesn't drain slowly
664+
while (_httpQueue.length) _httpQueue.shift().resolve(-1); // resolve dropped entries so their awaiters can observe the seq change and exit
665665
try {
666666
let st = await (await fetch(getURL('/json/state'), { cache: 'no-store' })).json();
667+
if (seq !== _applySeq) return; // superseded by a newer preview request
667668
if (!st.seg || !st.seg.length) return;
668669

669670
// get selected segments, use main segment if none selected
@@ -680,6 +681,7 @@
680681
arr.push(palCache[len > 1 ? Math.round(i * 255 / (len - 1)) : 0]);
681682
// send colors in chunks
682683
for (let j = 0; j < arr.length; j += maxCol) {
684+
if (seq !== _applySeq) return; // superseded mid-send
683685
let chunk = [s.start + j, ...arr.slice(j, j + maxCol)];
684686
await requestJson({ seg: { id: s.id, i: chunk } });
685687
}

0 commit comments

Comments
 (0)