neiam
/lambent-flex-c6
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
Log in to mark this repository.
Answer a GET to /ota instead of a 405
b81a582 · Gabriel Morell · 2026-09-16 20:46
Message
{commit_body(@commit)}
Files changed
modified
README.md
+7
−2
@@ -152,8 +152,9 @@ build.
| 152 | 152 | ### Driving it by hand |
| 153 | 153 | |
| 154 | 154 | `GET /` says what a box is running — note it answers **218**, not 200, which |
| 155 | −the packet sender matches on — and `POST /ota` makes it go and look now rather | |
| 156 | −than at the next interval: | |
| 155 | +the packet sender matches on. `GET /ota` reports what the updater last found | |
| 156 | +and does nothing; **`POST /ota`** is what makes it go and look now rather than | |
| 157 | +at the next interval: | |
| 157 | 158 | |
| 158 | 159 | ```console |
| 159 | 160 | $ curl -s http://172.16.15.139/ | jq '{version, ota_slot, ota_state, ota_available}' |
@@ -167,6 +168,10 @@ $ curl -s http://172.16.15.139/ | jq '{version, ota_slot, ota_state, ota_availab
| 167 | 168 | $ curl -s -i -X POST http://172.16.15.139/ota | head -1 |
| 168 | 169 | HTTP/1.1 202 Accepted |
| 169 | 170 | |
| 171 | +$ # a GET is safe, and says so | |
| 172 | +$ curl -s http://172.16.15.139/ota | jq -r .hint | |
| 173 | +POST to this URL to check for an update now | |
| 174 | + | |
| 170 | 175 | $ curl -s -X POST http://172.16.15.139/ota | jq |
| 171 | 176 | { |
| 172 | 177 | "queued": true, |
modified
src/main.rs
+26
−0
@@ -705,6 +705,7 @@ fn main() -> Result<(), Error> {
| 705 | 705 | let status_ota_slot = ota_slot.clone(); |
| 706 | 706 | let status_ota_state = ota_state.clone(); |
| 707 | 707 | let ota_updates = updates.clone(); |
| 708 | + let ota_report = updates.clone(); | |
| 708 | 709 | let mut status = StatusServer::bare()?.asset("/status", assets::STATUS_HTML)?; |
| 709 | 710 | |
| 710 | 711 | // Registered by hand rather than via `StatusServer::json`, which hardcodes |
@@ -746,6 +747,31 @@ fn main() -> Result<(), Error> {
| 746 | 747 | Ok::<(), EspIOError>(()) |
| 747 | 748 | })?; |
| 748 | 749 | |
| 750 | + // The same report, without doing anything — because `/ota` is a URL | |
| 751 | + // people paste into a browser, and a bare GET against a POST-only handler | |
| 752 | + // is a 405 from ESP-IDF's server (httpd_uri.c: URI found, method not | |
| 753 | + // allowed), which reads like a broken device rather than like "use POST". | |
| 754 | + // | |
| 755 | + // A GET that triggered an update would be worse than unfriendly: anything | |
| 756 | + // that prefetches a link would reboot the device. | |
| 757 | + status | |
| 758 | + .server_mut() | |
| 759 | + .fn_handler("/ota", Method::Get, move |req| { | |
| 760 | + let report = ota_report.report(); | |
| 761 | + let resp = json!({ | |
| 762 | + "running": ota::running_version(), | |
| 763 | + "available": report.available, | |
| 764 | + "last_error": report.last_error, | |
| 765 | + "checked": report.checked, | |
| 766 | + // Said plainly, since the reason to be reading this is | |
| 767 | + // usually "why has nothing happened". | |
| 768 | + "hint": "POST to this URL to check for an update now", | |
| 769 | + }); | |
| 770 | + req.into_response(200, None, &[("Content-Type", "application/json")])? | |
| 771 | + .write_all(resp.to_string().as_bytes())?; | |
| 772 | + Ok::<(), EspIOError>(()) | |
| 773 | + })?; | |
| 774 | + | |
| 749 | 775 | // Force a check now, for a device that should not wait out its interval. |
| 750 | 776 | // Deliberately not a GET: it has an effect, and a device that reboots |
| 751 | 777 | // itself because something prefetched a link would be its own bug. |
Parents: b36ef03