feat: serve static files, relay example

This commit is contained in:
2025-09-16 12:12:27 +02:00
parent 0b63efece0
commit 2d85f560bb
11 changed files with 834 additions and 100 deletions

View File

@@ -81,6 +81,11 @@ void ApiServer::addService(Service& service) {
LOG_INFO(ctx, "API", "Added service: " + String(service.getName()));
}
void ApiServer::serveStatic(const String& uri, fs::FS& fs, const String& path, const String& cache_header) {
server.serveStatic(uri.c_str(), fs, path.c_str(), cache_header.c_str()).setDefaultFile("index.html");
LOG_INFO(ctx, "API", "Registered static file serving: " + uri + " -> " + path);
}
void ApiServer::begin() {
// Register all service endpoints
for (auto& service : services) {

View File

@@ -16,95 +16,7 @@ void StaticFileService::registerEndpoints(ApiServer& api) {
}
LOG_INFO(ctx, "StaticFileService", "LittleFS mounted successfully");
// Root endpoint - serve index.html
api.addEndpoint("/", HTTP_GET,
[this](AsyncWebServerRequest* request) { handleRootRequest(request); },
std::vector<ParamSpec>{});
// Static file serving for any path
api.addEndpoint("/*", HTTP_GET,
[this](AsyncWebServerRequest* request) { handleStaticFileRequest(request); },
std::vector<ParamSpec>{});
// Use the built-in static file serving from ESPAsyncWebServer
api.serveStatic("/", LittleFS, "/public", "max-age=3600");
}
void StaticFileService::handleRootRequest(AsyncWebServerRequest* request) {
// Serve index.html from root
String path = "/index.html";
if (!fileExists(path)) {
request->send(404, "text/plain", "File not found");
return;
}
File file = LittleFS.open(path, "r");
if (!file) {
request->send(500, "text/plain", "Failed to open file");
return;
}
String contentType = getContentType(path);
request->send(LittleFS, path, contentType);
file.close();
}
void StaticFileService::handleStaticFileRequest(AsyncWebServerRequest* request) {
String path = request->url();
// Remove leading slash for LittleFS path
if (path.startsWith("/")) {
path = path.substring(1);
}
// If path is empty or just "/", serve index.html
if (path.isEmpty() || path == "/") {
path = "index.html";
}
// Check if file exists
if (!fileExists("/" + path)) {
request->send(404, "text/plain", "File not found: " + path);
return;
}
String contentType = getContentType(path);
request->send(LittleFS, "/" + path, contentType);
}
void StaticFileService::handleNotFound(AsyncWebServerRequest* request) {
// Try to serve index.html as fallback
if (fileExists("/index.html")) {
request->send(LittleFS, "/index.html", "text/html");
} else {
request->send(404, "text/plain", "Not found");
}
}
String StaticFileService::getContentType(const String& filename) {
if (filename.endsWith(".html") || filename.endsWith(".htm")) {
return "text/html";
} else if (filename.endsWith(".css")) {
return "text/css";
} else if (filename.endsWith(".js")) {
return "application/javascript";
} else if (filename.endsWith(".json")) {
return "application/json";
} else if (filename.endsWith(".png")) {
return "image/png";
} else if (filename.endsWith(".jpg") || filename.endsWith(".jpeg")) {
return "image/jpeg";
} else if (filename.endsWith(".gif")) {
return "image/gif";
} else if (filename.endsWith(".svg")) {
return "image/svg+xml";
} else if (filename.endsWith(".ico")) {
return "image/x-icon";
} else if (filename.endsWith(".txt")) {
return "text/plain";
} else {
return "application/octet-stream";
}
}
bool StaticFileService::fileExists(const String& path) {
return LittleFS.exists(path);
}