[ai] fixed web server issues, still some quirky behaviour. More robust.
This commit is contained in:
269
src/main.cpp
269
src/main.cpp
@@ -114,7 +114,11 @@ bool SDActive = false;
|
||||
|
||||
bool RFIDActive = false;
|
||||
|
||||
bool webrequestActive = false;
|
||||
|
||||
// Web request concurrency counter and helpers (atomic via GCC builtins)
|
||||
volatile uint32_t webreq_cnt = 0;
|
||||
static inline void webreq_enter() { __sync_add_and_fetch(&webreq_cnt, 1); }
|
||||
static inline void webreq_exit() { __sync_sub_and_fetch(&webreq_cnt, 1); }
|
||||
|
||||
uint16_t voltage_threshold_counter = 0;
|
||||
|
||||
@@ -319,6 +323,8 @@ void handleUpload(AsyncWebServerRequest *request, String filename, size_t index,
|
||||
|
||||
void handleMoveFile(AsyncWebServerRequest *request)
|
||||
{
|
||||
webreq_enter();
|
||||
request->onDisconnect([](){ webreq_exit(); });
|
||||
String from = request->arg("from");
|
||||
String to = request->arg("to");
|
||||
|
||||
@@ -339,6 +345,8 @@ void handleMoveFile(AsyncWebServerRequest *request)
|
||||
|
||||
void handleDeleteFile(AsyncWebServerRequest *request)
|
||||
{
|
||||
webreq_enter();
|
||||
request->onDisconnect([](){ webreq_exit(); });
|
||||
String filename = request->arg("filename");
|
||||
|
||||
if (SD.exists(filename))
|
||||
@@ -1147,6 +1155,136 @@ void readRFID()
|
||||
lastInteraction = millis();
|
||||
}
|
||||
|
||||
void init_webserver() {
|
||||
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||
{
|
||||
webreq_enter();
|
||||
request->onDisconnect([](){ webreq_exit(); });
|
||||
deactivateRFID();
|
||||
activateSD();
|
||||
String htmlPath = getSysDir("index.html");
|
||||
if (SD.exists(htmlPath))
|
||||
{
|
||||
AsyncWebServerResponse *response = request->beginResponse(SD, htmlPath, "text/html");
|
||||
request->send(response);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback: serve minimal error if file not found
|
||||
request->send(404, "text/plain", "ERROR: /system/index.html not found!");
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||
{
|
||||
webreq_enter();
|
||||
request->onDisconnect([](){ webreq_exit(); });
|
||||
deactivateRFID();
|
||||
activateSD();
|
||||
// Ensure SD is active and RFID is deactivated while serving files.
|
||||
String cssPath = getSysDir("style.css");
|
||||
if (SD.exists(cssPath))
|
||||
{
|
||||
request->send(SD, cssPath, "text/css");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback: serve minimal CSS if file not found
|
||||
request->send(404, "text/plain", "ERROR: /system/style.css not found!");
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
server.on("/script.js", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||
{
|
||||
webreq_enter();
|
||||
request->onDisconnect([](){ webreq_exit(); });
|
||||
deactivateRFID();
|
||||
activateSD();
|
||||
String jsPath = getSysDir("script.js");
|
||||
if (SD.exists(jsPath))
|
||||
{
|
||||
request->send(SD, jsPath, "application/javascript");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback: serve minimal JS if file not found
|
||||
request->send(404, "text/plain", "ERROR: /system/script.js not found!");
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Dynamic endpoints to avoid template processing heap spikes
|
||||
server.on("/directory", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||
{
|
||||
String html = processor(String("DIRECTORY"));
|
||||
request->send(200, "text/html; charset=UTF-8", html);
|
||||
});
|
||||
|
||||
server.on("/mapping", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||
{
|
||||
String html = processor(String("MAPPING"));
|
||||
request->send(200, "text/html; charset=UTF-8", html);
|
||||
});
|
||||
|
||||
server.on("/state", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||
{
|
||||
String state = getState();
|
||||
request->send(200, "application/json charset=UTF-8", state.c_str()); });
|
||||
|
||||
server.on("/start", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||
{
|
||||
|
||||
request->send(200, "text/plain charset=UTF-8", "start");
|
||||
start(); });
|
||||
|
||||
server.on("/toggleplaypause", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||
{
|
||||
|
||||
request->send(200, "text/plain charset=UTF-8", "toggleplaypause");
|
||||
togglePlayPause(); });
|
||||
|
||||
server.on("/stop", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||
{
|
||||
|
||||
request->send(200, "text/plain", "stop");
|
||||
stop(); });
|
||||
|
||||
server.on("/next", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||
{
|
||||
|
||||
request->send(200, "text/plain", "next");
|
||||
next(); });
|
||||
|
||||
server.on("/previous", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||
{
|
||||
|
||||
request->send(200, "text/plain", "previous");
|
||||
previous(); });
|
||||
|
||||
server.on("/playbyid", HTTP_GET, id_song_action);
|
||||
|
||||
server.on("/progress", HTTP_POST, progress_action);
|
||||
|
||||
server.on("/volume", HTTP_POST, volume_action);
|
||||
|
||||
server.on("/edit_mapping", HTTP_POST, editMapping);
|
||||
|
||||
// run handleUpload function when any file is uploaded
|
||||
server.on("/upload", HTTP_POST,
|
||||
[](AsyncWebServerRequest *request)
|
||||
{
|
||||
webreq_enter();
|
||||
request->onDisconnect([](){ webreq_exit(); });
|
||||
request->send(200);
|
||||
},
|
||||
handleUpload);
|
||||
|
||||
server.on("/move_file", HTTP_GET, handleMoveFile);
|
||||
server.on("/delete_file", HTTP_GET, handleDeleteFile);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
@@ -1245,111 +1383,7 @@ void setup()
|
||||
|
||||
if (wifiManager.autoConnect("HannaBox"))
|
||||
{
|
||||
|
||||
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||
{
|
||||
webrequestActive = true;
|
||||
deactivateRFID();
|
||||
activateSD();
|
||||
String htmlPath = getSysDir("index.html");
|
||||
if (SD.exists(htmlPath))
|
||||
{
|
||||
AsyncWebServerResponse *response = request->beginResponse(SD, htmlPath, "text/html", false, processor);
|
||||
response->addHeader("Content-Type", "text/html; charset=UTF-8");
|
||||
request->send(response);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback: serve minimal error if file not found
|
||||
request->send(404, "text/plain", "ERROR: /system/index.html not found!");
|
||||
}
|
||||
webrequestActive = false; });
|
||||
|
||||
server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||
{
|
||||
webrequestActive = true;
|
||||
deactivateRFID();
|
||||
activateSD();
|
||||
// Ensure SD is active and RFID is deactivated while serving files.
|
||||
String cssPath = getSysDir("style.css");
|
||||
if (SD.exists(cssPath))
|
||||
{
|
||||
request->send(SD, cssPath, "text/css");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback: serve minimal CSS if file not found
|
||||
request->send(404, "text/plain", "ERROR: /system/style.css not found!");
|
||||
}
|
||||
webrequestActive = false; });
|
||||
|
||||
server.on("/script.js", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||
{
|
||||
webrequestActive = true;
|
||||
deactivateRFID();
|
||||
activateSD();
|
||||
String jsPath = getSysDir("script.js");
|
||||
if (SD.exists(jsPath))
|
||||
{
|
||||
request->send(SD, jsPath, "application/javascript");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback: serve minimal JS if file not found
|
||||
request->send(404, "text/plain", "ERROR: /system/script.js not found!");
|
||||
}
|
||||
webrequestActive = false; });
|
||||
|
||||
server.on("/state", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||
{
|
||||
String state = getState();
|
||||
request->send(200, "application/json charset=UTF-8", state.c_str()); });
|
||||
|
||||
server.on("/start", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||
{
|
||||
|
||||
request->send(200, "text/plain charset=UTF-8", "start");
|
||||
start(); });
|
||||
|
||||
server.on("/toggleplaypause", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||
{
|
||||
|
||||
request->send(200, "text/plain charset=UTF-8", "toggleplaypause");
|
||||
togglePlayPause(); });
|
||||
|
||||
server.on("/stop", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||
{
|
||||
|
||||
request->send(200, "text/plain", "stop");
|
||||
stop(); });
|
||||
|
||||
server.on("/next", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||
{
|
||||
|
||||
request->send(200, "text/plain", "next");
|
||||
next(); });
|
||||
|
||||
server.on("/previous", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||
{
|
||||
|
||||
request->send(200, "text/plain", "previous");
|
||||
previous(); });
|
||||
|
||||
server.on("/playbyid", HTTP_GET, id_song_action);
|
||||
|
||||
server.on("/progress", HTTP_POST, progress_action);
|
||||
|
||||
server.on("/volume", HTTP_POST, volume_action);
|
||||
|
||||
server.on("/edit_mapping", HTTP_POST, editMapping);
|
||||
|
||||
// run handleUpload function when any file is uploaded
|
||||
server.on("/upload", HTTP_POST, [](AsyncWebServerRequest *request)
|
||||
{ request->send(200); }, handleUpload);
|
||||
|
||||
server.on("/move_file", HTTP_GET, handleMoveFile);
|
||||
server.on("/delete_file", HTTP_GET, handleDeleteFile);
|
||||
|
||||
init_webserver();
|
||||
server.begin();
|
||||
Serial.println("Wifi init");
|
||||
}
|
||||
@@ -1434,15 +1468,16 @@ const String getSysDir(const String filename)
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (webrequestActive && webrequest_blockings > 5000) {
|
||||
if (webreq_cnt > 0 && webrequest_blockings > 5000) {
|
||||
Serial.println("excessive webrequest blocking!");
|
||||
webreq_cnt = 0;
|
||||
webrequest_blockings = 0;
|
||||
webrequestActive = false;
|
||||
server.end();
|
||||
server.reset();
|
||||
init_webserver();
|
||||
server.begin();
|
||||
}
|
||||
|
||||
if (audio.isRunning() && !webrequestActive)
|
||||
if (audio.isRunning() && webreq_cnt == 0)
|
||||
{
|
||||
if (asyncStop)
|
||||
{
|
||||
@@ -1465,13 +1500,13 @@ void loop()
|
||||
pendingSeek = false;
|
||||
}
|
||||
}
|
||||
else if (asyncStart && !webrequestActive)
|
||||
else if (asyncStart && webreq_cnt == 0)
|
||||
{
|
||||
asyncStart = false;
|
||||
start();
|
||||
}
|
||||
|
||||
if (continuePlaying && !webrequestActive)
|
||||
if (continuePlaying && webreq_cnt == 0)
|
||||
{
|
||||
continuePlaying = false;
|
||||
startupSoundPlayed = true;
|
||||
@@ -1516,7 +1551,7 @@ void loop()
|
||||
asyncTogglePlayPause = false;
|
||||
togglePlayPause();
|
||||
}
|
||||
else if (asyncNext && !webrequestActive)
|
||||
else if (asyncNext && webreq_cnt == 0)
|
||||
{
|
||||
asyncNext = false;
|
||||
// If the play/start button is held, treat NEXT as volume up
|
||||
@@ -1585,7 +1620,7 @@ void loop()
|
||||
}
|
||||
}
|
||||
|
||||
if (loopCounter % config.rfidLoopInterval == 0 && !webrequestActive)
|
||||
if (loopCounter % config.rfidLoopInterval == 0 && webreq_cnt == 0)
|
||||
{
|
||||
deactivateSD();
|
||||
activateRFID();
|
||||
@@ -1597,7 +1632,7 @@ void loop()
|
||||
activateSD();
|
||||
}
|
||||
|
||||
if (loopCounter % VOLTAGE_LOOP_INTERVAL == 0 && !webrequestActive)
|
||||
if (loopCounter % VOLTAGE_LOOP_INTERVAL == 0 && webreq_cnt == 0)
|
||||
{
|
||||
lastVoltage = getBatteryVoltageMv();
|
||||
free_heap = xPortGetFreeHeapSize();
|
||||
@@ -1620,8 +1655,10 @@ void loop()
|
||||
}
|
||||
}
|
||||
|
||||
if (webrequestActive) {
|
||||
if (webreq_cnt>0) {
|
||||
webrequest_blockings++;
|
||||
} else {
|
||||
webrequest_blockings = 0;
|
||||
}
|
||||
|
||||
loopCounter++;
|
||||
|
||||
@@ -15,6 +15,8 @@ void progress_action(AsyncWebServerRequest *request);
|
||||
|
||||
void volume_action(AsyncWebServerRequest *request);
|
||||
|
||||
void init_webserver();
|
||||
|
||||
boolean buttonPressed(const uint8_t pin);
|
||||
|
||||
const String getSysDir(const String filename);
|
||||
|
||||
Reference in New Issue
Block a user