Redone protobuf receiving to be more dynamic and scalable
This commit is contained in:
@@ -8,10 +8,11 @@
|
|||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <pb_encode.h>
|
#include <pb_encode.h>
|
||||||
#include <pb_decode.h>
|
#include <pb_decode.h>
|
||||||
|
#include <platform_shared/api.pb.h>
|
||||||
|
|
||||||
using HttpGetHandler = std::function<esp_err_t(httpd_req_t*)>;
|
using HttpGetHandler = std::function<esp_err_t(httpd_req_t*)>;
|
||||||
using HttpPostHandler = std::function<esp_err_t(httpd_req_t*, JsonVariant&)>;
|
using HttpPostHandler = std::function<esp_err_t(httpd_req_t*, JsonVariant&)>;
|
||||||
using HttpRawHandler = std::function<esp_err_t(httpd_req_t*)>;
|
using HttpProtoHandler = std::function<esp_err_t(httpd_req_t*, api_Request*)>;
|
||||||
using WsFrameHandler = std::function<esp_err_t(httpd_req_t*, httpd_ws_frame_t*)>;
|
using WsFrameHandler = std::function<esp_err_t(httpd_req_t*, httpd_ws_frame_t*)>;
|
||||||
using WsOpenHandler = std::function<void(httpd_req_t*)>;
|
using WsOpenHandler = std::function<void(httpd_req_t*)>;
|
||||||
using WsCloseHandler = std::function<void(int)>;
|
using WsCloseHandler = std::function<void(int)>;
|
||||||
@@ -21,7 +22,7 @@ struct HttpRoute {
|
|||||||
httpd_method_t method;
|
httpd_method_t method;
|
||||||
HttpGetHandler getHandler;
|
HttpGetHandler getHandler;
|
||||||
HttpPostHandler postHandler;
|
HttpPostHandler postHandler;
|
||||||
HttpRawHandler rawHandler; // For proto handlers that don't need JSON parsing
|
HttpProtoHandler protoHandler; // For proto handlers that don't need JSON parsing
|
||||||
bool isWebsocket;
|
bool isWebsocket;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -36,7 +37,7 @@ class WebServer {
|
|||||||
|
|
||||||
void on(const char* uri, httpd_method_t method, HttpGetHandler handler);
|
void on(const char* uri, httpd_method_t method, HttpGetHandler handler);
|
||||||
void on(const char* uri, httpd_method_t method, HttpPostHandler handler);
|
void on(const char* uri, httpd_method_t method, HttpPostHandler handler);
|
||||||
void onRaw(const char* uri, httpd_method_t method, HttpRawHandler handler);
|
void onProto(const char* uri, httpd_method_t method, HttpProtoHandler handler);
|
||||||
|
|
||||||
void onWsFrame(WsFrameHandler handler);
|
void onWsFrame(WsFrameHandler handler);
|
||||||
void onWsOpen(WsOpenHandler handler);
|
void onWsOpen(WsOpenHandler handler);
|
||||||
|
|||||||
@@ -58,27 +58,22 @@ class StatefulProtoEndpoint {
|
|||||||
_responseAssigner(responseAssigner) {}
|
_responseAssigner(responseAssigner) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles POST requests: decodes Request, updates state, returns Response
|
* Handles POST requests: extracts payload from pre-decoded Request, updates state, returns Response
|
||||||
*/
|
*/
|
||||||
esp_err_t handleStateUpdate(httpd_req_t* request) {
|
esp_err_t handleStateUpdate(httpd_req_t* httpReq, api_Request* protoReq) {
|
||||||
api_Request req = api_Request_init_zero;
|
|
||||||
if (!NativeServer::receiveProto(request, req, api_Request_fields)) {
|
|
||||||
return sendErrorResponse(request, 400, "Failed to decode request");
|
|
||||||
}
|
|
||||||
|
|
||||||
ProtoT protoMsg = {};
|
ProtoT protoMsg = {};
|
||||||
if (!_requestExtractor(req, protoMsg)) {
|
if (!_requestExtractor(*protoReq, protoMsg)) {
|
||||||
return sendErrorResponse(request, 400, "Invalid request type");
|
return sendErrorResponse(httpReq, 400, "Invalid request type");
|
||||||
}
|
}
|
||||||
|
|
||||||
StateUpdateResult outcome = _statefulService->update(
|
StateUpdateResult outcome = _statefulService->update(
|
||||||
[this, &protoMsg](T& settings) { return _stateUpdater(protoMsg, settings); }, PROTO_ENDPOINT_ORIGIN_ID);
|
[this, &protoMsg](T& settings) { return _stateUpdater(protoMsg, settings); }, PROTO_ENDPOINT_ORIGIN_ID);
|
||||||
|
|
||||||
if (outcome == StateUpdateResult::ERROR) {
|
if (outcome == StateUpdateResult::ERROR) {
|
||||||
return sendErrorResponse(request, 400, "Invalid state");
|
return sendErrorResponse(httpReq, 400, "Invalid state");
|
||||||
}
|
}
|
||||||
|
|
||||||
return sendStateResponse(request, 200);
|
return sendStateResponse(httpReq, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -72,8 +72,45 @@ esp_err_t WebServer::httpHandler(httpd_req_t* req) {
|
|||||||
if (route.getHandler) {
|
if (route.getHandler) {
|
||||||
return route.getHandler(req);
|
return route.getHandler(req);
|
||||||
}
|
}
|
||||||
if (route.rawHandler) {
|
if (route.protoHandler) {
|
||||||
return route.rawHandler(req);
|
size_t contentLen = req->content_len;
|
||||||
|
if (contentLen == 0 || contentLen > 4096) {
|
||||||
|
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid content length");
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* buffer = (uint8_t*)malloc(contentLen);
|
||||||
|
if (!buffer) {
|
||||||
|
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Memory allocation failed");
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int received = 0;
|
||||||
|
int remaining = contentLen;
|
||||||
|
while (remaining > 0) {
|
||||||
|
int ret = httpd_req_recv(req, (char*)buffer + received, remaining);
|
||||||
|
if (ret <= 0) {
|
||||||
|
free(buffer);
|
||||||
|
if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
|
||||||
|
httpd_resp_send_err(req, HTTPD_408_REQ_TIMEOUT, "Request timeout");
|
||||||
|
}
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
received += ret;
|
||||||
|
remaining -= ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
api_Request protoReq = api_Request_init_zero;
|
||||||
|
pb_istream_t stream = pb_istream_from_buffer(buffer, contentLen);
|
||||||
|
bool success = pb_decode(&stream, api_Request_fields, &protoReq);
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Failed to decode protobuf");
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return route.protoHandler(req, &protoReq);
|
||||||
}
|
}
|
||||||
if (route.postHandler) {
|
if (route.postHandler) {
|
||||||
char* content = nullptr;
|
char* content = nullptr;
|
||||||
@@ -190,7 +227,7 @@ void WebServer::on(const char* uri, httpd_method_t method, HttpGetHandler handle
|
|||||||
route.method = method;
|
route.method = method;
|
||||||
route.getHandler = handler;
|
route.getHandler = handler;
|
||||||
route.postHandler = nullptr;
|
route.postHandler = nullptr;
|
||||||
route.rawHandler = nullptr;
|
route.protoHandler = nullptr;
|
||||||
route.isWebsocket = false;
|
route.isWebsocket = false;
|
||||||
routes_.push_back(route);
|
routes_.push_back(route);
|
||||||
|
|
||||||
@@ -205,7 +242,7 @@ void WebServer::on(const char* uri, httpd_method_t method, HttpPostHandler handl
|
|||||||
route.method = method;
|
route.method = method;
|
||||||
route.getHandler = nullptr;
|
route.getHandler = nullptr;
|
||||||
route.postHandler = handler;
|
route.postHandler = handler;
|
||||||
route.rawHandler = nullptr;
|
route.protoHandler = nullptr;
|
||||||
route.isWebsocket = false;
|
route.isWebsocket = false;
|
||||||
routes_.push_back(route);
|
routes_.push_back(route);
|
||||||
|
|
||||||
@@ -214,13 +251,13 @@ void WebServer::on(const char* uri, httpd_method_t method, HttpPostHandler handl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeServer::onRaw(const char* uri, httpd_method_t method, HttpRawHandler handler) {
|
void NativeServer::onProto(const char* uri, httpd_method_t method, HttpProtoHandler handler) {
|
||||||
HttpRoute route;
|
HttpRoute route;
|
||||||
route.uri = uri;
|
route.uri = uri;
|
||||||
route.method = method;
|
route.method = method;
|
||||||
route.getHandler = nullptr;
|
route.getHandler = nullptr;
|
||||||
route.postHandler = nullptr;
|
route.postHandler = nullptr;
|
||||||
route.rawHandler = handler;
|
route.protoHandler = handler;
|
||||||
route.isWebsocket = false;
|
route.isWebsocket = false;
|
||||||
routes_.push_back(route);
|
routes_.push_back(route);
|
||||||
|
|
||||||
@@ -246,7 +283,7 @@ void WebServer::registerWebsocket(const char* uri) {
|
|||||||
route.method = HTTP_GET;
|
route.method = HTTP_GET;
|
||||||
route.getHandler = nullptr;
|
route.getHandler = nullptr;
|
||||||
route.postHandler = nullptr;
|
route.postHandler = nullptr;
|
||||||
route.rawHandler = nullptr;
|
route.protoHandler = nullptr;
|
||||||
route.isWebsocket = true;
|
route.isWebsocket = true;
|
||||||
routes_.push_back(route);
|
routes_.push_back(route);
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -77,8 +77,10 @@ void setupServer() {
|
|||||||
server.on("/api/ap/status", HTTP_GET, [&](httpd_req_t *request) { return apService.getStatusProto(request); });
|
server.on("/api/ap/status", HTTP_GET, [&](httpd_req_t *request) { return apService.getStatusProto(request); });
|
||||||
server.on("/api/ap/settings", HTTP_GET,
|
server.on("/api/ap/settings", HTTP_GET,
|
||||||
[&](httpd_req_t *request) { return apService.protoEndpoint.getState(request); });
|
[&](httpd_req_t *request) { return apService.protoEndpoint.getState(request); });
|
||||||
server.onRaw("/api/ap/settings", HTTP_POST,
|
server.onProto("/api/ap/settings", HTTP_POST,
|
||||||
[&](httpd_req_t *request) { return apService.protoEndpoint.handleStateUpdate(request); });
|
[&](httpd_req_t *request, api_Request *protoReq) {
|
||||||
|
return apService.protoEndpoint.handleStateUpdate(request, protoReq);
|
||||||
|
});
|
||||||
|
|
||||||
server.on("/api/peripherals", HTTP_GET,
|
server.on("/api/peripherals", HTTP_GET,
|
||||||
[&](httpd_req_t *request) { return peripherals.endpoint.getState(request); });
|
[&](httpd_req_t *request) { return peripherals.endpoint.getState(request); });
|
||||||
|
|||||||
Reference in New Issue
Block a user