feat: implement complete JSON serialization system with response classes #7

Closed
master wants to merge 3 commits from refactoring/json-encapsulation into main
6 changed files with 55 additions and 12 deletions
Showing only changes of commit a9f56c1279 - Show all commits

View File

@@ -57,7 +57,23 @@ public:
* @param item The serializable item to add * @param item The serializable item to add
*/ */
void addItem(const util::JsonSerializable& item) { void addItem(const util::JsonSerializable& item) {
JsonArray arr = doc[collectionKey].to<JsonArray>(); if (!doc[collectionKey].is<JsonArray>()) {
doc[collectionKey] = JsonArray();
}
JsonArray arr = doc[collectionKey].as<JsonArray>();
JsonObject obj = arr.add<JsonObject>();
item.toJson(obj);
}
/**
* Add a serializable item to the collection (move version)
* @param item The serializable item to add
*/
void addItem(util::JsonSerializable&& item) {
if (!doc[collectionKey].is<JsonArray>()) {
doc[collectionKey] = JsonArray();
}
JsonArray arr = doc[collectionKey].as<JsonArray>();
JsonObject obj = arr.add<JsonObject>(); JsonObject obj = arr.add<JsonObject>();
item.toJson(obj); item.toJson(obj);
} }

View File

@@ -19,8 +19,7 @@ public:
* @param node The NodeInfo to add * @param node The NodeInfo to add
*/ */
void addNode(const NodeInfo& node) { void addNode(const NodeInfo& node) {
NodeInfoSerializable serializable(const_cast<NodeInfo&>(node)); addItem(NodeInfoSerializable(const_cast<NodeInfo&>(node)));
addItem(serializable);
} }
/** /**

View File

@@ -60,8 +60,7 @@ public:
* @param endpoint The EndpointInfo to add * @param endpoint The EndpointInfo to add
*/ */
void addEndpoint(const EndpointInfo& endpoint) { void addEndpoint(const EndpointInfo& endpoint) {
EndpointInfoSerializable serializable(endpoint); addItem(EndpointInfoSerializable(endpoint));
addItem(serializable);
} }
/** /**

View File

@@ -12,13 +12,16 @@ namespace types {
*/ */
class TaskInfoSerializable : public util::JsonSerializable { class TaskInfoSerializable : public util::JsonSerializable {
private: private:
const String& taskName; String taskName;
const JsonObject& taskData; const JsonObject& taskData;
public: public:
TaskInfoSerializable(const String& name, const JsonObject& data) TaskInfoSerializable(const String& name, const JsonObject& data)
: taskName(name), taskData(data) {} : taskName(name), taskData(data) {}
TaskInfoSerializable(const std::string& name, const JsonObject& data)
: taskName(name.c_str()), taskData(data) {}
/** /**
* Serialize task info to JsonObject * Serialize task info to JsonObject
*/ */

View File

@@ -30,7 +30,10 @@ public:
*/ */
void addTask(const String& taskName, const JsonObject& taskData) { void addTask(const String& taskName, const JsonObject& taskData) {
TaskInfoSerializable serializable(taskName, taskData); TaskInfoSerializable serializable(taskName, taskData);
JsonArray tasksArr = doc["tasks"].to<JsonArray>(); if (!doc["tasks"].is<JsonArray>()) {
doc["tasks"] = JsonArray();
}
JsonArray tasksArr = doc["tasks"].as<JsonArray>();
JsonObject taskObj = tasksArr.add<JsonObject>(); JsonObject taskObj = tasksArr.add<JsonObject>();
serializable.toJson(taskObj); serializable.toJson(taskObj);
} }
@@ -41,8 +44,11 @@ public:
* @param taskData Task data as JsonObject * @param taskData Task data as JsonObject
*/ */
void addTask(const std::string& taskName, const JsonObject& taskData) { void addTask(const std::string& taskName, const JsonObject& taskData) {
TaskInfoSerializable serializable(String(taskName.c_str()), taskData); TaskInfoSerializable serializable(taskName, taskData);
JsonArray tasksArr = doc["tasks"].to<JsonArray>(); if (!doc["tasks"].is<JsonArray>()) {
doc["tasks"] = JsonArray();
}
JsonArray tasksArr = doc["tasks"].as<JsonArray>();
JsonObject taskObj = tasksArr.add<JsonObject>(); JsonObject taskObj = tasksArr.add<JsonObject>();
serializable.toJson(taskObj); serializable.toJson(taskObj);
} }
@@ -93,6 +99,9 @@ public:
* @param taskStatuses Vector of pairs of task name to task data * @param taskStatuses Vector of pairs of task name to task data
*/ */
void buildCompleteResponse(const std::vector<std::pair<std::string, JsonObject>>& taskStatuses) { void buildCompleteResponse(const std::vector<std::pair<std::string, JsonObject>>& taskStatuses) {
// Clear the document first since getAllTaskStatuses creates a root array
doc.clear();
// Set summary // Set summary
size_t totalTasks = taskStatuses.size(); size_t totalTasks = taskStatuses.size();
size_t activeTasks = 0; size_t activeTasks = 0;
@@ -103,9 +112,23 @@ public:
} }
setSummary(totalTasks, activeTasks); setSummary(totalTasks, activeTasks);
// Add all tasks // Add all tasks - extract data before clearing to avoid invalid references
JsonArray tasksArr = doc["tasks"].to<JsonArray>();
for (const auto& pair : taskStatuses) { for (const auto& pair : taskStatuses) {
addTask(pair.first, pair.second); // Extract data from JsonObject before it becomes invalid
String taskName = pair.first.c_str();
unsigned long interval = pair.second["interval"];
bool enabled = pair.second["enabled"];
bool running = pair.second["running"];
bool autoStart = pair.second["autoStart"];
// Create new JsonObject in our document
JsonObject taskObj = tasksArr.add<JsonObject>();
taskObj["name"] = taskName;
taskObj["interval"] = interval;
taskObj["enabled"] = enabled;
taskObj["running"] = running;
taskObj["autoStart"] = autoStart;
} }
// Set system info // Set system info

View File

@@ -36,10 +36,13 @@ void TaskService::registerEndpoints(ApiServer& api) {
} }
void TaskService::handleStatusRequest(AsyncWebServerRequest* request) { void TaskService::handleStatusRequest(AsyncWebServerRequest* request) {
TaskStatusResponse response;
// Get task statuses using a separate document to avoid reference issues
JsonDocument scratch; JsonDocument scratch;
auto taskStatuses = taskManager.getAllTaskStatuses(scratch); auto taskStatuses = taskManager.getAllTaskStatuses(scratch);
TaskStatusResponse response; // Build the complete response with the task data
response.buildCompleteResponse(taskStatuses); response.buildCompleteResponse(taskStatuses);
request->send(200, "application/json", response.toJsonString()); request->send(200, "application/json", response.toJsonString());
} }