From f4ccb1c7ef0838ee8a425824c01b77cdef03b269 Mon Sep 17 00:00:00 2001 From: Patrick Balsiger Date: Sun, 28 Sep 2025 13:35:42 +0200 Subject: [PATCH] feat(cluster): centralize cluster/broadcast event for UDP CLUSTER_EVENT send Register core handler ctx.on("cluster/broadcast") in ClusterManager to send CLUSTER_EVENT via subnet-directed UDP broadcast; services now delegate broadcasting by firing this event. Fix lambda to reference this->ctx inside handler. Update NeoPatternService to fire cluster/broadcast with event JSON instead of sending UDP directly. Improves consistency and removes duplicated UDP code in services. --- examples/neopattern/NeoPatternService.cpp | 15 +++++---------- src/spore/core/ClusterManager.cpp | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/examples/neopattern/NeoPatternService.cpp b/examples/neopattern/NeoPatternService.cpp index eb7cc85..c5db8df 100644 --- a/examples/neopattern/NeoPatternService.cpp +++ b/examples/neopattern/NeoPatternService.cpp @@ -154,7 +154,7 @@ void NeoPatternService::handleControlRequest(AsyncWebServerRequest* request) { updated = true; } - // Broadcast to peers if requested + // Broadcast to peers if requested (delegate to core broadcast handler) if (broadcast && any) { JsonDocument eventDoc; eventDoc["event"] = "api/neopattern"; @@ -163,15 +163,10 @@ void NeoPatternService::handleControlRequest(AsyncWebServerRequest* request) { String eventJson; serializeJson(eventDoc, eventJson); - // Compute subnet-directed broadcast to improve delivery on some networks - IPAddress ip = WiFi.localIP(); - IPAddress mask = WiFi.subnetMask(); - IPAddress bcast(ip[0] | ~mask[0], ip[1] | ~mask[1], ip[2] | ~mask[2], ip[3] | ~mask[3]); - LOG_INFO("NeoPattern", String("Broadcasting CLUSTER_EVENT api/neopattern to ") + bcast.toString() + " payloadLen=" + String(payloadStr.length())); - ctx.udp->beginPacket(bcast, ctx.config.udp_port); - String msg = String(ClusterProtocol::CLUSTER_EVENT_MSG) + ":" + eventJson; - ctx.udp->write(msg.c_str()); - ctx.udp->endPacket(); + LOG_INFO("NeoPattern", String("Submitting cluster/broadcast for api/neopattern payloadLen=") + String(payloadStr.length())); + std::string ev = "cluster/broadcast"; + String eventStr = eventJson; + ctx.fire(ev, &eventStr); } // Return current state diff --git a/src/spore/core/ClusterManager.cpp b/src/spore/core/ClusterManager.cpp index 0d84378..1d6e2e9 100644 --- a/src/spore/core/ClusterManager.cpp +++ b/src/spore/core/ClusterManager.cpp @@ -8,6 +8,23 @@ ClusterManager::ClusterManager(NodeContext& ctx, TaskManager& taskMgr) : ctx(ctx NodeInfo* node = static_cast(data); this->addOrUpdateNode(node->hostname, node->ip); }); + // Centralized broadcast handler: services fire 'cluster/broadcast' with CLUSTER_EVENT JSON payload + ctx.on("cluster/broadcast", [this](void* data) { + String* jsonStr = static_cast(data); + if (!jsonStr) { + LOG_WARN("Cluster", "cluster/broadcast called with null data"); + return; + } + // Subnet-directed broadcast (more reliable than 255.255.255.255 on some networks) + IPAddress ip = WiFi.localIP(); + IPAddress mask = WiFi.subnetMask(); + IPAddress bcast(ip[0] | ~mask[0], ip[1] | ~mask[1], ip[2] | ~mask[2], ip[3] | ~mask[3]); + LOG_INFO("Cluster", String("Broadcasting CLUSTER_EVENT to ") + bcast.toString() + " len=" + String(jsonStr->length())); + this->ctx.udp->beginPacket(bcast, this->ctx.config.udp_port); + String msg = String(ClusterProtocol::CLUSTER_EVENT_MSG) + ":" + *jsonStr; + this->ctx.udp->write(msg.c_str()); + this->ctx.udp->endPacket(); + }); // Register tasks registerTasks(); initMessageHandlers();