#include "RuntimeControlCommand.h" namespace RenderCadenceCompositor { namespace { const JsonValue* RequireObjectField(const JsonValue& root, const char* fieldName, std::string& error) { const JsonValue* field = root.find(fieldName); if (!field) error = std::string("Request field '") + fieldName + "' is required."; return field; } bool RequireStringField(const JsonValue& root, const char* fieldName, std::string& value, std::string& error) { const JsonValue* field = RequireObjectField(root, fieldName, error); if (!field) return false; if (!field->isString() || field->asString().empty()) { error = std::string("Request field '") + fieldName + "' must be a non-empty string."; return false; } value = field->asString(); return true; } bool RequireBoolField(const JsonValue& root, const char* fieldName, bool& value, std::string& error) { const JsonValue* field = RequireObjectField(root, fieldName, error); if (!field) return false; if (!field->isBoolean()) { error = std::string("Request field '") + fieldName + "' must be a boolean."; return false; } value = field->asBoolean(); return true; } bool RequireIntegerField(const JsonValue& root, const char* fieldName, int& value, std::string& error) { const JsonValue* field = RequireObjectField(root, fieldName, error); if (!field) return false; if (!field->isNumber()) { error = std::string("Request field '") + fieldName + "' must be a number."; return false; } value = static_cast(field->asNumber()); return true; } } bool ParseRuntimeControlCommand( const std::string& path, const std::string& body, RuntimeControlCommand& command, std::string& error) { command = RuntimeControlCommand(); JsonValue root; std::string parseError; if (!ParseJson(body.empty() ? "{}" : body, root, parseError) || !root.isObject()) { error = parseError.empty() ? "Request body must be a JSON object." : parseError; return false; } if (path == "/api/layers/add") { command.type = RuntimeControlCommandType::AddLayer; return RequireStringField(root, "shaderId", command.shaderId, error); } if (path == "/api/layers/remove") { command.type = RuntimeControlCommandType::RemoveLayer; return RequireStringField(root, "layerId", command.layerId, error); } if (path == "/api/layers/reorder") { command.type = RuntimeControlCommandType::ReorderLayer; return RequireStringField(root, "layerId", command.layerId, error) && RequireIntegerField(root, "targetIndex", command.targetIndex, error); } if (path == "/api/layers/set-bypass") { command.type = RuntimeControlCommandType::SetLayerBypass; return RequireStringField(root, "layerId", command.layerId, error) && RequireBoolField(root, "bypass", command.bypass, error); } if (path == "/api/layers/set-shader") { command.type = RuntimeControlCommandType::SetLayerShader; return RequireStringField(root, "layerId", command.layerId, error) && RequireStringField(root, "shaderId", command.shaderId, error); } if (path == "/api/layers/update-parameter") { command.type = RuntimeControlCommandType::UpdateLayerParameter; const JsonValue* value = nullptr; if (!RequireStringField(root, "layerId", command.layerId, error) || !RequireStringField(root, "parameterId", command.parameterId, error)) { return false; } value = RequireObjectField(root, "value", error); if (!value) return false; command.value = *value; return true; } if (path == "/api/layers/reset-parameters") { command.type = RuntimeControlCommandType::ResetLayerParameters; return RequireStringField(root, "layerId", command.layerId, error); } command.type = RuntimeControlCommandType::Unsupported; error = "Endpoint is not implemented in RenderCadenceCompositor yet."; return false; } }