From b9a72c8b49b24efcfddf5b3833398ed6315fb0ed Mon Sep 17 00:00:00 2001 From: xIronic Date: Thu, 20 Feb 2025 21:04:54 +0100 Subject: [PATCH 1/7] Implemented a method to receive and store a snapshot of the current image via JSON. --- include/api/JsonAPI.h | 6 ++- include/api/JsonApiCommand.h | 7 +++- .../schema-getcurrentimage.json | 19 +++++++++ libsrc/api/JSONRPC_schema/schema.json | 2 +- libsrc/api/JSONRPC_schemas.qrc | 1 + libsrc/api/JsonAPI.cpp | 42 +++++++++++++++++++ 6 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 libsrc/api/JSONRPC_schema/schema-getcurrentimage.json diff --git a/include/api/JsonAPI.h b/include/api/JsonAPI.h index a5a54065..2c342210 100644 --- a/include/api/JsonAPI.h +++ b/include/api/JsonAPI.h @@ -285,6 +285,11 @@ private: /// void handleSystemCommand(const QJsonObject &message, const JsonApiCommand& cmd); + /// @brief Handle an incoming JSON message for actions related to the current image + /// @param message the incoming message + /// + void handleGetCurrentImageCommand(const QJsonObject &message, const JsonApiCommand& cmd); + void applyColorAdjustments(const QJsonObject &adjustment, ColorAdjustment *colorAdjustment); void applyColorAdjustment(const QString &colorName, const QJsonObject &adjustment, RgbChannelAdjustment &rgbAdjustment); void applyGammaTransform(const QString &transformName, const QJsonObject &adjustment, RgbTransform &rgbTransform, char channel); @@ -403,5 +408,4 @@ private: // The JsonCallbacks instance which handles data subscription/notifications QSharedPointer _jsonCB; - }; diff --git a/include/api/JsonApiCommand.h b/include/api/JsonApiCommand.h index 4345b56a..5e7f80b4 100644 --- a/include/api/JsonApiCommand.h +++ b/include/api/JsonApiCommand.h @@ -34,7 +34,8 @@ public: System, Temperature, Transform, - VideoMode + VideoMode, + GetCurrentImage }; static QString toString(Type type) { @@ -65,6 +66,7 @@ public: case Transform: return "transform"; case VideoMode: return "videomode"; case Service: return "service"; + case GetCurrentImage: return "getcurrentimage"; default: return "unknown"; } } @@ -322,7 +324,8 @@ public: { {"system", "toggleIdle"}, { Command::System, SubCommand::ToggleIdle, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} }, { {"temperature", ""}, { Command::Temperature, SubCommand::Empty, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::Yes} }, { {"transform", ""}, { Command::Transform, SubCommand::Empty, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::Yes} }, - { {"videomode", ""}, { Command::VideoMode, SubCommand::Empty, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} } + { {"videomode", ""}, { Command::VideoMode, SubCommand::Empty, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} }, + { {"getcurrentimage", ""}, { Command::GetCurrentImage, SubCommand::Empty, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} } }; return commandLookup; } diff --git a/libsrc/api/JSONRPC_schema/schema-getcurrentimage.json b/libsrc/api/JSONRPC_schema/schema-getcurrentimage.json new file mode 100644 index 00000000..e7e63f50 --- /dev/null +++ b/libsrc/api/JSONRPC_schema/schema-getcurrentimage.json @@ -0,0 +1,19 @@ +{ + "type":"object", + "required":true, + "properties":{ + "command": { + "type" : "string", + "required" : true, + "enum" : ["getcurrentimage"] + }, + "tan" : { + "type" : "integer" + }, + "path": { + "type": "string", + "required": false + } + }, + "additionalProperties": false +} diff --git a/libsrc/api/JSONRPC_schema/schema.json b/libsrc/api/JSONRPC_schema/schema.json index 4f742b2b..6bcd4403 100644 --- a/libsrc/api/JSONRPC_schema/schema.json +++ b/libsrc/api/JSONRPC_schema/schema.json @@ -5,7 +5,7 @@ "command": { "type" : "string", "required" : true, - "enum": [ "color", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "adjustment", "sourceselect", "config", "componentstate", "ledcolors", "logging", "processing", "sysinfo", "videomode", "authorize", "instance", "leddevice", "inputsource", "service", "system", "transform", "correction", "temperature" ] + "enum": [ "color", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "adjustment", "sourceselect", "config", "componentstate", "ledcolors", "logging", "processing", "sysinfo", "videomode", "authorize", "instance", "leddevice", "inputsource", "service", "system", "transform", "correction", "temperature", "getcurrentimage" ] } } } diff --git a/libsrc/api/JSONRPC_schemas.qrc b/libsrc/api/JSONRPC_schemas.qrc index 60e1c171..3782712c 100644 --- a/libsrc/api/JSONRPC_schemas.qrc +++ b/libsrc/api/JSONRPC_schemas.qrc @@ -4,6 +4,7 @@ JSONRPC_schema/schema-color.json JSONRPC_schema/schema-image.json JSONRPC_schema/schema-serverinfo.json + JSONRPC_schema/schema-getcurrentimage.json JSONRPC_schema/schema-sysinfo.json JSONRPC_schema/schema-clear.json JSONRPC_schema/schema-clearall.json diff --git a/libsrc/api/JsonAPI.cpp b/libsrc/api/JsonAPI.cpp index 96dc365d..3f9b702f 100644 --- a/libsrc/api/JsonAPI.cpp +++ b/libsrc/api/JsonAPI.cpp @@ -393,11 +393,53 @@ void JsonAPI::handleCommand(const JsonApiCommand& cmd, const QJsonObject &messag sendErrorReply("The command is deprecated, please use the Hyperion Web Interface to configure", cmd); break; // END + case Command::GetCurrentImage: + handleGetCurrentImageCommand(message, cmd); + break; default: break; } } +void JsonAPI::handleGetCurrentImageCommand(const QJsonObject &message, const JsonApiCommand& cmd) +{ + QString replyMsg; + + Debug(_log, "Get image command received"); + QString savePath = message["path"].toString(); + + Debug(_log,"Save path: %s", QSTRING_CSTR(savePath)); + + int priority = _hyperion->getCurrentPriority(); + const PriorityMuxer::InputInfo priorityInfo = _hyperion->getPriorityInfo(priority); + Image image = priorityInfo.image; + + QImage jpgImage(reinterpret_cast(image.memptr()), image.width(), image.height(), qsizetype(3) * image.width(), QImage::Format_RGB888); + QByteArray byteArray; + QBuffer buffer(&byteArray); + buffer.open(QIODevice::WriteOnly); + jpgImage.save(&buffer, "JPG"); + QString base64Image = QString::fromLatin1(byteArray.toBase64().data()); + if (!savePath.isEmpty()) + { + if (!jpgImage.save(savePath, "JPG")) + { + replyMsg = "Failed to save image to: " + savePath; + sendErrorReply(replyMsg, cmd); + return; + } + } + + QJsonObject info; + info["path"] = savePath; + info["format"] = "JPG"; + info["width"] = image.width(); + info["height"] = image.height(); + info["size"] = image.width() * image.height() * 3; + info["data"] = base64Image; + sendSuccessDataReply(info, cmd); +} + void JsonAPI::handleColorCommand(const QJsonObject &message, const JsonApiCommand& cmd) { emit forwardJsonMessage(message); From e7c46f4c9e536137ae8f8b1ad0874a8c13b58ff6 Mon Sep 17 00:00:00 2001 From: xIronic Date: Thu, 20 Feb 2025 21:18:47 +0100 Subject: [PATCH 2/7] Updated changelog for the implemented method to receive a snapshot of the current image via JSON-API --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a4a901b5..20c01dca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Support direct or multiple instance addressing via single requests (#809) - Support of `serverinfo` subcommands: `getInfo, subscribe, unsubscribe, getSubscriptions, getSubscriptionCommands` - [Overview](https://github.com/hyperion-project/hyperion.ng/blob/API_Auth/doc/development/JSON-API%20_Commands_Overview.md) of API commands and subscription updates +- Support for requesting a snapshot of the current image via JSON response of a base64 string. Also added the ability to specify a path to save a jpg to disk ### Changed From a30e67fc112765233868eca694884b7620b17a8c Mon Sep 17 00:00:00 2001 From: xIronic Date: Sun, 23 Feb 2025 20:57:01 +0100 Subject: [PATCH 3/7] Updated behaviour of the API to handle instance data requests such as getImageSnapshot and getLedSnapshot. --- include/api/JsonAPI.h | 21 +- include/api/JsonApiCommand.h | 16 +- .../schema-getcurrentimage.json | 19 - .../JSONRPC_schema/schema-instancedata.json | 29 + libsrc/api/JSONRPC_schema/schema.json | 2 +- libsrc/api/JSONRPC_schemas.qrc | 2 +- libsrc/api/JsonAPI.cpp | 735 ++++++++++-------- 7 files changed, 487 insertions(+), 337 deletions(-) delete mode 100644 libsrc/api/JSONRPC_schema/schema-getcurrentimage.json create mode 100644 libsrc/api/JSONRPC_schema/schema-instancedata.json diff --git a/include/api/JsonAPI.h b/include/api/JsonAPI.h index 2c342210..7b267e4a 100644 --- a/include/api/JsonAPI.h +++ b/include/api/JsonAPI.h @@ -285,10 +285,24 @@ private: /// void handleSystemCommand(const QJsonObject &message, const JsonApiCommand& cmd); - /// @brief Handle an incoming JSON message for actions related to the current image + /// Handle an incoming data request message + /// + /// @param message the incoming message + /// + void handleInstanceDataCommand(const QJsonObject &message, const JsonApiCommand& cmd); + + /// Handle an incoming JSON message to request the current image + /// /// @param message the incoming message /// - void handleGetCurrentImageCommand(const QJsonObject &message, const JsonApiCommand& cmd); + void handleGetImageSnapshotCommand(const QJsonObject &message, const JsonApiCommand& cmd); + + /// Handle an incoming JSON message to request the current led colors + /// + /// @param message the incoming message + /// + void handleGetLedSnapshotCommand(const QJsonObject &message, const JsonApiCommand& cmd); + void applyColorAdjustments(const QJsonObject &adjustment, ColorAdjustment *colorAdjustment); void applyColorAdjustment(const QString &colorName, const QJsonObject &adjustment, RgbChannelAdjustment &rgbAdjustment); @@ -408,4 +422,7 @@ private: // The JsonCallbacks instance which handles data subscription/notifications QSharedPointer _jsonCB; + + + }; diff --git a/include/api/JsonApiCommand.h b/include/api/JsonApiCommand.h index 5e7f80b4..9d31d5f7 100644 --- a/include/api/JsonApiCommand.h +++ b/include/api/JsonApiCommand.h @@ -23,6 +23,7 @@ public: Image, InputSource, Instance, + InstanceData, LedColors, LedDevice, Logging, @@ -34,8 +35,7 @@ public: System, Temperature, Transform, - VideoMode, - GetCurrentImage + VideoMode }; static QString toString(Type type) { @@ -54,6 +54,7 @@ public: case Image: return "image"; case InputSource: return "inputsource"; case Instance: return "instance"; + case InstanceData: return "instance-data"; case LedColors: return "ledcolors"; case LedDevice: return "leddevice"; case Logging: return "logging"; @@ -66,7 +67,6 @@ public: case Transform: return "transform"; case VideoMode: return "videomode"; case Service: return "service"; - case GetCurrentImage: return "getcurrentimage"; default: return "unknown"; } } @@ -87,7 +87,9 @@ public: Discover, GetConfig, GetConfigOld, + GetImageSnapshot, GetInfo, + GetLedSnapshot, GetPendingTokenRequests, GetProperties, GetSchema, @@ -138,7 +140,9 @@ public: case Discover: return "discover"; case GetConfig: return "getconfig"; case GetConfigOld: return "getconfig-old"; + case GetImageSnapshot: return "getImageSnapshot"; case GetInfo: return "getInfo"; + case GetLedSnapshot: return "getLedSnapshot"; case GetPendingTokenRequests: return "getPendingTokenRequests"; case GetProperties: return "getProperties"; case GetSchema: return "getschema"; @@ -296,6 +300,9 @@ public: { {"instance", "startInstance"}, { Command::Instance, SubCommand::StartInstance, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} }, { {"instance", "stopInstance"}, { Command::Instance, SubCommand::StopInstance, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} }, { {"instance", "switchTo"}, { Command::Instance, SubCommand::SwitchTo, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} }, + { {"instance-data", ""}, { Command::InstanceData, SubCommand::Empty, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::Yes} }, + { {"instance-data", "getImageSnapshot"}, { Command::InstanceData, SubCommand::GetImageSnapshot, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::Yes} }, + { {"instance-data", "getLedSnapshot"}, { Command::InstanceData, SubCommand::GetLedSnapshot, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::Yes } }, { {"ledcolors", "imagestream-start"}, { Command::LedColors, SubCommand::ImageStreamStart, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::Yes} }, { {"ledcolors", "imagestream-stop"}, { Command::LedColors, SubCommand::ImageStreamStop, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::Yes} }, { {"ledcolors", "ledstream-start"}, { Command::LedColors, SubCommand::LedStreamStart, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::Yes} }, @@ -324,8 +331,7 @@ public: { {"system", "toggleIdle"}, { Command::System, SubCommand::ToggleIdle, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} }, { {"temperature", ""}, { Command::Temperature, SubCommand::Empty, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::Yes} }, { {"transform", ""}, { Command::Transform, SubCommand::Empty, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::Yes} }, - { {"videomode", ""}, { Command::VideoMode, SubCommand::Empty, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} }, - { {"getcurrentimage", ""}, { Command::GetCurrentImage, SubCommand::Empty, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} } + { {"videomode", ""}, { Command::VideoMode, SubCommand::Empty, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} } }; return commandLookup; } diff --git a/libsrc/api/JSONRPC_schema/schema-getcurrentimage.json b/libsrc/api/JSONRPC_schema/schema-getcurrentimage.json deleted file mode 100644 index e7e63f50..00000000 --- a/libsrc/api/JSONRPC_schema/schema-getcurrentimage.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type":"object", - "required":true, - "properties":{ - "command": { - "type" : "string", - "required" : true, - "enum" : ["getcurrentimage"] - }, - "tan" : { - "type" : "integer" - }, - "path": { - "type": "string", - "required": false - } - }, - "additionalProperties": false -} diff --git a/libsrc/api/JSONRPC_schema/schema-instancedata.json b/libsrc/api/JSONRPC_schema/schema-instancedata.json new file mode 100644 index 00000000..a49f0348 --- /dev/null +++ b/libsrc/api/JSONRPC_schema/schema-instancedata.json @@ -0,0 +1,29 @@ +{ + "type":"object", + "required":true, + "properties":{ + "command": { + "type" : "string", + "required" : true, + "enum" : ["instance-data"] + }, + "subcommand" : { + "type" : "string", + "required" : true, + "enum" : ["getImageSnapshot","getLedSnapshot"] + }, + "instance" : { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "filetype" : { + "type" : "string", + "enum" : ["BMP","JPG","PNG"] + }, + "tan" : { + "type" : "integer" + } + }, + "additionalProperties": false +} diff --git a/libsrc/api/JSONRPC_schema/schema.json b/libsrc/api/JSONRPC_schema/schema.json index 6bcd4403..327f18b8 100644 --- a/libsrc/api/JSONRPC_schema/schema.json +++ b/libsrc/api/JSONRPC_schema/schema.json @@ -5,7 +5,7 @@ "command": { "type" : "string", "required" : true, - "enum": [ "color", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "adjustment", "sourceselect", "config", "componentstate", "ledcolors", "logging", "processing", "sysinfo", "videomode", "authorize", "instance", "leddevice", "inputsource", "service", "system", "transform", "correction", "temperature", "getcurrentimage" ] + "enum": [ "color", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "adjustment", "sourceselect", "config", "componentstate", "ledcolors", "logging", "processing", "sysinfo", "videomode", "authorize", "instance", "instance-data", "leddevice", "inputsource", "service", "system", "transform", "correction", "temperature" ] } } } diff --git a/libsrc/api/JSONRPC_schemas.qrc b/libsrc/api/JSONRPC_schemas.qrc index 3782712c..c36b76ac 100644 --- a/libsrc/api/JSONRPC_schemas.qrc +++ b/libsrc/api/JSONRPC_schemas.qrc @@ -4,7 +4,6 @@ JSONRPC_schema/schema-color.json JSONRPC_schema/schema-image.json JSONRPC_schema/schema-serverinfo.json - JSONRPC_schema/schema-getcurrentimage.json JSONRPC_schema/schema-sysinfo.json JSONRPC_schema/schema-clear.json JSONRPC_schema/schema-clearall.json @@ -21,6 +20,7 @@ JSONRPC_schema/schema-videomode.json JSONRPC_schema/schema-authorize.json JSONRPC_schema/schema-instance.json + JSONRPC_schema/schema-instancedata.json JSONRPC_schema/schema-leddevice.json JSONRPC_schema/schema-inputsource.json JSONRPC_schema/schema-service.json diff --git a/libsrc/api/JsonAPI.cpp b/libsrc/api/JsonAPI.cpp index 3f9b702f..fa3c5489 100644 --- a/libsrc/api/JsonAPI.cpp +++ b/libsrc/api/JsonAPI.cpp @@ -57,33 +57,31 @@ using namespace hyperion; // Constants -namespace { +namespace +{ -constexpr std::chrono::milliseconds NEW_TOKEN_REQUEST_TIMEOUT{ 180000 }; + constexpr std::chrono::milliseconds NEW_TOKEN_REQUEST_TIMEOUT{180000}; -const char TOKEN_TAG[] = "token"; -constexpr int TOKEN_TAG_LENGTH = sizeof(TOKEN_TAG) - 1; -const char BEARER_TOKEN_TAG[] = "Bearer"; -constexpr int BEARER_TOKEN_TAG_LENGTH = sizeof(BEARER_TOKEN_TAG) - 1; + const char TOKEN_TAG[] = "token"; + constexpr int TOKEN_TAG_LENGTH = sizeof(TOKEN_TAG) - 1; + const char BEARER_TOKEN_TAG[] = "Bearer"; + constexpr int BEARER_TOKEN_TAG_LENGTH = sizeof(BEARER_TOKEN_TAG) - 1; -const int MIN_PASSWORD_LENGTH = 8; -const int APP_TOKEN_LENGTH = 36; + const int MIN_PASSWORD_LENGTH = 8; + const int APP_TOKEN_LENGTH = 36; -const char SETTINGS_UI_SCHEMA_FILE[] = ":/schema-settings-ui.json"; + const char SETTINGS_UI_SCHEMA_FILE[] = ":/schema-settings-ui.json"; -const bool verbose = false; + const bool verbose = false; } JsonAPI::JsonAPI(QString peerAddress, Logger *log, bool localConnection, QObject *parent, bool noListener) - : API(log, localConnection, parent) - ,_noListener(noListener) - ,_peerAddress (std::move(peerAddress)) - ,_jsonCB (nullptr) + : API(log, localConnection, parent), _noListener(noListener), _peerAddress(std::move(peerAddress)), _jsonCB(nullptr) { Q_INIT_RESOURCE(JSONRPC_schemas); qRegisterMetaType("Event"); - _jsonCB = QSharedPointer(new JsonCallbacks( _log, _peerAddress, parent)); + _jsonCB = QSharedPointer(new JsonCallbacks(_log, _peerAddress, parent)); } QSharedPointer JsonAPI::getCallBack() const @@ -111,7 +109,7 @@ void JsonAPI::initialize() connect(this, &JsonAPI::forwardJsonMessage, _hyperion, &Hyperion::forwardJsonMessage); } - //notify eventhadler on suspend/resume/idle requests + // notify eventhadler on suspend/resume/idle requests connect(this, &JsonAPI::signalEvent, EventHandler::getInstance().data(), &EventHandler::handleEvent); } @@ -132,11 +130,11 @@ void JsonAPI::handleMessage(const QString &messageString, const QString &httpAut const QString ident = "JsonRpc@" + _peerAddress; QJsonObject message; - //parse the message + // parse the message QPair parsingResult = JsonUtils::parse(ident, messageString, message, _log); if (!parsingResult.first) { - //Try to find command and tan, even parsing failed + // Try to find command and tan, even parsing failed QString command = findCommand(messageString); int tan = findTan(messageString); @@ -144,13 +142,13 @@ void JsonAPI::handleMessage(const QString &messageString, const QString &httpAut return; } - DebugIf(verbose, _log, "message: [%s]", QJsonDocument(message).toJson(QJsonDocument::Compact).constData() ); + DebugIf(verbose, _log, "message: [%s]", QJsonDocument(message).toJson(QJsonDocument::Compact).constData()); // check specific message const QString command = message.value("command").toString(); const QString subCommand = message.value("subcommand").toString(); - int tan {0}; + int tan{0}; if (message.value("tan") != QJsonValue::Undefined) { tan = message["tan"].toInt(); @@ -170,7 +168,7 @@ void JsonAPI::handleMessage(const QString &messageString, const QString &httpAut if (cmd.command == Command::Unknown) { - const QStringList errorDetails (subCommand.isEmpty() ? "subcommand is missing" : QString("Invalid subcommand: %1").arg(subCommand)); + const QStringList errorDetails(subCommand.isEmpty() ? "subcommand is missing" : QString("Invalid subcommand: %1").arg(subCommand)); sendErrorReply("Invalid command", errorDetails, command, tan); return; } @@ -178,7 +176,7 @@ void JsonAPI::handleMessage(const QString &messageString, const QString &httpAut if (_noListener) { setAuthorization(false); - if(cmd.isNolistenerCmd == NoListenerCmd::No) + if (cmd.isNolistenerCmd == NoListenerCmd::No) { sendErrorReply("Command not supported via single API calls using HTTP/S", cmd); return; @@ -187,11 +185,13 @@ void JsonAPI::handleMessage(const QString &messageString, const QString &httpAut // Check authorization for HTTP requests if (!httpAuthHeader.isEmpty()) { - int bearTokenLenght {0}; - if (httpAuthHeader.startsWith(BEARER_TOKEN_TAG, Qt::CaseInsensitive)) { + int bearTokenLenght{0}; + if (httpAuthHeader.startsWith(BEARER_TOKEN_TAG, Qt::CaseInsensitive)) + { bearTokenLenght = BEARER_TOKEN_TAG_LENGTH; } - else if (httpAuthHeader.startsWith(TOKEN_TAG, Qt::CaseInsensitive)) { + else if (httpAuthHeader.startsWith(TOKEN_TAG, Qt::CaseInsensitive)) + { bearTokenLenght = TOKEN_TAG_LENGTH; } @@ -201,7 +201,7 @@ void JsonAPI::handleMessage(const QString &messageString, const QString &httpAut return; } - QString cToken =httpAuthHeader.mid(bearTokenLenght).trimmed(); + QString cToken = httpAuthHeader.mid(bearTokenLenght).trimmed(); API::isTokenAuthorized(cToken); // _authorized && _adminAuthorized are set } @@ -213,7 +213,7 @@ void JsonAPI::handleMessage(const QString &messageString, const QString &httpAut } } - if (cmd.authorization != Authorization::No ) + if (cmd.authorization != Authorization::No) { if (!isAuthorized() || (cmd.authorization == Authorization::Admin && !isAdminAuthorized())) { @@ -246,14 +246,15 @@ void JsonAPI::handleMessage(const QString &messageString, const QString &httpAut } } -void JsonAPI::handleInstanceCommand(const JsonApiCommand& cmd, const QJsonObject &message) +void JsonAPI::handleInstanceCommand(const JsonApiCommand &cmd, const QJsonObject &message) { const QJsonValue instanceElement = message.value("instance"); QJsonArray instances; if (instanceElement.isDouble()) { instances.append(instanceElement); - } else if (instanceElement.isArray()) + } + else if (instanceElement.isArray()) { instances = instanceElement.toArray(); } @@ -264,14 +265,15 @@ void JsonAPI::handleInstanceCommand(const JsonApiCommand& cmd, const QJsonObject QStringList errorDetails; if (instances.contains("all")) { - for (const auto& instanceIdx : runningInstanceIdxs) + for (const auto &instanceIdx : runningInstanceIdxs) { instanceIdxList.append(instanceIdx); } } else { - for (const auto &instance : std::as_const(instances)) { + for (const auto &instance : std::as_const(instances)) + { quint8 instanceIdx = static_cast(instance.toInt()); if (instance.isDouble() && runningInstanceIdxs.contains(instanceIdx)) @@ -285,7 +287,7 @@ void JsonAPI::handleInstanceCommand(const JsonApiCommand& cmd, const QJsonObject } } - if (instanceIdxList.isEmpty() || !errorDetails.isEmpty() ) + if (instanceIdxList.isEmpty() || !errorDetails.isEmpty()) { sendErrorReply("Invalid instance(s) given", errorDetails, cmd); return; @@ -312,135 +314,176 @@ void JsonAPI::handleInstanceCommand(const JsonApiCommand& cmd, const QJsonObject setHyperionInstance(currentInstanceIdx); } -void JsonAPI::handleCommand(const JsonApiCommand& cmd, const QJsonObject &message) +void JsonAPI::handleCommand(const JsonApiCommand &cmd, const QJsonObject &message) { - switch (cmd.command) { + switch (cmd.command) + { case Command::Authorize: handleAuthorizeCommand(message, cmd); - break; + break; case Command::Color: handleColorCommand(message, cmd); - break; + break; case Command::Image: handleImageCommand(message, cmd); - break; + break; #if defined(ENABLE_EFFECTENGINE) case Command::Effect: handleEffectCommand(message, cmd); - break; + break; case Command::CreateEffect: handleCreateEffectCommand(message, cmd); - break; + break; case Command::DeleteEffect: handleDeleteEffectCommand(message, cmd); - break; + break; #endif case Command::SysInfo: handleSysInfoCommand(message, cmd); - break; + break; case Command::ServerInfo: handleServerInfoCommand(message, cmd); - break; + break; case Command::Clear: handleClearCommand(message, cmd); - break; + break; case Command::Adjustment: handleAdjustmentCommand(message, cmd); - break; + break; case Command::SourceSelect: handleSourceSelectCommand(message, cmd); - break; + break; case Command::Config: handleConfigCommand(message, cmd); - break; + break; case Command::ComponentState: handleComponentStateCommand(message, cmd); - break; + break; case Command::LedColors: handleLedColorsCommand(message, cmd); - break; + break; case Command::Logging: handleLoggingCommand(message, cmd); - break; + break; case Command::Processing: handleProcessingCommand(message, cmd); - break; + break; case Command::VideoMode: handleVideoModeCommand(message, cmd); - break; + break; case Command::Instance: handleInstanceCommand(message, cmd); - break; + break; case Command::LedDevice: handleLedDeviceCommand(message, cmd); - break; + break; case Command::InputSource: handleInputSourceCommand(message, cmd); - break; + break; case Command::Service: handleServiceCommand(message, cmd); - break; + break; case Command::System: handleSystemCommand(message, cmd); - break; + break; case Command::ClearAll: handleClearallCommand(message, cmd); - break; + break; + case Command::InstanceData: + handleInstanceDataCommand(message, cmd); + break; // BEGIN | The following commands are deprecated but used to ensure backward compatibility with Hyperion Classic remote control case Command::Transform: case Command::Correction: case Command::Temperature: sendErrorReply("The command is deprecated, please use the Hyperion Web Interface to configure", cmd); - break; + break; // END - case Command::GetCurrentImage: - handleGetCurrentImageCommand(message, cmd); - break; default: - break; + break; } } -void JsonAPI::handleGetCurrentImageCommand(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleGetImageSnapshotCommand(const QJsonObject &message, const JsonApiCommand &cmd) { QString replyMsg; - - Debug(_log, "Get image command received"); - QString savePath = message["path"].toString(); - - Debug(_log,"Save path: %s", QSTRING_CSTR(savePath)); - - int priority = _hyperion->getCurrentPriority(); - const PriorityMuxer::InputInfo priorityInfo = _hyperion->getPriorityInfo(priority); - Image image = priorityInfo.image; - - QImage jpgImage(reinterpret_cast(image.memptr()), image.width(), image.height(), qsizetype(3) * image.width(), QImage::Format_RGB888); - QByteArray byteArray; - QBuffer buffer(&byteArray); - buffer.open(QIODevice::WriteOnly); - jpgImage.save(&buffer, "JPG"); - QString base64Image = QString::fromLatin1(byteArray.toBase64().data()); - if (!savePath.isEmpty()) + QString filetype = message["filetype"].toString(); + const QStringList fileTypes{"BMP", "JPG", "PNG"}; + if (filetype.isEmpty()) { - if (!jpgImage.save(savePath, "JPG")) - { - replyMsg = "Failed to save image to: " + savePath; - sendErrorReply(replyMsg, cmd); - return; - } + sendErrorReply("Missing filetype. Available filetypes: " + fileTypes.join(", "), cmd); + return; } - + else if (!fileTypes.contains(filetype, Qt::CaseInsensitive)) + { + sendErrorReply("Invalid filetype. Available filetypes: " + fileTypes.join(", "), cmd); + return; + } + const PriorityMuxer::InputInfo priorityInfo = _hyperion->getPriorityInfo(_hyperion->getCurrentPriority()); + Image image = priorityInfo.image; + QImage snapshot(reinterpret_cast(image.memptr()), image.width(), image.height(), qsizetype(3) * image.width(), QImage::Format_RGB888); + QByteArray byteArray; + + QBuffer buffer{&byteArray}; + buffer.open(QIODevice::WriteOnly); + if (!snapshot.save(&buffer, filetype.toUtf8().constData())) + { + replyMsg = QString("Failed to create snapshot of the current image in %1 format").arg(filetype); + sendErrorReply(replyMsg, cmd); + return; + } + QByteArray base64Image = byteArray.toBase64(); + QJsonObject info; - info["path"] = savePath; - info["format"] = "JPG"; + info["format"] = filetype; info["width"] = image.width(); info["height"] = image.height(); - info["size"] = image.width() * image.height() * 3; - info["data"] = base64Image; + info["data"] = QString::fromLatin1(base64Image.data()); sendSuccessDataReply(info, cmd); } -void JsonAPI::handleColorCommand(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleGetLedSnapshotCommand(const QJsonObject &message, const JsonApiCommand &cmd) +{ + QString replyMsg; + const PriorityMuxer::InputInfo priorityInfo = _hyperion->getPriorityInfo(_hyperion->getCurrentPriority()); + const std::vector ledColors = _hyperion->getImageProcessor()->process(priorityInfo.image); + if (ledColors.empty()) + { + replyMsg = "No led colors available"; + sendErrorReply(replyMsg, cmd); + return; + } + QJsonArray ledColorsArray; + for (const auto &color : ledColors) + { + QJsonArray rgbArray; + rgbArray.append(color.red); + rgbArray.append(color.green); + rgbArray.append(color.blue); + ledColorsArray.append(rgbArray); + } + QJsonObject info; + info["leds"] = ledColorsArray; + sendSuccessDataReply(info, cmd); +} + +void JsonAPI::handleInstanceDataCommand(const QJsonObject &message, const JsonApiCommand &cmd) +{ + + switch (cmd.subCommand) + { + case SubCommand::GetImageSnapshot: + handleGetImageSnapshotCommand(message, cmd); + break; + case SubCommand::GetLedSnapshot: + handleGetLedSnapshotCommand(message, cmd); + break; + default: + sendErrorReply("Unknown subcommand", cmd); + } +} + +void JsonAPI::handleColorCommand(const QJsonObject &message, const JsonApiCommand &cmd) { emit forwardJsonMessage(message); int priority = message["priority"].toInt(); @@ -452,13 +495,14 @@ void JsonAPI::handleColorCommand(const QJsonObject &message, const JsonApiComman colors.reserve(static_cast::size_type>(jsonColor.size())); // Transform each entry in jsonColor to uint8_t and append to colors std::transform(jsonColor.begin(), jsonColor.end(), std::back_inserter(colors), - [](const QJsonValue &value) { return static_cast(value.toInt()); }); + [](const QJsonValue &value) + { return static_cast(value.toInt()); }); API::setColor(priority, colors, duration, origin); sendSuccessReply(cmd); } -void JsonAPI::handleImageCommand(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleImageCommand(const QJsonObject &message, const JsonApiCommand &cmd) { emit forwardJsonMessage(message); @@ -474,15 +518,18 @@ void JsonAPI::handleImageCommand(const QJsonObject &message, const JsonApiComman idata.data = QByteArray::fromBase64(QByteArray(message["imagedata"].toString().toUtf8())); QString replyMsg; - if (API::setImage(idata, COMP_IMAGE, replyMsg)) { + if (API::setImage(idata, COMP_IMAGE, replyMsg)) + { sendSuccessReply(cmd); - } else { + } + else + { sendErrorReply(replyMsg, cmd); } } #if defined(ENABLE_EFFECTENGINE) -void JsonAPI::handleEffectCommand(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleEffectCommand(const QJsonObject &message, const JsonApiCommand &cmd) { emit forwardJsonMessage(message); @@ -495,37 +542,41 @@ void JsonAPI::handleEffectCommand(const QJsonObject &message, const JsonApiComma dat.data = message["imageData"].toString("").toUtf8(); dat.args = message["effect"].toObject()["args"].toObject(); - if (API::setEffect(dat)) { + if (API::setEffect(dat)) + { sendSuccessReply(cmd); - } else { + } + else + { sendErrorReply("Effect '" + dat.effectName + "' not found", cmd); } } -void JsonAPI::handleCreateEffectCommand(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleCreateEffectCommand(const QJsonObject &message, const JsonApiCommand &cmd) { const QString resultMsg = API::saveEffect(message); resultMsg.isEmpty() ? sendSuccessReply(cmd) : sendErrorReply(resultMsg, cmd); } -void JsonAPI::handleDeleteEffectCommand(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleDeleteEffectCommand(const QJsonObject &message, const JsonApiCommand &cmd) { const QString res = API::deleteEffect(message["name"].toString()); res.isEmpty() ? sendSuccessReply(cmd) : sendErrorReply(res, cmd); } #endif -void JsonAPI::handleSysInfoCommand(const QJsonObject & /*unused*/, const JsonApiCommand& cmd) +void JsonAPI::handleSysInfoCommand(const QJsonObject & /*unused*/, const JsonApiCommand &cmd) { sendSuccessDataReply(JsonInfo::getSystemInfo(_hyperion), cmd); } -void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const JsonApiCommand &cmd) { - QJsonObject info {}; + QJsonObject info{}; QStringList errorDetails; - switch (cmd.getSubCommand()) { + switch (cmd.getSubCommand()) + { case SubCommand::Empty: case SubCommand::GetInfo: info["priorities"] = JsonInfo::getPrioritiestInfo(_hyperion); @@ -540,7 +591,7 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const JsonApiC info["imageToLedMappingType"] = ImageProcessor::mappingTypeToStr(_hyperion->getLedMappingType()); info["instance"] = JsonInfo::getInstanceInfo(); info["leds"] = _hyperion->getSetting(settings::LEDS).array(); - info["activeLedColor"] = JsonInfo::getActiveColors(_hyperion); + info["activeLedColor"] = JsonInfo::getActiveColors(_hyperion); #if defined(ENABLE_EFFECTENGINE) info["effects"] = JsonInfo::getEffects(_hyperion); @@ -557,19 +608,20 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const JsonApiC QStringList invaliCommands = _jsonCB->subscribe(subscriptions); if (!invaliCommands.isEmpty()) { - errorDetails.append("subscribe - Invalid commands provided: " + invaliCommands.join(',')); + errorDetails.append("subscribe - Invalid commands provided: " + invaliCommands.join(',')); } } // END - break; + break; case SubCommand::Subscribe: case SubCommand::Unsubscribe: { const QJsonObject ¶ms = message["data"].toObject(); const QJsonArray &subscriptions = params["subscriptions"].toArray(); - if (subscriptions.isEmpty()) { + if (subscriptions.isEmpty()) + { sendErrorReply("Invalid params", {"No subscriptions provided"}, cmd); return; } @@ -586,27 +638,27 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const JsonApiC if (!invaliCommands.isEmpty()) { - errorDetails.append("subscriptions - Invalid commands provided: " + invaliCommands.join(',')); + errorDetails.append("subscriptions - Invalid commands provided: " + invaliCommands.join(',')); } } break; case SubCommand::GetSubscriptions: info["subscriptions"] = QJsonArray::fromStringList(_jsonCB->getSubscribedCommands()); - break; + break; case SubCommand::GetSubscriptionCommands: info["commands"] = QJsonArray::fromStringList(_jsonCB->getCommands()); - break; + break; default: - break; + break; } sendSuccessDataReplyWithError(info, cmd, errorDetails); } -void JsonAPI::handleClearCommand(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleClearCommand(const QJsonObject &message, const JsonApiCommand &cmd) { emit forwardJsonMessage(message); int priority = message["priority"].toInt(); @@ -620,7 +672,7 @@ void JsonAPI::handleClearCommand(const QJsonObject &message, const JsonApiComman sendSuccessReply(cmd); } -void JsonAPI::handleClearallCommand(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleClearallCommand(const QJsonObject &message, const JsonApiCommand &cmd) { emit forwardJsonMessage(message); QString replyMsg; @@ -628,19 +680,21 @@ void JsonAPI::handleClearallCommand(const QJsonObject &message, const JsonApiCom sendSuccessReply(cmd); } -void JsonAPI::handleAdjustmentCommand(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleAdjustmentCommand(const QJsonObject &message, const JsonApiCommand &cmd) { const QJsonObject &adjustment = message["adjustment"].toObject(); const QList adjustmentIds = _hyperion->getAdjustmentIds(); - if (adjustmentIds.isEmpty()) { + if (adjustmentIds.isEmpty()) + { sendErrorReply("No adjustment data available", cmd); return; } const QString adjustmentId = adjustment["id"].toString(adjustmentIds.first()); ColorAdjustment *colorAdjustment = _hyperion->getAdjustment(adjustmentId); - if (colorAdjustment == nullptr) { + if (colorAdjustment == nullptr) + { Warning(_log, "Incorrect adjustment identifier: %s", adjustmentId.toStdString().c_str()); return; } @@ -664,12 +718,14 @@ void JsonAPI::applyColorAdjustments(const QJsonObject &adjustment, ColorAdjustme void JsonAPI::applyColorAdjustment(const QString &colorName, const QJsonObject &adjustment, RgbChannelAdjustment &rgbAdjustment) { - if (adjustment.contains(colorName)) { + if (adjustment.contains(colorName)) + { const QJsonArray &values = adjustment[colorName].toArray(); - if (values.size() >= 3) { + if (values.size() >= 3) + { rgbAdjustment.setAdjustment(static_cast(values[0U].toInt()), - static_cast(values[1U].toInt()), - static_cast(values[2U].toInt())); + static_cast(values[1U].toInt()), + static_cast(values[2U].toInt())); } } } @@ -690,46 +746,51 @@ void JsonAPI::applyTransforms(const QJsonObject &adjustment, ColorAdjustment *co void JsonAPI::applyGammaTransform(const QString &transformName, const QJsonObject &adjustment, RgbTransform &rgbTransform, char channel) { - if (adjustment.contains(transformName)) { + if (adjustment.contains(transformName)) + { rgbTransform.setGamma(channel == 'r' ? adjustment[transformName].toDouble() : rgbTransform.getGammaR(), channel == 'g' ? adjustment[transformName].toDouble() : rgbTransform.getGammaG(), channel == 'b' ? adjustment[transformName].toDouble() : rgbTransform.getGammaB()); } } -template +template void JsonAPI::applyTransform(const QString &transformName, const QJsonObject &adjustment, T &transform, void (T::*setFunction)(bool)) { - if (adjustment.contains(transformName)) { + if (adjustment.contains(transformName)) + { (transform.*setFunction)(adjustment[transformName].toBool()); } } -template +template void JsonAPI::applyTransform(const QString &transformName, const QJsonObject &adjustment, T &transform, void (T::*setFunction)(double)) { - if (adjustment.contains(transformName)) { + if (adjustment.contains(transformName)) + { (transform.*setFunction)(adjustment[transformName].toDouble()); } } -template +template void JsonAPI::applyTransform(const QString &transformName, const QJsonObject &adjustment, T &transform, void (T::*setFunction)(int)) { - if (adjustment.contains(transformName)) { + if (adjustment.contains(transformName)) + { (transform.*setFunction)(adjustment[transformName].toInt()); } } -template +template void JsonAPI::applyTransform(const QString &transformName, const QJsonObject &adjustment, T &transform, void (T::*setFunction)(uint8_t)) { - if (adjustment.contains(transformName)) { + if (adjustment.contains(transformName)) + { (transform.*setFunction)(static_cast(adjustment[transformName].toInt())); } } -void JsonAPI::handleSourceSelectCommand(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleSourceSelectCommand(const QJsonObject &message, const JsonApiCommand &cmd) { if (message.contains("auto")) { @@ -747,45 +808,46 @@ void JsonAPI::handleSourceSelectCommand(const QJsonObject &message, const JsonAp sendSuccessReply(cmd); } -void JsonAPI::handleConfigCommand(const QJsonObject& message, const JsonApiCommand& cmd) +void JsonAPI::handleConfigCommand(const QJsonObject &message, const JsonApiCommand &cmd) { - switch (cmd.subCommand) { + switch (cmd.subCommand) + { case SubCommand::GetSchema: handleSchemaGetCommand(message, cmd); - break; + break; - case SubCommand::GetConfig: + case SubCommand::GetConfig: handleConfigGetCommand(message, cmd); - break; + break; case SubCommand::GetConfigOld: sendSuccessDataReply(_hyperion->getQJsonConfig(), cmd); - break; + break; case SubCommand::SetConfig: handleConfigSetCommand(message, cmd); - break; + break; case SubCommand::RestoreConfig: handleConfigRestoreCommand(message, cmd); - break; + break; case SubCommand::Reload: Debug(_log, "Restarting due to RPC command"); emit signalEvent(Event::Reload); sendSuccessReply(cmd); - break; + break; default: - break; + break; } } -void JsonAPI::handleConfigSetCommand(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleConfigSetCommand(const QJsonObject &message, const JsonApiCommand &cmd) { if (DBManager::isReadOnly()) { - sendErrorReply("Database Error", {"Hyperion is running in read-only mode","Configuration updates are not possible"}, cmd); + sendErrorReply("Database Error", {"Hyperion is running in read-only mode", "Configuration updates are not possible"}, cmd); return; } @@ -813,7 +875,7 @@ void JsonAPI::handleConfigSetCommand(const QJsonObject &message, const JsonApiCo quint8 instanceId = static_cast(idx.toInt()); if (configuredInstanceIds.contains(instanceId)) { - instancesNewConfigs.insert(instanceId,instanceObject.value("settings").toObject()); + instancesNewConfigs.insert(instanceId, instanceObject.value("settings").toObject()); } else { @@ -830,12 +892,13 @@ void JsonAPI::handleConfigSetCommand(const QJsonObject &message, const JsonApiCo instancesNewConfigs.insert(0, JsonUtils::mergeJsonObjects(instanceZeroConfig, globalSettings)); } - QMapIterator i (instancesNewConfigs); - while (i.hasNext()) { + QMapIterator i(instancesNewConfigs); + while (i.hasNext()) + { i.next(); quint8 idx = i.key(); - Hyperion* instance = HyperionIManager::getInstance()->getHyperionInstance(idx); + Hyperion *instance = HyperionIManager::getInstance()->getHyperionInstance(idx); QPair isSaved = instance->saveSettings(i.value()); errorDetails.append(isSaved.second); @@ -850,7 +913,7 @@ void JsonAPI::handleConfigSetCommand(const QJsonObject &message, const JsonApiCo sendSuccessReply(cmd); } -void JsonAPI::handleConfigGetCommand(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleConfigGetCommand(const QJsonObject &message, const JsonApiCommand &cmd) { QJsonObject settings; QStringList errorDetails; @@ -864,8 +927,10 @@ void JsonAPI::handleConfigGetCommand(const QJsonObject &message, const JsonApiCo if (!globalConfig.isEmpty()) { const QJsonArray globalTypes = globalConfig["types"].toArray(); - for (const auto &type : globalTypes) { - if (type.isString()) { + for (const auto &type : globalTypes) + { + if (type.isString()) + { globalFilterTypes.append(type.toString()); } } @@ -879,8 +944,10 @@ void JsonAPI::handleConfigGetCommand(const QJsonObject &message, const JsonApiCo { QList configuredInstanceIds = _instanceManager->getInstanceIds(); const QJsonArray instanceIds = instances["ids"].toArray(); - for (const auto &idx : instanceIds) { - if (idx.isDouble()) { + for (const auto &idx : instanceIds) + { + if (idx.isDouble()) + { quint8 instanceId = static_cast(idx.toInt()); if (configuredInstanceIds.contains(instanceId)) { @@ -894,8 +961,10 @@ void JsonAPI::handleConfigGetCommand(const QJsonObject &message, const JsonApiCo } const QJsonArray instanceTypes = instances["types"].toArray(); - for (const auto &type : instanceTypes) { - if (type.isString()) { + for (const auto &type : instanceTypes) + { + if (type.isString()) + { instanceFilterTypes.append(type.toString()); } } @@ -905,7 +974,7 @@ void JsonAPI::handleConfigGetCommand(const QJsonObject &message, const JsonApiCo } else { - //Get complete configuration + // Get complete configuration settings = JsonInfo::getConfiguration(); } @@ -919,7 +988,7 @@ void JsonAPI::handleConfigGetCommand(const QJsonObject &message, const JsonApiCo } } -void JsonAPI::handleConfigRestoreCommand(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleConfigRestoreCommand(const QJsonObject &message, const JsonApiCommand &cmd) { QJsonObject config = message["config"].toObject(); if (API::isHyperionEnabled()) @@ -928,7 +997,7 @@ void JsonAPI::handleConfigRestoreCommand(const QJsonObject &message, const JsonA QPair result = configManager.updateConfiguration(config, false); if (result.first) { - QString infoMsg {"Restarting after importing configuration successfully."}; + QString infoMsg{"Restarting after importing configuration successfully."}; sendSuccessDataReply(infoMsg, cmd); Info(_log, "%s", QSTRING_CSTR(infoMsg)); emit signalEvent(Event::Restart); @@ -944,7 +1013,7 @@ void JsonAPI::handleConfigRestoreCommand(const QJsonObject &message, const JsonA } } -void JsonAPI::handleSchemaGetCommand(const QJsonObject& /*message*/, const JsonApiCommand& cmd) +void JsonAPI::handleSchemaGetCommand(const QJsonObject & /*message*/, const JsonApiCommand &cmd) { // create result QJsonObject schemaJson; @@ -993,8 +1062,8 @@ void JsonAPI::handleSchemaGetCommand(const QJsonObject& /*message*/, const JsonA #if defined(ENABLE_EFFECTENGINE) // collect all available effect schemas QJsonArray schemaList; - const std::list& effectsSchemas = _hyperion->getEffectSchemas(); - for (const EffectSchema& effectSchema : effectsSchemas) + const std::list &effectsSchemas = _hyperion->getEffectSchemas(); + for (const EffectSchema &effectSchema : effectsSchemas) { QJsonObject schema; schema.insert("script", effectSchema.pyFile); @@ -1019,220 +1088,242 @@ void JsonAPI::handleSchemaGetCommand(const QJsonObject& /*message*/, const JsonA sendSuccessDataReply(schemaJson, cmd); } -void JsonAPI::handleComponentStateCommand(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleComponentStateCommand(const QJsonObject &message, const JsonApiCommand &cmd) { const QJsonObject &componentState = message["componentstate"].toObject(); QString comp = componentState["component"].toString("invalid"); bool compState = componentState["state"].toBool(true); QString replyMsg; - if (API::setComponentState(comp, compState, replyMsg)) { + if (API::setComponentState(comp, compState, replyMsg)) + { sendSuccessReply(cmd); - } else { + } + else + { sendErrorReply(replyMsg, cmd); } } -void JsonAPI::handleLedColorsCommand(const QJsonObject& /*message*/, const JsonApiCommand& cmd) +void JsonAPI::handleLedColorsCommand(const QJsonObject & /*message*/, const JsonApiCommand &cmd) { - switch (cmd.subCommand) { + switch (cmd.subCommand) + { case SubCommand::LedStreamStart: - _jsonCB->subscribe( Subscription::LedColorsUpdate); + _jsonCB->subscribe(Subscription::LedColorsUpdate); // push once _hyperion->update(); sendSuccessReply(cmd); - break; + break; case SubCommand::LedStreamStop: - _jsonCB->unsubscribe( Subscription::LedColorsUpdate); + _jsonCB->unsubscribe(Subscription::LedColorsUpdate); sendSuccessReply(cmd); - break; + break; case SubCommand::ImageStreamStart: _jsonCB->subscribe(Subscription::ImageUpdate); sendSuccessReply(cmd); - break; + break; case SubCommand::ImageStreamStop: _jsonCB->unsubscribe(Subscription::ImageUpdate); sendSuccessReply(cmd); - break; + break; default: - break; + break; } } -void JsonAPI::handleLoggingCommand(const QJsonObject& /*message*/, const JsonApiCommand& cmd) +void JsonAPI::handleLoggingCommand(const QJsonObject & /*message*/, const JsonApiCommand &cmd) { - switch (cmd.subCommand) { + switch (cmd.subCommand) + { case SubCommand::Start: _jsonCB->subscribe("logmsg-update"); sendSuccessReply(cmd); - break; + break; case SubCommand::Stop: _jsonCB->unsubscribe("logmsg-update"); sendSuccessReply(cmd); - break; + break; default: - break; + break; } } -void JsonAPI::handleProcessingCommand(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleProcessingCommand(const QJsonObject &message, const JsonApiCommand &cmd) { API::setLedMappingType(ImageProcessor::mappingTypeToInt(message["mappingType"].toString("multicolor_mean"))); sendSuccessReply(cmd); } -void JsonAPI::handleVideoModeCommand(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleVideoModeCommand(const QJsonObject &message, const JsonApiCommand &cmd) { API::setVideoMode(parse3DMode(message["videoMode"].toString("2D"))); sendSuccessReply(cmd); } -void JsonAPI::handleAuthorizeCommand(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleAuthorizeCommand(const QJsonObject &message, const JsonApiCommand &cmd) { - switch (cmd.subCommand) { + switch (cmd.subCommand) + { case SubCommand::TokenRequired: handleTokenRequired(cmd); - break; + break; case SubCommand::AdminRequired: handleAdminRequired(cmd); - break; + break; case SubCommand::NewPasswordRequired: handleNewPasswordRequired(cmd); - break; + break; case SubCommand::Logout: handleLogout(cmd); - break; + break; case SubCommand::NewPassword: handleNewPassword(message, cmd); - break; + break; case SubCommand::CreateToken: handleCreateToken(message, cmd); - break; + break; case SubCommand::RenameToken: handleRenameToken(message, cmd); - break; + break; case SubCommand::DeleteToken: handleDeleteToken(message, cmd); - break; + break; case SubCommand::RequestToken: handleRequestToken(message, cmd); - break; + break; case SubCommand::GetPendingTokenRequests: handleGetPendingTokenRequests(cmd); - break; + break; case SubCommand::AnswerRequest: handleAnswerRequest(message, cmd); - break; + break; case SubCommand::GetTokenList: handleGetTokenList(cmd); - break; + break; case SubCommand::Login: handleLogin(message, cmd); - break; + break; default: - return; + return; } } -void JsonAPI::handleTokenRequired(const JsonApiCommand& cmd) +void JsonAPI::handleTokenRequired(const JsonApiCommand &cmd) { bool isTokenRequired = !islocalConnection() || _authManager->isLocalAuthRequired(); - QJsonObject response { { "required", isTokenRequired} }; + QJsonObject response{{"required", isTokenRequired}}; sendSuccessDataReply(response, cmd); } -void JsonAPI::handleAdminRequired(const JsonApiCommand& cmd) +void JsonAPI::handleAdminRequired(const JsonApiCommand &cmd) { bool isAdminAuthRequired = true; - QJsonObject response { { "adminRequired", isAdminAuthRequired} }; + QJsonObject response{{"adminRequired", isAdminAuthRequired}}; sendSuccessDataReply(response, cmd); } -void JsonAPI::handleNewPasswordRequired(const JsonApiCommand& cmd) +void JsonAPI::handleNewPasswordRequired(const JsonApiCommand &cmd) { - QJsonObject response { { "newPasswordRequired", API::hasHyperionDefaultPw() } }; + QJsonObject response{{"newPasswordRequired", API::hasHyperionDefaultPw()}}; sendSuccessDataReply(response, cmd); } -void JsonAPI::handleLogout(const JsonApiCommand& cmd) +void JsonAPI::handleLogout(const JsonApiCommand &cmd) { API::logout(); sendSuccessReply(cmd); } -void JsonAPI::handleNewPassword(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleNewPassword(const QJsonObject &message, const JsonApiCommand &cmd) { const QString password = message["password"].toString().trimmed(); const QString newPassword = message["newPassword"].toString().trimmed(); - if (API::updateHyperionPassword(password, newPassword)) { + if (API::updateHyperionPassword(password, newPassword)) + { sendSuccessReply(cmd); - } else { + } + else + { sendErrorReply("Failed to update user password", cmd); } } -void JsonAPI::handleCreateToken(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleCreateToken(const QJsonObject &message, const JsonApiCommand &cmd) { const QString &comment = message["comment"].toString().trimmed(); AuthManager::AuthDefinition def; const QString createTokenResult = API::createToken(comment, def); - if (createTokenResult.isEmpty()) { + if (createTokenResult.isEmpty()) + { QJsonObject newTok; newTok["comment"] = def.comment; newTok["id"] = def.id; newTok["token"] = def.token; sendSuccessDataReply(newTok, cmd); - } else { + } + else + { sendErrorReply("Token creation failed", {createTokenResult}, cmd); } } -void JsonAPI::handleRenameToken(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleRenameToken(const QJsonObject &message, const JsonApiCommand &cmd) { const QString &identifier = message["id"].toString().trimmed(); const QString &comment = message["comment"].toString().trimmed(); const QString renameTokenResult = API::renameToken(identifier, comment); - if (renameTokenResult.isEmpty()) { + if (renameTokenResult.isEmpty()) + { sendSuccessReply(cmd); - } else { + } + else + { sendErrorReply("Token rename failed", {renameTokenResult}, cmd); } } -void JsonAPI::handleDeleteToken(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleDeleteToken(const QJsonObject &message, const JsonApiCommand &cmd) { const QString &identifier = message["id"].toString().trimmed(); const QString deleteTokenResult = API::deleteToken(identifier); - if (deleteTokenResult.isEmpty()) { + if (deleteTokenResult.isEmpty()) + { sendSuccessReply(cmd); - } else { + } + else + { sendErrorReply("Token deletion failed", {deleteTokenResult}, cmd); } } -void JsonAPI::handleRequestToken(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleRequestToken(const QJsonObject &message, const JsonApiCommand &cmd) { const QString &identifier = message["id"].toString().trimmed(); const QString &comment = message["comment"].toString().trimmed(); const bool &acc = message["accept"].toBool(true); - if (acc) { + if (acc) + { API::setNewTokenRequest(comment, identifier, cmd.tan); - } else { + } + else + { API::cancelNewTokenRequest(comment, identifier); // client should wait for answer } } -void JsonAPI::handleGetPendingTokenRequests(const JsonApiCommand& cmd) +void JsonAPI::handleGetPendingTokenRequests(const JsonApiCommand &cmd) { QVector vec; - if (API::getPendingTokenRequests(vec)) { + if (API::getPendingTokenRequests(vec)) + { QJsonArray pendingTokeRequests; for (const auto &entry : std::as_const(vec)) { @@ -1247,18 +1338,21 @@ void JsonAPI::handleGetPendingTokenRequests(const JsonApiCommand& cmd) } } -void JsonAPI::handleAnswerRequest(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleAnswerRequest(const QJsonObject &message, const JsonApiCommand &cmd) { const QString &identifier = message["id"].toString().trimmed(); const bool &accept = message["accept"].toBool(false); - if (API::handlePendingTokenRequest(identifier, accept)) { + if (API::handlePendingTokenRequest(identifier, accept)) + { sendSuccessReply(cmd); - } else { + } + else + { sendErrorReply("Unable to handle token acceptance or denial", cmd); } } -void JsonAPI::handleGetTokenList(const JsonApiCommand& cmd) +void JsonAPI::handleGetTokenList(const JsonApiCommand &cmd) { QVector defVect; if (API::getTokenList(defVect)) @@ -1277,7 +1371,7 @@ void JsonAPI::handleGetTokenList(const JsonApiCommand& cmd) } } -void JsonAPI::handleLogin(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleLogin(const QJsonObject &message, const JsonApiCommand &cmd) { const QString &token = message["token"].toString().trimmed(); if (!token.isEmpty()) @@ -1285,9 +1379,12 @@ void JsonAPI::handleLogin(const QJsonObject &message, const JsonApiCommand& cmd) // userToken is longer than app token if (token.size() > APP_TOKEN_LENGTH) { - if (API::isUserTokenAuthorized(token)) { + if (API::isUserTokenAuthorized(token)) + { sendSuccessReply(cmd); - } else { + } + else + { sendNoAuthorization(cmd); } @@ -1296,9 +1393,12 @@ void JsonAPI::handleLogin(const QJsonObject &message, const JsonApiCommand& cmd) if (token.size() == APP_TOKEN_LENGTH) { - if (API::isTokenAuthorized(token)) { + if (API::isTokenAuthorized(token)) + { sendSuccessReply(cmd); - } else { + } + else + { sendNoAuthorization(cmd); } } @@ -1313,7 +1413,7 @@ void JsonAPI::handleLogin(const QJsonObject &message, const JsonApiCommand& cmd) if (API::isUserAuthorized(password) && API::getUserToken(userTokenRep)) { // Return the current valid Hyperion user token - QJsonObject response { { "token", userTokenRep } }; + QJsonObject response{{"token", userTokenRep}}; sendSuccessDataReply(response, cmd); } else @@ -1345,50 +1445,52 @@ void JsonAPI::handleTokenResponse(bool success, const QString &token, const QStr result["comment"] = comment; result["id"] = identifier; - if (success) { + if (success) + { sendSuccessDataReply(result, cmd, tan); - } else { + } + else + { sendErrorReply("Token request timeout or denied", {}, cmd, tan); } } -void JsonAPI::handleInstanceCommand(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleInstanceCommand(const QJsonObject &message, const JsonApiCommand &cmd) { QString replyMsg; const quint8 inst = static_cast(message["instance"].toInt()); const QString &name = message["name"].toString(); - switch (cmd.subCommand) { + switch (cmd.subCommand) + { case SubCommand::SwitchTo: if (handleInstanceSwitch(inst)) { - QJsonObject response { { "instance", inst } }; + QJsonObject response{{"instance", inst}}; sendSuccessDataReply(response, cmd); } else { sendErrorReply("Selected Hyperion instance is not running", cmd); } - break; + break; case SubCommand::StartInstance: - //Only send update once - weakConnect(this, &API::onStartInstanceResponse, [this, cmd] () - { - sendSuccessReply(cmd); - }); + // Only send update once + weakConnect(this, &API::onStartInstanceResponse, [this, cmd]() + { sendSuccessReply(cmd); }); if (!API::startInstance(inst, cmd.tan)) { sendErrorReply("Cannot start Hyperion instance index " + QString::number(inst), cmd); } - break; + break; case SubCommand::StopInstance: // silent fail API::stopInstance(inst); sendSuccessReply(cmd); - break; + break; case SubCommand::DeleteInstance: if (API::deleteInstance(inst, replyMsg)) @@ -1399,108 +1501,120 @@ void JsonAPI::handleInstanceCommand(const QJsonObject &message, const JsonApiCom { sendErrorReply(replyMsg, cmd); } - break; + break; case SubCommand::CreateInstance: case SubCommand::SaveName: // create and save name requires name - if (name.isEmpty()) { + if (name.isEmpty()) + { sendErrorReply("Name string required for this command", cmd); return; } - if (cmd.subCommand == SubCommand::CreateInstance) { + if (cmd.subCommand == SubCommand::CreateInstance) + { replyMsg = API::createInstance(name); - } else { + } + else + { replyMsg = API::setInstanceName(inst, name); } - if (replyMsg.isEmpty()) { + if (replyMsg.isEmpty()) + { sendSuccessReply(cmd); - } else { + } + else + { sendErrorReply(replyMsg, cmd); } - break; + break; default: - break; + break; } } -void JsonAPI::handleLedDeviceCommand(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleLedDeviceCommand(const QJsonObject &message, const JsonApiCommand &cmd) { const QString &devType = message["ledDeviceType"].toString().trimmed(); - const LedDeviceRegistry& ledDevices = LedDeviceWrapper::getDeviceMap(); + const LedDeviceRegistry &ledDevices = LedDeviceWrapper::getDeviceMap(); - if (ledDevices.count(devType) == 0) { + if (ledDevices.count(devType) == 0) + { sendErrorReply(QString("Unknown LED-Device type: %1").arg(devType), cmd); return; } - QJsonObject config { { "type", devType } }; - LedDevice* ledDevice = LedDeviceFactory::construct(config); + QJsonObject config{{"type", devType}}; + LedDevice *ledDevice = LedDeviceFactory::construct(config); - switch (cmd.subCommand) { + switch (cmd.subCommand) + { case SubCommand::Discover: handleLedDeviceDiscover(*ledDevice, message, cmd); - break; + break; case SubCommand::GetProperties: handleLedDeviceGetProperties(*ledDevice, message, cmd); - break; + break; case SubCommand::Identify: handleLedDeviceIdentify(*ledDevice, message, cmd); - break; + break; case SubCommand::AddAuthorization: handleLedDeviceAddAuthorization(*ledDevice, message, cmd); - break; + break; default: - break; + break; } delete ledDevice; } -void JsonAPI::handleLedDeviceDiscover(LedDevice& ledDevice, const QJsonObject& message, const JsonApiCommand& cmd) +void JsonAPI::handleLedDeviceDiscover(LedDevice &ledDevice, const QJsonObject &message, const JsonApiCommand &cmd) { const QJsonObject ¶ms = message["params"].toObject(); const QJsonObject devicesDiscovered = ledDevice.discover(params); - Debug(_log, "response: [%s]", QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact).constData() ); + Debug(_log, "response: [%s]", QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact).constData()); sendSuccessDataReply(devicesDiscovered, cmd); } -void JsonAPI::handleLedDeviceGetProperties(LedDevice& ledDevice, const QJsonObject& message, const JsonApiCommand& cmd) +void JsonAPI::handleLedDeviceGetProperties(LedDevice &ledDevice, const QJsonObject &message, const JsonApiCommand &cmd) { const QJsonObject ¶ms = message["params"].toObject(); const QJsonObject deviceProperties = ledDevice.getProperties(params); - Debug(_log, "response: [%s]", QJsonDocument(deviceProperties).toJson(QJsonDocument::Compact).constData() ); + Debug(_log, "response: [%s]", QJsonDocument(deviceProperties).toJson(QJsonDocument::Compact).constData()); sendSuccessDataReply(deviceProperties, cmd); } -void JsonAPI::handleLedDeviceIdentify(LedDevice& ledDevice, const QJsonObject& message, const JsonApiCommand& cmd) +void JsonAPI::handleLedDeviceIdentify(LedDevice &ledDevice, const QJsonObject &message, const JsonApiCommand &cmd) { const QJsonObject ¶ms = message["params"].toObject(); ledDevice.identify(params); sendSuccessReply(cmd); } -void JsonAPI::handleLedDeviceAddAuthorization(LedDevice& ledDevice, const QJsonObject& message, const JsonApiCommand& cmd) +void JsonAPI::handleLedDeviceAddAuthorization(LedDevice &ledDevice, const QJsonObject &message, const JsonApiCommand &cmd) { - const QJsonObject& params = message["params"].toObject(); + const QJsonObject ¶ms = message["params"].toObject(); const QJsonObject response = ledDevice.addAuthorization(params); sendSuccessDataReply(response, cmd); } -void JsonAPI::handleInputSourceCommand(const QJsonObject& message, const JsonApiCommand& cmd) { - const QString& sourceType = message["sourceType"].toString().trimmed(); - const QStringList sourceTypes {"screen", "video", "audio"}; +void JsonAPI::handleInputSourceCommand(const QJsonObject &message, const JsonApiCommand &cmd) +{ + const QString &sourceType = message["sourceType"].toString().trimmed(); + const QStringList sourceTypes{"screen", "video", "audio"}; - if (!sourceTypes.contains(sourceType)) { + if (!sourceTypes.contains(sourceType)) + { sendErrorReply(QString("Unknown input source type: %1").arg(sourceType), cmd); return; } - if (cmd.subCommand == SubCommand::Discover) { + if (cmd.subCommand == SubCommand::Discover) + { - const QJsonObject& params = message["params"].toObject(); + const QJsonObject ¶ms = message["params"].toObject(); QJsonObject inputSourcesDiscovered = JsonInfo().discoverSources(sourceType, params); DebugIf(verbose, _log, "response: [%s]", QJsonDocument(inputSourcesDiscovered).toJson(QJsonDocument::Compact).constData()); @@ -1509,7 +1623,7 @@ void JsonAPI::handleInputSourceCommand(const QJsonObject& message, const JsonApi } } -void JsonAPI::handleServiceCommand(const QJsonObject &message, const JsonApiCommand& cmd) +void JsonAPI::handleServiceCommand(const QJsonObject &message, const JsonApiCommand &cmd) { if (cmd.subCommand == SubCommand::Discover) { @@ -1547,29 +1661,30 @@ void JsonAPI::handleServiceCommand(const QJsonObject &message, const JsonApiComm } } -void JsonAPI::handleSystemCommand(const QJsonObject& /*message*/, const JsonApiCommand& cmd) +void JsonAPI::handleSystemCommand(const QJsonObject & /*message*/, const JsonApiCommand &cmd) { - switch (cmd.subCommand) { + switch (cmd.subCommand) + { case SubCommand::Suspend: emit signalEvent(Event::Suspend); - break; + break; case SubCommand::Resume: emit signalEvent(Event::Resume); - break; + break; case SubCommand::Restart: emit signalEvent(Event::Restart); - break; + break; case SubCommand::ToggleSuspend: emit signalEvent(Event::ToggleSuspend); - break; + break; case SubCommand::Idle: emit signalEvent(Event::Idle); - break; + break; case SubCommand::ToggleIdle: emit signalEvent(Event::ToggleIdle); - break; + break; default: - return; + return; } sendSuccessReply(cmd); } @@ -1581,24 +1696,24 @@ QJsonObject JsonAPI::getBasicCommandReply(bool success, const QString &command, reply["command"] = command; reply["tan"] = tan; - if (isInstanceCmd == InstanceCmd::Yes || ( isInstanceCmd == InstanceCmd::Multi && !_noListener)) + if (isInstanceCmd == InstanceCmd::Yes || (isInstanceCmd == InstanceCmd::Multi && !_noListener)) { reply["instance"] = _hyperion->getInstanceIndex(); } return reply; } -void JsonAPI::sendSuccessReply(const JsonApiCommand& cmd) +void JsonAPI::sendSuccessReply(const JsonApiCommand &cmd) { sendSuccessReply(cmd.toString(), cmd.tan, cmd.isInstanceCmd); } void JsonAPI::sendSuccessReply(const QString &command, int tan, InstanceCmd::Type isInstanceCmd) { - emit callbackReady(getBasicCommandReply(true, command, tan , isInstanceCmd)); + emit callbackReady(getBasicCommandReply(true, command, tan, isInstanceCmd)); } -void JsonAPI::sendSuccessDataReply(const QJsonValue &infoData, const JsonApiCommand& cmd) +void JsonAPI::sendSuccessDataReply(const QJsonValue &infoData, const JsonApiCommand &cmd) { sendSuccessDataReplyWithError(infoData, cmd.toString(), cmd.tan, {}, cmd.isInstanceCmd); } @@ -1608,20 +1723,20 @@ void JsonAPI::sendSuccessDataReply(const QJsonValue &infoData, const QString &co sendSuccessDataReplyWithError(infoData, command, tan, {}, isInstanceCmd); } -void JsonAPI::sendSuccessDataReplyWithError(const QJsonValue &infoData, const JsonApiCommand& cmd, const QStringList& errorDetails) +void JsonAPI::sendSuccessDataReplyWithError(const QJsonValue &infoData, const JsonApiCommand &cmd, const QStringList &errorDetails) { sendSuccessDataReplyWithError(infoData, cmd.toString(), cmd.tan, errorDetails, cmd.isInstanceCmd); } -void JsonAPI::sendSuccessDataReplyWithError(const QJsonValue &infoData, const QString &command, int tan, const QStringList& errorDetails, InstanceCmd::Type isInstanceCmd) +void JsonAPI::sendSuccessDataReplyWithError(const QJsonValue &infoData, const QString &command, int tan, const QStringList &errorDetails, InstanceCmd::Type isInstanceCmd) { - QJsonObject reply {getBasicCommandReply(true, command, tan , isInstanceCmd)}; + QJsonObject reply{getBasicCommandReply(true, command, tan, isInstanceCmd)}; reply["info"] = infoData; if (!errorDetails.isEmpty()) { QJsonArray errorsArray; - for (const QString& errorString : errorDetails) + for (const QString &errorString : errorDetails) { QJsonObject errorObject; errorObject["description"] = errorString; @@ -1633,24 +1748,24 @@ void JsonAPI::sendSuccessDataReplyWithError(const QJsonValue &infoData, const QS emit callbackReady(reply); } -void JsonAPI::sendErrorReply(const QString &error, const JsonApiCommand& cmd) +void JsonAPI::sendErrorReply(const QString &error, const JsonApiCommand &cmd) { sendErrorReply(error, {}, cmd.toString(), cmd.tan, cmd.isInstanceCmd); } -void JsonAPI::sendErrorReply(const QString &error, const QStringList& errorDetails, const JsonApiCommand& cmd) +void JsonAPI::sendErrorReply(const QString &error, const QStringList &errorDetails, const JsonApiCommand &cmd) { sendErrorReply(error, errorDetails, cmd.toString(), cmd.tan, cmd.isInstanceCmd); } -void JsonAPI::sendErrorReply(const QString &error, const QStringList& errorDetails, const QString &command, int tan, InstanceCmd::Type isInstanceCmd) +void JsonAPI::sendErrorReply(const QString &error, const QStringList &errorDetails, const QString &command, int tan, InstanceCmd::Type isInstanceCmd) { - QJsonObject reply {getBasicCommandReply(false, command, tan , isInstanceCmd)}; + QJsonObject reply{getBasicCommandReply(false, command, tan, isInstanceCmd)}; reply["error"] = error; if (!errorDetails.isEmpty()) { QJsonArray errorsArray; - for (const QString& errorString : errorDetails) + for (const QString &errorString : errorDetails) { QJsonObject errorObject; errorObject["description"] = errorString; @@ -1662,7 +1777,7 @@ void JsonAPI::sendErrorReply(const QString &error, const QStringList& errorDetai emit callbackReady(reply); } -void JsonAPI::sendNewRequest(const QJsonValue &infoData, const JsonApiCommand& cmd) +void JsonAPI::sendNewRequest(const QJsonValue &infoData, const JsonApiCommand &cmd) { sendSuccessDataReplyWithError(infoData, cmd.toString(), cmd.isInstanceCmd); } @@ -1682,12 +1797,12 @@ void JsonAPI::sendNewRequest(const QJsonValue &infoData, const QString &command, emit callbackReady(request); } -void JsonAPI::sendNoAuthorization(const JsonApiCommand& cmd) +void JsonAPI::sendNoAuthorization(const JsonApiCommand &cmd) { sendErrorReply(NO_AUTHORIZATION, cmd); } -void JsonAPI::handleInstanceStateChange(InstanceState state, quint8 instance, const QString& /*name */) +void JsonAPI::handleInstanceStateChange(InstanceState state, quint8 instance, const QString & /*name */) { switch (state) { @@ -1696,13 +1811,13 @@ void JsonAPI::handleInstanceStateChange(InstanceState state, quint8 instance, co { handleInstanceSwitch(); } - break; + break; case InstanceState::H_STARTED: case InstanceState::H_STOPPED: case InstanceState::H_CREATED: case InstanceState::H_DELETED: - break; + break; } } @@ -1712,27 +1827,29 @@ void JsonAPI::stopDataConnections() LoggerManager::getInstance()->disconnect(); } -QString JsonAPI::findCommand (const QString& jsonString) +QString JsonAPI::findCommand(const QString &jsonString) { - QString commandValue {"unknown"}; + QString commandValue{"unknown"}; // Define a regular expression pattern to match the value associated with the key "command" static QRegularExpression regex("\"command\"\\s*:\\s*\"([^\"]+)\""); QRegularExpressionMatch match = regex.match(jsonString); - if (match.hasMatch()) { + if (match.hasMatch()) + { commandValue = match.captured(1); } return commandValue; } -int JsonAPI::findTan (const QString& jsonString) +int JsonAPI::findTan(const QString &jsonString) { - int tanValue {0}; + int tanValue{0}; static QRegularExpression regex("\"tan\"\\s*:\\s*(\\d+)"); QRegularExpressionMatch match = regex.match(jsonString); - if (match.hasMatch()) { + if (match.hasMatch()) + { QString valueStr = match.captured(1); tanValue = valueStr.toInt(); } From 06118fbcee417df530f5e2d6ccd6a9084ba00bc2 Mon Sep 17 00:00:00 2001 From: xIronic Date: Sun, 23 Feb 2025 21:46:47 +0100 Subject: [PATCH 4/7] fix formatting of JsonApi.cpp --- libsrc/api/JsonAPI.cpp | 631 ++++++++++++++++++----------------------- 1 file changed, 277 insertions(+), 354 deletions(-) diff --git a/libsrc/api/JsonAPI.cpp b/libsrc/api/JsonAPI.cpp index fa3c5489..05138df3 100644 --- a/libsrc/api/JsonAPI.cpp +++ b/libsrc/api/JsonAPI.cpp @@ -57,31 +57,33 @@ using namespace hyperion; // Constants -namespace -{ +namespace { - constexpr std::chrono::milliseconds NEW_TOKEN_REQUEST_TIMEOUT{180000}; +constexpr std::chrono::milliseconds NEW_TOKEN_REQUEST_TIMEOUT{ 180000 }; - const char TOKEN_TAG[] = "token"; - constexpr int TOKEN_TAG_LENGTH = sizeof(TOKEN_TAG) - 1; - const char BEARER_TOKEN_TAG[] = "Bearer"; - constexpr int BEARER_TOKEN_TAG_LENGTH = sizeof(BEARER_TOKEN_TAG) - 1; +const char TOKEN_TAG[] = "token"; +constexpr int TOKEN_TAG_LENGTH = sizeof(TOKEN_TAG) - 1; +const char BEARER_TOKEN_TAG[] = "Bearer"; +constexpr int BEARER_TOKEN_TAG_LENGTH = sizeof(BEARER_TOKEN_TAG) - 1; - const int MIN_PASSWORD_LENGTH = 8; - const int APP_TOKEN_LENGTH = 36; +const int MIN_PASSWORD_LENGTH = 8; +const int APP_TOKEN_LENGTH = 36; - const char SETTINGS_UI_SCHEMA_FILE[] = ":/schema-settings-ui.json"; +const char SETTINGS_UI_SCHEMA_FILE[] = ":/schema-settings-ui.json"; - const bool verbose = false; +const bool verbose = false; } JsonAPI::JsonAPI(QString peerAddress, Logger *log, bool localConnection, QObject *parent, bool noListener) - : API(log, localConnection, parent), _noListener(noListener), _peerAddress(std::move(peerAddress)), _jsonCB(nullptr) + : API(log, localConnection, parent) + ,_noListener(noListener) + ,_peerAddress (std::move(peerAddress)) + ,_jsonCB (nullptr) { Q_INIT_RESOURCE(JSONRPC_schemas); qRegisterMetaType("Event"); - _jsonCB = QSharedPointer(new JsonCallbacks(_log, _peerAddress, parent)); + _jsonCB = QSharedPointer(new JsonCallbacks( _log, _peerAddress, parent)); } QSharedPointer JsonAPI::getCallBack() const @@ -109,7 +111,7 @@ void JsonAPI::initialize() connect(this, &JsonAPI::forwardJsonMessage, _hyperion, &Hyperion::forwardJsonMessage); } - // notify eventhadler on suspend/resume/idle requests + //notify eventhadler on suspend/resume/idle requests connect(this, &JsonAPI::signalEvent, EventHandler::getInstance().data(), &EventHandler::handleEvent); } @@ -130,11 +132,11 @@ void JsonAPI::handleMessage(const QString &messageString, const QString &httpAut const QString ident = "JsonRpc@" + _peerAddress; QJsonObject message; - // parse the message + //parse the message QPair parsingResult = JsonUtils::parse(ident, messageString, message, _log); if (!parsingResult.first) { - // Try to find command and tan, even parsing failed + //Try to find command and tan, even parsing failed QString command = findCommand(messageString); int tan = findTan(messageString); @@ -142,13 +144,13 @@ void JsonAPI::handleMessage(const QString &messageString, const QString &httpAut return; } - DebugIf(verbose, _log, "message: [%s]", QJsonDocument(message).toJson(QJsonDocument::Compact).constData()); + DebugIf(verbose, _log, "message: [%s]", QJsonDocument(message).toJson(QJsonDocument::Compact).constData() ); // check specific message const QString command = message.value("command").toString(); const QString subCommand = message.value("subcommand").toString(); - int tan{0}; + int tan {0}; if (message.value("tan") != QJsonValue::Undefined) { tan = message["tan"].toInt(); @@ -168,7 +170,7 @@ void JsonAPI::handleMessage(const QString &messageString, const QString &httpAut if (cmd.command == Command::Unknown) { - const QStringList errorDetails(subCommand.isEmpty() ? "subcommand is missing" : QString("Invalid subcommand: %1").arg(subCommand)); + const QStringList errorDetails (subCommand.isEmpty() ? "subcommand is missing" : QString("Invalid subcommand: %1").arg(subCommand)); sendErrorReply("Invalid command", errorDetails, command, tan); return; } @@ -176,7 +178,7 @@ void JsonAPI::handleMessage(const QString &messageString, const QString &httpAut if (_noListener) { setAuthorization(false); - if (cmd.isNolistenerCmd == NoListenerCmd::No) + if(cmd.isNolistenerCmd == NoListenerCmd::No) { sendErrorReply("Command not supported via single API calls using HTTP/S", cmd); return; @@ -185,13 +187,11 @@ void JsonAPI::handleMessage(const QString &messageString, const QString &httpAut // Check authorization for HTTP requests if (!httpAuthHeader.isEmpty()) { - int bearTokenLenght{0}; - if (httpAuthHeader.startsWith(BEARER_TOKEN_TAG, Qt::CaseInsensitive)) - { + int bearTokenLenght {0}; + if (httpAuthHeader.startsWith(BEARER_TOKEN_TAG, Qt::CaseInsensitive)) { bearTokenLenght = BEARER_TOKEN_TAG_LENGTH; } - else if (httpAuthHeader.startsWith(TOKEN_TAG, Qt::CaseInsensitive)) - { + else if (httpAuthHeader.startsWith(TOKEN_TAG, Qt::CaseInsensitive)) { bearTokenLenght = TOKEN_TAG_LENGTH; } @@ -201,7 +201,7 @@ void JsonAPI::handleMessage(const QString &messageString, const QString &httpAut return; } - QString cToken = httpAuthHeader.mid(bearTokenLenght).trimmed(); + QString cToken =httpAuthHeader.mid(bearTokenLenght).trimmed(); API::isTokenAuthorized(cToken); // _authorized && _adminAuthorized are set } @@ -213,7 +213,7 @@ void JsonAPI::handleMessage(const QString &messageString, const QString &httpAut } } - if (cmd.authorization != Authorization::No) + if (cmd.authorization != Authorization::No ) { if (!isAuthorized() || (cmd.authorization == Authorization::Admin && !isAdminAuthorized())) { @@ -246,15 +246,14 @@ void JsonAPI::handleMessage(const QString &messageString, const QString &httpAut } } -void JsonAPI::handleInstanceCommand(const JsonApiCommand &cmd, const QJsonObject &message) +void JsonAPI::handleInstanceCommand(const JsonApiCommand& cmd, const QJsonObject &message) { const QJsonValue instanceElement = message.value("instance"); QJsonArray instances; if (instanceElement.isDouble()) { instances.append(instanceElement); - } - else if (instanceElement.isArray()) + } else if (instanceElement.isArray()) { instances = instanceElement.toArray(); } @@ -265,15 +264,14 @@ void JsonAPI::handleInstanceCommand(const JsonApiCommand &cmd, const QJsonObject QStringList errorDetails; if (instances.contains("all")) { - for (const auto &instanceIdx : runningInstanceIdxs) + for (const auto& instanceIdx : runningInstanceIdxs) { instanceIdxList.append(instanceIdx); } } else { - for (const auto &instance : std::as_const(instances)) - { + for (const auto &instance : std::as_const(instances)) { quint8 instanceIdx = static_cast(instance.toInt()); if (instance.isDouble() && runningInstanceIdxs.contains(instanceIdx)) @@ -287,7 +285,7 @@ void JsonAPI::handleInstanceCommand(const JsonApiCommand &cmd, const QJsonObject } } - if (instanceIdxList.isEmpty() || !errorDetails.isEmpty()) + if (instanceIdxList.isEmpty() || !errorDetails.isEmpty() ) { sendErrorReply("Invalid instance(s) given", errorDetails, cmd); return; @@ -314,81 +312,80 @@ void JsonAPI::handleInstanceCommand(const JsonApiCommand &cmd, const QJsonObject setHyperionInstance(currentInstanceIdx); } -void JsonAPI::handleCommand(const JsonApiCommand &cmd, const QJsonObject &message) +void JsonAPI::handleCommand(const JsonApiCommand& cmd, const QJsonObject &message) { - switch (cmd.command) - { + switch (cmd.command) { case Command::Authorize: handleAuthorizeCommand(message, cmd); - break; + break; case Command::Color: handleColorCommand(message, cmd); - break; + break; case Command::Image: handleImageCommand(message, cmd); - break; + break; #if defined(ENABLE_EFFECTENGINE) case Command::Effect: handleEffectCommand(message, cmd); - break; + break; case Command::CreateEffect: handleCreateEffectCommand(message, cmd); - break; + break; case Command::DeleteEffect: handleDeleteEffectCommand(message, cmd); - break; + break; #endif case Command::SysInfo: handleSysInfoCommand(message, cmd); - break; + break; case Command::ServerInfo: handleServerInfoCommand(message, cmd); - break; + break; case Command::Clear: handleClearCommand(message, cmd); - break; + break; case Command::Adjustment: handleAdjustmentCommand(message, cmd); - break; + break; case Command::SourceSelect: handleSourceSelectCommand(message, cmd); - break; + break; case Command::Config: handleConfigCommand(message, cmd); - break; + break; case Command::ComponentState: handleComponentStateCommand(message, cmd); - break; + break; case Command::LedColors: handleLedColorsCommand(message, cmd); - break; + break; case Command::Logging: handleLoggingCommand(message, cmd); - break; + break; case Command::Processing: handleProcessingCommand(message, cmd); - break; + break; case Command::VideoMode: handleVideoModeCommand(message, cmd); - break; + break; case Command::Instance: handleInstanceCommand(message, cmd); - break; + break; case Command::LedDevice: handleLedDeviceCommand(message, cmd); - break; + break; case Command::InputSource: handleInputSourceCommand(message, cmd); - break; + break; case Command::Service: handleServiceCommand(message, cmd); - break; + break; case Command::System: handleSystemCommand(message, cmd); - break; + break; case Command::ClearAll: handleClearallCommand(message, cmd); - break; + break; case Command::InstanceData: handleInstanceDataCommand(message, cmd); break; @@ -397,10 +394,10 @@ void JsonAPI::handleCommand(const JsonApiCommand &cmd, const QJsonObject &messag case Command::Correction: case Command::Temperature: sendErrorReply("The command is deprecated, please use the Hyperion Web Interface to configure", cmd); - break; + break; // END default: - break; + break; } } @@ -483,7 +480,7 @@ void JsonAPI::handleInstanceDataCommand(const QJsonObject &message, const JsonAp } } -void JsonAPI::handleColorCommand(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleColorCommand(const QJsonObject &message, const JsonApiCommand& cmd) { emit forwardJsonMessage(message); int priority = message["priority"].toInt(); @@ -495,14 +492,13 @@ void JsonAPI::handleColorCommand(const QJsonObject &message, const JsonApiComman colors.reserve(static_cast::size_type>(jsonColor.size())); // Transform each entry in jsonColor to uint8_t and append to colors std::transform(jsonColor.begin(), jsonColor.end(), std::back_inserter(colors), - [](const QJsonValue &value) - { return static_cast(value.toInt()); }); + [](const QJsonValue &value) { return static_cast(value.toInt()); }); API::setColor(priority, colors, duration, origin); sendSuccessReply(cmd); } -void JsonAPI::handleImageCommand(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleImageCommand(const QJsonObject &message, const JsonApiCommand& cmd) { emit forwardJsonMessage(message); @@ -518,18 +514,15 @@ void JsonAPI::handleImageCommand(const QJsonObject &message, const JsonApiComman idata.data = QByteArray::fromBase64(QByteArray(message["imagedata"].toString().toUtf8())); QString replyMsg; - if (API::setImage(idata, COMP_IMAGE, replyMsg)) - { + if (API::setImage(idata, COMP_IMAGE, replyMsg)) { sendSuccessReply(cmd); - } - else - { + } else { sendErrorReply(replyMsg, cmd); } } #if defined(ENABLE_EFFECTENGINE) -void JsonAPI::handleEffectCommand(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleEffectCommand(const QJsonObject &message, const JsonApiCommand& cmd) { emit forwardJsonMessage(message); @@ -542,41 +535,37 @@ void JsonAPI::handleEffectCommand(const QJsonObject &message, const JsonApiComma dat.data = message["imageData"].toString("").toUtf8(); dat.args = message["effect"].toObject()["args"].toObject(); - if (API::setEffect(dat)) - { + if (API::setEffect(dat)) { sendSuccessReply(cmd); - } - else - { + } else { sendErrorReply("Effect '" + dat.effectName + "' not found", cmd); } } -void JsonAPI::handleCreateEffectCommand(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleCreateEffectCommand(const QJsonObject &message, const JsonApiCommand& cmd) { const QString resultMsg = API::saveEffect(message); resultMsg.isEmpty() ? sendSuccessReply(cmd) : sendErrorReply(resultMsg, cmd); } -void JsonAPI::handleDeleteEffectCommand(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleDeleteEffectCommand(const QJsonObject &message, const JsonApiCommand& cmd) { const QString res = API::deleteEffect(message["name"].toString()); res.isEmpty() ? sendSuccessReply(cmd) : sendErrorReply(res, cmd); } #endif -void JsonAPI::handleSysInfoCommand(const QJsonObject & /*unused*/, const JsonApiCommand &cmd) +void JsonAPI::handleSysInfoCommand(const QJsonObject & /*unused*/, const JsonApiCommand& cmd) { sendSuccessDataReply(JsonInfo::getSystemInfo(_hyperion), cmd); } -void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const JsonApiCommand& cmd) { - QJsonObject info{}; + QJsonObject info {}; QStringList errorDetails; - switch (cmd.getSubCommand()) - { + switch (cmd.getSubCommand()) { case SubCommand::Empty: case SubCommand::GetInfo: info["priorities"] = JsonInfo::getPrioritiestInfo(_hyperion); @@ -591,7 +580,7 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const JsonApiC info["imageToLedMappingType"] = ImageProcessor::mappingTypeToStr(_hyperion->getLedMappingType()); info["instance"] = JsonInfo::getInstanceInfo(); info["leds"] = _hyperion->getSetting(settings::LEDS).array(); - info["activeLedColor"] = JsonInfo::getActiveColors(_hyperion); + info["activeLedColor"] = JsonInfo::getActiveColors(_hyperion); #if defined(ENABLE_EFFECTENGINE) info["effects"] = JsonInfo::getEffects(_hyperion); @@ -608,20 +597,19 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const JsonApiC QStringList invaliCommands = _jsonCB->subscribe(subscriptions); if (!invaliCommands.isEmpty()) { - errorDetails.append("subscribe - Invalid commands provided: " + invaliCommands.join(',')); + errorDetails.append("subscribe - Invalid commands provided: " + invaliCommands.join(',')); } } // END - break; + break; case SubCommand::Subscribe: case SubCommand::Unsubscribe: { const QJsonObject ¶ms = message["data"].toObject(); const QJsonArray &subscriptions = params["subscriptions"].toArray(); - if (subscriptions.isEmpty()) - { + if (subscriptions.isEmpty()) { sendErrorReply("Invalid params", {"No subscriptions provided"}, cmd); return; } @@ -638,27 +626,27 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const JsonApiC if (!invaliCommands.isEmpty()) { - errorDetails.append("subscriptions - Invalid commands provided: " + invaliCommands.join(',')); + errorDetails.append("subscriptions - Invalid commands provided: " + invaliCommands.join(',')); } } break; case SubCommand::GetSubscriptions: info["subscriptions"] = QJsonArray::fromStringList(_jsonCB->getSubscribedCommands()); - break; + break; case SubCommand::GetSubscriptionCommands: info["commands"] = QJsonArray::fromStringList(_jsonCB->getCommands()); - break; + break; default: - break; + break; } sendSuccessDataReplyWithError(info, cmd, errorDetails); } -void JsonAPI::handleClearCommand(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleClearCommand(const QJsonObject &message, const JsonApiCommand& cmd) { emit forwardJsonMessage(message); int priority = message["priority"].toInt(); @@ -672,7 +660,7 @@ void JsonAPI::handleClearCommand(const QJsonObject &message, const JsonApiComman sendSuccessReply(cmd); } -void JsonAPI::handleClearallCommand(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleClearallCommand(const QJsonObject &message, const JsonApiCommand& cmd) { emit forwardJsonMessage(message); QString replyMsg; @@ -680,21 +668,19 @@ void JsonAPI::handleClearallCommand(const QJsonObject &message, const JsonApiCom sendSuccessReply(cmd); } -void JsonAPI::handleAdjustmentCommand(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleAdjustmentCommand(const QJsonObject &message, const JsonApiCommand& cmd) { const QJsonObject &adjustment = message["adjustment"].toObject(); const QList adjustmentIds = _hyperion->getAdjustmentIds(); - if (adjustmentIds.isEmpty()) - { + if (adjustmentIds.isEmpty()) { sendErrorReply("No adjustment data available", cmd); return; } const QString adjustmentId = adjustment["id"].toString(adjustmentIds.first()); ColorAdjustment *colorAdjustment = _hyperion->getAdjustment(adjustmentId); - if (colorAdjustment == nullptr) - { + if (colorAdjustment == nullptr) { Warning(_log, "Incorrect adjustment identifier: %s", adjustmentId.toStdString().c_str()); return; } @@ -718,14 +704,12 @@ void JsonAPI::applyColorAdjustments(const QJsonObject &adjustment, ColorAdjustme void JsonAPI::applyColorAdjustment(const QString &colorName, const QJsonObject &adjustment, RgbChannelAdjustment &rgbAdjustment) { - if (adjustment.contains(colorName)) - { + if (adjustment.contains(colorName)) { const QJsonArray &values = adjustment[colorName].toArray(); - if (values.size() >= 3) - { + if (values.size() >= 3) { rgbAdjustment.setAdjustment(static_cast(values[0U].toInt()), - static_cast(values[1U].toInt()), - static_cast(values[2U].toInt())); + static_cast(values[1U].toInt()), + static_cast(values[2U].toInt())); } } } @@ -746,51 +730,46 @@ void JsonAPI::applyTransforms(const QJsonObject &adjustment, ColorAdjustment *co void JsonAPI::applyGammaTransform(const QString &transformName, const QJsonObject &adjustment, RgbTransform &rgbTransform, char channel) { - if (adjustment.contains(transformName)) - { + if (adjustment.contains(transformName)) { rgbTransform.setGamma(channel == 'r' ? adjustment[transformName].toDouble() : rgbTransform.getGammaR(), channel == 'g' ? adjustment[transformName].toDouble() : rgbTransform.getGammaG(), channel == 'b' ? adjustment[transformName].toDouble() : rgbTransform.getGammaB()); } } -template +template void JsonAPI::applyTransform(const QString &transformName, const QJsonObject &adjustment, T &transform, void (T::*setFunction)(bool)) { - if (adjustment.contains(transformName)) - { + if (adjustment.contains(transformName)) { (transform.*setFunction)(adjustment[transformName].toBool()); } } -template +template void JsonAPI::applyTransform(const QString &transformName, const QJsonObject &adjustment, T &transform, void (T::*setFunction)(double)) { - if (adjustment.contains(transformName)) - { + if (adjustment.contains(transformName)) { (transform.*setFunction)(adjustment[transformName].toDouble()); } } -template +template void JsonAPI::applyTransform(const QString &transformName, const QJsonObject &adjustment, T &transform, void (T::*setFunction)(int)) { - if (adjustment.contains(transformName)) - { + if (adjustment.contains(transformName)) { (transform.*setFunction)(adjustment[transformName].toInt()); } } -template +template void JsonAPI::applyTransform(const QString &transformName, const QJsonObject &adjustment, T &transform, void (T::*setFunction)(uint8_t)) { - if (adjustment.contains(transformName)) - { + if (adjustment.contains(transformName)) { (transform.*setFunction)(static_cast(adjustment[transformName].toInt())); } } -void JsonAPI::handleSourceSelectCommand(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleSourceSelectCommand(const QJsonObject &message, const JsonApiCommand& cmd) { if (message.contains("auto")) { @@ -808,46 +787,45 @@ void JsonAPI::handleSourceSelectCommand(const QJsonObject &message, const JsonAp sendSuccessReply(cmd); } -void JsonAPI::handleConfigCommand(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleConfigCommand(const QJsonObject& message, const JsonApiCommand& cmd) { - switch (cmd.subCommand) - { + switch (cmd.subCommand) { case SubCommand::GetSchema: handleSchemaGetCommand(message, cmd); - break; + break; - case SubCommand::GetConfig: + case SubCommand::GetConfig: handleConfigGetCommand(message, cmd); - break; + break; case SubCommand::GetConfigOld: sendSuccessDataReply(_hyperion->getQJsonConfig(), cmd); - break; + break; case SubCommand::SetConfig: handleConfigSetCommand(message, cmd); - break; + break; case SubCommand::RestoreConfig: handleConfigRestoreCommand(message, cmd); - break; + break; case SubCommand::Reload: Debug(_log, "Restarting due to RPC command"); emit signalEvent(Event::Reload); sendSuccessReply(cmd); - break; + break; default: - break; + break; } } -void JsonAPI::handleConfigSetCommand(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleConfigSetCommand(const QJsonObject &message, const JsonApiCommand& cmd) { if (DBManager::isReadOnly()) { - sendErrorReply("Database Error", {"Hyperion is running in read-only mode", "Configuration updates are not possible"}, cmd); + sendErrorReply("Database Error", {"Hyperion is running in read-only mode","Configuration updates are not possible"}, cmd); return; } @@ -875,7 +853,7 @@ void JsonAPI::handleConfigSetCommand(const QJsonObject &message, const JsonApiCo quint8 instanceId = static_cast(idx.toInt()); if (configuredInstanceIds.contains(instanceId)) { - instancesNewConfigs.insert(instanceId, instanceObject.value("settings").toObject()); + instancesNewConfigs.insert(instanceId,instanceObject.value("settings").toObject()); } else { @@ -892,13 +870,12 @@ void JsonAPI::handleConfigSetCommand(const QJsonObject &message, const JsonApiCo instancesNewConfigs.insert(0, JsonUtils::mergeJsonObjects(instanceZeroConfig, globalSettings)); } - QMapIterator i(instancesNewConfigs); - while (i.hasNext()) - { + QMapIterator i (instancesNewConfigs); + while (i.hasNext()) { i.next(); quint8 idx = i.key(); - Hyperion *instance = HyperionIManager::getInstance()->getHyperionInstance(idx); + Hyperion* instance = HyperionIManager::getInstance()->getHyperionInstance(idx); QPair isSaved = instance->saveSettings(i.value()); errorDetails.append(isSaved.second); @@ -913,7 +890,7 @@ void JsonAPI::handleConfigSetCommand(const QJsonObject &message, const JsonApiCo sendSuccessReply(cmd); } -void JsonAPI::handleConfigGetCommand(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleConfigGetCommand(const QJsonObject &message, const JsonApiCommand& cmd) { QJsonObject settings; QStringList errorDetails; @@ -927,10 +904,8 @@ void JsonAPI::handleConfigGetCommand(const QJsonObject &message, const JsonApiCo if (!globalConfig.isEmpty()) { const QJsonArray globalTypes = globalConfig["types"].toArray(); - for (const auto &type : globalTypes) - { - if (type.isString()) - { + for (const auto &type : globalTypes) { + if (type.isString()) { globalFilterTypes.append(type.toString()); } } @@ -944,10 +919,8 @@ void JsonAPI::handleConfigGetCommand(const QJsonObject &message, const JsonApiCo { QList configuredInstanceIds = _instanceManager->getInstanceIds(); const QJsonArray instanceIds = instances["ids"].toArray(); - for (const auto &idx : instanceIds) - { - if (idx.isDouble()) - { + for (const auto &idx : instanceIds) { + if (idx.isDouble()) { quint8 instanceId = static_cast(idx.toInt()); if (configuredInstanceIds.contains(instanceId)) { @@ -961,10 +934,8 @@ void JsonAPI::handleConfigGetCommand(const QJsonObject &message, const JsonApiCo } const QJsonArray instanceTypes = instances["types"].toArray(); - for (const auto &type : instanceTypes) - { - if (type.isString()) - { + for (const auto &type : instanceTypes) { + if (type.isString()) { instanceFilterTypes.append(type.toString()); } } @@ -974,7 +945,7 @@ void JsonAPI::handleConfigGetCommand(const QJsonObject &message, const JsonApiCo } else { - // Get complete configuration + //Get complete configuration settings = JsonInfo::getConfiguration(); } @@ -988,7 +959,7 @@ void JsonAPI::handleConfigGetCommand(const QJsonObject &message, const JsonApiCo } } -void JsonAPI::handleConfigRestoreCommand(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleConfigRestoreCommand(const QJsonObject &message, const JsonApiCommand& cmd) { QJsonObject config = message["config"].toObject(); if (API::isHyperionEnabled()) @@ -997,7 +968,7 @@ void JsonAPI::handleConfigRestoreCommand(const QJsonObject &message, const JsonA QPair result = configManager.updateConfiguration(config, false); if (result.first) { - QString infoMsg{"Restarting after importing configuration successfully."}; + QString infoMsg {"Restarting after importing configuration successfully."}; sendSuccessDataReply(infoMsg, cmd); Info(_log, "%s", QSTRING_CSTR(infoMsg)); emit signalEvent(Event::Restart); @@ -1013,7 +984,7 @@ void JsonAPI::handleConfigRestoreCommand(const QJsonObject &message, const JsonA } } -void JsonAPI::handleSchemaGetCommand(const QJsonObject & /*message*/, const JsonApiCommand &cmd) +void JsonAPI::handleSchemaGetCommand(const QJsonObject& /*message*/, const JsonApiCommand& cmd) { // create result QJsonObject schemaJson; @@ -1062,8 +1033,8 @@ void JsonAPI::handleSchemaGetCommand(const QJsonObject & /*message*/, const Json #if defined(ENABLE_EFFECTENGINE) // collect all available effect schemas QJsonArray schemaList; - const std::list &effectsSchemas = _hyperion->getEffectSchemas(); - for (const EffectSchema &effectSchema : effectsSchemas) + const std::list& effectsSchemas = _hyperion->getEffectSchemas(); + for (const EffectSchema& effectSchema : effectsSchemas) { QJsonObject schema; schema.insert("script", effectSchema.pyFile); @@ -1088,242 +1059,220 @@ void JsonAPI::handleSchemaGetCommand(const QJsonObject & /*message*/, const Json sendSuccessDataReply(schemaJson, cmd); } -void JsonAPI::handleComponentStateCommand(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleComponentStateCommand(const QJsonObject &message, const JsonApiCommand& cmd) { const QJsonObject &componentState = message["componentstate"].toObject(); QString comp = componentState["component"].toString("invalid"); bool compState = componentState["state"].toBool(true); QString replyMsg; - if (API::setComponentState(comp, compState, replyMsg)) - { + if (API::setComponentState(comp, compState, replyMsg)) { sendSuccessReply(cmd); - } - else - { + } else { sendErrorReply(replyMsg, cmd); } } -void JsonAPI::handleLedColorsCommand(const QJsonObject & /*message*/, const JsonApiCommand &cmd) +void JsonAPI::handleLedColorsCommand(const QJsonObject& /*message*/, const JsonApiCommand& cmd) { - switch (cmd.subCommand) - { + switch (cmd.subCommand) { case SubCommand::LedStreamStart: - _jsonCB->subscribe(Subscription::LedColorsUpdate); + _jsonCB->subscribe( Subscription::LedColorsUpdate); // push once _hyperion->update(); sendSuccessReply(cmd); - break; + break; case SubCommand::LedStreamStop: - _jsonCB->unsubscribe(Subscription::LedColorsUpdate); + _jsonCB->unsubscribe( Subscription::LedColorsUpdate); sendSuccessReply(cmd); - break; + break; case SubCommand::ImageStreamStart: _jsonCB->subscribe(Subscription::ImageUpdate); sendSuccessReply(cmd); - break; + break; case SubCommand::ImageStreamStop: _jsonCB->unsubscribe(Subscription::ImageUpdate); sendSuccessReply(cmd); - break; + break; default: - break; + break; } } -void JsonAPI::handleLoggingCommand(const QJsonObject & /*message*/, const JsonApiCommand &cmd) +void JsonAPI::handleLoggingCommand(const QJsonObject& /*message*/, const JsonApiCommand& cmd) { - switch (cmd.subCommand) - { + switch (cmd.subCommand) { case SubCommand::Start: _jsonCB->subscribe("logmsg-update"); sendSuccessReply(cmd); - break; + break; case SubCommand::Stop: _jsonCB->unsubscribe("logmsg-update"); sendSuccessReply(cmd); - break; + break; default: - break; + break; } } -void JsonAPI::handleProcessingCommand(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleProcessingCommand(const QJsonObject &message, const JsonApiCommand& cmd) { API::setLedMappingType(ImageProcessor::mappingTypeToInt(message["mappingType"].toString("multicolor_mean"))); sendSuccessReply(cmd); } -void JsonAPI::handleVideoModeCommand(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleVideoModeCommand(const QJsonObject &message, const JsonApiCommand& cmd) { API::setVideoMode(parse3DMode(message["videoMode"].toString("2D"))); sendSuccessReply(cmd); } -void JsonAPI::handleAuthorizeCommand(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleAuthorizeCommand(const QJsonObject &message, const JsonApiCommand& cmd) { - switch (cmd.subCommand) - { + switch (cmd.subCommand) { case SubCommand::TokenRequired: handleTokenRequired(cmd); - break; + break; case SubCommand::AdminRequired: handleAdminRequired(cmd); - break; + break; case SubCommand::NewPasswordRequired: handleNewPasswordRequired(cmd); - break; + break; case SubCommand::Logout: handleLogout(cmd); - break; + break; case SubCommand::NewPassword: handleNewPassword(message, cmd); - break; + break; case SubCommand::CreateToken: handleCreateToken(message, cmd); - break; + break; case SubCommand::RenameToken: handleRenameToken(message, cmd); - break; + break; case SubCommand::DeleteToken: handleDeleteToken(message, cmd); - break; + break; case SubCommand::RequestToken: handleRequestToken(message, cmd); - break; + break; case SubCommand::GetPendingTokenRequests: handleGetPendingTokenRequests(cmd); - break; + break; case SubCommand::AnswerRequest: handleAnswerRequest(message, cmd); - break; + break; case SubCommand::GetTokenList: handleGetTokenList(cmd); - break; + break; case SubCommand::Login: handleLogin(message, cmd); - break; + break; default: - return; + return; } } -void JsonAPI::handleTokenRequired(const JsonApiCommand &cmd) +void JsonAPI::handleTokenRequired(const JsonApiCommand& cmd) { bool isTokenRequired = !islocalConnection() || _authManager->isLocalAuthRequired(); - QJsonObject response{{"required", isTokenRequired}}; + QJsonObject response { { "required", isTokenRequired} }; sendSuccessDataReply(response, cmd); } -void JsonAPI::handleAdminRequired(const JsonApiCommand &cmd) +void JsonAPI::handleAdminRequired(const JsonApiCommand& cmd) { bool isAdminAuthRequired = true; - QJsonObject response{{"adminRequired", isAdminAuthRequired}}; + QJsonObject response { { "adminRequired", isAdminAuthRequired} }; sendSuccessDataReply(response, cmd); } -void JsonAPI::handleNewPasswordRequired(const JsonApiCommand &cmd) +void JsonAPI::handleNewPasswordRequired(const JsonApiCommand& cmd) { - QJsonObject response{{"newPasswordRequired", API::hasHyperionDefaultPw()}}; + QJsonObject response { { "newPasswordRequired", API::hasHyperionDefaultPw() } }; sendSuccessDataReply(response, cmd); } -void JsonAPI::handleLogout(const JsonApiCommand &cmd) +void JsonAPI::handleLogout(const JsonApiCommand& cmd) { API::logout(); sendSuccessReply(cmd); } -void JsonAPI::handleNewPassword(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleNewPassword(const QJsonObject &message, const JsonApiCommand& cmd) { const QString password = message["password"].toString().trimmed(); const QString newPassword = message["newPassword"].toString().trimmed(); - if (API::updateHyperionPassword(password, newPassword)) - { + if (API::updateHyperionPassword(password, newPassword)) { sendSuccessReply(cmd); - } - else - { + } else { sendErrorReply("Failed to update user password", cmd); } } -void JsonAPI::handleCreateToken(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleCreateToken(const QJsonObject &message, const JsonApiCommand& cmd) { const QString &comment = message["comment"].toString().trimmed(); AuthManager::AuthDefinition def; const QString createTokenResult = API::createToken(comment, def); - if (createTokenResult.isEmpty()) - { + if (createTokenResult.isEmpty()) { QJsonObject newTok; newTok["comment"] = def.comment; newTok["id"] = def.id; newTok["token"] = def.token; sendSuccessDataReply(newTok, cmd); - } - else - { + } else { sendErrorReply("Token creation failed", {createTokenResult}, cmd); } } -void JsonAPI::handleRenameToken(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleRenameToken(const QJsonObject &message, const JsonApiCommand& cmd) { const QString &identifier = message["id"].toString().trimmed(); const QString &comment = message["comment"].toString().trimmed(); const QString renameTokenResult = API::renameToken(identifier, comment); - if (renameTokenResult.isEmpty()) - { + if (renameTokenResult.isEmpty()) { sendSuccessReply(cmd); - } - else - { + } else { sendErrorReply("Token rename failed", {renameTokenResult}, cmd); } } -void JsonAPI::handleDeleteToken(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleDeleteToken(const QJsonObject &message, const JsonApiCommand& cmd) { const QString &identifier = message["id"].toString().trimmed(); const QString deleteTokenResult = API::deleteToken(identifier); - if (deleteTokenResult.isEmpty()) - { + if (deleteTokenResult.isEmpty()) { sendSuccessReply(cmd); - } - else - { + } else { sendErrorReply("Token deletion failed", {deleteTokenResult}, cmd); } } -void JsonAPI::handleRequestToken(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleRequestToken(const QJsonObject &message, const JsonApiCommand& cmd) { const QString &identifier = message["id"].toString().trimmed(); const QString &comment = message["comment"].toString().trimmed(); const bool &acc = message["accept"].toBool(true); - if (acc) - { + if (acc) { API::setNewTokenRequest(comment, identifier, cmd.tan); - } - else - { + } else { API::cancelNewTokenRequest(comment, identifier); // client should wait for answer } } -void JsonAPI::handleGetPendingTokenRequests(const JsonApiCommand &cmd) +void JsonAPI::handleGetPendingTokenRequests(const JsonApiCommand& cmd) { QVector vec; - if (API::getPendingTokenRequests(vec)) - { + if (API::getPendingTokenRequests(vec)) { QJsonArray pendingTokeRequests; for (const auto &entry : std::as_const(vec)) { @@ -1338,21 +1287,18 @@ void JsonAPI::handleGetPendingTokenRequests(const JsonApiCommand &cmd) } } -void JsonAPI::handleAnswerRequest(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleAnswerRequest(const QJsonObject &message, const JsonApiCommand& cmd) { const QString &identifier = message["id"].toString().trimmed(); const bool &accept = message["accept"].toBool(false); - if (API::handlePendingTokenRequest(identifier, accept)) - { + if (API::handlePendingTokenRequest(identifier, accept)) { sendSuccessReply(cmd); - } - else - { + } else { sendErrorReply("Unable to handle token acceptance or denial", cmd); } } -void JsonAPI::handleGetTokenList(const JsonApiCommand &cmd) +void JsonAPI::handleGetTokenList(const JsonApiCommand& cmd) { QVector defVect; if (API::getTokenList(defVect)) @@ -1371,7 +1317,7 @@ void JsonAPI::handleGetTokenList(const JsonApiCommand &cmd) } } -void JsonAPI::handleLogin(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleLogin(const QJsonObject &message, const JsonApiCommand& cmd) { const QString &token = message["token"].toString().trimmed(); if (!token.isEmpty()) @@ -1379,12 +1325,9 @@ void JsonAPI::handleLogin(const QJsonObject &message, const JsonApiCommand &cmd) // userToken is longer than app token if (token.size() > APP_TOKEN_LENGTH) { - if (API::isUserTokenAuthorized(token)) - { + if (API::isUserTokenAuthorized(token)) { sendSuccessReply(cmd); - } - else - { + } else { sendNoAuthorization(cmd); } @@ -1393,12 +1336,9 @@ void JsonAPI::handleLogin(const QJsonObject &message, const JsonApiCommand &cmd) if (token.size() == APP_TOKEN_LENGTH) { - if (API::isTokenAuthorized(token)) - { + if (API::isTokenAuthorized(token)) { sendSuccessReply(cmd); - } - else - { + } else { sendNoAuthorization(cmd); } } @@ -1413,7 +1353,7 @@ void JsonAPI::handleLogin(const QJsonObject &message, const JsonApiCommand &cmd) if (API::isUserAuthorized(password) && API::getUserToken(userTokenRep)) { // Return the current valid Hyperion user token - QJsonObject response{{"token", userTokenRep}}; + QJsonObject response { { "token", userTokenRep } }; sendSuccessDataReply(response, cmd); } else @@ -1445,52 +1385,50 @@ void JsonAPI::handleTokenResponse(bool success, const QString &token, const QStr result["comment"] = comment; result["id"] = identifier; - if (success) - { + if (success) { sendSuccessDataReply(result, cmd, tan); - } - else - { + } else { sendErrorReply("Token request timeout or denied", {}, cmd, tan); } } -void JsonAPI::handleInstanceCommand(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleInstanceCommand(const QJsonObject &message, const JsonApiCommand& cmd) { QString replyMsg; const quint8 inst = static_cast(message["instance"].toInt()); const QString &name = message["name"].toString(); - switch (cmd.subCommand) - { + switch (cmd.subCommand) { case SubCommand::SwitchTo: if (handleInstanceSwitch(inst)) { - QJsonObject response{{"instance", inst}}; + QJsonObject response { { "instance", inst } }; sendSuccessDataReply(response, cmd); } else { sendErrorReply("Selected Hyperion instance is not running", cmd); } - break; + break; case SubCommand::StartInstance: - // Only send update once - weakConnect(this, &API::onStartInstanceResponse, [this, cmd]() - { sendSuccessReply(cmd); }); + //Only send update once + weakConnect(this, &API::onStartInstanceResponse, [this, cmd] () + { + sendSuccessReply(cmd); + }); if (!API::startInstance(inst, cmd.tan)) { sendErrorReply("Cannot start Hyperion instance index " + QString::number(inst), cmd); } - break; + break; case SubCommand::StopInstance: // silent fail API::stopInstance(inst); sendSuccessReply(cmd); - break; + break; case SubCommand::DeleteInstance: if (API::deleteInstance(inst, replyMsg)) @@ -1501,120 +1439,108 @@ void JsonAPI::handleInstanceCommand(const QJsonObject &message, const JsonApiCom { sendErrorReply(replyMsg, cmd); } - break; + break; case SubCommand::CreateInstance: case SubCommand::SaveName: // create and save name requires name - if (name.isEmpty()) - { + if (name.isEmpty()) { sendErrorReply("Name string required for this command", cmd); return; } - if (cmd.subCommand == SubCommand::CreateInstance) - { + if (cmd.subCommand == SubCommand::CreateInstance) { replyMsg = API::createInstance(name); - } - else - { + } else { replyMsg = API::setInstanceName(inst, name); } - if (replyMsg.isEmpty()) - { + if (replyMsg.isEmpty()) { sendSuccessReply(cmd); - } - else - { + } else { sendErrorReply(replyMsg, cmd); } - break; + break; default: - break; + break; } } -void JsonAPI::handleLedDeviceCommand(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleLedDeviceCommand(const QJsonObject &message, const JsonApiCommand& cmd) { const QString &devType = message["ledDeviceType"].toString().trimmed(); - const LedDeviceRegistry &ledDevices = LedDeviceWrapper::getDeviceMap(); + const LedDeviceRegistry& ledDevices = LedDeviceWrapper::getDeviceMap(); - if (ledDevices.count(devType) == 0) - { + if (ledDevices.count(devType) == 0) { sendErrorReply(QString("Unknown LED-Device type: %1").arg(devType), cmd); return; } - QJsonObject config{{"type", devType}}; - LedDevice *ledDevice = LedDeviceFactory::construct(config); + QJsonObject config { { "type", devType } }; + LedDevice* ledDevice = LedDeviceFactory::construct(config); - switch (cmd.subCommand) - { + switch (cmd.subCommand) { case SubCommand::Discover: handleLedDeviceDiscover(*ledDevice, message, cmd); - break; + break; case SubCommand::GetProperties: handleLedDeviceGetProperties(*ledDevice, message, cmd); - break; + break; case SubCommand::Identify: handleLedDeviceIdentify(*ledDevice, message, cmd); - break; + break; case SubCommand::AddAuthorization: handleLedDeviceAddAuthorization(*ledDevice, message, cmd); - break; + break; default: - break; + break; } delete ledDevice; } -void JsonAPI::handleLedDeviceDiscover(LedDevice &ledDevice, const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleLedDeviceDiscover(LedDevice& ledDevice, const QJsonObject& message, const JsonApiCommand& cmd) { const QJsonObject ¶ms = message["params"].toObject(); const QJsonObject devicesDiscovered = ledDevice.discover(params); - Debug(_log, "response: [%s]", QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact).constData()); + Debug(_log, "response: [%s]", QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact).constData() ); sendSuccessDataReply(devicesDiscovered, cmd); } -void JsonAPI::handleLedDeviceGetProperties(LedDevice &ledDevice, const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleLedDeviceGetProperties(LedDevice& ledDevice, const QJsonObject& message, const JsonApiCommand& cmd) { const QJsonObject ¶ms = message["params"].toObject(); const QJsonObject deviceProperties = ledDevice.getProperties(params); - Debug(_log, "response: [%s]", QJsonDocument(deviceProperties).toJson(QJsonDocument::Compact).constData()); + Debug(_log, "response: [%s]", QJsonDocument(deviceProperties).toJson(QJsonDocument::Compact).constData() ); sendSuccessDataReply(deviceProperties, cmd); } -void JsonAPI::handleLedDeviceIdentify(LedDevice &ledDevice, const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleLedDeviceIdentify(LedDevice& ledDevice, const QJsonObject& message, const JsonApiCommand& cmd) { const QJsonObject ¶ms = message["params"].toObject(); ledDevice.identify(params); sendSuccessReply(cmd); } -void JsonAPI::handleLedDeviceAddAuthorization(LedDevice &ledDevice, const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleLedDeviceAddAuthorization(LedDevice& ledDevice, const QJsonObject& message, const JsonApiCommand& cmd) { - const QJsonObject ¶ms = message["params"].toObject(); + const QJsonObject& params = message["params"].toObject(); const QJsonObject response = ledDevice.addAuthorization(params); sendSuccessDataReply(response, cmd); } -void JsonAPI::handleInputSourceCommand(const QJsonObject &message, const JsonApiCommand &cmd) -{ - const QString &sourceType = message["sourceType"].toString().trimmed(); - const QStringList sourceTypes{"screen", "video", "audio"}; +void JsonAPI::handleInputSourceCommand(const QJsonObject& message, const JsonApiCommand& cmd) { + const QString& sourceType = message["sourceType"].toString().trimmed(); + const QStringList sourceTypes {"screen", "video", "audio"}; - if (!sourceTypes.contains(sourceType)) - { + if (!sourceTypes.contains(sourceType)) { sendErrorReply(QString("Unknown input source type: %1").arg(sourceType), cmd); return; } - if (cmd.subCommand == SubCommand::Discover) - { + if (cmd.subCommand == SubCommand::Discover) { - const QJsonObject ¶ms = message["params"].toObject(); + const QJsonObject& params = message["params"].toObject(); QJsonObject inputSourcesDiscovered = JsonInfo().discoverSources(sourceType, params); DebugIf(verbose, _log, "response: [%s]", QJsonDocument(inputSourcesDiscovered).toJson(QJsonDocument::Compact).constData()); @@ -1623,7 +1549,7 @@ void JsonAPI::handleInputSourceCommand(const QJsonObject &message, const JsonApi } } -void JsonAPI::handleServiceCommand(const QJsonObject &message, const JsonApiCommand &cmd) +void JsonAPI::handleServiceCommand(const QJsonObject &message, const JsonApiCommand& cmd) { if (cmd.subCommand == SubCommand::Discover) { @@ -1661,30 +1587,29 @@ void JsonAPI::handleServiceCommand(const QJsonObject &message, const JsonApiComm } } -void JsonAPI::handleSystemCommand(const QJsonObject & /*message*/, const JsonApiCommand &cmd) +void JsonAPI::handleSystemCommand(const QJsonObject& /*message*/, const JsonApiCommand& cmd) { - switch (cmd.subCommand) - { + switch (cmd.subCommand) { case SubCommand::Suspend: emit signalEvent(Event::Suspend); - break; + break; case SubCommand::Resume: emit signalEvent(Event::Resume); - break; + break; case SubCommand::Restart: emit signalEvent(Event::Restart); - break; + break; case SubCommand::ToggleSuspend: emit signalEvent(Event::ToggleSuspend); - break; + break; case SubCommand::Idle: emit signalEvent(Event::Idle); - break; + break; case SubCommand::ToggleIdle: emit signalEvent(Event::ToggleIdle); - break; + break; default: - return; + return; } sendSuccessReply(cmd); } @@ -1696,24 +1621,24 @@ QJsonObject JsonAPI::getBasicCommandReply(bool success, const QString &command, reply["command"] = command; reply["tan"] = tan; - if (isInstanceCmd == InstanceCmd::Yes || (isInstanceCmd == InstanceCmd::Multi && !_noListener)) + if (isInstanceCmd == InstanceCmd::Yes || ( isInstanceCmd == InstanceCmd::Multi && !_noListener)) { reply["instance"] = _hyperion->getInstanceIndex(); } return reply; } -void JsonAPI::sendSuccessReply(const JsonApiCommand &cmd) +void JsonAPI::sendSuccessReply(const JsonApiCommand& cmd) { sendSuccessReply(cmd.toString(), cmd.tan, cmd.isInstanceCmd); } void JsonAPI::sendSuccessReply(const QString &command, int tan, InstanceCmd::Type isInstanceCmd) { - emit callbackReady(getBasicCommandReply(true, command, tan, isInstanceCmd)); + emit callbackReady(getBasicCommandReply(true, command, tan , isInstanceCmd)); } -void JsonAPI::sendSuccessDataReply(const QJsonValue &infoData, const JsonApiCommand &cmd) +void JsonAPI::sendSuccessDataReply(const QJsonValue &infoData, const JsonApiCommand& cmd) { sendSuccessDataReplyWithError(infoData, cmd.toString(), cmd.tan, {}, cmd.isInstanceCmd); } @@ -1723,20 +1648,20 @@ void JsonAPI::sendSuccessDataReply(const QJsonValue &infoData, const QString &co sendSuccessDataReplyWithError(infoData, command, tan, {}, isInstanceCmd); } -void JsonAPI::sendSuccessDataReplyWithError(const QJsonValue &infoData, const JsonApiCommand &cmd, const QStringList &errorDetails) +void JsonAPI::sendSuccessDataReplyWithError(const QJsonValue &infoData, const JsonApiCommand& cmd, const QStringList& errorDetails) { sendSuccessDataReplyWithError(infoData, cmd.toString(), cmd.tan, errorDetails, cmd.isInstanceCmd); } -void JsonAPI::sendSuccessDataReplyWithError(const QJsonValue &infoData, const QString &command, int tan, const QStringList &errorDetails, InstanceCmd::Type isInstanceCmd) +void JsonAPI::sendSuccessDataReplyWithError(const QJsonValue &infoData, const QString &command, int tan, const QStringList& errorDetails, InstanceCmd::Type isInstanceCmd) { - QJsonObject reply{getBasicCommandReply(true, command, tan, isInstanceCmd)}; + QJsonObject reply {getBasicCommandReply(true, command, tan , isInstanceCmd)}; reply["info"] = infoData; if (!errorDetails.isEmpty()) { QJsonArray errorsArray; - for (const QString &errorString : errorDetails) + for (const QString& errorString : errorDetails) { QJsonObject errorObject; errorObject["description"] = errorString; @@ -1748,24 +1673,24 @@ void JsonAPI::sendSuccessDataReplyWithError(const QJsonValue &infoData, const QS emit callbackReady(reply); } -void JsonAPI::sendErrorReply(const QString &error, const JsonApiCommand &cmd) +void JsonAPI::sendErrorReply(const QString &error, const JsonApiCommand& cmd) { sendErrorReply(error, {}, cmd.toString(), cmd.tan, cmd.isInstanceCmd); } -void JsonAPI::sendErrorReply(const QString &error, const QStringList &errorDetails, const JsonApiCommand &cmd) +void JsonAPI::sendErrorReply(const QString &error, const QStringList& errorDetails, const JsonApiCommand& cmd) { sendErrorReply(error, errorDetails, cmd.toString(), cmd.tan, cmd.isInstanceCmd); } -void JsonAPI::sendErrorReply(const QString &error, const QStringList &errorDetails, const QString &command, int tan, InstanceCmd::Type isInstanceCmd) +void JsonAPI::sendErrorReply(const QString &error, const QStringList& errorDetails, const QString &command, int tan, InstanceCmd::Type isInstanceCmd) { - QJsonObject reply{getBasicCommandReply(false, command, tan, isInstanceCmd)}; + QJsonObject reply {getBasicCommandReply(false, command, tan , isInstanceCmd)}; reply["error"] = error; if (!errorDetails.isEmpty()) { QJsonArray errorsArray; - for (const QString &errorString : errorDetails) + for (const QString& errorString : errorDetails) { QJsonObject errorObject; errorObject["description"] = errorString; @@ -1777,7 +1702,7 @@ void JsonAPI::sendErrorReply(const QString &error, const QStringList &errorDetai emit callbackReady(reply); } -void JsonAPI::sendNewRequest(const QJsonValue &infoData, const JsonApiCommand &cmd) +void JsonAPI::sendNewRequest(const QJsonValue &infoData, const JsonApiCommand& cmd) { sendSuccessDataReplyWithError(infoData, cmd.toString(), cmd.isInstanceCmd); } @@ -1797,12 +1722,12 @@ void JsonAPI::sendNewRequest(const QJsonValue &infoData, const QString &command, emit callbackReady(request); } -void JsonAPI::sendNoAuthorization(const JsonApiCommand &cmd) +void JsonAPI::sendNoAuthorization(const JsonApiCommand& cmd) { sendErrorReply(NO_AUTHORIZATION, cmd); } -void JsonAPI::handleInstanceStateChange(InstanceState state, quint8 instance, const QString & /*name */) +void JsonAPI::handleInstanceStateChange(InstanceState state, quint8 instance, const QString& /*name */) { switch (state) { @@ -1811,13 +1736,13 @@ void JsonAPI::handleInstanceStateChange(InstanceState state, quint8 instance, co { handleInstanceSwitch(); } - break; + break; case InstanceState::H_STARTED: case InstanceState::H_STOPPED: case InstanceState::H_CREATED: case InstanceState::H_DELETED: - break; + break; } } @@ -1827,29 +1752,27 @@ void JsonAPI::stopDataConnections() LoggerManager::getInstance()->disconnect(); } -QString JsonAPI::findCommand(const QString &jsonString) +QString JsonAPI::findCommand (const QString& jsonString) { - QString commandValue{"unknown"}; + QString commandValue {"unknown"}; // Define a regular expression pattern to match the value associated with the key "command" static QRegularExpression regex("\"command\"\\s*:\\s*\"([^\"]+)\""); QRegularExpressionMatch match = regex.match(jsonString); - if (match.hasMatch()) - { + if (match.hasMatch()) { commandValue = match.captured(1); } return commandValue; } -int JsonAPI::findTan(const QString &jsonString) +int JsonAPI::findTan (const QString& jsonString) { - int tanValue{0}; + int tanValue {0}; static QRegularExpression regex("\"tan\"\\s*:\\s*(\\d+)"); QRegularExpressionMatch match = regex.match(jsonString); - if (match.hasMatch()) - { + if (match.hasMatch()) { QString valueStr = match.captured(1); tanValue = valueStr.toInt(); } From 0f91510a766a3ac3c8bf0e7708e8998c2b41d260 Mon Sep 17 00:00:00 2001 From: xIronic Date: Sun, 23 Feb 2025 22:05:39 +0100 Subject: [PATCH 5/7] removed unnecessary filetype checks --- libsrc/api/JsonAPI.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/libsrc/api/JsonAPI.cpp b/libsrc/api/JsonAPI.cpp index 05138df3..80828c84 100644 --- a/libsrc/api/JsonAPI.cpp +++ b/libsrc/api/JsonAPI.cpp @@ -406,16 +406,6 @@ void JsonAPI::handleGetImageSnapshotCommand(const QJsonObject &message, const Js QString replyMsg; QString filetype = message["filetype"].toString(); const QStringList fileTypes{"BMP", "JPG", "PNG"}; - if (filetype.isEmpty()) - { - sendErrorReply("Missing filetype. Available filetypes: " + fileTypes.join(", "), cmd); - return; - } - else if (!fileTypes.contains(filetype, Qt::CaseInsensitive)) - { - sendErrorReply("Invalid filetype. Available filetypes: " + fileTypes.join(", "), cmd); - return; - } const PriorityMuxer::InputInfo priorityInfo = _hyperion->getPriorityInfo(_hyperion->getCurrentPriority()); Image image = priorityInfo.image; QImage snapshot(reinterpret_cast(image.memptr()), image.width(), image.height(), qsizetype(3) * image.width(), QImage::Format_RGB888); From 5f89d641dd503f76ed942e4eb2c07f92e742becf Mon Sep 17 00:00:00 2001 From: xIronic Date: Sun, 23 Feb 2025 22:07:45 +0100 Subject: [PATCH 6/7] clean up code --- libsrc/api/JsonAPI.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libsrc/api/JsonAPI.cpp b/libsrc/api/JsonAPI.cpp index 80828c84..8e54729d 100644 --- a/libsrc/api/JsonAPI.cpp +++ b/libsrc/api/JsonAPI.cpp @@ -405,7 +405,6 @@ void JsonAPI::handleGetImageSnapshotCommand(const QJsonObject &message, const Js { QString replyMsg; QString filetype = message["filetype"].toString(); - const QStringList fileTypes{"BMP", "JPG", "PNG"}; const PriorityMuxer::InputInfo priorityInfo = _hyperion->getPriorityInfo(_hyperion->getCurrentPriority()); Image image = priorityInfo.image; QImage snapshot(reinterpret_cast(image.memptr()), image.width(), image.height(), qsizetype(3) * image.width(), QImage::Format_RGB888); @@ -466,7 +465,7 @@ void JsonAPI::handleInstanceDataCommand(const QJsonObject &message, const JsonAp handleGetLedSnapshotCommand(message, cmd); break; default: - sendErrorReply("Unknown subcommand", cmd); + break; } } From d07feea13cdcbcffb0dad0008ba8c9131e50029e Mon Sep 17 00:00:00 2001 From: xIronic <140331965+xIronic@users.noreply.github.com> Date: Mon, 24 Feb 2025 14:40:07 +0100 Subject: [PATCH 7/7] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20c01dca..252a91a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,7 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Support direct or multiple instance addressing via single requests (#809) - Support of `serverinfo` subcommands: `getInfo, subscribe, unsubscribe, getSubscriptions, getSubscriptionCommands` - [Overview](https://github.com/hyperion-project/hyperion.ng/blob/API_Auth/doc/development/JSON-API%20_Commands_Overview.md) of API commands and subscription updates -- Support for requesting a snapshot of the current image via JSON response of a base64 string. Also added the ability to specify a path to save a jpg to disk +- Support for requesting instance-data via JSON-API. Implemented requesting the current image in different formats or led colors. ### Changed