| 88 | CrossPointWebServer::~CrossPointWebServer() { stop(); } |
| 89 | |
| 90 | void CrossPointWebServer::begin() { |
| 91 | if (running) { |
| 92 | LOG_DBG("WEB", "Web server already running"); |
| 93 | return; |
| 94 | } |
| 95 | |
| 96 | // Check if we have a valid network connection (either STA connected or AP mode) |
| 97 | const wifi_mode_t wifiMode = WiFi.getMode(); |
| 98 | const bool isStaConnected = (wifiMode & WIFI_MODE_STA) && (WiFi.status() == WL_CONNECTED); |
| 99 | const bool isInApMode = (wifiMode & WIFI_MODE_AP) && (WiFi.softAPgetStationNum() >= 0); // AP is running |
| 100 | |
| 101 | if (!isStaConnected && !isInApMode) { |
| 102 | LOG_DBG("WEB", "Cannot start webserver - no valid network (mode=%d, status=%d)", wifiMode, WiFi.status()); |
| 103 | return; |
| 104 | } |
| 105 | |
| 106 | // Store AP mode flag for later use (e.g., in handleStatus) |
| 107 | apMode = isInApMode; |
| 108 | |
| 109 | LOG_DBG("WEB", "[MEM] Free heap before begin: %d bytes", ESP.getFreeHeap()); |
| 110 | LOG_DBG("WEB", "Network mode: %s", apMode ? "AP" : "STA"); |
| 111 | |
| 112 | LOG_DBG("WEB", "Creating web server on port %d...", port); |
| 113 | server.reset(new WebServer(port)); |
| 114 | |
| 115 | // Disable WiFi sleep to improve responsiveness and prevent 'unreachable' errors. |
| 116 | // This is critical for reliable web server operation on ESP32. |
| 117 | WiFi.setSleep(false); |
| 118 | // Default varies by ESP32 core version. The activity's loss-recovery loop |
| 119 | // relies on driver retries during transient disconnects. |
| 120 | WiFi.setAutoReconnect(true); |
| 121 | |
| 122 | // Note: WebServer class doesn't have setNoDelay() in the standard ESP32 library. |
| 123 | // We rely on disabling WiFi sleep for responsiveness. |
| 124 | |
| 125 | LOG_DBG("WEB", "[MEM] Free heap after WebServer allocation: %d bytes", ESP.getFreeHeap()); |
| 126 | |
| 127 | if (!server) { |
| 128 | LOG_ERR("WEB", "Failed to create WebServer!"); |
| 129 | return; |
| 130 | } |
| 131 | |
| 132 | // Setup routes |
| 133 | LOG_DBG("WEB", "Setting up routes..."); |
| 134 | server->on("/", HTTP_GET, [this] { handleRoot(); }); |
| 135 | server->on("/files", HTTP_GET, [this] { handleFileList(); }); |
| 136 | server->on("/js/jszip.min.js", HTTP_GET, [this] { handleJszip(); }); |
| 137 | |
| 138 | server->on("/api/status", HTTP_GET, [this] { handleStatus(); }); |
| 139 | server->on("/api/files", HTTP_GET, [this] { handleFileListData(); }); |
| 140 | server->on("/download", HTTP_GET, [this] { handleDownload(); }); |
| 141 | |
| 142 | // Upload endpoint with special handling for multipart form data |
| 143 | server->on("/upload", HTTP_POST, [this] { handleUploadPost(upload); }, [this] { handleUpload(upload); }); |
| 144 | |
| 145 | // Create folder endpoint |
| 146 | server->on("/mkdir", HTTP_POST, [this] { handleCreateFolder(); }); |
| 147 | |