-
-
Notifications
You must be signed in to change notification settings - Fork 134
Auto Update #366
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: mdev
Are you sure you want to change the base?
Auto Update #366
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,9 +3,55 @@ | |
| <head> | ||
| <meta content='width=device-width' name='viewport'> | ||
| <title>WLED Update</title> | ||
| <script src="common.js" type="text/javascript"></script> | ||
| <script> | ||
| function B() { window.history.back(); } | ||
| function U() { document.getElementById("uf").style.display="none";document.getElementById("msg").style.display="block"; } | ||
| async function autoUpdate() { | ||
| const btn = gId('autoUpdBtn'); | ||
| const status = gId('autoUpdStatus'); | ||
| btn.disabled = true; | ||
| status.textContent = ''; | ||
| try { | ||
| status.textContent = 'Fetching device info...'; | ||
| const infoResp = await fetch(getURL('/json/info')); | ||
| if (!infoResp.ok) throw new Error('Failed to fetch device info'); | ||
| const info = await infoResp.json(); | ||
| if (!info || !info.repo || info.repo === 'unknown') { | ||
| status.textContent = 'No release repository available for this build.'; | ||
| btn.disabled = false; | ||
| return; | ||
| } | ||
| status.textContent = 'Checking GitHub for latest release...'; | ||
| const ghResp = await fetch(`https://api.github.com/repos/${info.repo}/releases/latest`); | ||
| if (!ghResp.ok) throw new Error(`GitHub API error: ${ghResp.status}`); | ||
| const ghRelease = await ghResp.json(); | ||
| const releaseVer = ghRelease.tag_name.replace(/^v/, ''); | ||
| const assetSuffix = `_${releaseVer}_${info.release}.bin`; | ||
| const asset = ghRelease.assets.find(a => a.name.endsWith(assetSuffix)); | ||
| if (!asset) { | ||
| const available = ghRelease.assets.map(a => a.name).join(', '); | ||
|
Comment on lines
+29
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Show referenced section with line numbers
nl -ba wled00/data/update.htm | sed -n '1,120p'
# Show around the cited lines (29-70 in file are likely different due to offsets; also search exact snippet)
rg -n "ghRelease\.tag_name|assetSuffix|ghRelease\.assets\.find|info\.release" wled00/data/update.htm
# Extract larger surrounding context near matches
rg -n "ghRelease\.tag_name" wled00/data/update.htm | cut -d: -f1 | head -n 5 | while read -r ln; do
start=$((ln-30)); end=$((ln+80))
echo "---- context around line $ln ($start-$end) ----"
nl -ba wled00/data/update.htm | sed -n "${start},${end}p"
done
# Find where ghRelease is fetched/parsed and whether there is any schema guard
rg -n "fetch\\(|api\\.github|releases|json\\(|tag_name|assets" wled00/data/update.htm
# Show any catch blocks / error messaging
rg -n "catch\\(|show.*status|status.*msg|alert\\(|toast\\(|error" wled00/data/update.htmRepository: MoonModules/WLED-MM Length of output: 106 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Basic sanity: list file exists
ls -la wled00/data/update.htm
# Print first ~160 lines with line numbers via awk
awk '{printf "%6d\t%s\n", NR, $0}' wled00/data/update.htm | sed -n '1,160p'
# Print around the referenced snippet area by searching for the exact line fragments
# (no nl needed)
awk '{if ($0 ~ /ghRelease\.tag_name/ || $0 ~ /assetSuffix/ || $0 ~ /ghRelease\.assets\.find/ || $0 ~ /info\.release/) print NR "\t" $0}' wled00/data/update.htm
# Get broader context around where ghRelease.tag_name appears
ln=$(awk '/ghRelease\.tag_name/ {print NR; exit}' wled00/data/update.htm)
start=$((ln-60)); end=$((ln+120))
awk -v s="$start" -v e="$end" '{if(NR>=s && NR<=e) printf "%6d\t%s\n", NR, $0}' wled00/data/update.htm
# Find where ghRelease is constructed/assigned
rg -n --context 3 "ghRelease\s*=" wled00/data/update.htm || true
rg -n --context 3 "tag_name|assets" wled00/data/update.htm || true
# Find where info.release is created/assigned
rg -n --context 3 "info\.release" wled00/data/update.htm || true
# Find relevant error handling paths
rg -n --context 3 "catch\\(|show.*status|status.*msg|alert\\(|toast\\(|error" wled00/data/update.htm || trueRepository: MoonModules/WLED-MM Length of output: 10817 Harden GitHub release parsing before using release fields 🤖 Prompt for AI Agents
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please suggest some minimal code that would ensure that the code catches unexpected response content. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
// After: const info = await infoResp.json();
if (!info || typeof info.release !== 'string' || !info.release) {
status.textContent = 'Missing device release info (info.release).';
btn.disabled = false;
return;
}// After: const ghRelease = await ghResp.json();
if (typeof ghRelease.tag_name !== 'string' || !ghRelease.tag_name) {
status.textContent = 'Missing release tag from GitHub response.';
btn.disabled = false;
return;
}
if (!Array.isArray(ghRelease.assets)) {
status.textContent = 'No assets array in GitHub release response.';
btn.disabled = false;
return;
}That gives a targeted, readable error for each unexpected shape instead of falling through to the generic 🧠 Learnings used |
||
| status.textContent = `Firmware not found (*${assetSuffix}). Available: ${available}`; | ||
| btn.disabled = false; | ||
| return; | ||
| } | ||
| status.textContent = `Downloading ${asset.name} (${Math.round(asset.size/1024)} KB)...`; | ||
| const fwUrl = asset.browser_download_url.replace(/^https?:\/\/[^/]+/, 'https://download.wled.me'); | ||
| const fwResp = await fetch(fwUrl); | ||
| if (!fwResp.ok) throw new Error(`Download failed: ${fwResp.status}`); | ||
| const blob = await fwResp.blob(); | ||
| const file = new File([blob], asset.name, {type: 'application/octet-stream'}); | ||
| const dt = new DataTransfer(); | ||
| dt.items.add(file); | ||
| document.querySelector('input[name="update"]').files = dt.files; | ||
| status.textContent = `Downloaded ${asset.name}. Uploading to device...`; | ||
| U(); | ||
| gId('uf').submit(); | ||
| } catch(e) { | ||
| status.textContent = 'Auto-update failed: ' + e.message; | ||
| btn.disabled = false; | ||
| } | ||
| } | ||
| function GetV() {/*injected values here*/} | ||
| </script> | ||
| <style> | ||
|
|
@@ -19,6 +65,9 @@ <h2>MoonMod WLED Software Update</h2> | |
| Installed version: <span class="sip">WLEDMM ##VERSION##</span><br> <!--WLEDMM: show bin name--> | ||
| Download the latest release: <a href="https://github.com/MoonModules/WLED-MM/releases/latest" target="_blank" rel="noopener noreferrer"> | ||
| <img src="https://img.shields.io/github/release/MoonModules/WLED-MM.svg?style=flat-square"></a><br> | ||
| <button type="button" id="autoUpdBtn" onclick="autoUpdate()">Auto update</button><br> | ||
| <span id="autoUpdStatus" style="display:block;margin-top:4px;font-size:13px;"></span> | ||
| <hr> | ||
| <input type='file' name='update' required><br> <!--should have accept='.bin', but it prevents file upload from android app--> | ||
| <button type="submit">Update!</button><br> | ||
| <button type="button" onclick="B()">Back</button> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: MoonModules/WLED-MM
Length of output: 159
🏁 Script executed:
Repository: MoonModules/WLED-MM
Length of output: 12732
Add fetch timeouts (AbortController) to prevent the Auto update flow from hanging
autoUpdate()has threefetch()calls with no timeout, so the button can remain disabled indefinitely on a stalled network request (device info, GitHub latest release, and firmware download).AbortController-based timeout wrapper and use it for allfetch()calls inautoUpdate().// WLEDMMmarker(s) for the WLED-MM-specific JS additions in this file (there are no// WLEDMMcomments in the inline<script>).Suggested patch
async function autoUpdate() { const btn = gId('autoUpdBtn'); const status = gId('autoUpdStatus'); + const fetchWithTimeout = async (url, options = {}, timeoutMs = 15000) => { + const controller = new AbortController(); + const t = setTimeout(() => controller.abort(), timeoutMs); + try { + return await fetch(url, {...options, signal: controller.signal}); + } finally { + clearTimeout(t); + } + }; btn.disabled = true; status.textContent = ''; try { status.textContent = 'Fetching device info...'; - const infoResp = await fetch(getURL('/json/info')); + const infoResp = await fetchWithTimeout(getURL('/json/info')); if (!infoResp.ok) throw new Error('Failed to fetch device info'); const info = await infoResp.json(); @@ - const ghResp = await fetch(`https://api.github.com/repos/${info.repo}/releases/latest`); + const ghResp = await fetchWithTimeout(`https://api.github.com/repos/${info.repo}/releases/latest`); @@ - const fwResp = await fetch(fwUrl); + const fwResp = await fetchWithTimeout(fwUrl);🤖 Prompt for AI Agents