feat(gateway_network): integrate GatewayBridgeService and add bridge handling

- Updated CMakeLists.txt to require gateway_bridge component.
- Modified GatewayNetworkService to include a pointer to GatewayBridgeService.
- Added new HTTP handlers for bridge GET and POST requests.
- Implemented query utility functions for handling request parameters.
- Enhanced response handling for bridge actions with JSON responses.

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
Tony
2026-05-01 03:54:02 +08:00
parent 2c1aa28d4f
commit d16c289626
19 changed files with 3186 additions and 10 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
idf_component_register(
SRCS "src/gateway_network.cpp"
INCLUDE_DIRS "include"
REQUIRES dali_domain esp_event esp_http_server esp_netif esp_wifi freertos gateway_controller gateway_runtime log lwip espressif__cjson
REQUIRES dali_domain esp_event esp_http_server esp_netif esp_wifi freertos gateway_bridge gateway_controller gateway_runtime log lwip espressif__cjson
)
set_property(TARGET ${COMPONENT_LIB} PROPERTY CXX_STANDARD 17)
@@ -21,6 +21,7 @@ namespace gateway {
class GatewayController;
class DaliDomainService;
class GatewayBridgeService;
struct DaliRawFrame;
struct GatewayNetworkServiceConfig {
@@ -48,7 +49,9 @@ struct GatewayNetworkServiceConfig {
class GatewayNetworkService {
public:
GatewayNetworkService(GatewayController& controller, GatewayRuntime& runtime,
DaliDomainService& dali_domain, GatewayNetworkServiceConfig config = {});
DaliDomainService& dali_domain,
GatewayNetworkServiceConfig config = {},
GatewayBridgeService* bridge_service = nullptr);
esp_err_t start();
@@ -58,6 +61,8 @@ class GatewayNetworkService {
static esp_err_t HandleInfoGet(httpd_req_t* req);
static esp_err_t HandleCommandGet(httpd_req_t* req);
static esp_err_t HandleCommandPost(httpd_req_t* req);
static esp_err_t HandleBridgeGet(httpd_req_t* req);
static esp_err_t HandleBridgePost(httpd_req_t* req);
static esp_err_t HandleLedOnGet(httpd_req_t* req);
static esp_err_t HandleLedOffGet(httpd_req_t* req);
static esp_err_t HandleJqJsGet(httpd_req_t* req);
@@ -91,12 +96,14 @@ class GatewayNetworkService {
std::string deviceInfoJson() const;
std::string deviceInfoDoubleEncodedJson() const;
std::string gatewaySnapshotJson();
esp_err_t sendBridgeResponse(httpd_req_t* req, bool post);
void setStatusLed(bool on);
GatewayController& controller_;
GatewayRuntime& runtime_;
DaliDomainService& dali_domain_;
GatewayNetworkServiceConfig config_;
GatewayBridgeService* bridge_service_{nullptr};
bool started_{false};
httpd_handle_t http_server_{nullptr};
esp_netif_t* wifi_sta_netif_{nullptr};
@@ -1,6 +1,7 @@
#include "gateway_network.hpp"
#include "dali_domain.hpp"
#include "gateway_bridge.hpp"
#include "gateway_controller.hpp"
#include "gateway_runtime.hpp"
@@ -18,6 +19,7 @@
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <string_view>
#include <utility>
#include <vector>
@@ -182,14 +184,79 @@ esp_err_t RegisterUri(httpd_handle_t server, const char* uri, httpd_method_t met
return httpd_register_uri_handler(server, &route);
}
std::string QueryValue(httpd_req_t* req, const char* key) {
if (req == nullptr || key == nullptr) {
return {};
}
const size_t len = httpd_req_get_url_query_len(req) + 1;
if (len <= 1) {
return {};
}
std::string query(len, '\0');
if (httpd_req_get_url_query_str(req, query.data(), query.size()) != ESP_OK) {
return {};
}
char value[64] = {0};
if (httpd_query_key_value(query.c_str(), key, value, sizeof(value)) != ESP_OK) {
return {};
}
return std::string(value);
}
std::string QueryString(httpd_req_t* req) {
if (req == nullptr) {
return {};
}
const size_t len = httpd_req_get_url_query_len(req) + 1;
if (len <= 1) {
return {};
}
std::string query(len, '\0');
if (httpd_req_get_url_query_str(req, query.data(), query.size()) != ESP_OK) {
return {};
}
if (!query.empty() && query.back() == '\0') {
query.pop_back();
}
return query;
}
std::optional<uint8_t> QueryGatewayId(httpd_req_t* req) {
const auto raw = QueryValue(req, "gw");
if (raw.empty()) {
return std::nullopt;
}
char* end = nullptr;
const long parsed = std::strtol(raw.c_str(), &end, 10);
if (end == raw.c_str() || *end != '\0' || parsed < 0 || parsed > 255) {
return std::nullopt;
}
return static_cast<uint8_t>(parsed);
}
esp_err_t SendJsonResponse(httpd_req_t* req, const GatewayBridgeHttpResponse& response) {
if (response.err == ESP_ERR_INVALID_ARG) {
return httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, response.body.c_str());
}
if (response.err == ESP_ERR_NOT_FOUND) {
return httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, response.body.c_str());
}
if (response.err != ESP_OK) {
return httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, response.body.c_str());
}
httpd_resp_set_type(req, "application/json");
return httpd_resp_send(req, response.body.data(), response.body.size());
}
} // namespace
GatewayNetworkService::GatewayNetworkService(GatewayController& controller,
GatewayRuntime& runtime,
DaliDomainService& dali_domain,
GatewayNetworkServiceConfig config)
GatewayNetworkServiceConfig config,
GatewayBridgeService* bridge_service)
: controller_(controller), runtime_(runtime), dali_domain_(dali_domain), config_(config),
udp_lock_(xSemaphoreCreateMutex()) {}
bridge_service_(bridge_service), udp_lock_(xSemaphoreCreateMutex()) {}
esp_err_t GatewayNetworkService::start() {
if (started_) {
@@ -635,6 +702,8 @@ esp_err_t GatewayNetworkService::startHttpServer() {
{"/info", HTTP_GET, &GatewayNetworkService::HandleInfoGet},
{"/dali/cmd", HTTP_GET, &GatewayNetworkService::HandleCommandGet},
{"/dali/cmd", HTTP_POST, &GatewayNetworkService::HandleCommandPost},
{"/bridge", HTTP_GET, &GatewayNetworkService::HandleBridgeGet},
{"/bridge", HTTP_POST, &GatewayNetworkService::HandleBridgePost},
{"/led/1", HTTP_GET, &GatewayNetworkService::HandleLedOnGet},
{"/led/0", HTTP_GET, &GatewayNetworkService::HandleLedOffGet},
{"/jq.js", HTTP_GET, &GatewayNetworkService::HandleJqJsGet},
@@ -1227,6 +1296,42 @@ esp_err_t GatewayNetworkService::HandleCommandPost(httpd_req_t* req) {
return httpd_resp_sendstr(req, "ok");
}
esp_err_t GatewayNetworkService::HandleBridgeGet(httpd_req_t* req) {
auto* service = static_cast<GatewayNetworkService*>(req->user_ctx);
if (service == nullptr) {
return ESP_FAIL;
}
return service->sendBridgeResponse(req, false);
}
esp_err_t GatewayNetworkService::HandleBridgePost(httpd_req_t* req) {
auto* service = static_cast<GatewayNetworkService*>(req->user_ctx);
if (service == nullptr) {
return ESP_FAIL;
}
return service->sendBridgeResponse(req, true);
}
esp_err_t GatewayNetworkService::sendBridgeResponse(httpd_req_t* req, bool post) {
if (bridge_service_ == nullptr) {
return httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "Bridge service is not enabled");
}
const std::string action = QueryValue(req, "action");
const auto gateway_id = QueryGatewayId(req);
const int selected_gateway_id = gateway_id.has_value() ? gateway_id.value() : -1;
if (!post) {
return SendJsonResponse(req, bridge_service_->handleGet(action, selected_gateway_id,
QueryString(req)));
}
std::string body;
if (ReadRequestBody(req, body) != ESP_OK) {
return httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Bad Request");
}
return SendJsonResponse(req, bridge_service_->handlePost(action, selected_gateway_id, body));
}
esp_err_t GatewayNetworkService::HandleLedOnGet(httpd_req_t* req) {
auto* service = static_cast<GatewayNetworkService*>(req->user_ctx);
if (service == nullptr) {