#ifndef HttpEndpoint_h #define HttpEndpoint_h #include #include #include #include #define HTTP_ENDPOINT_ORIGIN_ID "http" using namespace std::placeholders; // for `_1` etc template class HttpGetEndpoint { public: HttpGetEndpoint(JsonStateReader stateReader, StatefulService * statefulService, AsyncWebServer * server, const String & servicePath, SecurityManager * securityManager, AuthenticationPredicate authenticationPredicate = AuthenticationPredicates::IS_ADMIN, size_t bufferSize = DEFAULT_BUFFER_SIZE) : _stateReader(stateReader) , _statefulService(statefulService) , _bufferSize(bufferSize) { server->on(servicePath.c_str(), HTTP_GET, securityManager->wrapRequest(std::bind(&HttpGetEndpoint::fetchSettings, this, _1), authenticationPredicate)); } HttpGetEndpoint(JsonStateReader stateReader, StatefulService * statefulService, AsyncWebServer * server, const String & servicePath, size_t bufferSize = DEFAULT_BUFFER_SIZE) : _stateReader(stateReader) , _statefulService(statefulService) , _bufferSize(bufferSize) { server->on(servicePath.c_str(), HTTP_GET, std::bind(&HttpGetEndpoint::fetchSettings, this, _1)); } protected: JsonStateReader _stateReader; StatefulService * _statefulService; size_t _bufferSize; void fetchSettings(AsyncWebServerRequest * request) { AsyncJsonResponse * response = new AsyncJsonResponse(false, _bufferSize); JsonObject jsonObject = response->getRoot().to(); _statefulService->read(jsonObject, _stateReader); response->setLength(); request->send(response); } }; template class HttpPostEndpoint { public: HttpPostEndpoint(JsonStateReader stateReader, JsonStateUpdater stateUpdater, StatefulService * statefulService, AsyncWebServer * server, const String & servicePath, SecurityManager * securityManager, AuthenticationPredicate authenticationPredicate = AuthenticationPredicates::IS_ADMIN, size_t bufferSize = DEFAULT_BUFFER_SIZE) : _stateReader(stateReader) , _stateUpdater(stateUpdater) , _statefulService(statefulService) , _updateHandler(servicePath, securityManager->wrapCallback(std::bind(&HttpPostEndpoint::updateSettings, this, _1, _2), authenticationPredicate), bufferSize) , _bufferSize(bufferSize) { _updateHandler.setMethod(HTTP_POST); server->addHandler(&_updateHandler); } HttpPostEndpoint(JsonStateReader stateReader, JsonStateUpdater stateUpdater, StatefulService * statefulService, AsyncWebServer * server, const String & servicePath, size_t bufferSize = DEFAULT_BUFFER_SIZE) : _stateReader(stateReader) , _stateUpdater(stateUpdater) , _statefulService(statefulService) , _updateHandler(servicePath, std::bind(&HttpPostEndpoint::updateSettings, this, _1, _2), bufferSize) , _bufferSize(bufferSize) { _updateHandler.setMethod(HTTP_POST); server->addHandler(&_updateHandler); } protected: JsonStateReader _stateReader; JsonStateUpdater _stateUpdater; StatefulService * _statefulService; AsyncCallbackJsonWebHandler _updateHandler; size_t _bufferSize; void updateSettings(AsyncWebServerRequest * request, JsonVariant & json) { if (!json.is()) { request->send(400); return; } JsonObject jsonObject = json.as(); StateUpdateResult outcome = _statefulService->updateWithoutPropagation(jsonObject, _stateUpdater); if (outcome == StateUpdateResult::ERROR) { request->send(400); return; } else if ((outcome == StateUpdateResult::CHANGED) || (outcome == StateUpdateResult::CHANGED_RESTART)) { request->onDisconnect([this]() { _statefulService->callUpdateHandlers(HTTP_ENDPOINT_ORIGIN_ID); }); } AsyncJsonResponse * response = new AsyncJsonResponse(false, _bufferSize); jsonObject = response->getRoot().to(); _statefulService->read(jsonObject, _stateReader); response->setLength(); if (outcome == StateUpdateResult::CHANGED_RESTART) { response->setCode(205); // reboot required } request->send(response); } }; template class HttpEndpoint : public HttpGetEndpoint, public HttpPostEndpoint { public: HttpEndpoint(JsonStateReader stateReader, JsonStateUpdater stateUpdater, StatefulService * statefulService, AsyncWebServer * server, const String & servicePath, SecurityManager * securityManager, AuthenticationPredicate authenticationPredicate = AuthenticationPredicates::IS_ADMIN, size_t bufferSize = DEFAULT_BUFFER_SIZE) : HttpGetEndpoint(stateReader, statefulService, server, servicePath, securityManager, authenticationPredicate, bufferSize) , HttpPostEndpoint(stateReader, stateUpdater, statefulService, server, servicePath, securityManager, authenticationPredicate, bufferSize) { } HttpEndpoint(JsonStateReader stateReader, JsonStateUpdater stateUpdater, StatefulService * statefulService, AsyncWebServer * server, const String & servicePath, size_t bufferSize = DEFAULT_BUFFER_SIZE) : HttpGetEndpoint(stateReader, statefulService, server, servicePath, bufferSize) , HttpPostEndpoint(stateReader, stateUpdater, statefulService, server, servicePath, bufferSize) { } }; #endif