feat: add labels to NodeInfo

This commit is contained in:
2025-08-29 13:30:08 +02:00
parent f8e5a9c66f
commit d3a9802ec9
7 changed files with 67 additions and 12 deletions

View File

@@ -16,20 +16,27 @@ ClusterManager cluster(ctx, taskManager);
ApiServer apiServer(ctx, taskManager, ctx.config.api_server_port); ApiServer apiServer(ctx, taskManager, ctx.config.api_server_port);
void setup() { void setup() {
// Setup WiFi first // Setup WiFi first
network.setupWiFi(); network.setupWiFi();
// Initialize and start all tasks // Add example labels for this node
taskManager.initialize(); auto it = ctx.memberList->find(ctx.hostname);
if (it != ctx.memberList->end()) {
it->second.labels["app"] = "base";
it->second.labels["role"] = "demo";
}
// Start the API server // Initialize and start all tasks
apiServer.begin(); taskManager.initialize();
// Print initial task status // Start the API server
taskManager.printTaskStatus(); apiServer.begin();
// Print initial task status
taskManager.printTaskStatus();
} }
void loop() { void loop() {
taskManager.execute(); taskManager.execute();
yield(); yield();
} }

View File

@@ -349,6 +349,15 @@ NeoPixelService neoService(ctx, taskManager, NEOPIXEL_COUNT, NEOPIXEL_PIN, NEOPI
void setup() { void setup() {
network.setupWiFi(); network.setupWiFi();
// Add example labels for this node
auto it = ctx.memberList->find(ctx.hostname);
if (it != ctx.memberList->end()) {
it->second.labels["app"] = "neopixel";
it->second.labels["device"] = "light";
it->second.labels["pixels"] = String(NEOPIXEL_COUNT);
it->second.labels["pin"] = String(NEOPIXEL_PIN);
}
taskManager.initialize(); taskManager.initialize();
apiServer.begin(); apiServer.begin();

View File

@@ -107,6 +107,14 @@ void setup() {
// Setup WiFi first // Setup WiFi first
network.setupWiFi(); network.setupWiFi();
// Add example labels for this node
auto it = ctx.memberList->find(ctx.hostname);
if (it != ctx.memberList->end()) {
it->second.labels["app"] = "relay";
it->second.labels["device"] = "actuator";
it->second.labels["pin"] = String(RELAY_PIN);
}
// Initialize and start all tasks // Initialize and start all tasks
taskManager.initialize(); taskManager.initialize();

View File

@@ -3,6 +3,7 @@
#include <IPAddress.h> #include <IPAddress.h>
#include <vector> #include <vector>
#include <tuple> #include <tuple>
#include <map>
struct NodeInfo { struct NodeInfo {
String hostname; String hostname;
@@ -18,6 +19,7 @@ struct NodeInfo {
} resources; } resources;
unsigned long latency = 0; // ms since lastSeen unsigned long latency = 0; // ms since lastSeen
std::vector<std::tuple<String, int>> apiEndpoints; // List of registered endpoints std::vector<std::tuple<String, int>> apiEndpoints; // List of registered endpoints
std::map<String, String> labels; // Arbitrary node labels (key -> value)
}; };
const char* statusToStr(NodeInfo::Status status); const char* statusToStr(NodeInfo::Status status);

View File

@@ -95,6 +95,16 @@ void ApiServer::onSystemStatusRequest(AsyncWebServerRequest *request) {
apiObj["uri"] = std::get<0>(entry); apiObj["uri"] = std::get<0>(entry);
apiObj["method"] = std::get<1>(entry); apiObj["method"] = std::get<1>(entry);
} }
// Include local node labels if present
if (ctx.memberList) {
auto it = ctx.memberList->find(ctx.hostname);
if (it != ctx.memberList->end()) {
JsonObject labelsObj = doc["labels"].to<JsonObject>();
for (const auto& kv : it->second.labels) {
labelsObj[kv.first.c_str()] = kv.second;
}
}
}
String json; String json;
serializeJson(doc, json); serializeJson(doc, json);
request->send(200, "application/json", json); request->send(200, "application/json", json);
@@ -122,6 +132,13 @@ void ApiServer::onClusterMembersRequest(AsyncWebServerRequest *request) {
apiObj["uri"] = std::get<0>(endpoint); apiObj["uri"] = std::get<0>(endpoint);
methodToStr(endpoint, apiObj); methodToStr(endpoint, apiObj);
} }
// Add labels if present
if (!node.labels.empty()) {
JsonObject labelsObj = obj["labels"].to<JsonObject>();
for (const auto& kv : node.labels) {
labelsObj[kv.first.c_str()] = kv.second;
}
}
} }
String json; String json;
serializeJson(doc, json); serializeJson(doc, json);

View File

@@ -118,6 +118,16 @@ void ClusterManager::fetchNodeInfo(const IPAddress& ip) {
node.apiEndpoints.push_back(std::make_tuple(uri, method)); node.apiEndpoints.push_back(std::make_tuple(uri, method));
} }
} }
// Parse labels if present
node.labels.clear();
if (doc["labels"].is<JsonObject>()) {
JsonObject labelsObj = doc["labels"].as<JsonObject>();
for (JsonPair kvp : labelsObj) {
String k = String(kvp.key().c_str());
String v = String(labelsObj[kvp.key()]);
node.labels[k] = v;
}
}
Serial.printf("[Cluster] Fetched info for node: %s @ %s\n", node.hostname.c_str(), ip.toString().c_str()); Serial.printf("[Cluster] Fetched info for node: %s @ %s\n", node.hostname.c_str(), ip.toString().c_str());
break; break;
} }

View File

@@ -54,5 +54,7 @@ void NetworkManager::setupWiFi() {
} }
self.lastSeen = millis(); self.lastSeen = millis();
self.status = NodeInfo::ACTIVE; self.status = NodeInfo::ACTIVE;
// Initialize a default label for demonstration; users can modify at runtime
self.labels["hostname"] = ctx.hostname;
ctx.fire("node_discovered", &self); ctx.fire("node_discovered", &self);
} }