#include #include "GwWebServer.h" #include class EmbeddedFile; static std::map embeddedFiles; class EmbeddedFile { public: const uint8_t *start; int len; String contentType; EmbeddedFile(String name,String contentType, const uint8_t *start,int len){ this->start=start; this->len=len; this->contentType=contentType; embeddedFiles[name]=this; } } ; #define EMBED_GZ_FILE(fileName, binName, contentType) \ extern const uint8_t binName##_File[] asm("_binary_" #binName "_start"); \ extern const uint8_t binName##_FileLen[] asm("_binary_" #binName "_size"); \ const EmbeddedFile binName##_Config(fileName,contentType,(const uint8_t*)binName##_File,(int)binName##_FileLen); #include "GwEmbeddedFiles.h" void sendEmbeddedFile(String name,String contentType,AsyncWebServerRequest *request){ std::map::iterator it=embeddedFiles.find(name); if (it != embeddedFiles.end()){ EmbeddedFile* found=it->second; AsyncWebServerResponse *response=request->beginResponse_P(200,contentType,found->start,found->len); response->addHeader(F("Content-Encoding"), F("gzip")); request->send(response); } else{ request->send(404, "text/plain", "Not found"); } } GwWebServer::GwWebServer(GwLog* logger,GwRequestQueue *queue,int port){ server=new AsyncWebServer(port); this->queue=queue; this->logger=logger; } void GwWebServer::begin(){ server->onNotFound([](AsyncWebServerRequest *request){ request->send(404, "text/plain", "Not found"); }); server->on("/", HTTP_GET, [](AsyncWebServerRequest *request){ sendEmbeddedFile("index.html","text/html",request); }); for (auto it=embeddedFiles.begin();it != embeddedFiles.end();it++){ String uri=String("/")+it->first; server->on(uri.c_str(), HTTP_GET, [it](AsyncWebServerRequest *request){ sendEmbeddedFile(it->first,it->second->contentType,request); }); } server->begin(); LOG_DEBUG(GwLog::LOG,"HTTP server started"); MDNS.addService("_http","_tcp",80); } GwWebServer::~GwWebServer(){ server->end(); delete server; vQueueDelete(queue); } void GwWebServer::handleAsyncWebRequest(AsyncWebServerRequest *request, GwRequestMessage *msg) { GwRequestQueue::MessageSendStatus st=queue->sendAndWait(msg,500); if (st == GwRequestQueue::MSG_ERR) { msg->unref(); //our request->send(500, "text/plain", "queue full"); return; } if (st == GwRequestQueue::MSG_OK) { request->send(200, msg->getContentType(), msg->getResult()); msg->unref(); return; } LOG_DEBUG(GwLog::DEBUG + 1, "switching to async for %s",msg->getName().c_str()); //msg is handed over to async handling bool finished = false; AsyncWebServerResponse *r = request->beginChunkedResponse( msg->getContentType(), [this,msg, finished](uint8_t *ptr, size_t len, size_t len2) -> size_t { LOG_DEBUG(GwLog::DEBUG + 1, "try read for %s",msg->getName().c_str()); if (msg->isHandled() || msg->wait(1)) { int rt = msg->consume(ptr, len); LOG_DEBUG(GwLog::DEBUG + 1, "async response available, return %d\n", rt); return rt; } else return RESPONSE_TRY_AGAIN; }, NULL); request->onDisconnect([this,msg](void) { LOG_DEBUG(GwLog::DEBUG + 1, "onDisconnect"); msg->unref(); }); request->send(r); } bool GwWebServer::registerMainHandler(const char *url,RequestCreator creator){ server->on(url,HTTP_GET, [this,creator,url](AsyncWebServerRequest *request){ GwRequestMessage *msg=(*creator)(request); if (!msg){ LOG_DEBUG(GwLog::DEBUG,"creator returns NULL for %s",url); request->send(404, "text/plain", "Not found"); return; } handleAsyncWebRequest(request,msg); }); return true; }