diff --git a/assets/webconfig/i18n/en.json b/assets/webconfig/i18n/en.json
index 68344d73..0d638c53 100644
--- a/assets/webconfig/i18n/en.json
+++ b/assets/webconfig/i18n/en.json
@@ -186,6 +186,7 @@
"conf_network_json_intro": "The JSON-RPC-Port of all Hyperion instances, used for remote control.",
"conf_network_net_intro": "Network related settings which are applied to all network services.",
"conf_network_proto_intro": "The PROTO-Port of all Hyperion instances, used for picture streams (HyperionScreenCap, Kodi Addon, Android Hyperion Grabber, ...)",
+ "conf_network_tok_idhead": "ID",
"conf_network_tok_cidhead": "Description",
"conf_network_tok_comment_title": "Token description",
"conf_network_tok_desc": "Tokens grant other applications access to the Hyperion API, an application can request a token where you need to accept it or you create them on your own below. These tokens are just required when \"API Authorization\" is enabled in network settings.",
@@ -500,19 +501,16 @@
"edt_conf_log_level_expl": "Depending on loglevel you see less or more messages in your log.",
"edt_conf_log_level_title": "Log-Level",
"edt_conf_net_apiAuth_expl": "Enforce all applications that use the Hyperion API to authenticate themself against Hyperion (Exception: see \"Local API Authentication\"). Higher security, as you control the access and revoke it at any time.",
- "edt_conf_net_apiAuth_title": "API Authentication",
"edt_conf_net_heading_title": "Network",
- "edt_conf_net_internetAccessAPI_expl": "Allow access to the Hyperion API/Webinterface from the internet. Disable for higher security.",
+ "edt_conf_net_internetAccessAPI_expl": "Allow access to the Hyperion API/Web Interface from the Internet. Disable for increased security.",
"edt_conf_net_internetAccessAPI_title": "Internet API Access",
- "edt_conf_net_ipWhitelist_expl": "You can whitelist IP addresses instead allowing all connections from internet to connect to the Hyperion API/Webinterface.",
- "edt_conf_net_ipWhitelist_title": "Whitelisted IP's",
+ "edt_conf_net_ipWhitelist_expl": "Define whitelisted IP addresses from which API requests from the Internet are allowed. All other external connections will be denied.",
+ "edt_conf_net_ipWhitelist_title": "Whitelisted IP addresses",
"edt_conf_net_ip_itemtitle": "IP",
- "edt_conf_net_localAdminAuth_expl": "When enabled, administration access from your local network needs a password.",
- "edt_conf_net_localAdminAuth_title": "Local Admin API Authentication",
- "edt_conf_net_localApiAuth_expl": "When enabled, connections from your home network needs to authenticate themselves against Hyperion with a token.",
+ "edt_conf_net_localApiAuth_expl": "When disabled, API authorisation via password or token is not required for local connections. The exception is administrative commands.",
"edt_conf_net_localApiAuth_title": "Local API Authentication",
- "edt_conf_net_restirctedInternetAccessAPI_expl": "You can restrict the access to the API through the internet to certain IP's.",
- "edt_conf_net_restirctedInternetAccessAPI_title": "Restrict to IP's",
+ "edt_conf_net_restirctedInternetAccessAPI_expl": "You can restrict API requests over the Internet to only those IP addresses on the whitelist.",
+ "edt_conf_net_restirctedInternetAccessAPI_title": "Restrict to IP addresses",
"edt_conf_os_events_lockEnable_title": "Listen to lock events",
"edt_conf_os_events_lockEnable_expl": "Listen to screen lock/unlock events",
"edt_conf_os_events_suspendEnable_title": "Listen to suspend events",
diff --git a/assets/webconfig/js/content_index.js b/assets/webconfig/js/content_index.js
index e8ec28a8..00b1ba3d 100644
--- a/assets/webconfig/js/content_index.js
+++ b/assets/webconfig/js/content_index.js
@@ -73,26 +73,30 @@ $(document).ready(function () {
//End language selection
$(window.hyperion).on("cmd-authorize-tokenRequest cmd-authorize-getPendingTokenRequests", function (event) {
- var val = event.response.info;
- if (Array.isArray(event.response.info)) {
- if (event.response.info.length == 0) {
- return
- }
- val = event.response.info[0]
- if (val.comment == '')
- $('#modal_dialog').modal('hide');
- }
- showInfoDialog("grantToken", $.i18n('conf_network_tok_grantT'), $.i18n('conf_network_tok_grantMsg') + '
App: ' + val.comment + '
Code: ' + val.id + '')
- $("#tok_grant_acc").off().on('click', function () {
- tokenList.push(val)
- // forward event, in case we need to rebuild the list now
- $(window.hyperion).trigger({ type: "build-token-list" });
- requestHandleTokenRequest(val.id, true)
- });
- $("#tok_deny_acc").off().on('click', function () {
- requestHandleTokenRequest(val.id, false)
- });
+ if (event.response && event.response.info !== undefined) {
+ var val = event.response.info;
+
+ if (Array.isArray(event.response.info)) {
+ if (event.response.info.length == 0) {
+ return
+ }
+ val = event.response.info[0]
+ if (val.comment == '')
+ $('#modal_dialog').modal('hide');
+ }
+
+ showInfoDialog("grantToken", $.i18n('conf_network_tok_grantT'), $.i18n('conf_network_tok_grantMsg') + '
App: ' + val.comment + '
Code: ' + val.id + '')
+ $("#tok_grant_acc").off().on('click', function () {
+ tokenList.push(val)
+ // forward event, in case we need to rebuild the list now
+ $(window.hyperion).trigger({ type: "build-token-list" });
+ requestHandleTokenRequest(val.id, true)
+ });
+ $("#tok_deny_acc").off().on('click', function () {
+ requestHandleTokenRequest(val.id, false)
+ });
+ }
});
$(window.hyperion).one("cmd-authorize-getTokenList", function (event) {
diff --git a/assets/webconfig/js/content_logging.js b/assets/webconfig/js/content_logging.js
index 7a9c791d..3fbe7aef 100644
--- a/assets/webconfig/js/content_logging.js
+++ b/assets/webconfig/js/content_logging.js
@@ -3,10 +3,13 @@ var createdCont = false;
var isScroll = true;
performTranslation();
-requestLoggingStop();
$(document).ready(function () {
+ window.addEventListener('hashchange', function(event) {
+ requestLoggingStop();
+ });
+
requestLoggingStart();
$('#conf_cont').append(createOptPanel('fa-reorder', $.i18n("edt_conf_log_heading_title"), 'editor_container', 'btn_submit'));
@@ -180,7 +183,7 @@ $(document).ready(function () {
$(window.hyperion).on("cmd-logging-update", function (event) {
- var messages = (event.response.result.messages);
+ var messages = (event.response.data.messages);
if (messages.length != 0) {
if (!createdCont) {
diff --git a/assets/webconfig/js/content_network.js b/assets/webconfig/js/content_network.js
index 26fec2c8..9f9f68c3 100644
--- a/assets/webconfig/js/content_network.js
+++ b/assets/webconfig/js/content_network.js
@@ -213,13 +213,13 @@ $(document).ready(function () {
for (var key in tokenList) {
var lastUse = (tokenList[key].last_use) ? tokenList[key].last_use : "-";
var btn = '';
- $('.tktbody').append(createTableRow([tokenList[key].comment, lastUse, btn], false, true));
+ $('.tktbody').append(createTableRow([tokenList[key].id, tokenList[key].comment, lastUse, btn], false, true));
$('#tok' + tokenList[key].id).off().on('click', handleDeleteToken);
}
}
createTable('tkthead', 'tktbody', 'tktable');
- $('.tkthead').html(createTableRow([$.i18n('conf_network_tok_cidhead'), $.i18n('conf_network_tok_lastuse'), $.i18n('general_btn_delete')], true, true));
+ $('.tkthead').html(createTableRow([$.i18n('conf_network_tok_idhead'), $.i18n('conf_network_tok_cidhead'), $.i18n('conf_network_tok_lastuse'), $.i18n('general_btn_delete')], true, true));
buildTokenList();
function handleDeleteToken(e) {
diff --git a/assets/webconfig/js/ledsim.js b/assets/webconfig/js/ledsim.js
index 32a8898b..af633ba7 100644
--- a/assets/webconfig/js/ledsim.js
+++ b/assets/webconfig/js/ledsim.js
@@ -261,7 +261,7 @@ $(document).ready(function () {
$("body").get(0).style.setProperty("--background-var", "none");
}
else {
- printLedsToCanvas(event.response.result.leds)
+ printLedsToCanvas(event.response.data.leds)
$("body").get(0).style.setProperty("--background-var", "url(" + ($('#leds_preview_canv')[0]).toDataURL("image/jpg") + ") no-repeat top left");
}
});
@@ -275,7 +275,7 @@ $(document).ready(function () {
}
}
else {
- var imageData = (event.response.result.image);
+ var imageData = (event.response.data.image);
var image = new Image();
image.onload = function () {
diff --git a/config/hyperion.config.json.default b/config/hyperion.config.json.default
index 18fc9dc9..f126b638 100644
--- a/config/hyperion.config.json.default
+++ b/config/hyperion.config.json.default
@@ -220,9 +220,7 @@
"internetAccessAPI": false,
"restirctedInternetAccessAPI": false,
"ipWhitelist": [],
- "apiAuth": true,
- "localApiAuth": false,
- "localAdminAuth": true
+ "localApiAuth": false
},
"ledConfig": {
diff --git a/include/api/API.h b/include/api/API.h
index 31a60f97..f50f5d2c 100644
--- a/include/api/API.h
+++ b/include/api/API.h
@@ -14,11 +14,15 @@
// qt includes
#include
-class QTimer;
-class JsonCB;
+class JsonCallbacks;
class HyperionIManager;
-const QString NO_AUTH = "No Authorization";
+// Constants
+namespace {
+
+const char NO_AUTHORIZATION[] = "No Authorization";;
+
+}
///
/// @brief API for Hyperion to be inherted from a child class with specific protocol implementations
@@ -31,205 +35,208 @@ const QString NO_AUTH = "No Authorization";
class API : public QObject
{
- Q_OBJECT
+ Q_OBJECT
public:
#include
- // workaround Q_ARG std::map template issues
- typedef std::map MapRegister;
- typedef QMap MapAuthDefs;
- ///
- /// Constructor
- ///
- ///@ param The parent Logger
- /// @param localConnection Is this a local network connection? Use utils/NetOrigin to check that
- /// @param parent Parent QObject
- ///
- API(Logger *log, bool localConnection, QObject *parent);
-
-protected:
- ///
- /// @brief Initialize the API
- /// This call is REQUIRED!
- ///
- void init();
-
- ///
- /// @brief Set a single color
- /// @param[in] priority The priority of the written color
- /// @param[in] ledColor The color to write to the leds
- /// @param[in] timeout_ms The time the leds are set to the given color [ms]
- /// @param[in] origin The setter
- ///
- void setColor(int priority, const std::vector &ledColors, int timeout_ms = -1, const QString &origin = "API", hyperion::Components callerComp = hyperion::COMP_INVALID);
-
- ///
- /// @brief Set a image
- /// @param[in] data The command data
- /// @param[in] comp The component that should be used
- /// @param[out] replyMsg The replyMsg on failure
- /// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
- /// @return True on success
- ///
- bool setImage(ImageCmdData &data, hyperion::Components comp, QString &replyMsg, hyperion::Components callerComp = hyperion::COMP_INVALID);
-
- ///
- /// @brief Clear a priority in the Muxer, if -1 all priorities are cleared
- /// @param priority The priority to clear
- /// @param replyMsg the message on failure
- /// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
- /// @return True on success
- ///
- bool clearPriority(int priority, QString &replyMsg, hyperion::Components callerComp = hyperion::COMP_INVALID);
-
- ///
- /// @brief Set a new component state
- /// @param comp The component name
- /// @param compState The new state of the comp
- /// @param replyMsg The reply on failure
- /// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
- /// @ return True on success
- ///
- bool setComponentState(const QString &comp, bool &compState, QString &replyMsg, hyperion::Components callerComp = hyperion::COMP_INVALID);
-
- ///
- /// @brief Set a ledToImageMapping type
- /// @param type mapping type string
- /// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
- ///
- void setLedMappingType(int type, hyperion::Components callerComp = hyperion::COMP_INVALID);
-
- ///
- /// @brief Set the 2D/3D modes type
- /// @param mode The VideoMode
- /// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
- ///
- void setVideoMode(VideoMode mode, hyperion::Components callerComp = hyperion::COMP_INVALID);
-
-#if defined(ENABLE_EFFECTENGINE)
- ///
- /// @brief Set an effect
- /// @param dat The effect data
- /// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
- /// REQUIRED dat fields: effectName, priority, duration, origin
- /// @return True on success else false
- ///
- bool setEffect(const EffectCmdData &dat, hyperion::Components callerComp = hyperion::COMP_INVALID);
-#endif
-
- ///
- /// @brief Set source auto select enabled or disabled
- /// @param sate The new state
- /// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
- ///
- void setSourceAutoSelect(bool state, hyperion::Components callerComp = hyperion::COMP_INVALID);
-
- ///
- /// @brief Set the visible priority to given priority
- /// @param priority The priority to set
- /// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
- ///
- void setVisiblePriority(int priority, hyperion::Components callerComp = hyperion::COMP_INVALID);
-
- ///
- /// @brief Register a input or update the meta data of a previous register call
- /// ATTENTION: Check unregisterInput() method description !!!
- /// @param[in] priority The priority of the channel
- /// @param[in] component The component of the channel
- /// @param[in] origin Who set the channel (CustomString@IP)
- /// @param[in] owner Specific owner string, might be empty
- /// @param[in] callerComp The component that call this (e.g. PROTO/FLAT)
- ///
- void registerInput(int priority, hyperion::Components component, const QString &origin, const QString &owner, hyperion::Components callerComp);
-
- ///
- /// @brief Revoke a registerInput() call by priority. We maintain all registered priorities in this scope
- /// ATTENTION: This is MANDATORY if you change (priority change) or stop(clear/timeout) DURING lifetime. If this class destructs it's not needed
- /// @param priority The priority to unregister
- ///
- void unregisterInput(int priority);
-
- ///
- /// @brief Handle the instance switching
- /// @param inst The requested instance
- /// @return True on success else false
- ///
- bool setHyperionInstance(quint8 inst);
+ // workaround Q_ARG std::map template issues
+ typedef std::map MapRegister;
+ typedef QMap MapAuthDefs;
///
- /// @brief Check if Hyperion ist enabled
- /// @return True when enabled else false
- ///
- bool isHyperionEnabled();
+ /// Constructor
+ ///
+ ///@ param The parent Logger
+ /// @param localConnection Is this a local network connection? Use utils/NetOrigin to check that
+ /// @param parent Parent QObject
+ ///
+ API(Logger *log, bool localConnection, QObject *parent);
- ///
- /// @brief Get all instances data
- /// @return The instance data
- ///
- QVector getAllInstanceData();
+protected:
+ ///
+ /// @brief Initialize the API
+ /// This call is REQUIRED!
+ ///
+ void init();
- ///
- /// @brief Start instance
- /// @param index The instance index
- /// @param tan The tan
- /// @return True on success else false
- ///
- bool startInstance(quint8 index, int tan = 0);
+ virtual void stopDataConnections() = 0;
- ///
- /// @brief Stop instance
- /// @param index The instance index
- ///
- void stopInstance(quint8 index);
+ ///
+ /// @brief Set a single color
+ /// @param[in] priority The priority of the written color
+ /// @param[in] ledColor The color to write to the leds
+ /// @param[in] timeout_ms The time the leds are set to the given color [ms]
+ /// @param[in] origin The setter
+ ///
+ void setColor(int priority, const std::vector &ledColors, int timeout_ms = -1, const QString &origin = "API", hyperion::Components callerComp = hyperion::COMP_INVALID);
- //////////////////////////////////
- /// AUTH / ADMINISTRATION METHODS
- //////////////////////////////////
+ ///
+ /// @brief Set a image
+ /// @param[in] data The command data
+ /// @param[in] comp The component that should be used
+ /// @param[out] replyMsg The replyMsg on failure
+ /// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
+ /// @return True on success
+ ///
+ bool setImage(ImageCmdData &data, hyperion::Components comp, QString &replyMsg, hyperion::Components callerComp = hyperion::COMP_INVALID);
- ///
- /// @brief Delete instance. Requires ADMIN ACCESS
- /// @param index The instance index
- /// @param replyMsg The reply Msg
- /// @return False with reply
- ///
- bool deleteInstance(quint8 index, QString &replyMsg);
+ ///
+ /// @brief Clear a priority in the Muxer, if -1 all priorities are cleared
+ /// @param priority The priority to clear
+ /// @param replyMsg the message on failure
+ /// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
+ /// @return True on success
+ ///
+ bool clearPriority(int priority, QString &replyMsg, hyperion::Components callerComp = hyperion::COMP_INVALID);
- ///
- /// @brief Create instance. Requires ADMIN ACCESS
- /// @param name With given name
- /// @return False with reply
- ///
- QString createInstance(const QString &name);
+ ///
+ /// @brief Set a new component state
+ /// @param comp The component name
+ /// @param compState The new state of the comp
+ /// @param replyMsg The reply on failure
+ /// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
+ /// @ return True on success
+ ///
+ bool setComponentState(const QString &comp, bool &compState, QString &replyMsg, hyperion::Components callerComp = hyperion::COMP_INVALID);
- ///
- /// @brief Rename an instance. Requires ADMIN ACCESS
- /// @param index The instance index
- /// @param name With given name
- /// @return False with reply
- ///
- QString setInstanceName(quint8 index, const QString &name);
+ ///
+ /// @brief Set a ledToImageMapping type
+ /// @param type mapping type string
+ /// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
+ ///
+ void setLedMappingType(int type, hyperion::Components callerComp = hyperion::COMP_INVALID);
+
+ ///
+ /// @brief Set the 2D/3D modes type
+ /// @param mode The VideoMode
+ /// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
+ ///
+ void setVideoMode(VideoMode mode, hyperion::Components callerComp = hyperion::COMP_INVALID);
#if defined(ENABLE_EFFECTENGINE)
- ///
- /// @brief Delete an effect. Requires ADMIN ACCESS
- /// @param name The effect name
- /// @return True on success else false
- ///
- QString deleteEffect(const QString &name);
-
- ///
- /// @brief Delete an effect. Requires ADMIN ACCESS
- /// @param name The effect name
- /// @return True on success else false
- ///
- QString saveEffect(const QJsonObject &data);
+ ///
+ /// @brief Set an effect
+ /// @param dat The effect data
+ /// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
+ /// REQUIRED dat fields: effectName, priority, duration, origin
+ /// @return True on success else false
+ ///
+ bool setEffect(const EffectCmdData &dat, hyperion::Components callerComp = hyperion::COMP_INVALID);
#endif
- ///
- /// @brief Save settings object. Requires ADMIN ACCESS
- /// @param data The data object
- ///
+ ///
+ /// @brief Set source auto select enabled or disabled
+ /// @param sate The new state
+ /// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
+ ///
+ void setSourceAutoSelect(bool state, hyperion::Components callerComp = hyperion::COMP_INVALID);
+
+ ///
+ /// @brief Set the visible priority to given priority
+ /// @param priority The priority to set
+ /// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
+ ///
+ void setVisiblePriority(int priority, hyperion::Components callerComp = hyperion::COMP_INVALID);
+
+ ///
+ /// @brief Register a input or update the meta data of a previous register call
+ /// ATTENTION: Check unregisterInput() method description !!!
+ /// @param[in] priority The priority of the channel
+ /// @param[in] component The component of the channel
+ /// @param[in] origin Who set the channel (CustomString@IP)
+ /// @param[in] owner Specific owner string, might be empty
+ /// @param[in] callerComp The component that call this (e.g. PROTO/FLAT)
+ ///
+ void registerInput(int priority, hyperion::Components component, const QString &origin, const QString &owner, hyperion::Components callerComp);
+
+ ///
+ /// @brief Revoke a registerInput() call by priority. We maintain all registered priorities in this scope
+ /// ATTENTION: This is MANDATORY if you change (priority change) or stop(clear/timeout) DURING lifetime. If this class destructs it's not needed
+ /// @param priority The priority to unregister
+ ///
+ void unregisterInput(int priority);
+
+ ///
+ /// @brief Handle the instance switching
+ /// @param inst The requested instance
+ /// @return True on success else false
+ ///
+ bool setHyperionInstance(quint8 inst);
+
+ ///
+ /// @brief Check if Hyperion ist enabled
+ /// @return True when enabled else false
+ ///
+ bool isHyperionEnabled();
+
+ ///
+ /// @brief Get all instances data
+ /// @return The instance data
+ ///
+ QVector getAllInstanceData() const;
+
+ ///
+ /// @brief Start instance
+ /// @param index The instance index
+ /// @param tan The tan
+ /// @return True on success else false
+ ///
+ bool startInstance(quint8 index, int tan = 0);
+
+ ///
+ /// @brief Stop instance
+ /// @param index The instance index
+ ///
+ void stopInstance(quint8 index);
+
+ //////////////////////////////////
+ /// AUTH / ADMINISTRATION METHODS
+ //////////////////////////////////
+
+ ///
+ /// @brief Delete instance. Requires ADMIN ACCESS
+ /// @param index The instance index
+ /// @param replyMsg The reply Msg
+ /// @return False with reply
+ ///
+ bool deleteInstance(quint8 index, QString &replyMsg);
+
+ ///
+ /// @brief Create instance. Requires ADMIN ACCESS
+ /// @param name With given name
+ /// @return False with reply
+ ///
+ QString createInstance(const QString &name);
+
+ ///
+ /// @brief Rename an instance. Requires ADMIN ACCESS
+ /// @param index The instance index
+ /// @param name With given name
+ /// @return False with reply
+ ///
+ QString setInstanceName(quint8 index, const QString &name);
+
+#if defined(ENABLE_EFFECTENGINE)
+ ///
+ /// @brief Delete an effect. Requires ADMIN ACCESS
+ /// @param name The effect name
+ /// @return True on success else false
+ ///
+ QString deleteEffect(const QString &name);
+
+ ///
+ /// @brief Delete an effect. Requires ADMIN ACCESS
+ /// @param name The effect name
+ /// @return True on success else false
+ ///
+ QString saveEffect(const QJsonObject &data);
+#endif
+
+ ///
+ /// @brief Save settings object. Requires ADMIN ACCESS
+ /// @param data The data object
+ ///
bool saveSettings(const QJsonObject &data);
///
@@ -238,171 +245,189 @@ protected:
///
bool restoreSettings(const QJsonObject &data);
- ///
- /// @brief Test if we are authorized to use the interface
- /// @return The result
- ///
- bool isAuthorized() { return _authorized; };
+ ///
+ /// @brief Set the authorizationn state
+ /// @param authorized True, if authorized
+ ///
+ void setAuthorization(bool authorized) { _authorized = authorized; }
- ///
- /// @brief Test if we are authorized to use the admin interface
- /// @return The result
- ///
- bool isAdminAuthorized() { return _adminAuthorized; };
+ ///
+ /// @brief Test if we are authorized to use the interface
+ /// @return The result
+ ///
+ bool isAuthorized() const { return _authorized; }
- ///
- /// @brief Update the Password of Hyperion. Requires ADMIN ACCESS
- /// @param password Old password
- /// @param newPassword New password
- /// @return True on success else false
- ///
- bool updateHyperionPassword(const QString &password, const QString &newPassword);
+ ///
+ /// @brief Set the authorizationn state for admin activities
+ /// @param authorized True, if authorized
+ ///
+ void setAdminAuthorization(bool adminAuthorized) { _adminAuthorized = adminAuthorized; }
- ///
- /// @brief Get a new token from AuthManager. Requires ADMIN ACCESS
- /// @param comment The comment of the request
- /// @param def The final definition
- /// @return Empty string on success else error message
- ///
- QString createToken(const QString &comment, AuthManager::AuthDefinition &def);
+ ///
+ /// @brief Test if we are authorized to use admin activites
+ /// @return The result
+ ///
+ bool isAdminAuthorized() const { return _adminAuthorized; }
- ///
- /// @brief Rename a token by given id. Requires ADMIN ACCESS
- /// @param id The id of the token
- /// @param comment The new comment
- /// @return Empty string on success else error message
- ///
- QString renameToken(const QString &id, const QString &comment);
+ ///
+ /// @brief Return, if connection is from local network segment
+ /// @return The result
+ ///
+ bool islocalConnection() const { return _localConnection; }
- ///
- /// @brief Delete a token by given id. Requires ADMIN ACCESS
- /// @param id The id of the token
- /// @return Empty string on success else error message
- ///
- QString deleteToken(const QString &id);
+ ///
+ /// @brief Update the Password of Hyperion. Requires ADMIN ACCESS
+ /// @param password Old password
+ /// @param newPassword New password
+ /// @return True on success else false
+ ///
+ bool updateHyperionPassword(const QString &password, const QString &newPassword);
- ///
- /// @brief Set a new token request
- /// @param comment The comment
- /// @param id The id
+ ///
+ /// @brief Get a new token from AuthManager. Requires ADMIN ACCESS
+ /// @param comment The comment of the request
+ /// @param def The final definition
+ /// @return Empty string on success else error message
+ ///
+ QString createToken(const QString &comment, AuthManager::AuthDefinition &def);
+
+ ///
+ /// @brief Rename a token by given id. Requires ADMIN ACCESS
+ /// @param tokenId The id of the token
+ /// @param comment The new comment
+ /// @return Empty string on success else error message
+ ///
+ QString renameToken(const QString &tokenId, const QString &comment);
+
+ ///
+ /// @brief Delete a token by given id. Requires ADMIN ACCESS
+ /// @param tokenId The id of the token
+ /// @return Empty string on success else error message
+ ///
+ QString deleteToken(const QString &tokenId);
+
+ ///
+ /// @brief Set a new token request
+ /// @param comment The comment
+ /// @param tokenId The id of the token
/// @param tan The tan
- ///
- void setNewTokenRequest(const QString &comment, const QString &id, const int &tan);
+ ///
+ void setNewTokenRequest(const QString &comment, const QString &tokenId, const int &tan);
- ///
- /// @brief Cancel new token request
- /// @param comment The comment
- /// @param id The id
- ///
- void cancelNewTokenRequest(const QString &comment, const QString &id);
+ ///
+ /// @brief Cancel new token request
+ /// @param comment The comment
+ /// @param tokenId The id of the token
+ ///
+ void cancelNewTokenRequest(const QString &comment, const QString &tokenId);
- ///
- /// @brief Handle a pending token request. Requires ADMIN ACCESS
- /// @param id The id fo the request
- /// @param accept True when it should be accepted, else false
- /// @return True on success
- bool handlePendingTokenRequest(const QString &id, bool accept);
-
- ///
- /// @brief Get the current List of Tokens. Requires ADMIN ACCESS
- /// @param def returns the defintions
- /// @return True on success
- ///
- bool getTokenList(QVector &def);
-
- ///
- /// @brief Get all current pending token requests. Requires ADMIN ACCESS
- /// @return True on success
- ///
- bool getPendingTokenRequests(QVector &map);
-
- ///
- /// @brief Is User Token Authorized. On success this will grant acces to API and ADMIN API
- /// @param userToken The user Token
- /// @return True on succes
- ///
- bool isUserTokenAuthorized(const QString &userToken);
-
- ///
- /// @brief Get the current User Token (session token). Requires ADMIN ACCESS
- /// @param userToken The user Token
- /// @return True on success
- ///
- bool getUserToken(QString &userToken);
-
- ///
- /// @brief Is a token authorized. On success this will grant acces to the API (NOT ADMIN API)
- /// @param token The user Token
+ ///
+ /// @brief Handle a pending token request. Requires ADMIN ACCESS
+ /// @param tokenId The id fo the request
+ /// @param accept True when it should be accepted, else false
/// @return True on success
- ///
- bool isTokenAuthorized(const QString &token);
+ bool handlePendingTokenRequest(const QString &tokenId, bool accept);
- ///
- /// @brief Is User authorized. On success this will grant acces to the API and ADMIN API
- /// @param password The password of the User
- /// @return True if authorized
- ///
- bool isUserAuthorized(const QString &password);
+ ///
+ /// @brief Get the current List of Tokens. Requires ADMIN ACCESS
+ /// @param def returns the defintions
+ /// @return True on success
+ ///
+ bool getTokenList(QVector &def);
- ///
- /// @brief Test if Hyperion has the default PW
- /// @return The result
- ///
- bool hasHyperionDefaultPw();
+ ///
+ /// @brief Get all current pending token requests. Requires ADMIN ACCESS
+ /// @return True on success
+ ///
+ bool getPendingTokenRequests(QVector &map);
- ///
- /// @brief Logout revokes all authorizations
- ///
- void logout();
+ ///
+ /// @brief Is User Token Authorized. On success this will grant acces to API and ADMIN API
+ /// @param userToken The user Token
+ /// @return True on succes
+ ///
+ bool isUserTokenAuthorized(const QString &userToken);
- /// Reflect auth status of this client
- bool _authorized;
- bool _adminAuthorized;
+ ///
+ /// @brief Get the current User Token (session token). Requires ADMIN ACCESS
+ /// @param userToken The user Token
+ /// @return True on success
+ ///
+ bool getUserToken(QString &userToken);
- /// Is this a local connection
- bool _localConnection;
+ ///
+ /// @brief Is a token authorized. On success this will grant acces to the API (NOT ADMIN API)
+ /// @param token The user Token
+ /// @return True on success
+ ///
+ bool isTokenAuthorized(const QString &token);
- AuthManager *_authManager;
- HyperionIManager *_instanceManager;
+ ///
+ /// @brief Is User authorized. On success this will grant acces to the API and ADMIN API
+ /// @param password The password of the User
+ /// @return True if authorized
+ ///
+ bool isUserAuthorized(const QString &password);
- Logger *_log;
- Hyperion *_hyperion;
+ ///
+ /// @brief Test if Hyperion has the default PW
+ /// @return The result
+ ///
+ bool hasHyperionDefaultPw();
+
+ ///
+ /// @brief Logout revokes all authorizations
+ ///
+ void logout();
+
+
+ AuthManager *_authManager;
+ HyperionIManager *_instanceManager;
+
+ Logger *_log;
+ Hyperion *_hyperion;
signals:
- ///
- /// @brief The API might decide to block connections for security reasons, this emitter should close the socket
- ///
- void forceClose();
+ ///
+ /// @brief The API might decide to block connections for security reasons, this emitter should close the socket
+ ///
+ void forceClose();
- ///
- /// @brief Emits whenever a new Token request is pending. This signal is just active when ADMIN ACCESS has been granted
- /// @param id The id of the request
- /// @param comment The comment of the request; If the commen is EMPTY the request has been revoked by the caller. So remove it from the pending list
- ///
- void onPendingTokenRequest(const QString &id, const QString &comment);
+ ///
+ /// @brief Emits whenever a new Token request is pending. This signal is just active when ADMIN ACCESS has been granted
+ /// @param tokenId The id of the request
+ /// @param comment The comment of the request; If the commen is EMPTY the request has been revoked by the caller. So remove it from the pending list
+ ///
+ void onPendingTokenRequest(const QString &tokenId, const QString &comment);
- ///
- /// @brief Handle emits from AuthManager of accepted/denied/timeouts token request, just if QObject matches with this instance it will emit.
- /// @param success If true the request was accepted else false and no token was created
- /// @param token The new token that is now valid
- /// @param comment The comment that was part of the request
- /// @param id The id that was part of the request
- /// @param tan The tan that was part of the request
- ///
- void onTokenResponse(bool success, const QString &token, const QString &comment, const QString &id, const int &tan);
+ ///
+ /// @brief Handle emits from AuthManager of accepted/denied/timeouts token request, just if QObject matches with this instance it will emit.
+ /// @param success If true the request was accepted else false and no token was created
+ /// @param token The new token that is now valid
+ /// @param comment The comment that was part of the request
+ /// @param tokenId The id that was part of the request
+ /// @param tan The tan that was part of the request
+ ///
+ void onTokenResponse(bool success, const QString &token, const QString &comment, const QString &tokenId, const int &tan);
- ///
- /// @brief Handle emits from HyperionIManager of startInstance request, just if QObject matches with this instance it will emit.
- /// @param tan The tan that was part of the request
- ///
- void onStartInstanceResponse(const int &tan);
+ ///
+ /// @brief Handle emits from HyperionIManager of startInstance request, just if QObject matches with this instance it will emit.
+ /// @param tan The tan that was part of the request
+ ///
+ void onStartInstanceResponse(const int &tan);
private:
- void stopDataConnectionss();
- // Contains all active register call data
- std::map _activeRegisters;
+ /// Reflect authorization status of this client
+ bool _authorized;
+ bool _adminAuthorized;
- // current instance index
- quint8 _currInstanceIndex;
+ /// Is this a local connection
+ bool _localConnection;
+
+ // Contains all active register call data
+ std::map _activeRegisters;
+
+ // current instance index
+ quint8 _currInstanceIndex;
};
diff --git a/include/api/JsonAPI.h b/include/api/JsonAPI.h
index 8e36b158..7cef7f14 100644
--- a/include/api/JsonAPI.h
+++ b/include/api/JsonAPI.h
@@ -2,19 +2,24 @@
// parent class
#include
+#include
+
#include
// hyperion includes
#include
#include
#include
+#include
// qt includes
#include
#include
+#include
+#include
class QTimer;
-class JsonCB;
+class JsonCallbacks;
class AuthManager;
class JsonAPI : public API
@@ -46,40 +51,24 @@ public:
void initialize();
public slots:
- ///
- /// @brief Is called whenever the current Hyperion instance pushes new led raw values (if enabled)
- /// @param ledColors The current led colors
- ///
- void streamLedcolorsUpdate(const std::vector &ledColors);
-
- ///
- /// @brief Push images whenever hyperion emits (if enabled)
- /// @param image The current image
- ///
- void setImage(const Image &image);
-
- ///
- /// @brief Process and push new log messages from logger (if enabled)
- ///
- void incommingLogMessage(const Logger::T_LOG_MESSAGE &);
private slots:
///
/// @brief Handle emits from API of a new Token request.
- /// @param id The id of the request
+ /// @param identifier The identifier of the request
/// @param comment The comment which needs to be accepted
///
- void newPendingTokenRequest(const QString &id, const QString &comment);
+ void issueNewPendingTokenRequest(const QString &identifier, const QString &comment);
///
/// @brief Handle emits from AuthManager of accepted/denied/timeouts token request, just if QObject matches with this instance we are allowed to send response.
/// @param success If true the request was accepted else false and no token was created
/// @param token The new token that is now valid
/// @param comment The comment that was part of the request
- /// @param id The id that was part of the request
+ /// @param identifier The identifier that was part of the request
/// @param tan The tan that was part of the request
///
- void handleTokenResponse(bool success, const QString &token, const QString &comment, const QString &id, const int &tan);
+ void handleTokenResponse(bool success, const QString &token, const QString &comment, const QString &identifier, const int &tan);
///
/// @brief Handle whenever the state of a instance (HyperionIManager) changes according to enum instanceState
@@ -89,11 +78,6 @@ private slots:
///
void handleInstanceStateChange(InstanceState state, quint8 instance, const QString &name = QString());
- ///
- /// @brief Stream a new LED Colors update
- ///
- void streamLedColorsUpdate();
-
signals:
///
/// Signal emits with the reply message provided with handleMessage()
@@ -111,31 +95,8 @@ signals:
void signalEvent(Event event);
private:
- // true if further callbacks are forbidden (http)
- bool _noListener;
- /// The peer address of the client
- QString _peerAddress;
-
- // The JsonCB instance which handles data subscription/notifications
- JsonCB *_jsonCB;
-
- // streaming buffers
- QJsonObject _streaming_leds_reply;
- QJsonObject _streaming_image_reply;
- QJsonObject _streaming_logging_reply;
-
- /// flag to determine state of log streaming
- bool _streaming_logging_activated;
-
- /// timer for led color refresh
- QTimer *_ledStreamTimer;
-
- /// led stream connection handle
- QMetaObject::Connection _ledStreamConnection;
-
- /// the current streaming led values
- std::vector _currentLedValues;
+ void handleCommand(const JsonApiCommand& cmd, const QJsonObject &message);
///
/// @brief Handle the switches of Hyperion instances
@@ -150,14 +111,14 @@ private:
///
/// @param message the incoming message
///
- void handleColorCommand(const QJsonObject &message, const QString &command, int tan);
+ void handleColorCommand(const QJsonObject& message, const JsonApiCommand& cmd);
///
/// Handle an incoming JSON Image message
///
/// @param message the incoming message
///
- void handleImageCommand(const QJsonObject &message, const QString &command, int tan);
+ void handleImageCommand(const QJsonObject &message, const JsonApiCommand& cmd);
#if defined(ENABLE_EFFECTENGINE)
///
@@ -165,21 +126,21 @@ private:
///
/// @param message the incoming message
///
- void handleEffectCommand(const QJsonObject &message, const QString &command, int tan);
+ void handleEffectCommand(const QJsonObject &message, const JsonApiCommand& cmd);
///
/// Handle an incoming JSON Effect message (Write JSON Effect)
///
/// @param message the incoming message
///
- void handleCreateEffectCommand(const QJsonObject &message, const QString &command, int tan);
+ void handleCreateEffectCommand(const QJsonObject &message, const JsonApiCommand& cmd);
///
/// Handle an incoming JSON Effect message (Delete JSON Effect)
///
/// @param message the incoming message
///
- void handleDeleteEffectCommand(const QJsonObject &message, const QString &command, int tan);
+ void handleDeleteEffectCommand(const QJsonObject &message, const JsonApiCommand& cmd);
#endif
///
@@ -187,138 +148,170 @@ private:
///
/// @param message the incoming message
///
- void handleSysInfoCommand(const QJsonObject &message, const QString &command, int tan);
+ void handleSysInfoCommand(const QJsonObject &message, const JsonApiCommand& cmd);
///
/// Handle an incoming JSON Server info message
///
/// @param message the incoming message
///
- void handleServerInfoCommand(const QJsonObject &message, const QString &command, int tan);
+ void handleServerInfoCommand(const QJsonObject &message, const JsonApiCommand& cmd);
///
/// Handle an incoming JSON Clear message
///
/// @param message the incoming message
///
- void handleClearCommand(const QJsonObject &message, const QString &command, int tan);
+ void handleClearCommand(const QJsonObject &message, const JsonApiCommand& cmd);
///
/// Handle an incoming JSON Clearall message
///
/// @param message the incoming message
///
- void handleClearallCommand(const QJsonObject &message, const QString &command, int tan);
+ void handleClearallCommand(const QJsonObject &message, const JsonApiCommand& cmd);
///
/// Handle an incoming JSON Adjustment message
///
/// @param message the incoming message
///
- void handleAdjustmentCommand(const QJsonObject &message, const QString &command, int tan);
+ void handleAdjustmentCommand(const QJsonObject &message, const JsonApiCommand& cmd);
///
/// Handle an incoming JSON SourceSelect message
///
/// @param message the incoming message
///
- void handleSourceSelectCommand(const QJsonObject &message, const QString &command, int tan);
+ void handleSourceSelectCommand(const QJsonObject &message, const JsonApiCommand& cmd);
/// Handle an incoming JSON GetConfig message and check subcommand
///
/// @param message the incoming message
///
- void handleConfigCommand(const QJsonObject &message, const QString &command, int tan);
+ void handleConfigCommand(const QJsonObject &message, const JsonApiCommand& cmd);
/// Handle an incoming JSON GetSchema message from handleConfigCommand()
///
/// @param message the incoming message
///
- void handleSchemaGetCommand(const QJsonObject &message, const QString &command, int tan);
+ void handleSchemaGetCommand(const QJsonObject &message, const JsonApiCommand& cmd);
/// Handle an incoming JSON SetConfig message from handleConfigCommand()
///
/// @param message the incoming message
///
- void handleConfigSetCommand(const QJsonObject &message, const QString &command, int tan);
+ void handleConfigSetCommand(const QJsonObject &message, const JsonApiCommand& cmd);
/// Handle an incoming JSON RestoreConfig message from handleConfigCommand()
///
/// @param message the incoming message
///
- void handleConfigRestoreCommand(const QJsonObject &message, const QString &command, int tan);
+ void handleConfigRestoreCommand(const QJsonObject &message, const JsonApiCommand& cmd);
///
/// Handle an incoming JSON Component State message
///
/// @param message the incoming message
///
- void handleComponentStateCommand(const QJsonObject &message, const QString &command, int tan);
+ void handleComponentStateCommand(const QJsonObject &message, const JsonApiCommand& cmd);
/// Handle an incoming JSON Led Colors message
///
/// @param message the incoming message
///
- void handleLedColorsCommand(const QJsonObject &message, const QString &command, int tan);
+ void handleLedColorsCommand(const QJsonObject &message, const JsonApiCommand& cmd);
/// Handle an incoming JSON Logging message
///
/// @param message the incoming message
///
- void handleLoggingCommand(const QJsonObject &message, const QString &command, int tan);
+ void handleLoggingCommand(const QJsonObject &message, const JsonApiCommand& cmd);
/// Handle an incoming JSON Processing message
///
/// @param message the incoming message
///
- void handleProcessingCommand(const QJsonObject &message, const QString &command, int tan);
+ void handleProcessingCommand(const QJsonObject &message, const JsonApiCommand& cmd);
/// Handle an incoming JSON VideoMode message
///
/// @param message the incoming message
///
- void handleVideoModeCommand(const QJsonObject &message, const QString &command, int tan);
+ void handleVideoModeCommand(const QJsonObject &message, const JsonApiCommand& cmd);
/// Handle an incoming JSON plugin message
///
/// @param message the incoming message
///
- void handleAuthorizeCommand(const QJsonObject &message, const QString &command, int tan);
+ void handleAuthorizeCommand(const QJsonObject &message, const JsonApiCommand& cmd);
/// Handle an incoming JSON instance message
///
/// @param message the incoming message
///
- void handleInstanceCommand(const QJsonObject &message, const QString &command, int tan);
+ void handleInstanceCommand(const QJsonObject &message, const JsonApiCommand& cmd);
/// Handle an incoming JSON Led Device message
///
/// @param message the incoming message
///
- void handleLedDeviceCommand(const QJsonObject &message, const QString &command, int tan);
+ void handleLedDeviceCommand(const QJsonObject &message, const JsonApiCommand& cmd);
/// Handle an incoming JSON message regarding Input Sources (Grabbers)
///
/// @param message the incoming message
///
- void handleInputSourceCommand(const QJsonObject& message, const QString& command, int tan);
+ void handleInputSourceCommand(const QJsonObject& message, const JsonApiCommand& cmd);
/// Handle an incoming JSON message to request remote hyperion servers providing a given hyperion service
///
/// @param message the incoming message
///
- void handleServiceCommand(const QJsonObject &message, const QString &command, int tan);
+ void handleServiceCommand(const QJsonObject &message, const JsonApiCommand& cmd);
/// Handle an incoming JSON message for actions related to the overall Hyperion system
///
/// @param message the incoming message
///
- void handleSystemCommand(const QJsonObject &message, const QString &command, int tan);
+ void handleSystemCommand(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);
+
+ void applyTransforms(const QJsonObject &adjustment, ColorAdjustment *colorAdjustment);
+ template
+ void applyTransform(const QString &transformName, const QJsonObject &adjustment, T &transform, void (T::*setFunction)(bool));
+ template
+ void applyTransform(const QString &transformName, const QJsonObject &adjustment, T &transform, void (T::*setFunction)(double));
+ template
+ void applyTransform(const QString &transformName, const QJsonObject &adjustment, T &transform, void (T::*setFunction)(uint8_t));
+
+ void handleTokenRequired(const JsonApiCommand& cmd);
+ void handleAdminRequired(const JsonApiCommand& cmd);
+ void handleNewPasswordRequired(const JsonApiCommand& cmd);
+ void handleLogout(const JsonApiCommand& cmd);
+ void handleNewPassword(const QJsonObject &message, const JsonApiCommand& cmd);
+ void handleCreateToken(const QJsonObject &message, const JsonApiCommand& cmd);
+ void handleRenameToken(const QJsonObject &message, const JsonApiCommand& cmd);
+ void handleDeleteToken(const QJsonObject &message, const JsonApiCommand& cmd);
+ void handleRequestToken(const QJsonObject &message, const JsonApiCommand& cmd);
+ void handleGetPendingTokenRequests(const JsonApiCommand& cmd);
+ void handleAnswerRequest(const QJsonObject &message, const JsonApiCommand& cmd);
+ void handleGetTokenList(const JsonApiCommand& cmd);
+ void handleLogin(const QJsonObject &message, const JsonApiCommand& cmd);
+
+ void handleLedDeviceDiscover(LedDevice& ledDevice, const QJsonObject& message, const JsonApiCommand& cmd);
+ void handleLedDeviceGetProperties(LedDevice& ledDevice, const QJsonObject& message, const JsonApiCommand& cmd);
+ void handleLedDeviceIdentify(LedDevice& ledDevice, const QJsonObject& message, const JsonApiCommand& cmd);
+ void handleLedDeviceAddAuthorization(LedDevice& ledDevice, const QJsonObject& message, const JsonApiCommand& cmd);
///
- /// Handle an incoming JSON message of unknown type
+ /// Send a standard reply indicating success
///
- void handleNotImplemented(const QString &command, int tan);
+ void sendSuccessReply(const JsonApiCommand& cmd);
///
/// Send a standard reply indicating success
@@ -328,17 +321,76 @@ private:
///
/// Send a standard reply indicating success with data
///
- void sendSuccessDataReply(const QJsonDocument &doc, const QString &command = "", int tan = 0);
+ void sendSuccessDataReply(const QJsonValue &infoData, const JsonApiCommand& cmd);
+
+ ///
+ /// Send a standard reply indicating success with data
+ ///
+ void sendSuccessDataReply(const QJsonValue &infoData, const QString &command = "", int tan = 0);
+
+ ///
+ /// Send a standard reply indicating success with data and error details
+ ///
+ void sendSuccessDataReplyWithError(const QJsonValue &infoData, const JsonApiCommand& cmd, const QStringList& errorDetails = {});
+
+ ///
+ /// Send a standard reply indicating success with data and error details
+ ///
+ void sendSuccessDataReplyWithError(const QJsonValue &infoData, const QString &command = "", int tan = 0, const QStringList& errorDetails = {});
+
+
+ ///
+ /// Send a message with data.
+ /// Note: To be used as a new message and not as a response to a previous request.
+ ///
+ void sendNewRequest(const QJsonValue &infoData, const JsonApiCommand& cmd);
+
+ ///
+ /// Send a message with data
+ /// Note: To be used as a new message and not as a response to a previous request.
+ ///
+ void sendNewRequest(const QJsonValue &infoData, const QString &command);
///
/// Send an error message back to the client
///
/// @param error String describing the error
///
- void sendErrorReply(const QString &error, const QString &command = "", int tan = 0);
+ void sendErrorReply(const QString &error, const JsonApiCommand& cmd);
+
+ ///
+ /// Send an error message back to the client
+ ///
+ /// @param error String describing the error
+ /// @param errorDetails additional information detailing the error scenario
+ ///
+ void sendErrorReply(const QString &error, const QStringList& errorDetails, const JsonApiCommand& cmd);
+
+ ///
+ /// Send an error message back to the client
+ ///
+ /// @param error String describing the error
+ /// @param errorDetails additional information detailing the error scenario
+ ///
+ void sendErrorReply(const QString &error, const QStringList& errorDetails = {}, const QString &command = "", int tan = 0);
+
+ void sendNoAuthorization(const JsonApiCommand& cmd);
///
/// @brief Kill all signal/slot connections to stop possible data emitter
///
- void stopDataConnections();
+ void stopDataConnections() override;
+
+ static QString findCommand (const QString& jsonS);
+ static int findTan (const QString& jsonString);
+
+ // true if further callbacks are forbidden (http)
+ bool _noListener;
+
+ /// The peer address of the client
+ QString _peerAddress;
+
+ // The JsonCallbacks instance which handles data subscription/notifications
+ QSharedPointer _jsonCB;
+
};
diff --git a/include/api/JsonApiCommand.h b/include/api/JsonApiCommand.h
new file mode 100644
index 00000000..5ec8caf8
--- /dev/null
+++ b/include/api/JsonApiCommand.h
@@ -0,0 +1,320 @@
+#ifndef JSONAPICOMMAND_H
+#define JSONAPICOMMAND_H
+
+#include
+#include
+#include
+
+class Command {
+public:
+ enum Type {
+ Unknown,
+ Adjustment,
+ Authorize,
+ Clear,
+ ClearAll,
+ Color,
+ ComponentState,
+ Config,
+ Correction,
+ CreateEffect,
+ DeleteEffect,
+ Effect,
+ Image,
+ InputSource,
+ Instance,
+ LedColors,
+ LedDevice,
+ Logging,
+ Processing,
+ ServerInfo,
+ Service,
+ SourceSelect,
+ SysInfo,
+ System,
+ Temperature,
+ Transform,
+ VideoMode
+ };
+
+ static QString toString(Type type) {
+ switch (type) {
+ case Adjustment: return "adjustment";
+ case Authorize: return "authorize";
+ case Clear: return "clear";
+ case ClearAll: return "clearall";
+ case Color: return "color";
+ case ComponentState: return "componentstate";
+ case Config: return "config";
+ case Correction: return "correction";
+ case CreateEffect: return "create-effect";
+ case DeleteEffect: return "delete-effect";
+ case Effect: return "effect";
+ case Image: return "image";
+ case InputSource: return "inputsource";
+ case Instance: return "instance";
+ case LedColors: return "ledcolors";
+ case LedDevice: return "leddevice";
+ case Logging: return "logging";
+ case Processing: return "processing";
+ case ServerInfo: return "serverinfo";
+ case SourceSelect: return "sourceselect";
+ case SysInfo: return "sysinfo";
+ case System: return "system";
+ case Temperature: return "temperature";
+ case Transform: return "transform";
+ case VideoMode: return "videomode";
+ case Service: return "service";
+ default: return "unknown";
+ }
+ }
+};
+
+class SubCommand {
+public:
+ enum Type {
+ Unknown,
+ Empty,
+ AdminRequired,
+ AddAuthorization,
+ AnswerRequest,
+ CreateInstance,
+ CreateToken,
+ DeleteInstance,
+ DeleteToken,
+ Discover,
+ GetConfig,
+ GetInfo,
+ GetPendingTokenRequests,
+ GetProperties,
+ GetSchema,
+ GetSubscriptionCommands,
+ GetSubscriptions,
+ GetTokenList,
+ Identify,
+ Idle,
+ ImageStreamStart,
+ ImageStreamStop,
+ LedStreamStart,
+ LedStreamStop,
+ Login,
+ Logout,
+ NewPassword,
+ NewPasswordRequired,
+ Reload,
+ RenameToken,
+ RequestToken,
+ Restart,
+ RestoreConfig,
+ Resume,
+ SaveName,
+ SetConfig,
+ Start,
+ StartInstance,
+ Stop,
+ StopInstance,
+ Subscribe,
+ Suspend,
+ SwitchTo,
+ ToggleIdle,
+ ToggleSuspend,
+ TokenRequired,
+ Unsubscribe,
+ Update
+ };
+
+ static QString toString(Type type) {
+ switch (type) {
+ case Empty: return "";
+ case AdminRequired: return "adminRequired";
+ case AddAuthorization: return "addAuthorization";
+ case AnswerRequest: return "answerRequest";
+ case CreateInstance: return "createInstance";
+ case CreateToken: return "createToken";
+ case DeleteInstance: return "deleteInstance";
+ case DeleteToken: return "deleteToken";
+ case Discover: return "discover";
+ case GetConfig: return "getconfig";
+ case GetInfo: return "getInfo";
+ case GetPendingTokenRequests: return "getPendingTokenRequests";
+ case GetProperties: return "getProperties";
+ case GetSchema: return "getschema";
+ case GetSubscriptionCommands: return "getSubscriptionCommands";
+ case GetSubscriptions: return "getSubscriptions";
+ case GetTokenList: return "getTokenList";
+ case Identify: return "identify";
+ case Idle: return "idle";
+ case ImageStreamStart: return "imagestream-start";
+ case ImageStreamStop: return "imagestream-stop";
+ case LedStreamStart: return "ledstream-start";
+ case LedStreamStop: return "ledstream-stop";
+ case Login: return "login";
+ case Logout: return "logout";
+ case NewPassword: return "newPassword";
+ case NewPasswordRequired: return "newPasswordRequired";
+ case Reload: return "reload";
+ case RenameToken: return "renameToken";
+ case RequestToken: return "requestToken";
+ case Restart: return "restart";
+ case RestoreConfig: return "restoreconfig";
+ case Resume: return "resume";
+ case SaveName: return "saveName";
+ case SetConfig: return "setconfig";
+ case Start: return "start";
+ case StartInstance: return "startInstance";
+ case Stop: return "stop";
+ case StopInstance: return "stopInstance";
+ case Subscribe: return "subscribe";
+ case Suspend: return "suspend";
+ case SwitchTo: return "switchTo";
+ case ToggleIdle: return "toggleIdle";
+ case ToggleSuspend: return "toggleSuspend";
+ case TokenRequired: return "tokenRequired";
+ case Unsubscribe: return "unsubscribe";
+ case Update: return "update";
+ default: return "unknown";
+ }
+ }
+};
+
+class Authorization {
+public:
+ enum Type {
+ Admin,
+ Yes,
+ No
+ };
+};
+
+class NoListenerCmd {
+public:
+ enum Type {
+ No,
+ Yes
+ };
+};
+
+class JsonApiCommand {
+public:
+
+ JsonApiCommand()
+ : command(Command::Unknown),
+ subCommand(SubCommand::Unknown),
+ tan(0),
+ authorization(Authorization::Admin),
+ isNolistenerCmd(NoListenerCmd::Yes)
+ {}
+
+ JsonApiCommand(Command::Type command, SubCommand::Type subCommand,
+ Authorization::Type authorization,
+ NoListenerCmd::Type isNolistenerCmd, int tan = 0)
+ : command(command),
+ subCommand(subCommand),
+ tan(tan),
+ authorization(authorization),
+ isNolistenerCmd(isNolistenerCmd)
+ {}
+
+ Command::Type getCommand() const { return command; }
+ SubCommand::Type getSubCommand() const { return subCommand; }
+ int getTan() const { return tan; }
+
+ QString toString() const {
+ QString cmd = Command::toString(command);
+ if (subCommand > SubCommand::Empty) {
+ cmd += QString("-%2").arg(SubCommand::toString(subCommand));
+ }
+ return cmd;
+ }
+
+ Command::Type command;
+ SubCommand::Type subCommand;
+ int tan;
+
+ Authorization::Type authorization;
+ NoListenerCmd::Type isNolistenerCmd;
+};
+
+typedef QMap, JsonApiCommand> CommandLookupMap;
+
+class ApiCommandRegister {
+public:
+
+ static const CommandLookupMap& getCommandLookup() {
+ static const CommandLookupMap commandLookup {
+ { {"adjustment", ""}, { Command::Adjustment, SubCommand::Empty, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"authorize", "adminRequired"}, { Command::Authorize, SubCommand::AdminRequired, Authorization::No, NoListenerCmd::Yes} },
+ { {"authorize", "answerRequest"}, { Command::Authorize, SubCommand::AnswerRequest, Authorization::Admin, NoListenerCmd::No} },
+ { {"authorize", "createToken"}, { Command::Authorize, SubCommand::CreateToken, Authorization::Admin, NoListenerCmd::No} },
+ { {"authorize", "deleteToken"}, { Command::Authorize, SubCommand::DeleteToken, Authorization::Admin, NoListenerCmd::Yes} },
+ { {"authorize", "getPendingTokenRequests"}, { Command::Authorize, SubCommand::GetPendingTokenRequests, Authorization::Admin, NoListenerCmd::No} },
+ { {"authorize", "getTokenList"}, { Command::Authorize, SubCommand::GetTokenList, Authorization::Admin, NoListenerCmd::Yes} },
+ { {"authorize", "login"}, { Command::Authorize, SubCommand::Login, Authorization::No, NoListenerCmd::No} },
+ { {"authorize", "logout"}, { Command::Authorize, SubCommand::Logout, Authorization::No, NoListenerCmd::No} },
+ { {"authorize", "newPassword"}, { Command::Authorize, SubCommand::NewPassword, Authorization::Admin, NoListenerCmd::Yes} },
+ { {"authorize", "newPasswordRequired"}, { Command::Authorize, SubCommand::NewPasswordRequired, Authorization::No, NoListenerCmd::Yes} },
+ { {"authorize", "renameToken"}, { Command::Authorize, SubCommand::RenameToken, Authorization::Admin, NoListenerCmd::Yes} },
+ { {"authorize", "requestToken"}, { Command::Authorize, SubCommand::RequestToken, Authorization::No, NoListenerCmd::Yes} },
+ { {"authorize", "tokenRequired"}, { Command::Authorize, SubCommand::TokenRequired, Authorization::No, NoListenerCmd::Yes} },
+ { {"clear", ""}, { Command::Clear, SubCommand::Empty, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"clearall", ""}, { Command::ClearAll, SubCommand::Empty, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"color", ""}, { Command::Color, SubCommand::Empty, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"componentstate", ""}, { Command::ComponentState, SubCommand::Empty, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"config", "getconfig"}, { Command::Config, SubCommand::GetConfig, Authorization::Admin, NoListenerCmd::Yes} },
+ { {"config", "getschema"}, { Command::Config, SubCommand::GetSchema, Authorization::Admin, NoListenerCmd::Yes} },
+ { {"config", "reload"}, { Command::Config, SubCommand::Reload, Authorization::Admin, NoListenerCmd::Yes} },
+ { {"config", "restoreconfig"}, { Command::Config, SubCommand::RestoreConfig, Authorization::Admin, NoListenerCmd::Yes} },
+ { {"config", "setconfig"}, { Command::Config, SubCommand::SetConfig, Authorization::Admin, NoListenerCmd::Yes} },
+ { {"correction", ""}, { Command::Correction, SubCommand::Empty, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"create-effect", ""}, { Command::CreateEffect, SubCommand::Empty, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"delete-effect", ""}, { Command::DeleteEffect, SubCommand::Empty, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"effect", ""}, { Command::Effect, SubCommand::Empty, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"image", ""}, { Command::Image, SubCommand::Empty, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"inputsource", "discover"}, { Command::InputSource, SubCommand::Discover, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"inputsource", "getProperties"}, { Command::InputSource, SubCommand::GetProperties, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"instance", "createInstance"}, { Command::Instance, SubCommand::CreateInstance, Authorization::Admin, NoListenerCmd::Yes} },
+ { {"instance", "deleteInstance"}, { Command::Instance, SubCommand::DeleteInstance, Authorization::Admin, NoListenerCmd::Yes} },
+ { {"instance", "saveName"}, { Command::Instance, SubCommand::SaveName, Authorization::Admin, NoListenerCmd::Yes} },
+ { {"instance", "startInstance"}, { Command::Instance, SubCommand::StartInstance, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"instance", "stopInstance"}, { Command::Instance, SubCommand::StopInstance, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"instance", "switchTo"}, { Command::Instance, SubCommand::SwitchTo, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"ledcolors", "imagestream-start"}, { Command::LedColors, SubCommand::ImageStreamStart, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"ledcolors", "imagestream-stop"}, { Command::LedColors, SubCommand::ImageStreamStop, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"ledcolors", "ledstream-start"}, { Command::LedColors, SubCommand::LedStreamStart, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"ledcolors", "ledstream-stop"}, { Command::LedColors, SubCommand::LedStreamStop, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"leddevice", "addAuthorization"}, { Command::LedDevice, SubCommand::AddAuthorization, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"leddevice", "discover"}, { Command::LedDevice, SubCommand::Discover, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"leddevice", "getProperties"}, { Command::LedDevice, SubCommand::GetProperties, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"leddevice", "identify"}, { Command::LedDevice, SubCommand::Identify, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"logging", "start"}, { Command::Logging, SubCommand::Start, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"logging", "stop"}, { Command::Logging, SubCommand::Stop, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"logging", "update"}, { Command::Logging, SubCommand::Update, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"processing", ""}, { Command::Processing, SubCommand::Empty, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"sourceselect", ""}, { Command::SourceSelect, SubCommand::Empty, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"serverinfo", ""}, { Command::ServerInfo, SubCommand::Empty, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"serverinfo", "getInfo"}, { Command::ServerInfo, SubCommand::GetInfo, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"serverinfo", "subscribe"}, { Command::ServerInfo, SubCommand::Subscribe, Authorization::Yes, NoListenerCmd::No} },
+ { {"serverinfo", "unsubscribe"}, { Command::ServerInfo, SubCommand::Unsubscribe, Authorization::Yes, NoListenerCmd::No} },
+ { {"serverinfo", "getSubscriptions"}, { Command::ServerInfo, SubCommand::GetSubscriptions, Authorization::Yes, NoListenerCmd::No} },
+ { {"serverinfo", "getSubscriptionCommands"}, { Command::ServerInfo, SubCommand::GetSubscriptionCommands, Authorization::No, NoListenerCmd::No} },
+ { {"sysinfo", ""}, { Command::SysInfo, SubCommand::Empty, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"system", "restart"}, { Command::System, SubCommand::Restart, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"system", "resume"}, { Command::System, SubCommand::Resume, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"system", "suspend"}, { Command::System, SubCommand::Suspend, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"system", "toggleSuspend"}, { Command::System, SubCommand::ToggleSuspend, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"system", "idle"}, { Command::System, SubCommand::Idle, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"system", "toggleIdle"}, { Command::System, SubCommand::ToggleIdle, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"temperature", ""}, { Command::Temperature, SubCommand::Empty, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"transform", ""}, { Command::Transform, SubCommand::Empty, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"videomode", ""}, { Command::VideoMode, SubCommand::Empty, Authorization::Yes, NoListenerCmd::Yes} },
+ { {"service", "discover"}, { Command::Service, SubCommand::Discover, Authorization::Yes, NoListenerCmd::Yes} }
+ };
+ return commandLookup;
+ }
+
+ static JsonApiCommand getCommandInfo(const QString& command, const QString& subCommand) {
+ return getCommandLookup().value({command, subCommand});
+ }
+};
+
+#endif // JSONAPICOMMAND_H
diff --git a/include/api/JsonApiSubscription.h b/include/api/JsonApiSubscription.h
new file mode 100644
index 00000000..f924099f
--- /dev/null
+++ b/include/api/JsonApiSubscription.h
@@ -0,0 +1,108 @@
+#ifndef JSONAPISUBSCRIPTION_H
+#define JSONAPISUBSCRIPTION_H
+
+#include // Required to determine the cmake options
+
+#include
+#include
+
+
+class Subscription {
+public:
+ enum Type {
+ Unknown,
+ AdjustmentUpdate,
+ ComponentsUpdate,
+#if defined(ENABLE_EFFECTENGINE)
+ EffectsUpdate,
+#endif
+ ImageToLedMappingUpdate,
+ ImageUpdate,
+ InstanceUpdate,
+ LedColorsUpdate,
+ LedsUpdate,
+ LogMsgUpdate,
+ PrioritiesUpdate,
+ SettingsUpdate,
+ TokenUpdate,
+ VideomodeUpdate
+ };
+
+ static QString toString(Type type) {
+ switch (type) {
+ case AdjustmentUpdate: return "adjustment-update";
+ case ComponentsUpdate: return "components-update";
+#if defined(ENABLE_EFFECTENGINE)
+ case EffectsUpdate: return "effects-update";
+#endif
+ case ImageToLedMappingUpdate: return "imageToLedMapping-update";
+ case ImageUpdate: return "image-update";
+ case InstanceUpdate: return "instance-update";
+ case LedColorsUpdate: return "led-colors-update";
+ case LedsUpdate: return "leds-update";
+ case LogMsgUpdate: return "logmsg-update";
+ case PrioritiesUpdate: return "priorities-update";
+ case SettingsUpdate: return "settings-update";
+ case TokenUpdate: return "token-update";
+ case VideomodeUpdate: return "videomode-update";
+ default: return "unknown";
+ }
+ }
+};
+
+class JsonApiSubscription {
+public:
+
+ JsonApiSubscription()
+ : cmd(Subscription::Unknown),
+ isAll(false)
+ {}
+
+ JsonApiSubscription(Subscription::Type cmd, bool isAll)
+ : cmd(cmd),
+ isAll(isAll)
+ {}
+
+ Subscription::Type getSubscription() const { return cmd; }
+ bool isPartOfAll() const { return isAll; }
+
+ QString toString() const {
+ return Subscription::toString(cmd);
+ }
+
+ Subscription::Type cmd;
+ bool isAll;
+};
+
+typedef QMap SubscriptionLookupMap;
+
+class ApiSubscriptionRegister {
+public:
+
+ static const SubscriptionLookupMap& getSubscriptionLookup() {
+ static const SubscriptionLookupMap subscriptionLookup {
+ { {"adjustment-update"}, { Subscription::AdjustmentUpdate, true} },
+ { {"components-update"}, { Subscription::ComponentsUpdate, true} },
+#if defined(ENABLE_EFFECTENGINE)
+ { {"effects-update"}, { Subscription::EffectsUpdate, true} },
+#endif
+ { {"imageToLedMapping-update"}, { Subscription::ImageToLedMappingUpdate, true} },
+ { {"image-update"}, { Subscription::ImageUpdate, false} },
+ { {"instance-update"}, { Subscription::InstanceUpdate, true} },
+ { {"led-colors-update"}, { Subscription::LedColorsUpdate, true} },
+ { {"leds-update"}, { Subscription::LedsUpdate, false} },
+ { {"logmsg-update"}, { Subscription::LogMsgUpdate, false} },
+ { {"priorities-update"}, { Subscription::PrioritiesUpdate, true} },
+ { {"settings-update"}, { Subscription::SettingsUpdate, true} },
+ { {"token-update"}, { Subscription::TokenUpdate, true} },
+ { {"videomode-update"}, { Subscription::VideomodeUpdate, true} }
+ };
+ return subscriptionLookup;
+ }
+
+ static JsonApiSubscription getSubscriptionInfo(const QString& subscription) {
+ return getSubscriptionLookup().value({subscription});
+ }
+};
+
+#endif // JSONAPISUBSCRIPTION_H
diff --git a/include/api/JsonCB.h b/include/api/JsonCallbacks.h
similarity index 56%
rename from include/api/JsonCB.h
rename to include/api/JsonCallbacks.h
index 2d59b3eb..88bc9689 100644
--- a/include/api/JsonCB.h
+++ b/include/api/JsonCallbacks.h
@@ -1,8 +1,12 @@
#pragma once
+#include "api/JsonApiSubscription.h"
+#include
+
// qt incl
#include
#include
+#include
// components def
#include
@@ -20,32 +24,64 @@ class Hyperion;
class ComponentRegister;
class PriorityMuxer;
-class JsonCB : public QObject
+class JsonCallbacks : public QObject
{
Q_OBJECT
public:
- JsonCB(QObject* parent);
+ JsonCallbacks(Logger* log, const QString& peerAddress, QObject* parent);
///
/// @brief Subscribe to future data updates given by cmd
- /// @param cmd The cmd which will be subscribed for
- /// @param unsubscribe Revert subscription
+ /// @param cmd The cmd which will be subscribed for
/// @return True on success, false if not found
///
- bool subscribeFor(const QString& cmd, bool unsubscribe = false);
+ bool subscribe(const QString& cmd);
+
+ ///
+ /// @brief Subscribe to future data updates given by subscription list
+ /// @param type Array of subscriptionsm
+ ///
+ QStringList subscribe(const QJsonArray& subscriptions);
+
+ ///
+ /// @brief Subscribe to future data updates given by cmd
+ /// @param cmd The cmd which will be subscribed to
+ /// @return True on success, false if not found
+ ///
+ bool subscribe(Subscription::Type subscription);
+
+ ///
+ /// @brief Unsubscribe to future data updates given by cmd
+ /// @param cmd The cmd which will be unsubscribed
+ /// @return True on success, false if not found
+ ///
+ bool unsubscribe(const QString& cmd);
+
+ ///
+ /// @brief Unsubscribe to future data updates given by subscription list
+ /// @param type Array of subscriptions
+ ///
+ QStringList unsubscribe(const QJsonArray& subscriptions);
+
+ ///
+ /// @brief Unsubscribe to future data updates given by cmd
+ /// @param cmd The cmd which will be subscribed to
+ /// @return True on success, false if not found
+ ///
+ bool unsubscribe(Subscription::Type cmd);
///
/// @brief Get all possible commands to subscribe for
+ /// @param fullList Return all possible commands or those not triggered by API requests (subscriptions="ALL")
/// @return The list of commands
///
- QStringList getCommands() { return _availableCommands; };
-
+ QStringList getCommands(bool fullList = true) const;
///
/// @brief Get all subscribed commands
/// @return The list of commands
///
- QStringList getSubscribedCommands() { return _subscribedCommands; };
+ QStringList getSubscribedCommands() const;
///
/// @brief Reset subscriptions, disconnect all signals
@@ -124,18 +160,42 @@ private slots:
///
void handleTokenChange(const QVector &def);
+ ///
+ /// @brief Is called whenever the current Hyperion instance pushes new led raw values (if enabled)
+ /// @param ledColors The current led colors
+ ///
+ void handleLedColorUpdate(const std::vector &ledColors);
+
+ ///
+ /// @brief Is called whenever the current Hyperion instance pushes new image update (if enabled)
+ /// @param image The current image
+ ///
+ void handleImageUpdate(const Image &image);
+
+ ///
+ /// @brief Process and push new log messages from logger (if enabled)
+ ///
+ void handleLogMessageUpdate(const Logger::T_LOG_MESSAGE &);
+
private:
- /// pointer of Hyperion instance
+
+ /// construct callback msg
+ void doCallback(Subscription::Type cmd, const QVariant& data);
+
+ Logger *_log;
Hyperion* _hyperion;
+
+ /// The peer address of the client
+ QString _peerAddress;
+
/// pointer of comp register
ComponentRegister* _componentRegister;
/// priority muxer instance
PriorityMuxer* _prioMuxer;
- /// contains all available commands
- QStringList _availableCommands;
/// contains active subscriptions
- QStringList _subscribedCommands;
- /// construct callback msg
- void doCallback(const QString& cmd, const QVariant& data);
+ QSet _subscribedCommands;
+
+ /// flag to determine state of log streaming
+ bool _islogMsgStreamingActive;
};
diff --git a/include/api/JsonInfo.h b/include/api/JsonInfo.h
new file mode 100644
index 00000000..1346f97e
--- /dev/null
+++ b/include/api/JsonInfo.h
@@ -0,0 +1,43 @@
+#ifndef JSONINFO_H
+#define JSONINFO_H
+
+#include
+#include
+#include
+
+#include
+#include
+
+class JsonInfo
+{
+
+public:
+ static QJsonArray getAdjustmentInfo(const Hyperion* hyperion, Logger* log);
+ static QJsonArray getPrioritiestInfo(const Hyperion* hyperion);
+ static QJsonArray getPrioritiestInfo(int currentPriority, const PriorityMuxer::InputsMap& activeInputs);
+ static QJsonArray getEffects(const Hyperion* hyperion);
+ static QJsonArray getAvailableScreenGrabbers();
+ static QJsonArray getAvailableVideoGrabbers();
+ static QJsonArray getAvailableAudioGrabbers();
+ static QJsonObject getGrabbers(const Hyperion* hyperion);
+ static QJsonObject getAvailableLedDevices();
+ static QJsonObject getCecInfo();
+ static QJsonArray getServices();
+ static QJsonArray getComponents(const Hyperion* hyperion);
+ static QJsonArray getInstanceInfo();
+ static QJsonArray getActiveEffects(const Hyperion* hyperion);
+ static QJsonArray getActiveColors(const Hyperion* hyperion);
+ static QJsonArray getTransformationInfo(const Hyperion* hyperion);
+ static QJsonObject getSystemInfo(const Hyperion* hyperion);
+ QJsonObject discoverSources (const QString& sourceType, const QJsonObject& params);
+
+private:
+
+ template
+ void discoverGrabber(QJsonArray& inputs, const QJsonObject& params) const;
+ QJsonArray discoverScreenInputs(const QJsonObject& params) const;
+ QJsonArray discoverVideoInputs(const QJsonObject& params) const;
+ QJsonArray discoverAudioInputs(const QJsonObject& params) const;
+};
+
+#endif // JSONINFO_H
diff --git a/include/api/apiStructs.h b/include/api/apiStructs.h
index 112132fc..de1d6e67 100644
--- a/include/api/apiStructs.h
+++ b/include/api/apiStructs.h
@@ -2,6 +2,9 @@
#include
#include
+#include
+
+#include
struct ImageCmdData
{
diff --git a/include/grabber/GrabberConfig.h b/include/grabber/GrabberConfig.h
new file mode 100644
index 00000000..f3a575c2
--- /dev/null
+++ b/include/grabber/GrabberConfig.h
@@ -0,0 +1,58 @@
+#ifndef GRABBERCONFIG_H
+#define GRABBERCONFIG_H
+
+#if defined(ENABLE_MF)
+#include
+#elif defined(ENABLE_V4L2)
+#include
+#endif
+
+#if defined(ENABLE_AUDIO)
+#include
+
+#ifdef WIN32
+#include
+#endif
+
+#ifdef __linux__
+#include
+#endif
+#endif
+
+#ifdef ENABLE_QT
+#include
+#endif
+
+#ifdef ENABLE_DX
+#include
+#endif
+
+#if defined(ENABLE_X11)
+#include
+#endif
+
+#if defined(ENABLE_XCB)
+#include
+#endif
+
+#if defined(ENABLE_DX)
+#include
+#endif
+
+#if defined(ENABLE_FB)
+#include
+#endif
+
+#if defined(ENABLE_DISPMANX)
+#include
+#endif
+
+#if defined(ENABLE_AMLOGIC)
+#include
+#endif
+
+#if defined(ENABLE_OSX)
+#include
+#endif
+
+#endif // GRABBERCONFIG_H
diff --git a/include/hyperion/AuthManager.h b/include/hyperion/AuthManager.h
index a7750552..790f70b6 100644
--- a/include/hyperion/AuthManager.h
+++ b/include/hyperion/AuthManager.h
@@ -43,24 +43,12 @@ public:
///
QString getID() const { return _uuid; }
- ///
- /// @brief Check authorization is required according to the user setting
- /// @return True if authorization required else false
- ///
- bool isAuthRequired() const { return _authRequired; }
-
///
/// @brief Check if authorization is required for local network connections
/// @return True if authorization required else false
///
bool isLocalAuthRequired() const { return _localAuthRequired; }
- ///
- /// @brief Check if authorization is required for local network connections for admin access
- /// @return True if authorization required else false
- ///
- bool isLocalAdminAuthRequired() const { return _localAdminAuthRequired; }
-
///
/// @brief Reset Hyperion user
/// @return True on success else false
@@ -232,15 +220,9 @@ private:
/// All pending requests
QMap _pendingRequests;
- /// Reflect state of global auth
- bool _authRequired;
-
/// Reflect state of local auth
bool _localAuthRequired;
- /// Reflect state of local admin auth
- bool _localAdminAuthRequired;
-
/// Timer for counting against pendingRequest timeouts
QTimer *_timer;
diff --git a/include/hyperion/Hyperion.h b/include/hyperion/Hyperion.h
index 3a442f40..f9b34e33 100644
--- a/include/hyperion/Hyperion.h
+++ b/include/hyperion/Hyperion.h
@@ -67,6 +67,7 @@ class Hyperion : public QObject
Q_OBJECT
public:
/// Type definition of the info structure used by the priority muxer
+ using InputsMap = PriorityMuxer::InputsMap;
using InputInfo = PriorityMuxer::InputInfo;
///
@@ -107,7 +108,7 @@ public:
///
QString getActiveDeviceType() const;
- bool getReadOnlyMode() {return _readOnlyMode; }
+ bool getReadOnlyMode() const {return _readOnlyMode; }
public slots:
@@ -235,13 +236,13 @@ public slots:
/// @param priority The priority channel of the effect
/// @param timeout The timeout of the effect (after the timout, the effect will be cleared)
int setEffect(const QString &effectName
- , const QJsonObject &args
- , int priority
- , int timeout = PriorityMuxer::ENDLESS
- , const QString &pythonScript = ""
- , const QString &origin="System"
- , const QString &imageData = ""
- );
+ , const QJsonObject &args
+ , int priority
+ , int timeout = PriorityMuxer::ENDLESS
+ , const QString &pythonScript = ""
+ , const QString &origin="System"
+ , const QString &imageData = ""
+ );
/// Get the list of available effects
/// @return The list of available effects
@@ -303,7 +304,14 @@ public slots:
QList getActivePriorities() const;
///
- /// Returns the information of a specific priorrity channel
+ /// Returns the information of all priority channels.
+ ///
+ /// @return The information fo all priority channels
+ ///
+ PriorityMuxer::InputsMap getPriorityInfo() const;
+
+ ///
+ /// Returns the information of a specific priority channel
///
/// @param[in] priority The priority channel
///
@@ -346,7 +354,7 @@ public slots:
/// @brief Get the component Register
/// return Component register pointer
///
- ComponentRegister* getComponentRegister() { return _componentRegister; }
+ ComponentRegister* getComponentRegister() const { return _componentRegister; }
///
/// @brief Called from components to update their current state. DO NOT CALL FROM USERS
diff --git a/include/hyperion/PriorityMuxer.h b/include/hyperion/PriorityMuxer.h
index ed8d4fb5..d307843b 100644
--- a/include/hyperion/PriorityMuxer.h
+++ b/include/hyperion/PriorityMuxer.h
@@ -141,6 +141,13 @@ public:
///
QList getPriorities() const;
+ ///
+ /// Returns the information of all priority channels.
+ ///
+ /// @return The information fo all priority channels
+ ///
+ InputsMap getInputInfo() const;
+
///
/// Returns the information of a specified priority channel.
/// If a priority is no longer available the _lowestPriorityInfo (255) is returned
diff --git a/include/utils/JsonUtils.h b/include/utils/JsonUtils.h
index 694e279f..10b89d90 100644
--- a/include/utils/JsonUtils.h
+++ b/include/utils/JsonUtils.h
@@ -3,6 +3,8 @@
#include
#include
+#include
+#include
#include
namespace JsonUtils {
@@ -14,7 +16,7 @@ namespace JsonUtils {
/// @param[in] ignError Ignore errors during file read (no log output)
/// @return true on success else false
///
- bool readFile(const QString& path, QJsonObject& obj, Logger* log, bool ignError=false);
+ QPair readFile(const QString& path, QJsonObject& obj, Logger* log, bool ignError=false);
///
/// @brief read a schema file and resolve $refs
@@ -33,7 +35,7 @@ namespace JsonUtils {
/// @param[in] log The logger of the caller to print errors
/// @return true on success else false
///
- bool parse(const QString& path, const QString& data, QJsonObject& obj, Logger* log);
+ QPair parse(const QString& path, const QString& data, QJsonObject& obj, Logger* log);
///
/// @brief parse a json QString and get a QJsonArray. Overloaded function
@@ -42,8 +44,8 @@ namespace JsonUtils {
/// @param[out] arr Retuns the parsed QJsonArray
/// @param[in] log The logger of the caller to print errors
/// @return true on success else false
- ///
- bool parse(const QString& path, const QString& data, QJsonArray& arr, Logger* log);
+ //
+ QPair parse(const QString& path, const QString& data, QJsonArray& arr, Logger* log);
///
/// @brief parse a json QString and get a QJsonDocument
@@ -53,7 +55,7 @@ namespace JsonUtils {
/// @param[in] log The logger of the caller to print errors
/// @return true on success else false
///
- bool parse(const QString& path, const QString& data, QJsonDocument& doc, Logger* log);
+ QPair parse(const QString& path, const QString& data, QJsonDocument& doc, Logger* log);
///
/// @brief Validate json data against a schema
@@ -63,7 +65,7 @@ namespace JsonUtils {
/// @param[in] log The logger of the caller to print errors
/// @return true on success else false
///
- bool validate(const QString& file, const QJsonObject& json, const QString& schemaPath, Logger* log);
+ QPair validate(const QString& file, const QJsonObject& json, const QString& schemaPath, Logger* log);
///
/// @brief Validate json data against a schema
@@ -73,7 +75,7 @@ namespace JsonUtils {
/// @param[in] log The logger of the caller to print errors
/// @return true on success else false
///
- bool validate(const QString& file, const QJsonObject& json, const QJsonObject& schema, Logger* log);
+ QPair validate(const QString& file, const QJsonObject& json, const QJsonObject& schema, Logger* log);
///
/// @brief Write json data to file
diff --git a/include/utils/NetOrigin.h b/include/utils/NetOrigin.h
index 75796e66..648d3de3 100644
--- a/include/utils/NetOrigin.h
+++ b/include/utils/NetOrigin.h
@@ -47,7 +47,9 @@ private slots:
private:
Logger* _log;
/// True when internet access is allowed
- bool _internetAccessAllowed;
+ bool _isInternetAccessAllowed;
+ /// True when internet access is restricted by a white list
+ bool _isInternetAccessRestricted;
/// Whitelisted ip addresses
QList _ipWhitelist;
diff --git a/include/utils/jsonschema/QJsonFactory.h b/include/utils/jsonschema/QJsonFactory.h
index 2fcf5882..1a9190cd 100644
--- a/include/utils/jsonschema/QJsonFactory.h
+++ b/include/utils/jsonschema/QJsonFactory.h
@@ -31,7 +31,9 @@ public:
if (!schemaChecker.validate(configTree).first)
{
for (int i = 0; i < messages.size(); ++i)
+ {
std::cout << messages[i].toStdString() << std::endl;
+ }
std::cerr << "Validation failed for configuration file: " << config.toStdString() << std::endl;
return -3;
@@ -61,9 +63,10 @@ public:
if (error.error != QJsonParseError::NoError)
{
// report to the user the failure and their locations in the document.
- int errorLine(0), errorColumn(0);
+ int errorLine(0);
+ int errorColumn(0);
- for( int i=0, count=qMin( error.offset,config.size()); i
// stl includes
-#include
-#include
// Qt includes
#include
@@ -27,92 +25,91 @@
// ledmapping int <> string transform methods
#include
-// api includes
-#include
-
using namespace hyperion;
+// Constants
+namespace {
+
+const int IMAGE_HEIGHT_MAX = 2000;
+const int IMAGE_WIDTH_MAX = 2000;
+const int IMAGE_SCALE = 2000;
+}
+
API::API(Logger *log, bool localConnection, QObject *parent)
- : QObject(parent)
+ : QObject(parent)
{
qRegisterMetaType("int64_t");
qRegisterMetaType("VideoMode");
qRegisterMetaType>("std::map");
- // Init
- _log = log;
- _authManager = AuthManager::getInstance();
+ // Init
+ _log = log;
+ _authManager = AuthManager::getInstance();
_instanceManager = HyperionIManager::getInstance();
- _localConnection = localConnection;
+ _localConnection = localConnection;
- _authorized = false;
- _adminAuthorized = false;
+ _authorized = false;
+ _adminAuthorized = false;
- _currInstanceIndex = 0;
+ _currInstanceIndex = 0;
- // connect to possible token responses that has been requested
- connect(_authManager, &AuthManager::tokenResponse, [=] (bool success, QObject *caller, const QString &token, const QString &comment, const QString &id, const int &tan)
- {
- if (this == caller)
- emit onTokenResponse(success, token, comment, id, tan);
- });
+ // connect to possible token responses that has been requested
+ connect(_authManager, &AuthManager::tokenResponse, this, [=] (bool success, const QObject *caller, const QString &token, const QString &comment, const QString &tokenId, const int &tan)
+ {
+ if (this == caller)
+ {
+ emit onTokenResponse(success, token, comment, tokenId, tan);
+ }
+ });
- // connect to possible startInstance responses that has been requested
- connect(_instanceManager, &HyperionIManager::startInstanceResponse, [=] (QObject *caller, const int &tan)
- {
- if (this == caller)
- emit onStartInstanceResponse(tan);
- });
+ connect(_instanceManager, &HyperionIManager::startInstanceResponse, this, [=] (const QObject *caller, const int &tan)
+ {
+ if (this == caller)
+ {
+ emit onStartInstanceResponse(tan);
+ }
+ });
}
void API::init()
{
_hyperion = _instanceManager->getHyperionInstance(0);
+ _authorized = false;
- bool apiAuthRequired = _authManager->isAuthRequired();
- qDebug() << "API::init - apiAuthRequired: " << apiAuthRequired;
+ // For security we block external connections, if default PW is set
+ if (!_localConnection && API::hasHyperionDefaultPw())
+ {
+ Warning(_log, "Non local network connect attempt identified, but default Hyperion passwort set! - Reject connection.");
+ emit forceClose();
+ }
- // For security we block external connections if default PW is set
- if (!_localConnection && API::hasHyperionDefaultPw())
- {
- emit forceClose();
- }
- // if this is localConnection and network allows unauth locals, set authorized flag
- if (!_authManager->isLocalAuthRequired() && _localConnection)
+ // if this is localConnection and network allows unauth locals
+ if ( _localConnection && !_authManager->isLocalAuthRequired())
{
_authorized = true;
- _adminAuthorized = !_authManager->isLocalAdminAuthRequired();
-
}
- else
+
+ // // admin access is only allowed after login via user & password or via authorization via token.
+ _adminAuthorized = false;
+}
+
+void API::setColor(int priority, const std::vector &ledColors, int timeout_ms, const QString &origin, hyperion::Components /*callerComp*/)
+{
+ if (ledColors.size() % 3 == 0)
{
- if (_localConnection)
+ std::vector fledColors;
+ for (unsigned i = 0; i < ledColors.size(); i += 3)
{
- _authorized = !_authManager->isLocalAuthRequired();
- _adminAuthorized = !_authManager->isLocalAdminAuthRequired();
- }
+ fledColors.emplace_back(ColorRgb{ledColors[i], ledColors[i + 1], ledColors[i + 2]});
+ }
+ QMetaObject::invokeMethod(_hyperion, "setColor", Qt::QueuedConnection, Q_ARG(int, priority), Q_ARG(std::vector, fledColors), Q_ARG(int, timeout_ms), Q_ARG(QString, origin));
}
- qDebug() << "API::init - _authorized: " << _authorized;
- qDebug() << "API::init - _adminAuthorized: " << _adminAuthorized;
}
-void API::setColor(int priority, const std::vector &ledColors, int timeout_ms, const QString &origin, hyperion::Components callerComp)
+bool API::setImage(ImageCmdData &data, hyperion::Components comp, QString &replyMsg, hyperion::Components /*callerComp*/)
{
- std::vector fledColors;
- if (ledColors.size() % 3 == 0)
- {
- for (unsigned i = 0; i < ledColors.size(); i += 3)
- {
- fledColors.emplace_back(ColorRgb{ledColors[i], ledColors[i + 1], ledColors[i + 2]});
- }
- QMetaObject::invokeMethod(_hyperion, "setColor", Qt::QueuedConnection, Q_ARG(int, priority), Q_ARG(std::vector, fledColors), Q_ARG(int, timeout_ms), Q_ARG(QString, origin));
- }
-}
-
-bool API::setImage(ImageCmdData &data, hyperion::Components comp, QString &replyMsg, hyperion::Components callerComp)
-{
- // truncate name length
- data.imgName.truncate(16);
+ // truncate name length
+ data.imgName.truncate(16);
if (!data.format.isEmpty())
{
@@ -130,424 +127,475 @@ bool API::setImage(ImageCmdData &data, hyperion::Components comp, QString &reply
}
QImage img = QImage::fromData(data.data, QSTRING_CSTR(data.format));
- if (img.isNull())
- {
+ if (img.isNull())
+ {
replyMsg = "Failed to parse picture, the file might be corrupted or content does not match the given format [" + data.format + "]";
- return false;
- }
+ return false;
+ }
- // check for requested scale
- if (data.scale > 24)
- {
- if (img.height() > data.scale)
- {
- img = img.scaledToHeight(data.scale);
- }
- if (img.width() > data.scale)
- {
- img = img.scaledToWidth(data.scale);
- }
- }
+ // check for requested scale
+ if (data.scale > 24)
+ {
+ if (img.height() > data.scale)
+ {
+ img = img.scaledToHeight(data.scale);
+ }
+ if (img.width() > data.scale)
+ {
+ img = img.scaledToWidth(data.scale);
+ }
+ }
- // check if we need to force a scale
- if (img.width() > 2000 || img.height() > 2000)
- {
- data.scale = 2000;
- if (img.height() > data.scale)
- {
- img = img.scaledToHeight(data.scale);
- }
- if (img.width() > data.scale)
- {
- img = img.scaledToWidth(data.scale);
- }
- }
+ // check if we need to force a scale
+ if (img.width() > IMAGE_WIDTH_MAX || img.height() > IMAGE_HEIGHT_MAX)
+ {
+ data.scale = IMAGE_SCALE;
+ if (img.height() > data.scale)
+ {
+ img = img.scaledToHeight(data.scale);
+ }
+ if (img.width() > data.scale)
+ {
+ img = img.scaledToWidth(data.scale);
+ }
+ }
- data.width = img.width();
- data.height = img.height();
+ data.width = img.width();
+ data.height = img.height();
- // extract image
- img = img.convertToFormat(QImage::Format_ARGB32_Premultiplied);
- data.data.clear();
- data.data.reserve(img.width() * img.height() * 3);
- for (int i = 0; i < img.height(); ++i)
- {
- const QRgb *scanline = reinterpret_cast(img.scanLine(i));
- for (int j = 0; j < img.width(); ++j)
- {
- data.data.append((char)qRed(scanline[j]));
- data.data.append((char)qGreen(scanline[j]));
- data.data.append((char)qBlue(scanline[j]));
- }
- }
- }
- else
- {
- // check consistency of the size of the received data
- if (data.data.size() != data.width * data.height * 3)
- {
- replyMsg = "Size of image data does not match with the width and height";
- return false;
- }
- }
+ // extract image
+ img = img.convertToFormat(QImage::Format_ARGB32_Premultiplied);
+ data.data.clear();
+ data.data.reserve(static_cast(img.width() * img.height() * 3));
+ for (int i = 0; i < img.height(); ++i)
+ {
+ const QRgb *scanline = reinterpret_cast(img.scanLine(i));
+ for (int j = 0; j < img.width(); ++j)
+ {
+ data.data.append(static_cast(qRed(scanline[j])));
+ data.data.append(static_cast(qGreen(scanline[j])));
+ data.data.append(static_cast(qBlue(scanline[j])));
+ }
+ }
+ }
+ else
+ {
+ // check consistency of the size of the received data
+ if (static_cast(data.data.size()) != data.width * data.height * 3)
+ {
+ replyMsg = "Size of image data does not match with the width and height";
+ return false;
+ }
+ }
- // copy image
- Image image(data.width, data.height);
- memcpy(image.memptr(), data.data.data(), data.data.size());
+ // copy image
+ Image image(data.width, data.height);
+ memcpy(image.memptr(), data.data.data(), static_cast(data.data.size()));
- QMetaObject::invokeMethod(_hyperion, "registerInput", Qt::QueuedConnection, Q_ARG(int, data.priority), Q_ARG(hyperion::Components, comp), Q_ARG(QString, data.origin), Q_ARG(QString, data.imgName));
- QMetaObject::invokeMethod(_hyperion, "setInputImage", Qt::QueuedConnection, Q_ARG(int, data.priority), Q_ARG(Image, image), Q_ARG(int64_t, data.duration));
+ QMetaObject::invokeMethod(_hyperion, "registerInput", Qt::QueuedConnection, Q_ARG(int, data.priority), Q_ARG(hyperion::Components, comp), Q_ARG(QString, data.origin), Q_ARG(QString, data.imgName));
+ QMetaObject::invokeMethod(_hyperion, "setInputImage", Qt::QueuedConnection, Q_ARG(int, data.priority), Q_ARG(Image, image), Q_ARG(int64_t, data.duration));
- return true;
+ return true;
}
-bool API::clearPriority(int priority, QString &replyMsg, hyperion::Components callerComp)
+bool API::clearPriority(int priority, QString &replyMsg, hyperion::Components /*callerComp*/)
{
- if (priority < 0 || (priority > 0 && priority < 254))
- {
- QMetaObject::invokeMethod(_hyperion, "clear", Qt::QueuedConnection, Q_ARG(int, priority));
- }
- else
- {
- replyMsg = QString("Priority %1 is not allowed to be cleared").arg(priority);
- return false;
- }
- return true;
+ if (priority < 0 || (priority > 0 && priority < PriorityMuxer::BG_PRIORITY))
+ {
+ QMetaObject::invokeMethod(_hyperion, "clear", Qt::QueuedConnection, Q_ARG(int, priority));
+ }
+ else
+ {
+ replyMsg = QString("Priority %1 is not allowed to be cleared").arg(priority);
+ return false;
+ }
+ return true;
}
-bool API::setComponentState(const QString &comp, bool &compState, QString &replyMsg, hyperion::Components callerComp)
+bool API::setComponentState(const QString &comp, bool &compState, QString &replyMsg, hyperion::Components /*callerComp*/)
{
- Components component = stringToComponent(comp);
+ Components component = stringToComponent(comp);
- if (component != COMP_INVALID)
- {
- QMetaObject::invokeMethod(_hyperion, "compStateChangeRequest", Qt::QueuedConnection, Q_ARG(hyperion::Components, component), Q_ARG(bool, compState));
- return true;
- }
- replyMsg = QString("Unknown component name: %1").arg(comp);
- return false;
+ if (component != COMP_INVALID)
+ {
+ QMetaObject::invokeMethod(_hyperion, "compStateChangeRequest", Qt::QueuedConnection, Q_ARG(hyperion::Components, component), Q_ARG(bool, compState));
+ return true;
+ }
+ replyMsg = QString("Unknown component name: %1").arg(comp);
+ return false;
}
-void API::setLedMappingType(int type, hyperion::Components callerComp)
+void API::setLedMappingType(int type, hyperion::Components /*callerComp*/)
{
- QMetaObject::invokeMethod(_hyperion, "setLedMappingType", Qt::QueuedConnection, Q_ARG(int, type));
+ QMetaObject::invokeMethod(_hyperion, "setLedMappingType", Qt::QueuedConnection, Q_ARG(int, type));
}
-void API::setVideoMode(VideoMode mode, hyperion::Components callerComp)
+void API::setVideoMode(VideoMode mode, hyperion::Components /*callerComp*/)
{
- QMetaObject::invokeMethod(_hyperion, "setVideoMode", Qt::QueuedConnection, Q_ARG(VideoMode, mode));
+ QMetaObject::invokeMethod(_hyperion, "setVideoMode", Qt::QueuedConnection, Q_ARG(VideoMode, mode));
}
#if defined(ENABLE_EFFECTENGINE)
-bool API::setEffect(const EffectCmdData &dat, hyperion::Components callerComp)
+bool API::setEffect(const EffectCmdData &dat, hyperion::Components /*callerComp*/)
{
- int res;
- if (!dat.args.isEmpty())
- {
- QMetaObject::invokeMethod(_hyperion, "setEffect", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, res), Q_ARG(QString, dat.effectName), Q_ARG(QJsonObject, dat.args), Q_ARG(int, dat.priority), Q_ARG(int, dat.duration), Q_ARG(QString, dat.pythonScript), Q_ARG(QString, dat.origin), Q_ARG(QString, dat.data));
- }
- else
- {
- QMetaObject::invokeMethod(_hyperion, "setEffect", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, res), Q_ARG(QString, dat.effectName), Q_ARG(int, dat.priority), Q_ARG(int, dat.duration), Q_ARG(QString, dat.origin));
- }
+ int isStarted;
+ if (!dat.args.isEmpty())
+ {
+ QMetaObject::invokeMethod(_hyperion, "setEffect", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, isStarted), Q_ARG(QString, dat.effectName), Q_ARG(QJsonObject, dat.args), Q_ARG(int, dat.priority), Q_ARG(int, dat.duration), Q_ARG(QString, dat.pythonScript), Q_ARG(QString, dat.origin), Q_ARG(QString, dat.data));
+ }
+ else
+ {
+ QMetaObject::invokeMethod(_hyperion, "setEffect", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, isStarted), Q_ARG(QString, dat.effectName), Q_ARG(int, dat.priority), Q_ARG(int, dat.duration), Q_ARG(QString, dat.origin));
+ }
- return res >= 0;
+ return isStarted >= 0;
}
#endif
-void API::setSourceAutoSelect(bool state, hyperion::Components callerComp)
+void API::setSourceAutoSelect(bool state, hyperion::Components /*callerComp*/)
{
- QMetaObject::invokeMethod(_hyperion, "setSourceAutoSelect", Qt::QueuedConnection, Q_ARG(bool, state));
+ QMetaObject::invokeMethod(_hyperion, "setSourceAutoSelect", Qt::QueuedConnection, Q_ARG(bool, state));
}
-void API::setVisiblePriority(int priority, hyperion::Components callerComp)
+void API::setVisiblePriority(int priority, hyperion::Components /*callerComp*/)
{
- QMetaObject::invokeMethod(_hyperion, "setVisiblePriority", Qt::QueuedConnection, Q_ARG(int, priority));
+ QMetaObject::invokeMethod(_hyperion, "setVisiblePriority", Qt::QueuedConnection, Q_ARG(int, priority));
}
void API::registerInput(int priority, hyperion::Components component, const QString &origin, const QString &owner, hyperion::Components callerComp)
{
- if (_activeRegisters.count(priority))
- _activeRegisters.erase(priority);
+ if (_activeRegisters.count(priority) != 0)
+ {
+ _activeRegisters.erase(priority);
+ }
- _activeRegisters.insert({priority, registerData{component, origin, owner, callerComp}});
+ _activeRegisters.insert({priority, registerData{component, origin, owner, callerComp}});
- QMetaObject::invokeMethod(_hyperion, "registerInput", Qt::QueuedConnection, Q_ARG(int, priority), Q_ARG(hyperion::Components, component), Q_ARG(QString, origin), Q_ARG(QString, owner));
+ QMetaObject::invokeMethod(_hyperion, "registerInput", Qt::QueuedConnection, Q_ARG(int, priority), Q_ARG(hyperion::Components, component), Q_ARG(QString, origin), Q_ARG(QString, owner));
}
void API::unregisterInput(int priority)
{
- if (_activeRegisters.count(priority))
- _activeRegisters.erase(priority);
+ if (_activeRegisters.count(priority) != 0)
+ {
+ _activeRegisters.erase(priority);
+ }
}
bool API::setHyperionInstance(quint8 inst)
{
- if (_currInstanceIndex == inst)
- return true;
- bool isRunning;
- QMetaObject::invokeMethod(_instanceManager, "IsInstanceRunning", Qt::DirectConnection, Q_RETURN_ARG(bool, isRunning), Q_ARG(quint8, inst));
- if (!isRunning)
- return false;
+ if (_currInstanceIndex == inst)
+ {
+ return true;
+ }
- disconnect(_hyperion, 0, this, 0);
- QMetaObject::invokeMethod(_instanceManager, "getHyperionInstance", Qt::DirectConnection, Q_RETURN_ARG(Hyperion *, _hyperion), Q_ARG(quint8, inst));
- _currInstanceIndex = inst;
- return true;
+ bool isRunning;
+ QMetaObject::invokeMethod(_instanceManager, "IsInstanceRunning", Qt::DirectConnection, Q_RETURN_ARG(bool, isRunning), Q_ARG(quint8, inst));
+ if (!isRunning)
+ {
+ return false;
+ }
+
+ disconnect(_hyperion, nullptr, this, nullptr);
+ QMetaObject::invokeMethod(_instanceManager, "getHyperionInstance", Qt::DirectConnection, Q_RETURN_ARG(Hyperion *, _hyperion), Q_ARG(quint8, inst));
+ _currInstanceIndex = inst;
+ return true;
}
bool API::isHyperionEnabled()
{
- int res;
- QMetaObject::invokeMethod(_hyperion, "isComponentEnabled", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, res), Q_ARG(hyperion::Components, hyperion::COMP_ALL));
- return res > 0;
+ int isEnabled;
+ QMetaObject::invokeMethod(_hyperion, "isComponentEnabled", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, isEnabled), Q_ARG(hyperion::Components, hyperion::COMP_ALL));
+ return isEnabled > 0;
}
-QVector API::getAllInstanceData()
+QVector API::getAllInstanceData() const
{
- QVector vec;
- QMetaObject::invokeMethod(_instanceManager, "getInstanceData", Qt::DirectConnection, Q_RETURN_ARG(QVector, vec));
- return vec;
+ QVector vec;
+ QMetaObject::invokeMethod(_instanceManager, "getInstanceData", Qt::DirectConnection, Q_RETURN_ARG(QVector, vec));
+ return vec;
}
bool API::startInstance(quint8 index, int tan)
{
- bool res;
- (_instanceManager->thread() != this->thread())
- ? QMetaObject::invokeMethod(_instanceManager, "startInstance", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, res), Q_ARG(quint8, index), Q_ARG(bool, false), Q_ARG(QObject*, this), Q_ARG(int, tan))
- : res = _instanceManager->startInstance(index, false, this, tan);
+ bool isStarted;
+ (_instanceManager->thread() != this->thread())
+ ? QMetaObject::invokeMethod(_instanceManager, "startInstance", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, isStarted), Q_ARG(quint8, index), Q_ARG(bool, false), Q_ARG(QObject*, this), Q_ARG(int, tan))
+ : isStarted = _instanceManager->startInstance(index, false, this, tan);
- return res;
+ return isStarted;
}
void API::stopInstance(quint8 index)
{
- QMetaObject::invokeMethod(_instanceManager, "stopInstance", Qt::QueuedConnection, Q_ARG(quint8, index));
+ QMetaObject::invokeMethod(_instanceManager, "stopInstance", Qt::QueuedConnection, Q_ARG(quint8, index));
}
bool API::deleteInstance(quint8 index, QString &replyMsg)
{
- if (_adminAuthorized)
- {
- QMetaObject::invokeMethod(_instanceManager, "deleteInstance", Qt::QueuedConnection, Q_ARG(quint8, index));
- return true;
- }
- replyMsg = NO_AUTH;
- return false;
+ if (_adminAuthorized)
+ {
+ QMetaObject::invokeMethod(_instanceManager, "deleteInstance", Qt::QueuedConnection, Q_ARG(quint8, index));
+ return true;
+ }
+ replyMsg = NO_AUTHORIZATION;
+ return false;
}
QString API::createInstance(const QString &name)
{
- if (_adminAuthorized)
- {
- bool success;
- QMetaObject::invokeMethod(_instanceManager, "createInstance", Qt::DirectConnection, Q_RETURN_ARG(bool, success), Q_ARG(QString, name));
- if (!success)
- return QString("Instance name '%1' is already in use").arg(name);
-
- return "";
- }
- return NO_AUTH;
+ if (_adminAuthorized)
+ {
+ bool success;
+ QMetaObject::invokeMethod(_instanceManager, "createInstance", Qt::DirectConnection, Q_RETURN_ARG(bool, success), Q_ARG(QString, name));
+ if (!success)
+ {
+ return QString("Instance name '%1' is already in use").arg(name);
+ }
+ return "";
+ }
+ return NO_AUTHORIZATION;
}
QString API::setInstanceName(quint8 index, const QString &name)
{
- if (_adminAuthorized)
- {
- QMetaObject::invokeMethod(_instanceManager, "saveName", Qt::QueuedConnection, Q_ARG(quint8, index), Q_ARG(QString, name));
- return "";
- }
- return NO_AUTH;
+ if (_adminAuthorized)
+ {
+ QMetaObject::invokeMethod(_instanceManager, "saveName", Qt::QueuedConnection, Q_ARG(quint8, index), Q_ARG(QString, name));
+ return "";
+ }
+ return NO_AUTHORIZATION;
}
#if defined(ENABLE_EFFECTENGINE)
QString API::deleteEffect(const QString &name)
{
- if (_adminAuthorized)
- {
- QString res;
- QMetaObject::invokeMethod(_hyperion, "deleteEffect", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, res), Q_ARG(QString, name));
- return res;
- }
- return NO_AUTH;
+ if (_adminAuthorized)
+ {
+ QString res;
+ QMetaObject::invokeMethod(_hyperion, "deleteEffect", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, res), Q_ARG(QString, name));
+ return res;
+ }
+ return NO_AUTHORIZATION;
}
QString API::saveEffect(const QJsonObject &data)
{
- if (_adminAuthorized)
- {
- QString res;
- QMetaObject::invokeMethod(_hyperion, "saveEffect", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, res), Q_ARG(QJsonObject, data));
- return res;
- }
- return NO_AUTH;
+ if (_adminAuthorized)
+ {
+ QString res;
+ QMetaObject::invokeMethod(_hyperion, "saveEffect", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, res), Q_ARG(QJsonObject, data));
+ return res;
+ }
+ return NO_AUTHORIZATION;
}
#endif
bool API::saveSettings(const QJsonObject &data)
{
- bool rc = true;
- if (!_adminAuthorized)
+ bool isSaved {true};
+ if (!_adminAuthorized)
{
- rc = false;
+ isSaved = false;
}
else
{
- QMetaObject::invokeMethod(_hyperion, "saveSettings", Qt::DirectConnection, Q_RETURN_ARG(bool, rc), Q_ARG(QJsonObject, data), Q_ARG(bool, true));
+ QMetaObject::invokeMethod(_hyperion, "saveSettings", Qt::DirectConnection, Q_RETURN_ARG(bool, isSaved), Q_ARG(QJsonObject, data), Q_ARG(bool, true));
}
- return rc;
+ return isSaved;
}
bool API::restoreSettings(const QJsonObject &data)
{
- bool rc = true;
+ bool isRestored {true};
if (!_adminAuthorized)
{
- rc = false;
+ isRestored = false;
}
else
{
- QMetaObject::invokeMethod(_hyperion, "restoreSettings", Qt::DirectConnection, Q_RETURN_ARG(bool, rc), Q_ARG(QJsonObject, data), Q_ARG(bool, true));
+ QMetaObject::invokeMethod(_hyperion, "restoreSettings", Qt::DirectConnection, Q_RETURN_ARG(bool, isRestored), Q_ARG(QJsonObject, data), Q_ARG(bool, true));
}
- return rc;
+ return isRestored;
}
bool API::updateHyperionPassword(const QString &password, const QString &newPassword)
{
- if (!_adminAuthorized)
- return false;
- bool res;
- QMetaObject::invokeMethod(_authManager, "updateUserPassword", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, res), Q_ARG(QString, DEFAULT_USER), Q_ARG(QString, password), Q_ARG(QString, newPassword));
- return res;
+ bool isPwUpdated {true};
+ if (!_adminAuthorized)
+ {
+ isPwUpdated = false;
+ }
+ else
+ {
+ QMetaObject::invokeMethod(_authManager, "updateUserPassword", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, isPwUpdated), Q_ARG(QString, DEFAULT_USER), Q_ARG(QString, password), Q_ARG(QString, newPassword));
+ }
+ return isPwUpdated;
}
QString API::createToken(const QString &comment, AuthManager::AuthDefinition &def)
{
- if (!_adminAuthorized)
- return NO_AUTH;
- if (comment.isEmpty())
- return "comment is empty";
- QMetaObject::invokeMethod(_authManager, "createToken", Qt::BlockingQueuedConnection, Q_RETURN_ARG(AuthManager::AuthDefinition, def), Q_ARG(QString, comment));
- return "";
+ if (!_adminAuthorized)
+ {
+ return NO_AUTHORIZATION;
+ }
+
+ if (comment.isEmpty())
+ {
+ return "Missing token comment";
+ }
+ QMetaObject::invokeMethod(_authManager, "createToken", Qt::BlockingQueuedConnection, Q_RETURN_ARG(AuthManager::AuthDefinition, def), Q_ARG(QString, comment));
+ return "";
}
-QString API::renameToken(const QString &id, const QString &comment)
+QString API::renameToken(const QString &tokenId, const QString &comment)
{
- if (!_adminAuthorized)
- return NO_AUTH;
- if (comment.isEmpty() || id.isEmpty())
- return "Empty comment or id";
+ if (!_adminAuthorized)
+ {
+ return NO_AUTHORIZATION;
+ }
- QMetaObject::invokeMethod(_authManager, "renameToken", Qt::QueuedConnection, Q_ARG(QString, id), Q_ARG(QString, comment));
- return "";
+ if (comment.isEmpty())
+ {
+ return "Missing token comment";
+ }
+
+ if (tokenId.isEmpty()) {
+ return "Missing token id";
+ }
+
+ bool isTokenRenamed {false};
+ QMetaObject::invokeMethod(_authManager, "renameToken", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, isTokenRenamed), Q_ARG(QString, tokenId), Q_ARG(QString, comment));
+
+ return (!isTokenRenamed) ? "Token does not exist" : "";
}
-QString API::deleteToken(const QString &id)
+QString API::deleteToken(const QString &tokenId)
{
- if (!_adminAuthorized)
- return NO_AUTH;
- if (id.isEmpty())
- return "Empty id";
+ if (!_adminAuthorized)
+ {
+ return NO_AUTHORIZATION;
+ }
- QMetaObject::invokeMethod(_authManager, "deleteToken", Qt::QueuedConnection, Q_ARG(QString, id));
- return "";
+ if (tokenId.isEmpty())
+ {
+ return "Missing token id";
+ }
+
+ bool isTokenDeleted {false};
+ QMetaObject::invokeMethod(_authManager, "deleteToken", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, isTokenDeleted), Q_ARG(QString, tokenId));
+
+ return (!isTokenDeleted) ? "Token does not exist" : "";
}
-void API::setNewTokenRequest(const QString &comment, const QString &id, const int &tan)
+void API::setNewTokenRequest(const QString &comment, const QString &tokenId, const int &tan)
{
- QMetaObject::invokeMethod(_authManager, "setNewTokenRequest", Qt::QueuedConnection, Q_ARG(QObject *, this), Q_ARG(QString, comment), Q_ARG(QString, id), Q_ARG(int, tan));
+ QMetaObject::invokeMethod(_authManager, "setNewTokenRequest", Qt::QueuedConnection, Q_ARG(QObject *, this), Q_ARG(QString, comment), Q_ARG(QString, tokenId), Q_ARG(int, tan));
}
-void API::cancelNewTokenRequest(const QString &comment, const QString &id)
+void API::cancelNewTokenRequest(const QString &comment, const QString &tokenId)
{
- QMetaObject::invokeMethod(_authManager, "cancelNewTokenRequest", Qt::QueuedConnection, Q_ARG(QObject *, this), Q_ARG(QString, comment), Q_ARG(QString, id));
+ QMetaObject::invokeMethod(_authManager, "cancelNewTokenRequest", Qt::QueuedConnection, Q_ARG(QObject *, this), Q_ARG(QString, comment), Q_ARG(QString, tokenId));
}
-bool API::handlePendingTokenRequest(const QString &id, bool accept)
+bool API::handlePendingTokenRequest(const QString &tokenId, bool accept)
{
- if (!_adminAuthorized)
- return false;
- QMetaObject::invokeMethod(_authManager, "handlePendingTokenRequest", Qt::QueuedConnection, Q_ARG(QString, id), Q_ARG(bool, accept));
- return true;
+ if (!_adminAuthorized)
+ {
+ return false;
+ }
+ QMetaObject::invokeMethod(_authManager, "handlePendingTokenRequest", Qt::QueuedConnection, Q_ARG(QString, tokenId), Q_ARG(bool, accept));
+ return true;
}
bool API::getTokenList(QVector &def)
{
- if (!_adminAuthorized)
- return false;
- QMetaObject::invokeMethod(_authManager, "getTokenList", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QVector, def));
- return true;
+ if (!_adminAuthorized)
+ {
+ return false;
+ }
+ QMetaObject::invokeMethod(_authManager, "getTokenList", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QVector, def));
+ return true;
}
bool API::getPendingTokenRequests(QVector &map)
{
- if (!_adminAuthorized)
- return false;
- QMetaObject::invokeMethod(_authManager, "getPendingRequests", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QVector, map));
- return true;
+ if (!_adminAuthorized)
+ {
+ return false;
+ }
+ QMetaObject::invokeMethod(_authManager, "getPendingRequests", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QVector, map));
+ return true;
}
bool API::isUserTokenAuthorized(const QString &userToken)
{
- bool res;
- QMetaObject::invokeMethod(_authManager, "isUserTokenAuthorized", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, res), Q_ARG(QString, DEFAULT_USER), Q_ARG(QString, userToken));
- if (res)
- {
- _authorized = true;
- _adminAuthorized = true;
- // Listen for ADMIN ACCESS protected signals
- connect(_authManager, &AuthManager::newPendingTokenRequest, this, &API::onPendingTokenRequest, Qt::UniqueConnection);
- }
- return res;
+ QMetaObject::invokeMethod(_authManager, "isUserTokenAuthorized", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, _authorized), Q_ARG(QString, DEFAULT_USER), Q_ARG(QString, userToken));
+ _adminAuthorized = _authorized;
+
+ if (_authorized)
+ {
+ // Listen for ADMIN ACCESS protected signals
+ connect(_authManager, &AuthManager::newPendingTokenRequest, this, &API::onPendingTokenRequest);
+ }
+ else
+ {
+ disconnect(_authManager, &AuthManager::newPendingTokenRequest, this, &API::onPendingTokenRequest);
+ }
+ return _authorized;
}
bool API::getUserToken(QString &userToken)
{
- if (!_adminAuthorized)
- return false;
- QMetaObject::invokeMethod(_authManager, "getUserToken", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, userToken));
- return true;
+ if (!_adminAuthorized)
+ {
+ return false;
+ }
+ QMetaObject::invokeMethod(_authManager, "getUserToken", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, userToken));
+ return true;
}
bool API::isTokenAuthorized(const QString &token)
{
(_authManager->thread() != this->thread())
- ? QMetaObject::invokeMethod(_authManager, "isTokenAuthorized", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, _authorized), Q_ARG(QString, token))
- : _authorized = _authManager->isTokenAuthorized(token);
+ ? QMetaObject::invokeMethod(_authManager, "isTokenAuthorized", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, _authorized), Q_ARG(QString, token))
+ : _authorized = _authManager->isTokenAuthorized(token);
+ _adminAuthorized = _authorized;
- return _authorized;
+ return _authorized;
}
bool API::isUserAuthorized(const QString &password)
{
- bool res;
- QMetaObject::invokeMethod(_authManager, "isUserAuthorized", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, res), Q_ARG(QString, DEFAULT_USER), Q_ARG(QString, password));
- if (res)
- {
- _authorized = true;
- _adminAuthorized = true;
- // Listen for ADMIN ACCESS protected signals
- connect(_authManager, &AuthManager::newPendingTokenRequest, this, &API::onPendingTokenRequest, Qt::UniqueConnection);
- }
- return res;
+ bool isUserAuthorized;
+ QMetaObject::invokeMethod(_authManager, "isUserAuthorized", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, isUserAuthorized), Q_ARG(QString, DEFAULT_USER), Q_ARG(QString, password));
+ if (isUserAuthorized)
+ {
+ _authorized = true;
+ _adminAuthorized = true;
+
+ // Listen for ADMIN ACCESS protected signals
+ connect(_authManager, &AuthManager::newPendingTokenRequest, this, &API::onPendingTokenRequest);
+ }
+ else
+ {
+ disconnect(_authManager, &AuthManager::newPendingTokenRequest, this, &API::onPendingTokenRequest);
+ }
+ return isUserAuthorized;
}
bool API::hasHyperionDefaultPw()
{
- bool res;
- QMetaObject::invokeMethod(_authManager, "isUserAuthorized", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, res), Q_ARG(QString, DEFAULT_USER), Q_ARG(QString, DEFAULT_PASSWORD));
- return res;
+ bool isDefaultPassort;
+ QMetaObject::invokeMethod(_authManager, "isUserAuthorized", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, isDefaultPassort), Q_ARG(QString, DEFAULT_USER), Q_ARG(QString, DEFAULT_PASSWORD));
+ return isDefaultPassort;
}
void API::logout()
{
- _authorized = false;
- _adminAuthorized = false;
- // Stop listenig for ADMIN ACCESS protected signals
- disconnect(_authManager, &AuthManager::newPendingTokenRequest, this, &API::onPendingTokenRequest);
- stopDataConnectionss();
-}
-
-void API::stopDataConnectionss()
-{
+ _authorized = false;
+ _adminAuthorized = false;
+ // Stop listenig for ADMIN ACCESS protected signals
+ disconnect(_authManager, &AuthManager::newPendingTokenRequest, this, &API::onPendingTokenRequest);
+ stopDataConnections();
}
diff --git a/libsrc/api/CMakeLists.txt b/libsrc/api/CMakeLists.txt
index ac5cdcfd..6818e752 100644
--- a/libsrc/api/CMakeLists.txt
+++ b/libsrc/api/CMakeLists.txt
@@ -2,10 +2,14 @@ add_library(hyperion-api
${CMAKE_SOURCE_DIR}/include/api/apiStructs.h
${CMAKE_SOURCE_DIR}/include/api/API.h
${CMAKE_SOURCE_DIR}/include/api/JsonAPI.h
- ${CMAKE_SOURCE_DIR}/include/api/JsonCB.h
+ ${CMAKE_SOURCE_DIR}/include/api/JsonCallbacks.h
+ ${CMAKE_SOURCE_DIR}/include/api/JsonApiCommand.h
+ ${CMAKE_SOURCE_DIR}/include/api/JsonApiSubscription.h
+ ${CMAKE_SOURCE_DIR}/include/api/JsonInfo.h
${CMAKE_SOURCE_DIR}/libsrc/api/JsonAPI.cpp
${CMAKE_SOURCE_DIR}/libsrc/api/API.cpp
- ${CMAKE_SOURCE_DIR}/libsrc/api/JsonCB.cpp
+ ${CMAKE_SOURCE_DIR}/libsrc/api/JsonCallbacks.cpp
+ ${CMAKE_SOURCE_DIR}/libsrc/api/JsonInfo.cpp
${CMAKE_SOURCE_DIR}/libsrc/api/JSONRPC_schemas.qrc
)
diff --git a/libsrc/api/JSONRPC_schema/schema-ledcolors.json b/libsrc/api/JSONRPC_schema/schema-ledcolors.json
index b1bda0a3..e0f3d905 100644
--- a/libsrc/api/JSONRPC_schema/schema-ledcolors.json
+++ b/libsrc/api/JSONRPC_schema/schema-ledcolors.json
@@ -13,15 +13,7 @@
"subcommand": {
"type" : "string",
"required" : true,
- "enum" : ["ledstream-stop","ledstream-start","testled","imagestream-start","imagestream-stop"]
- },
- "oneshot": {
- "type" : "bool"
- },
- "interval": {
- "type" : "integer",
- "required" : false,
- "minimum": 50
+ "enum" : ["ledstream-stop","ledstream-start","imagestream-start","imagestream-stop"]
}
},
diff --git a/libsrc/api/JSONRPC_schema/schema-serverinfo.json b/libsrc/api/JSONRPC_schema/schema-serverinfo.json
index 990eec04..4ead4617 100644
--- a/libsrc/api/JSONRPC_schema/schema-serverinfo.json
+++ b/libsrc/api/JSONRPC_schema/schema-serverinfo.json
@@ -7,6 +7,20 @@
"required" : true,
"enum" : ["serverinfo"]
},
+ "subcommand": {
+ "type": "string",
+ "enum": ["getInfo", "subscribe", "unsubscribe", "getSubscriptions", "getSubscriptionCommands"]
+ },
+ "data": {
+ "type": ["null", "array"],
+ "properties": {
+ "subscriptions": {
+ "type": "array",
+ "items": {}
+ }
+ },
+ "additionalProperties": false
+ },
"subscribe" : {
"type" : "array"
},
diff --git a/libsrc/api/JsonAPI.cpp b/libsrc/api/JsonAPI.cpp
index 45b9594a..19b4aef9 100644
--- a/libsrc/api/JsonAPI.cpp
+++ b/libsrc/api/JsonAPI.cpp
@@ -1,5 +1,6 @@
// project includes
#include
+#include
// Qt includes
#include
@@ -10,8 +11,8 @@
#include
#include
#include
-#include
-#include
+#include
+#include
// hyperion includes
#include
@@ -20,62 +21,11 @@
#include // Required to determine the cmake options
-#include
-#include
-
#include
#include
-#if defined(ENABLE_MF)
- #include
-#elif defined(ENABLE_V4L2)
- #include
-#endif
-
-#if defined(ENABLE_AUDIO)
- #include
-
- #ifdef WIN32
- #include
- #endif
-
- #ifdef __linux__
- #include
- #endif
-#endif
-
-#if defined(ENABLE_X11)
- #include
-#endif
-
-#if defined(ENABLE_XCB)
- #include
-#endif
-
-#if defined(ENABLE_DX)
- #include
-#endif
-
-#if defined(ENABLE_FB)
- #include
-#endif
-
-#if defined(ENABLE_DISPMANX)
- #include
-#endif
-
-#if defined(ENABLE_AMLOGIC)
- #include
-#endif
-
-#if defined(ENABLE_OSX)
- #include
-#endif
-
#include
#include
-#include
-#include
#include
#include
#include
@@ -84,7 +34,7 @@
#include
// api includes
-#include
+#include
#include
// auth manager
@@ -99,42 +49,52 @@
#include
#endif
+#include
+#include
+
using namespace hyperion;
// Constants
-namespace { const bool verbose = false; }
+namespace {
+
+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 int MIN_PASSWORD_LENGTH = 8;
+const int APP_TOKEN_LENGTH = 36;
+
+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)
{
- _noListener = noListener;
- _peerAddress = peerAddress;
- _jsonCB = new JsonCB(this);
- _streaming_logging_activated = false;
- _ledStreamTimer = new QTimer(this);
-
Q_INIT_RESOURCE(JSONRPC_schemas);
qRegisterMetaType("Event");
+ _jsonCB = QSharedPointer(new JsonCallbacks( _log, _peerAddress, parent));
}
void JsonAPI::initialize()
{
- Debug(_log,"");
// init API, REQUIRED!
API::init();
- // Initialise jsonCB with current instance
- _jsonCB->setSubscriptionsTo(_hyperion);
// setup auth interface
- connect(this, &API::onPendingTokenRequest, this, &JsonAPI::newPendingTokenRequest);
- connect(this, &API::onTokenResponse, this, &JsonAPI::handleTokenResponse);
+ connect(this, &API::onPendingTokenRequest, this, &JsonAPI::issueNewPendingTokenRequest);
// listen for killed instances
connect(_instanceManager, &HyperionIManager::instanceStateChanged, this, &JsonAPI::handleInstanceStateChange);
// pipe callbacks from subscriptions to parent
- connect(_jsonCB, &JsonCB::newCallback, this, &JsonAPI::callbackMessage);
+ connect(_jsonCB.data(), &JsonCallbacks::newCallback, this, &JsonAPI::callbackMessage);
// notify hyperion about a jsonMessageForward
if (_hyperion != nullptr)
@@ -146,8 +106,6 @@ void JsonAPI::initialize()
//notify eventhadler on suspend/resume/idle requests
connect(this, &JsonAPI::signalEvent, EventHandler::getInstance().data(), &EventHandler::handleEvent);
-
- connect(_ledStreamTimer, &QTimer::timeout, this, &JsonAPI::streamLedColorsUpdate, Qt::UniqueConnection);
}
bool JsonAPI::handleInstanceSwitch(quint8 inst, bool /*forced*/)
@@ -164,129 +122,202 @@ bool JsonAPI::handleInstanceSwitch(quint8 inst, bool /*forced*/)
void JsonAPI::handleMessage(const QString &messageString, const QString &httpAuthHeader)
{
- Debug(_log,"");
const QString ident = "JsonRpc@" + _peerAddress;
QJsonObject message;
- //std::cout << "JsonAPI::handleMessage | [" << static_cast(_hyperion->getInstanceIndex()) << "] Received: ["<< messageString.toStdString() << "]" << std::endl;
- //std::cout << "JsonAPI::handleMessage - _noListener [" << _noListener << "]" << std::endl;
- //std::cout << "JsonAPI::handleMessage - _authorized [" << _authorized << "] _adminAuthorized [" << _adminAuthorized << "]" << std::endl;
- // parse the message
- if (!JsonUtils::parse(ident, messageString, message, _log))
+ //parse the message
+ QPair parsingResult = JsonUtils::parse(ident, messageString, message, _log);
+ if (!parsingResult.first)
{
- sendErrorReply("Errors during message parsing, please consult the Hyperion Log.");
+ //Try to find command and tan, even parsing failed
+ QString command = findCommand(messageString);
+ int tan = findTan(messageString);
+
+ sendErrorReply("Parse error", parsingResult.second, command, tan);
return;
}
- int tan = 0;
- if (message.value("tan") != QJsonValue::Undefined)
- tan = message["tan"].toInt();
-
- // check basic message
- if (!JsonUtils::validate(ident, message, ":schema", _log))
- {
- sendErrorReply("Errors during message validation, please consult the Hyperion Log.", "" /*command*/, tan);
- return;
- }
+ DebugIf(verbose, _log, "message: [%s]", QJsonDocument(message).toJson(QJsonDocument::Compact).constData() );
// check specific message
- const QString command = message["command"].toString();
- if (!JsonUtils::validate(ident, message, QString(":schema-%1").arg(command), _log))
+ const QString command = message.value("command").toString();
+ const QString subCommand = message.value("subcommand").toString();
+
+ int tan {0};
+ if (message.value("tan") != QJsonValue::Undefined)
{
- sendErrorReply("Errors during specific message validation, please consult the Hyperion Log", command, tan);
+ tan = message["tan"].toInt();
+ }
+
+ // check basic message
+ QJsonObject schemaJson = QJsonFactory::readSchema(":schema");
+ QPair validationResult = JsonUtils::validate(ident, message, schemaJson, _log);
+ if (!validationResult.first)
+ {
+ sendErrorReply("Invalid command", validationResult.second, command, tan);
return;
}
- // check auth state
- if (!API::isAuthorized())
+ JsonApiCommand cmd = ApiCommandRegister::getCommandInfo(command, subCommand);
+ cmd.tan = tan;
+
+ if (cmd.command == Command::Unknown)
{
- Debug(_log,"!API::isAuthorized(), _noListener [%d]", _noListener);
- // on the fly auth available for http from http Auth header
- if (_noListener)
+ const QStringList errorDetails (subCommand.isEmpty() ? "subcommand is missing" : QString("Invalid subcommand: %1").arg(subCommand));
+ sendErrorReply("Invalid command", errorDetails, command, tan);
+ return;
+ }
+
+ if (_noListener)
+ {
+ if(cmd.isNolistenerCmd == NoListenerCmd::No)
{
- QString cToken = httpAuthHeader.mid(5).trimmed();
- if (API::isTokenAuthorized(cToken))
- {
- _authorized = true;
- if (!_authManager->isLocalAdminAuthRequired())
- {
- _adminAuthorized = true;
- }
- goto proceed;
+ sendErrorReply("Command not supported via single API calls using HTTP/S", cmd);
+ return;
+ }
+
+ // Check authorization for HTTP requests
+ if (!httpAuthHeader.isEmpty())
+ {
+ int bearTokenLenght {0};
+ if (httpAuthHeader.startsWith(BEARER_TOKEN_TAG, Qt::CaseInsensitive)) {
+ bearTokenLenght = BEARER_TOKEN_TAG_LENGTH;
}
- sendErrorReply("No Authorization", command, tan);
+ else if (httpAuthHeader.startsWith(TOKEN_TAG, Qt::CaseInsensitive)) {
+ bearTokenLenght = TOKEN_TAG_LENGTH;
+ }
+
+ if (bearTokenLenght == 0)
+ {
+ sendErrorReply("No bearer token found in Authorization header", cmd);
+ return;
+ }
+
+ QString cToken =httpAuthHeader.mid(bearTokenLenght).trimmed();
+ API::isTokenAuthorized(cToken); // _authorized && _adminAuthorized are set
+ }
+
+ if (islocalConnection() && !_authManager->isLocalAuthRequired())
+ {
+ // if the request comes via a local network connection, plus authorization is disabled for local request,
+ // no token authorization is required for non-admin requests
+ setAuthorization(true);
+ }
+ }
+
+ if (cmd.authorization != Authorization::No )
+ {
+ if (!isAuthorized() || (cmd.authorization == Authorization::Admin && !isAdminAuthorized()))
+ {
+ sendNoAuthorization(cmd);
return;
}
}
-proceed:
- if (_hyperion == nullptr)
+
+ schemaJson = QJsonFactory::readSchema(QString(":schema-%1").arg(command));
+ validationResult = JsonUtils::validate(ident, message, schemaJson, _log);
+ if (!validationResult.first)
{
- sendErrorReply("Service Unavailable", command, tan);
+ sendErrorReply("Invalid params", validationResult.second, cmd);
return;
}
- //Debug(_log,"proceed - cmd: [%s], _authorized[%d], _adminAuthorized[%d]", QSTRING_CSTR(command), _authorized, _adminAuthorized);
- // switch over all possible commands and handle them
- if (command == "authorize")
- handleAuthorizeCommand(message, command, tan);
- else if (command == "color")
- handleColorCommand(message, command, tan);
- else if (command == "image")
- handleImageCommand(message, command, tan);
-#if defined(ENABLE_EFFECTENGINE)
- else if (command == "effect")
- handleEffectCommand(message, command, tan);
- else if (command == "create-effect")
- handleCreateEffectCommand(message, command, tan);
- else if (command == "delete-effect")
- handleDeleteEffectCommand(message, command, tan);
-#endif
- else if (command == "sysinfo")
- handleSysInfoCommand(message, command, tan);
- else if (command == "serverinfo")
- handleServerInfoCommand(message, command, tan);
- else if (command == "clear")
- handleClearCommand(message, command, tan);
- else if (command == "adjustment")
- handleAdjustmentCommand(message, command, tan);
- else if (command == "sourceselect")
- handleSourceSelectCommand(message, command, tan);
- else if (command == "config")
- handleConfigCommand(message, command, tan);
- else if (command == "componentstate")
- handleComponentStateCommand(message, command, tan);
- else if (command == "ledcolors")
- handleLedColorsCommand(message, command, tan);
- else if (command == "logging")
- handleLoggingCommand(message, command, tan);
- else if (command == "processing")
- handleProcessingCommand(message, command, tan);
- else if (command == "videomode")
- handleVideoModeCommand(message, command, tan);
- else if (command == "instance")
- handleInstanceCommand(message, command, tan);
- else if (command == "leddevice")
- handleLedDeviceCommand(message, command, tan);
- else if (command == "inputsource")
- handleInputSourceCommand(message, command, tan);
- else if (command == "service")
- handleServiceCommand(message, command, tan);
- else if (command == "system")
- handleSystemCommand(message, command, tan);
+ if (_hyperion == nullptr)
+ {
+ sendErrorReply("Service Unavailable", cmd);
+ return;
+ }
- // BEGIN | The following commands are deprecated but used to ensure backward compatibility with hyperion Classic remote control
- else if (command == "clearall")
- handleClearallCommand(message, command, tan);
- else if (command == "transform" || command == "correction" || command == "temperature")
- sendErrorReply("The command " + command + "is deprecated, please use the Hyperion Web Interface to configure", command, tan);
- // END
-
- // handle not implemented commands
- else
- handleNotImplemented(command, tan);
+ handleCommand(cmd, message);
}
-void JsonAPI::handleColorCommand(const QJsonObject &message, const QString &command, int tan)
+void JsonAPI::handleCommand(const JsonApiCommand& cmd, const QJsonObject &message)
+{
+ switch (cmd.command) {
+ case Command::Authorize:
+ handleAuthorizeCommand(message, cmd);
+ break;
+ case Command::Color:
+ handleColorCommand(message, cmd);
+ break;
+ case Command::Image:
+ handleImageCommand(message, cmd);
+ break;
+#if defined(ENABLE_EFFECTENGINE)
+ case Command::Effect:
+ handleEffectCommand(message, cmd);
+ break;
+ case Command::CreateEffect:
+ handleCreateEffectCommand(message, cmd);
+ break;
+ case Command::DeleteEffect:
+ handleDeleteEffectCommand(message, cmd);
+ break;
+#endif
+ case Command::SysInfo:
+ handleSysInfoCommand(message, cmd);
+ break;
+ case Command::ServerInfo:
+ handleServerInfoCommand(message, cmd);
+ break;
+ case Command::Clear:
+ handleClearCommand(message, cmd);
+ break;
+ case Command::Adjustment:
+ handleAdjustmentCommand(message, cmd);
+ break;
+ case Command::SourceSelect:
+ handleSourceSelectCommand(message, cmd);
+ break;
+ case Command::Config:
+ handleConfigCommand(message, cmd);
+ break;
+ case Command::ComponentState:
+ handleComponentStateCommand(message, cmd);
+ break;
+ case Command::LedColors:
+ handleLedColorsCommand(message, cmd);
+ break;
+ case Command::Logging:
+ handleLoggingCommand(message, cmd);
+ break;
+ case Command::Processing:
+ handleProcessingCommand(message, cmd);
+ break;
+ case Command::VideoMode:
+ handleVideoModeCommand(message, cmd);
+ break;
+ case Command::Instance:
+ handleInstanceCommand(message, cmd);
+ break;
+ case Command::LedDevice:
+ handleLedDeviceCommand(message, cmd);
+ break;
+ case Command::InputSource:
+ handleInputSourceCommand(message, cmd);
+ break;
+ case Command::Service:
+ handleServiceCommand(message, cmd);
+ break;
+ case Command::System:
+ handleSystemCommand(message, cmd);
+ break;
+ case Command::ClearAll:
+ handleClearallCommand(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;
+ // END
+ default:
+ break;
+ }
+}
+
+void JsonAPI::handleColorCommand(const QJsonObject &message, const JsonApiCommand& cmd)
{
emit forwardJsonMessage(message);
int priority = message["priority"].toInt();
@@ -295,17 +326,16 @@ void JsonAPI::handleColorCommand(const QJsonObject &message, const QString &comm
const QJsonArray &jsonColor = message["color"].toArray();
std::vector colors;
- // TODO faster copy
- for (const auto &entry : jsonColor)
- {
- colors.emplace_back(uint8_t(entry.toInt()));
- }
+ 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()); });
API::setColor(priority, colors, duration, origin);
- sendSuccessReply(command, tan);
+ sendSuccessReply(cmd);
}
-void JsonAPI::handleImageCommand(const QJsonObject &message, const QString &command, int tan)
+void JsonAPI::handleImageCommand(const QJsonObject &message, const JsonApiCommand& cmd)
{
emit forwardJsonMessage(message);
@@ -321,16 +351,15 @@ void JsonAPI::handleImageCommand(const QJsonObject &message, const QString &comm
idata.data = QByteArray::fromBase64(QByteArray(message["imagedata"].toString().toUtf8()));
QString replyMsg;
- if (!API::setImage(idata, COMP_IMAGE, replyMsg))
- {
- sendErrorReply(replyMsg, command, tan);
- return;
+ if (API::setImage(idata, COMP_IMAGE, replyMsg)) {
+ sendSuccessReply(cmd);
+ } else {
+ sendErrorReply(replyMsg, cmd);
}
- sendSuccessReply(command, tan);
}
#if defined(ENABLE_EFFECTENGINE)
-void JsonAPI::handleEffectCommand(const QJsonObject &message, const QString &command, int tan)
+void JsonAPI::handleEffectCommand(const QJsonObject &message, const JsonApiCommand& cmd)
{
emit forwardJsonMessage(message);
@@ -343,524 +372,118 @@ void JsonAPI::handleEffectCommand(const QJsonObject &message, const QString &com
dat.data = message["imageData"].toString("").toUtf8();
dat.args = message["effect"].toObject()["args"].toObject();
- if (API::setEffect(dat))
- sendSuccessReply(command, tan);
- else
- sendErrorReply("Effect '" + dat.effectName + "' not found", command, tan);
+ if (API::setEffect(dat)) {
+ sendSuccessReply(cmd);
+ } else {
+ sendErrorReply("Effect '" + dat.effectName + "' not found", cmd);
+ }
}
-void JsonAPI::handleCreateEffectCommand(const QJsonObject &message, const QString &command, int tan)
+void JsonAPI::handleCreateEffectCommand(const QJsonObject &message, const JsonApiCommand& cmd)
{
const QString resultMsg = API::saveEffect(message);
- resultMsg.isEmpty() ? sendSuccessReply(command, tan) : sendErrorReply(resultMsg, command, tan);
+ resultMsg.isEmpty() ? sendSuccessReply(cmd) : sendErrorReply(resultMsg, cmd);
}
-void JsonAPI::handleDeleteEffectCommand(const QJsonObject &message, const QString &command, int tan)
+void JsonAPI::handleDeleteEffectCommand(const QJsonObject &message, const JsonApiCommand& cmd)
{
const QString res = API::deleteEffect(message["name"].toString());
- res.isEmpty() ? sendSuccessReply(command, tan) : sendErrorReply(res, command, tan);
+ res.isEmpty() ? sendSuccessReply(cmd) : sendErrorReply(res, cmd);
}
#endif
-void JsonAPI::handleSysInfoCommand(const QJsonObject &, const QString &command, int tan)
+void JsonAPI::handleSysInfoCommand(const QJsonObject & /*unused*/, const JsonApiCommand& cmd)
{
- // create result
- QJsonObject result;
- QJsonObject info;
- result["success"] = true;
- result["command"] = command;
- result["tan"] = tan;
-
- SysInfo::HyperionSysInfo data = SysInfo::get();
- QJsonObject system;
- system["kernelType"] = data.kernelType;
- system["kernelVersion"] = data.kernelVersion;
- system["architecture"] = data.architecture;
- system["cpuModelName"] = data.cpuModelName;
- system["cpuModelType"] = data.cpuModelType;
- system["cpuHardware"] = data.cpuHardware;
- system["cpuRevision"] = data.cpuRevision;
- system["wordSize"] = data.wordSize;
- system["productType"] = data.productType;
- system["productVersion"] = data.productVersion;
- system["prettyName"] = data.prettyName;
- system["hostName"] = data.hostName;
- system["domainName"] = data.domainName;
- system["isUserAdmin"] = data.isUserAdmin;
- system["qtVersion"] = data.qtVersion;
-#if defined(ENABLE_EFFECTENGINE)
- system["pyVersion"] = data.pyVersion;
-#endif
- info["system"] = system;
-
- QJsonObject hyperion;
- hyperion["version"] = QString(HYPERION_VERSION);
- hyperion["build"] = QString(HYPERION_BUILD_ID);
- hyperion["gitremote"] = QString(HYPERION_GIT_REMOTE);
- hyperion["time"] = QString(__DATE__ " " __TIME__);
- hyperion["id"] = _authManager->getID();
- hyperion["rootPath"] = _instanceManager->getRootPath();
- hyperion["readOnlyMode"] = _hyperion->getReadOnlyMode();
-
- QCoreApplication* app = QCoreApplication::instance();
- hyperion["isGuiMode"] = qobject_cast(app) ? true : false;
-
- info["hyperion"] = hyperion;
-
- // send the result
- result["info"] = info;
- emit callbackMessage(result);
+ sendSuccessDataReply(JsonInfo::getSystemInfo(_hyperion), cmd);
}
-void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const QString &command, int tan)
+void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const JsonApiCommand& cmd)
{
- QJsonObject info;
+ QJsonObject info {};
+ QStringList errorDetails;
- // collect priority information
- QJsonArray priorities;
- uint64_t now = QDateTime::currentMSecsSinceEpoch();
- QList activePriorities = _hyperion->getActivePriorities();
- activePriorities.removeAll(PriorityMuxer::LOWEST_PRIORITY);
- int currentPriority = _hyperion->getCurrentPriority();
-
- for(int priority : std::as_const(activePriorities))
- {
- const Hyperion::InputInfo &priorityInfo = _hyperion->getPriorityInfo(priority);
-
- QJsonObject item;
- item["priority"] = priority;
-
- if (priorityInfo.timeoutTime_ms > 0 )
- {
- item["duration_ms"] = int(priorityInfo.timeoutTime_ms - now);
- }
-
- // owner has optional informations to the component
- if (!priorityInfo.owner.isEmpty())
- {
- item["owner"] = priorityInfo.owner;
- }
-
- item["componentId"] = QString(hyperion::componentToIdString(priorityInfo.componentId));
- item["origin"] = priorityInfo.origin;
- item["active"] = (priorityInfo.timeoutTime_ms >= -1);
- item["visible"] = (priority == currentPriority);
-
- if (priorityInfo.componentId == hyperion::COMP_COLOR && !priorityInfo.ledColors.empty())
- {
- QJsonObject LEDcolor;
-
- // add RGB Value to Array
- QJsonArray RGBValue;
- RGBValue.append(priorityInfo.ledColors.begin()->red);
- RGBValue.append(priorityInfo.ledColors.begin()->green);
- RGBValue.append(priorityInfo.ledColors.begin()->blue);
- LEDcolor.insert("RGB", RGBValue);
-
- uint16_t Hue;
- float Saturation;
- float Luminace;
-
- // add HSL Value to Array
- QJsonArray HSLValue;
- ColorSys::rgb2hsl(priorityInfo.ledColors.begin()->red,
- priorityInfo.ledColors.begin()->green,
- priorityInfo.ledColors.begin()->blue,
- Hue, Saturation, Luminace);
-
- HSLValue.append(Hue);
- HSLValue.append(Saturation);
- HSLValue.append(Luminace);
- LEDcolor.insert("HSL", HSLValue);
-
- item["value"] = LEDcolor;
- }
-
- (priority == currentPriority)
- ? priorities.prepend(item)
- : priorities.append(item);
- }
-
- info["priorities"] = priorities;
- info["priorities_autoselect"] = _hyperion->sourceAutoSelectEnabled();
-
- // collect adjustment information
- QJsonArray adjustmentArray;
- for (const QString &adjustmentId : _hyperion->getAdjustmentIds())
- {
- const ColorAdjustment *colorAdjustment = _hyperion->getAdjustment(adjustmentId);
- if (colorAdjustment == nullptr)
- {
- Error(_log, "Incorrect color adjustment id: %s", QSTRING_CSTR(adjustmentId));
- continue;
- }
-
- QJsonObject adjustment;
- adjustment["id"] = adjustmentId;
-
- QJsonArray whiteAdjust;
- whiteAdjust.append(colorAdjustment->_rgbWhiteAdjustment.getAdjustmentR());
- whiteAdjust.append(colorAdjustment->_rgbWhiteAdjustment.getAdjustmentG());
- whiteAdjust.append(colorAdjustment->_rgbWhiteAdjustment.getAdjustmentB());
- adjustment.insert("white", whiteAdjust);
-
- QJsonArray redAdjust;
- redAdjust.append(colorAdjustment->_rgbRedAdjustment.getAdjustmentR());
- redAdjust.append(colorAdjustment->_rgbRedAdjustment.getAdjustmentG());
- redAdjust.append(colorAdjustment->_rgbRedAdjustment.getAdjustmentB());
- adjustment.insert("red", redAdjust);
-
- QJsonArray greenAdjust;
- greenAdjust.append(colorAdjustment->_rgbGreenAdjustment.getAdjustmentR());
- greenAdjust.append(colorAdjustment->_rgbGreenAdjustment.getAdjustmentG());
- greenAdjust.append(colorAdjustment->_rgbGreenAdjustment.getAdjustmentB());
- adjustment.insert("green", greenAdjust);
-
- QJsonArray blueAdjust;
- blueAdjust.append(colorAdjustment->_rgbBlueAdjustment.getAdjustmentR());
- blueAdjust.append(colorAdjustment->_rgbBlueAdjustment.getAdjustmentG());
- blueAdjust.append(colorAdjustment->_rgbBlueAdjustment.getAdjustmentB());
- adjustment.insert("blue", blueAdjust);
-
- QJsonArray cyanAdjust;
- cyanAdjust.append(colorAdjustment->_rgbCyanAdjustment.getAdjustmentR());
- cyanAdjust.append(colorAdjustment->_rgbCyanAdjustment.getAdjustmentG());
- cyanAdjust.append(colorAdjustment->_rgbCyanAdjustment.getAdjustmentB());
- adjustment.insert("cyan", cyanAdjust);
-
- QJsonArray magentaAdjust;
- magentaAdjust.append(colorAdjustment->_rgbMagentaAdjustment.getAdjustmentR());
- magentaAdjust.append(colorAdjustment->_rgbMagentaAdjustment.getAdjustmentG());
- magentaAdjust.append(colorAdjustment->_rgbMagentaAdjustment.getAdjustmentB());
- adjustment.insert("magenta", magentaAdjust);
-
- QJsonArray yellowAdjust;
- yellowAdjust.append(colorAdjustment->_rgbYellowAdjustment.getAdjustmentR());
- yellowAdjust.append(colorAdjustment->_rgbYellowAdjustment.getAdjustmentG());
- yellowAdjust.append(colorAdjustment->_rgbYellowAdjustment.getAdjustmentB());
- adjustment.insert("yellow", yellowAdjust);
-
- adjustment["backlightThreshold"] = colorAdjustment->_rgbTransform.getBacklightThreshold();
- adjustment["backlightColored"] = colorAdjustment->_rgbTransform.getBacklightColored();
- adjustment["brightness"] = colorAdjustment->_rgbTransform.getBrightness();
- adjustment["brightnessCompensation"] = colorAdjustment->_rgbTransform.getBrightnessCompensation();
- adjustment["gammaRed"] = colorAdjustment->_rgbTransform.getGammaR();
- adjustment["gammaGreen"] = colorAdjustment->_rgbTransform.getGammaG();
- adjustment["gammaBlue"] = colorAdjustment->_rgbTransform.getGammaB();
-
- adjustment["saturationGain"] = colorAdjustment->_okhsvTransform.getSaturationGain();
- adjustment["brightnessGain"] = colorAdjustment->_okhsvTransform.getBrightnessGain();
-
- adjustmentArray.append(adjustment);
- }
-
- info["adjustment"] = adjustmentArray;
+ switch (cmd.getSubCommand()) {
+ case SubCommand::Empty:
+ case SubCommand::GetInfo:
+ info["priorities"] = JsonInfo::getPrioritiestInfo(_hyperion);
+ info["priorities_autoselect"] = _hyperion->sourceAutoSelectEnabled();
+ info["adjustment"] = JsonInfo::getAdjustmentInfo(_hyperion, _log);
+ info["ledDevices"] = JsonInfo::getAvailableLedDevices();
+ info["grabbers"] = JsonInfo::getGrabbers(_hyperion);
+ info["videomode"] = QString(videoMode2String(_hyperion->getCurrentVideoMode()));
+ info["cec"] = JsonInfo::getCecInfo();
+ info["services"] = JsonInfo::getServices();
+ info["components"] = JsonInfo::getComponents(_hyperion);
+ info["imageToLedMappingType"] = ImageProcessor::mappingTypeToStr(_hyperion->getLedMappingType());
+ info["instance"] = JsonInfo::getInstanceInfo();
+ info["leds"] = _hyperion->getSetting(settings::LEDS).array();
+ info["activeLedColor"] = JsonInfo::getActiveColors(_hyperion);
#if defined(ENABLE_EFFECTENGINE)
- // collect effect info
- QJsonArray effects;
- const std::list &effectsDefinitions = _hyperion->getEffects();
- for (const EffectDefinition &effectDefinition : effectsDefinitions)
- {
- QJsonObject effect;
- effect["name"] = effectDefinition.name;
- effect["file"] = effectDefinition.file;
- effect["script"] = effectDefinition.script;
- effect["args"] = effectDefinition.args;
- effects.append(effect);
- }
-
- info["effects"] = effects;
+ info["effects"] = JsonInfo::getEffects(_hyperion);
+ info["activeEffects"] = JsonInfo::getActiveEffects(_hyperion);
#endif
- // get available led devices
- QJsonObject ledDevices;
- QJsonArray availableLedDevices;
- for (auto dev : LedDeviceWrapper::getDeviceMap())
- {
- availableLedDevices.append(dev.first);
- }
+ // BEGIN | The following entries are deprecated but used to ensure backward compatibility with hyperion Classic or up to Hyperion 2.0.16
+ info["hostname"] = QHostInfo::localHostName();
+ info["transform"] = JsonInfo::getTransformationInfo(_hyperion);
- ledDevices["available"] = availableLedDevices;
- info["ledDevices"] = ledDevices;
-
- QJsonObject grabbers;
- // SCREEN
- QJsonObject screenGrabbers;
- if (GrabberWrapper::getInstance() != nullptr)
- {
- QStringList activeGrabbers = GrabberWrapper::getInstance()->getActive(_hyperion->getInstanceIndex(), GrabberTypeFilter::SCREEN);
- QJsonArray activeGrabberNames;
- for (auto grabberName : activeGrabbers)
+ if (!_noListener && message.contains("subscribe"))
{
- activeGrabberNames.append(grabberName);
- }
-
- screenGrabbers["active"] = activeGrabberNames;
- }
- QJsonArray availableScreenGrabbers;
- for (auto grabber : GrabberWrapper::availableGrabbers(GrabberTypeFilter::SCREEN))
- {
- availableScreenGrabbers.append(grabber);
- }
- screenGrabbers["available"] = availableScreenGrabbers;
-
- // VIDEO
- QJsonObject videoGrabbers;
- if (GrabberWrapper::getInstance() != nullptr)
- {
- QStringList activeGrabbers = GrabberWrapper::getInstance()->getActive(_hyperion->getInstanceIndex(), GrabberTypeFilter::VIDEO);
- QJsonArray activeGrabberNames;
- for (auto grabberName : activeGrabbers)
- {
- activeGrabberNames.append(grabberName);
- }
-
- videoGrabbers["active"] = activeGrabberNames;
- }
- QJsonArray availableVideoGrabbers;
- for (auto grabber : GrabberWrapper::availableGrabbers(GrabberTypeFilter::VIDEO))
- {
- availableVideoGrabbers.append(grabber);
- }
- videoGrabbers["available"] = availableVideoGrabbers;
-
- // AUDIO
- QJsonObject audioGrabbers;
- if (GrabberWrapper::getInstance() != nullptr)
- {
- QStringList activeGrabbers = GrabberWrapper::getInstance()->getActive(_hyperion->getInstanceIndex(), GrabberTypeFilter::AUDIO);
-
- QJsonArray activeGrabberNames;
- for (auto grabberName : activeGrabbers)
- {
- activeGrabberNames.append(grabberName);
- }
-
- audioGrabbers["active"] = activeGrabberNames;
- }
- QJsonArray availableAudioGrabbers;
- for (auto grabber : GrabberWrapper::availableGrabbers(GrabberTypeFilter::AUDIO))
- {
- availableAudioGrabbers.append(grabber);
- }
- audioGrabbers["available"] = availableAudioGrabbers;
-
- grabbers.insert("screen", screenGrabbers);
- grabbers.insert("video", videoGrabbers);
- grabbers.insert("audio", audioGrabbers);
-
- info["grabbers"] = grabbers;
-
- info["videomode"] = QString(videoMode2String(_hyperion->getCurrentVideoMode()));
-
- QJsonObject cecInfo;
-#if defined(ENABLE_CEC)
- cecInfo["enabled"] = true;
-#else
- cecInfo["enabled"] = false;
-#endif
- info["cec"] = cecInfo;
-
- // get available services
- QJsonArray services;
-
-#if defined(ENABLE_BOBLIGHT_SERVER)
- services.append("boblight");
-#endif
-
-#if defined(ENABLE_CEC)
- services.append("cec");
-#endif
-
-#if defined(ENABLE_EFFECTENGINE)
- services.append("effectengine");
-#endif
-
-#if defined(ENABLE_FORWARDER)
- services.append("forwarder");
-#endif
-
-#if defined(ENABLE_FLATBUF_SERVER)
- services.append("flatbuffer");
-#endif
-
-#if defined(ENABLE_PROTOBUF_SERVER)
- services.append("protobuffer");
-#endif
-
-#if defined(ENABLE_MDNS)
- services.append("mDNS");
-#endif
- services.append("SSDP");
-
- if (!availableScreenGrabbers.isEmpty() || !availableVideoGrabbers.isEmpty() || services.contains("flatbuffer") || services.contains("protobuffer"))
- {
- services.append("borderdetection");
- }
-
- info["services"] = services;
-
- // get available components
- QJsonArray component;
- std::map components = _hyperion->getComponentRegister()->getRegister();
- for (auto comp : components)
- {
- QJsonObject item;
- item["name"] = QString::fromStdString(hyperion::componentToIdString(comp.first));
- item["enabled"] = comp.second;
-
- component.append(item);
- }
-
- info["components"] = component;
- info["imageToLedMappingType"] = ImageProcessor::mappingTypeToStr(_hyperion->getLedMappingType());
-
- // add instance info
- QJsonArray instanceInfo;
- for (const auto &entry : API::getAllInstanceData())
- {
- QJsonObject obj;
- obj.insert("friendly_name", entry["friendly_name"].toString());
- obj.insert("instance", entry["instance"].toInt());
- obj.insert("running", entry["running"].toBool());
- instanceInfo.append(obj);
- }
- info["instance"] = instanceInfo;
-
- // add leds configs
- info["leds"] = _hyperion->getSetting(settings::LEDS).array();
-
- // BEGIN | The following entries are deprecated but used to ensure backward compatibility with hyperion Classic remote control
- // TODO Output the real transformation information instead of default
-
- // HOST NAME
- info["hostname"] = QHostInfo::localHostName();
-
- // TRANSFORM INFORMATION (DEFAULT VALUES)
- QJsonArray transformArray;
- for (const QString &transformId : _hyperion->getAdjustmentIds())
- {
- QJsonObject transform;
- QJsonArray blacklevel, whitelevel, gamma, threshold;
-
- transform["id"] = transformId;
- transform["saturationGain"] = 1.0;
- transform["brightnessGain"] = 1.0;
- transform["saturationLGain"] = 1.0;
- transform["luminanceGain"] = 1.0;
- transform["luminanceMinimum"] = 0.0;
-
- for (int i = 0; i < 3; i++)
- {
- blacklevel.append(0.0);
- whitelevel.append(1.0);
- gamma.append(2.50);
- threshold.append(0.0);
- }
-
- transform.insert("blacklevel", blacklevel);
- transform.insert("whitelevel", whitelevel);
- transform.insert("gamma", gamma);
- transform.insert("threshold", threshold);
-
- transformArray.append(transform);
- }
- info["transform"] = transformArray;
-
-#if defined(ENABLE_EFFECTENGINE)
- // ACTIVE EFFECT INFO
- QJsonArray activeEffects;
- for (const ActiveEffectDefinition &activeEffectDefinition : _hyperion->getActiveEffects())
- {
- if (activeEffectDefinition.priority != PriorityMuxer::LOWEST_PRIORITY - 1)
- {
- QJsonObject activeEffect;
- activeEffect["script"] = activeEffectDefinition.script;
- activeEffect["name"] = activeEffectDefinition.name;
- activeEffect["priority"] = activeEffectDefinition.priority;
- activeEffect["timeout"] = activeEffectDefinition.timeout;
- activeEffect["args"] = activeEffectDefinition.args;
- activeEffects.append(activeEffect);
- }
- }
- info["activeEffects"] = activeEffects;
-#endif
-
- // ACTIVE STATIC LED COLOR
- QJsonArray activeLedColors;
- const Hyperion::InputInfo &priorityInfo = _hyperion->getPriorityInfo(_hyperion->getCurrentPriority());
- if (priorityInfo.componentId == hyperion::COMP_COLOR && !priorityInfo.ledColors.empty())
- {
- // check if LED Color not Black (0,0,0)
- if ((priorityInfo.ledColors.begin()->red +
- priorityInfo.ledColors.begin()->green +
- priorityInfo.ledColors.begin()->blue !=
- 0))
- {
- QJsonObject LEDcolor;
-
- // add RGB Value to Array
- QJsonArray RGBValue;
- RGBValue.append(priorityInfo.ledColors.begin()->red);
- RGBValue.append(priorityInfo.ledColors.begin()->green);
- RGBValue.append(priorityInfo.ledColors.begin()->blue);
- LEDcolor.insert("RGB Value", RGBValue);
-
- uint16_t Hue;
- float Saturation, Luminace;
-
- // add HSL Value to Array
- QJsonArray HSLValue;
- ColorSys::rgb2hsl(priorityInfo.ledColors.begin()->red,
- priorityInfo.ledColors.begin()->green,
- priorityInfo.ledColors.begin()->blue,
- Hue, Saturation, Luminace);
-
- HSLValue.append(Hue);
- HSLValue.append(Saturation);
- HSLValue.append(Luminace);
- LEDcolor.insert("HSL Value", HSLValue);
-
- activeLedColors.append(LEDcolor);
- }
- }
- info["activeLedColor"] = activeLedColors;
-
- // END
-
- sendSuccessDataReply(QJsonDocument(info), command, tan);
-
- // AFTER we send the info, the client might want to subscribe to future updates
- if (message.contains("subscribe"))
- {
- // check if listeners are allowed
- if (_noListener)
- return;
-
- QJsonArray subsArr = message["subscribe"].toArray();
- // catch the all keyword and build a list of all cmds
- if (subsArr.contains("all"))
- {
- subsArr = QJsonArray();
- for (const auto& entry : _jsonCB->getCommands())
+ const QJsonArray &subscriptions = message["subscribe"].toArray();
+ QStringList invaliCommands = _jsonCB->subscribe(subscriptions);
+ if (!invaliCommands.isEmpty())
{
- subsArr.append(entry);
+ errorDetails.append("subscribe - Invalid commands provided: " + invaliCommands.join(','));
}
}
+ // END
- for (const QJsonValueRef entry : subsArr)
+ break;
+
+ case SubCommand::Subscribe:
+ case SubCommand::Unsubscribe:
+ {
+ const QJsonObject ¶ms = message["data"].toObject();
+ const QJsonArray &subscriptions = params["subscriptions"].toArray();
+ if (subscriptions.isEmpty()) {
+ sendErrorReply("Invalid params", {"No subscriptions provided"}, cmd);
+ return;
+ }
+
+ QStringList invaliCommands;
+ if (cmd.subCommand == SubCommand::Subscribe)
{
- // config callbacks just if auth is set
- if ((entry == "settings-update" || entry == "token-update") && !API::isAdminAuthorized())
- continue;
- // silent failure if a subscribe type is not found
- _jsonCB->subscribeFor(entry.toString());
+ invaliCommands = _jsonCB->subscribe(subscriptions);
+ }
+ else
+ {
+ invaliCommands = _jsonCB->unsubscribe(subscriptions);
+ }
+
+ if (!invaliCommands.isEmpty())
+ {
+ errorDetails.append("subscriptions - Invalid commands provided: " + invaliCommands.join(','));
}
}
+ break;
+
+ case SubCommand::GetSubscriptions:
+ info["subscriptions"] = QJsonArray::fromStringList(_jsonCB->getSubscribedCommands());
+ break;
+
+ case SubCommand::GetSubscriptionCommands:
+ info["commands"] = QJsonArray::fromStringList(_jsonCB->getCommands());
+ break;
+
+ default:
+ break;
+ }
+
+ sendSuccessDataReplyWithError(info, cmd, errorDetails);
}
-void JsonAPI::handleClearCommand(const QJsonObject &message, const QString &command, int tan)
+void JsonAPI::handleClearCommand(const QJsonObject &message, const JsonApiCommand& cmd)
{
emit forwardJsonMessage(message);
int priority = message["priority"].toInt();
@@ -868,117 +491,113 @@ void JsonAPI::handleClearCommand(const QJsonObject &message, const QString &comm
if (!API::clearPriority(priority, replyMsg))
{
- sendErrorReply(replyMsg, command, tan);
+ sendErrorReply(replyMsg, cmd);
return;
}
- sendSuccessReply(command, tan);
+ sendSuccessReply(cmd);
}
-void JsonAPI::handleClearallCommand(const QJsonObject &message, const QString &command, int tan)
+void JsonAPI::handleClearallCommand(const QJsonObject &message, const JsonApiCommand& cmd)
{
emit forwardJsonMessage(message);
QString replyMsg;
API::clearPriority(-1, replyMsg);
- sendSuccessReply(command, tan);
+ sendSuccessReply(cmd);
}
-void JsonAPI::handleAdjustmentCommand(const QJsonObject &message, const QString &command, int tan)
+void JsonAPI::handleAdjustmentCommand(const QJsonObject &message, const JsonApiCommand& cmd)
{
const QJsonObject &adjustment = message["adjustment"].toObject();
- const QString adjustmentId = adjustment["id"].toString(_hyperion->getAdjustmentIds().first());
+ const QList adjustmentIds = _hyperion->getAdjustmentIds();
+ 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;
}
- if (adjustment.contains("red"))
- {
- const QJsonArray &values = adjustment["red"].toArray();
- colorAdjustment->_rgbRedAdjustment.setAdjustment(values[0u].toInt(), values[1u].toInt(), values[2u].toInt());
- }
-
- if (adjustment.contains("green"))
- {
- const QJsonArray &values = adjustment["green"].toArray();
- colorAdjustment->_rgbGreenAdjustment.setAdjustment(values[0u].toInt(), values[1u].toInt(), values[2u].toInt());
- }
-
- if (adjustment.contains("blue"))
- {
- const QJsonArray &values = adjustment["blue"].toArray();
- colorAdjustment->_rgbBlueAdjustment.setAdjustment(values[0u].toInt(), values[1u].toInt(), values[2u].toInt());
- }
- if (adjustment.contains("cyan"))
- {
- const QJsonArray &values = adjustment["cyan"].toArray();
- colorAdjustment->_rgbCyanAdjustment.setAdjustment(values[0u].toInt(), values[1u].toInt(), values[2u].toInt());
- }
- if (adjustment.contains("magenta"))
- {
- const QJsonArray &values = adjustment["magenta"].toArray();
- colorAdjustment->_rgbMagentaAdjustment.setAdjustment(values[0u].toInt(), values[1u].toInt(), values[2u].toInt());
- }
- if (adjustment.contains("yellow"))
- {
- const QJsonArray &values = adjustment["yellow"].toArray();
- colorAdjustment->_rgbYellowAdjustment.setAdjustment(values[0u].toInt(), values[1u].toInt(), values[2u].toInt());
- }
- if (adjustment.contains("white"))
- {
- const QJsonArray &values = adjustment["white"].toArray();
- colorAdjustment->_rgbWhiteAdjustment.setAdjustment(values[0u].toInt(), values[1u].toInt(), values[2u].toInt());
- }
-
- if (adjustment.contains("gammaRed"))
- {
- colorAdjustment->_rgbTransform.setGamma(adjustment["gammaRed"].toDouble(), colorAdjustment->_rgbTransform.getGammaG(), colorAdjustment->_rgbTransform.getGammaB());
- }
- if (adjustment.contains("gammaGreen"))
- {
- colorAdjustment->_rgbTransform.setGamma(colorAdjustment->_rgbTransform.getGammaR(), adjustment["gammaGreen"].toDouble(), colorAdjustment->_rgbTransform.getGammaB());
- }
- if (adjustment.contains("gammaBlue"))
- {
- colorAdjustment->_rgbTransform.setGamma(colorAdjustment->_rgbTransform.getGammaR(), colorAdjustment->_rgbTransform.getGammaG(), adjustment["gammaBlue"].toDouble());
- }
-
- if (adjustment.contains("backlightThreshold"))
- {
- colorAdjustment->_rgbTransform.setBacklightThreshold(adjustment["backlightThreshold"].toDouble());
- }
- if (adjustment.contains("backlightColored"))
- {
- colorAdjustment->_rgbTransform.setBacklightColored(adjustment["backlightColored"].toBool());
- }
- if (adjustment.contains("brightness"))
- {
- colorAdjustment->_rgbTransform.setBrightness(adjustment["brightness"].toInt());
- }
- if (adjustment.contains("brightnessCompensation"))
- {
- colorAdjustment->_rgbTransform.setBrightnessCompensation(adjustment["brightnessCompensation"].toInt());
- }
-
- if (adjustment.contains("saturationGain"))
- {
- colorAdjustment->_okhsvTransform.setSaturationGain(adjustment["saturationGain"].toDouble());
- }
-
- if (adjustment.contains("brightnessGain"))
- {
- colorAdjustment->_okhsvTransform.setBrightnessGain(adjustment["brightnessGain"].toDouble());
- }
-
- // commit the changes
+ applyColorAdjustments(adjustment, colorAdjustment);
+ applyTransforms(adjustment, colorAdjustment);
_hyperion->adjustmentsUpdated();
-
- sendSuccessReply(command, tan);
+ sendSuccessReply(cmd);
}
-void JsonAPI::handleSourceSelectCommand(const QJsonObject &message, const QString &command, int tan)
+void JsonAPI::applyColorAdjustments(const QJsonObject &adjustment, ColorAdjustment *colorAdjustment)
+{
+ applyColorAdjustment("red", adjustment, colorAdjustment->_rgbRedAdjustment);
+ applyColorAdjustment("green", adjustment, colorAdjustment->_rgbGreenAdjustment);
+ applyColorAdjustment("blue", adjustment, colorAdjustment->_rgbBlueAdjustment);
+ applyColorAdjustment("cyan", adjustment, colorAdjustment->_rgbCyanAdjustment);
+ applyColorAdjustment("magenta", adjustment, colorAdjustment->_rgbMagentaAdjustment);
+ applyColorAdjustment("yellow", adjustment, colorAdjustment->_rgbYellowAdjustment);
+ applyColorAdjustment("white", adjustment, colorAdjustment->_rgbWhiteAdjustment);
+}
+
+void JsonAPI::applyColorAdjustment(const QString &colorName, const QJsonObject &adjustment, RgbChannelAdjustment &rgbAdjustment)
+{
+ if (adjustment.contains(colorName)) {
+ const QJsonArray &values = adjustment[colorName].toArray();
+ if (values.size() >= 3) {
+ rgbAdjustment.setAdjustment(static_cast(values[0U].toInt()),
+ static_cast(values[1U].toInt()),
+ static_cast(values[2U].toInt()));
+ }
+ }
+}
+
+void JsonAPI::applyTransforms(const QJsonObject &adjustment, ColorAdjustment *colorAdjustment)
+{
+ applyGammaTransform("gammaRed", adjustment, colorAdjustment->_rgbTransform, 'r');
+ applyGammaTransform("gammaGreen", adjustment, colorAdjustment->_rgbTransform, 'g');
+ applyGammaTransform("gammaBlue", adjustment, colorAdjustment->_rgbTransform, 'b');
+ applyTransform("backlightThreshold", adjustment, colorAdjustment->_rgbTransform, &RgbTransform::setBacklightThreshold);
+ applyTransform("backlightColored", adjustment, colorAdjustment->_rgbTransform, &RgbTransform::setBacklightColored);
+ applyTransform("brightness", adjustment, colorAdjustment->_rgbTransform, &RgbTransform::setBrightness);
+ applyTransform("brightnessCompensation", adjustment, colorAdjustment->_rgbTransform, &RgbTransform::setBrightnessCompensation);
+ applyTransform("saturationGain", adjustment, colorAdjustment->_okhsvTransform, &OkhsvTransform::setSaturationGain);
+ applyTransform("brightnessGain", adjustment, colorAdjustment->_okhsvTransform, &OkhsvTransform::setBrightnessGain);
+}
+
+void JsonAPI::applyGammaTransform(const QString &transformName, const QJsonObject &adjustment, RgbTransform &rgbTransform, char channel)
+{
+ 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
+void JsonAPI::applyTransform(const QString &transformName, const QJsonObject &adjustment, T &transform, void (T::*setFunction)(bool))
+{
+ if (adjustment.contains(transformName)) {
+ (transform.*setFunction)(adjustment[transformName].toBool());
+ }
+}
+
+template
+void JsonAPI::applyTransform(const QString &transformName, const QJsonObject &adjustment, T &transform, void (T::*setFunction)(double))
+{
+ if (adjustment.contains(transformName)) {
+ (transform.*setFunction)(adjustment[transformName].toDouble());
+ }
+}
+
+template
+void JsonAPI::applyTransform(const QString &transformName, const QJsonObject &adjustment, T &transform, void (T::*setFunction)(uint8_t))
+{
+ if (adjustment.contains(transformName)) {
+ (transform.*setFunction)(static_cast(adjustment[transformName].toInt()));
+ }
+}
+
+void JsonAPI::handleSourceSelectCommand(const QJsonObject &message, const JsonApiCommand& cmd)
{
if (message.contains("auto"))
{
@@ -990,84 +609,63 @@ void JsonAPI::handleSourceSelectCommand(const QJsonObject &message, const QStrin
}
else
{
- sendErrorReply("Priority request is invalid", command, tan);
+ sendErrorReply("Priority request is invalid", cmd);
return;
}
- sendSuccessReply(command, tan);
+ sendSuccessReply(cmd);
}
-void JsonAPI::handleConfigCommand(const QJsonObject &message, const QString &command, int tan)
+void JsonAPI::handleConfigCommand(const QJsonObject& message, const JsonApiCommand& cmd)
{
- QString subcommand = message["subcommand"].toString("");
- QString full_command = command + "-" + subcommand;
+ switch (cmd.subCommand) {
+ case SubCommand::GetSchema:
+ handleSchemaGetCommand(message, cmd);
+ break;
- if (subcommand == "getschema")
- {
- handleSchemaGetCommand(message, full_command, tan);
- }
- else if (subcommand == "getconfig")
- {
- if (_adminAuthorized)
- sendSuccessDataReply(QJsonDocument(_hyperion->getQJsonConfig()), full_command, tan);
- else
- sendErrorReply("No Authorization", command, tan);
- }
- else if (subcommand == "setconfig")
- {
- if (_adminAuthorized)
- handleConfigSetCommand(message, full_command, tan);
- else
- sendErrorReply("No Authorization", command, tan);
- }
- else if (subcommand == "restoreconfig")
- {
- if (_adminAuthorized)
- handleConfigRestoreCommand(message, full_command, tan);
- else
- sendErrorReply("No Authorization", command, tan);
- }
- else if (subcommand == "reload")
- {
- if (_adminAuthorized)
- {
- Debug(_log, "Restarting due to RPC command");
- emit signalEvent(Event::Reload);
+ case SubCommand::GetConfig:
+ sendSuccessDataReply(_hyperion->getQJsonConfig(), cmd);
+ break;
- sendSuccessReply(command + "-" + subcommand, tan);
- }
- else
- {
- sendErrorReply("No Authorization", command, tan);
- }
- }
- else
- {
- sendErrorReply("unknown or missing subcommand", full_command, tan);
+ case SubCommand::SetConfig:
+ handleConfigSetCommand(message, cmd);
+ break;
+
+ case SubCommand::RestoreConfig:
+ handleConfigRestoreCommand(message, cmd);
+ break;
+
+ case SubCommand::Reload:
+ Debug(_log, "Restarting due to RPC command");
+ emit signalEvent(Event::Reload);
+ sendSuccessReply(cmd);
+ break;
+
+ default:
+ break;
}
}
-void JsonAPI::handleConfigSetCommand(const QJsonObject &message, const QString &command, int tan)
+void JsonAPI::handleConfigSetCommand(const QJsonObject &message, const JsonApiCommand& cmd)
{
if (message.contains("config"))
{
QJsonObject config = message["config"].toObject();
if (API::isHyperionEnabled())
{
- if ( API::saveSettings(config) )
- {
- sendSuccessReply(command, tan);
- }
- else
- {
- sendErrorReply("Save settings failed", command, tan);
+ if ( API::saveSettings(config) ) {
+ sendSuccessReply(cmd);
+ } else {
+ sendErrorReply("Save settings failed", cmd);
}
}
else
- sendErrorReply("Saving configuration while Hyperion is disabled isn't possible", command, tan);
+ {
+ sendErrorReply("Saving configuration while Hyperion is disabled isn't possible", cmd);
+ }
}
}
-void JsonAPI::handleConfigRestoreCommand(const QJsonObject &message, const QString &command, int tan)
+void JsonAPI::handleConfigRestoreCommand(const QJsonObject &message, const JsonApiCommand& cmd)
{
if (message.contains("config"))
{
@@ -1076,22 +674,26 @@ void JsonAPI::handleConfigRestoreCommand(const QJsonObject &message, const QStri
{
if ( API::restoreSettings(config) )
{
- sendSuccessReply(command, tan);
+ sendSuccessReply(cmd);
}
else
{
- sendErrorReply("Restore settings failed", command, tan);
+ sendErrorReply("Restore settings failed", cmd);
}
}
else
- sendErrorReply("Restoring configuration while Hyperion is disabled isn't possible", command, tan);
+ {
+ sendErrorReply("Restoring configuration while Hyperion is disabled is not possible", cmd);
+ }
}
}
-void JsonAPI::handleSchemaGetCommand(const QJsonObject& /*message*/, const QString &command, int tan)
+void JsonAPI::handleSchemaGetCommand(const QJsonObject& /*message*/, const JsonApiCommand& cmd)
{
// create result
- QJsonObject schemaJson, alldevices, properties;
+ QJsonObject schemaJson;
+ QJsonObject alldevices;
+ QJsonObject properties;
// make sure the resources are loaded (they may be left out after static linking)
Q_INIT_RESOURCE(resource);
@@ -1139,710 +741,507 @@ void JsonAPI::handleSchemaGetCommand(const QJsonObject& /*message*/, const QStri
schemaJson.insert("properties", properties);
// send the result
- sendSuccessDataReply(QJsonDocument(schemaJson), command, tan);
+ sendSuccessDataReply(schemaJson, cmd);
}
-void JsonAPI::handleComponentStateCommand(const QJsonObject &message, const QString &command, int tan)
+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))
- {
- sendErrorReply(replyMsg, command, tan);
- return;
+ if (API::setComponentState(comp, compState, replyMsg)) {
+ sendSuccessReply(cmd);
+ } else {
+ sendErrorReply(replyMsg, cmd);
}
- sendSuccessReply(command, tan);
}
-void JsonAPI::streamLedColorsUpdate()
+void JsonAPI::handleLedColorsCommand(const QJsonObject& /*message*/, const JsonApiCommand& cmd)
{
- emit streamLedcolorsUpdate(_currentLedValues);
-}
-
-void JsonAPI::handleLedColorsCommand(const QJsonObject &message, const QString &command, int tan)
-{
- // create result
- QString subcommand = message["subcommand"].toString("");
-
- // max 20 Hz (50ms) interval for streaming (default: 10 Hz (100ms))
- qint64 streaming_interval = qMax(message["interval"].toInt(100), 50);
-
- if (subcommand == "ledstream-start")
- {
- _streaming_leds_reply["success"] = true;
- _streaming_leds_reply["command"] = command + "-ledstream-update";
- _streaming_leds_reply["tan"] = tan;
-
- connect(_hyperion, &Hyperion::rawLedColors, this, [=](const std::vector &ledValues) {
-
- if (ledValues != _currentLedValues)
- {
- _currentLedValues = ledValues;
- if (!_ledStreamTimer->isActive() || _ledStreamTimer->interval() != streaming_interval)
- {
- _ledStreamTimer->start(streaming_interval);
- }
- }
- else
- {
- _ledStreamTimer->stop();
- }
- });
-
+ switch (cmd.subCommand) {
+ case SubCommand::LedStreamStart:
+ _jsonCB->subscribe( Subscription::LedColorsUpdate);
+ // TODO: Check if to be moved to CB
// push once
_hyperion->update();
- }
- else if (subcommand == "ledstream-stop")
- {
- disconnect(_hyperion, &Hyperion::rawLedColors, this, 0);
- _ledStreamTimer->stop();
- disconnect(_ledStreamConnection);
- }
- else if (subcommand == "imagestream-start")
- {
- _streaming_image_reply["success"] = true;
- _streaming_image_reply["command"] = command + "-imagestream-update";
- _streaming_image_reply["tan"] = tan;
+ sendSuccessReply(cmd);
+ break;
- connect(_hyperion, &Hyperion::currentImage, this, &JsonAPI::setImage, Qt::UniqueConnection);
- }
- else if (subcommand == "imagestream-stop")
- {
- disconnect(_hyperion, &Hyperion::currentImage, this, 0);
- }
- else
- {
- return;
- }
+ case SubCommand::LedStreamStop:
+ _jsonCB->unsubscribe( Subscription::LedColorsUpdate);
+ sendSuccessReply(cmd);
+ break;
- sendSuccessReply(command + "-" + subcommand, tan);
+ case SubCommand::ImageStreamStart:
+ _jsonCB->subscribe(Subscription::ImageUpdate);
+ sendSuccessReply(cmd);
+ break;
+
+ case SubCommand::ImageStreamStop:
+ _jsonCB->unsubscribe(Subscription::ImageUpdate);
+ sendSuccessReply(cmd);
+ break;
+
+ default:
+ break;
+ }
}
-void JsonAPI::handleLoggingCommand(const QJsonObject &message, const QString &command, int tan)
+void JsonAPI::handleLoggingCommand(const QJsonObject& /*message*/, const JsonApiCommand& cmd)
{
- // create result
- QString subcommand = message["subcommand"].toString("");
+ switch (cmd.subCommand) {
+ case SubCommand::Start:
+ _jsonCB->subscribe("logmsg-update");
+ sendSuccessReply(cmd);
+ break;
- if (API::isAdminAuthorized())
- {
- _streaming_logging_reply["success"] = true;
- _streaming_logging_reply["command"] = command;
- _streaming_logging_reply["tan"] = tan;
-
- if (subcommand == "start")
- {
- if (!_streaming_logging_activated)
- {
- _streaming_logging_reply["command"] = command + "-update";
- connect(LoggerManager::getInstance().data(), &LoggerManager::newLogMessage, this, &JsonAPI::incommingLogMessage);
-
- emit incommingLogMessage (Logger::T_LOG_MESSAGE{}); // needed to trigger log sending
- Debug(_log, "log streaming activated for client %s", _peerAddress.toStdString().c_str());
- }
- }
- else if (subcommand == "stop")
- {
- if (_streaming_logging_activated)
- {
- disconnect(LoggerManager::getInstance().data(), &LoggerManager::newLogMessage, this, &JsonAPI::incommingLogMessage);
- _streaming_logging_activated = false;
- Debug(_log, "log streaming deactivated for client %s", _peerAddress.toStdString().c_str());
- }
- }
- else
- {
- return;
- }
-
- sendSuccessReply(command + "-" + subcommand, tan);
- }
- else
- {
- sendErrorReply("No Authorization", command + "-" + subcommand, tan);
+ case SubCommand::Stop:
+ _jsonCB->unsubscribe("logmsg-update");
+ sendSuccessReply(cmd);
+ break;
+ default:
+ break;
}
}
-void JsonAPI::handleProcessingCommand(const QJsonObject &message, const QString &command, int tan)
+void JsonAPI::handleProcessingCommand(const QJsonObject &message, const JsonApiCommand& cmd)
{
API::setLedMappingType(ImageProcessor::mappingTypeToInt(message["mappingType"].toString("multicolor_mean")));
- sendSuccessReply(command, tan);
+ sendSuccessReply(cmd);
}
-void JsonAPI::handleVideoModeCommand(const QJsonObject &message, const QString &command, int tan)
+void JsonAPI::handleVideoModeCommand(const QJsonObject &message, const JsonApiCommand& cmd)
{
API::setVideoMode(parse3DMode(message["videoMode"].toString("2D")));
- sendSuccessReply(command, tan);
+ sendSuccessReply(cmd);
}
-void JsonAPI::handleAuthorizeCommand(const QJsonObject &message, const QString &command, int tan)
+void JsonAPI::handleAuthorizeCommand(const QJsonObject &message, const JsonApiCommand& cmd)
+{
+ switch (cmd.subCommand) {
+ case SubCommand::TokenRequired:
+ handleTokenRequired(cmd);
+ break;
+ case SubCommand::AdminRequired:
+ handleAdminRequired(cmd);
+ break;
+ case SubCommand::NewPasswordRequired:
+ handleNewPasswordRequired(cmd);
+ break;
+ case SubCommand::Logout:
+ handleLogout(cmd);
+ break;
+ case SubCommand::NewPassword:
+ handleNewPassword(message, cmd);
+ break;
+ case SubCommand::CreateToken:
+ handleCreateToken(message, cmd);
+ break;
+ case SubCommand::RenameToken:
+ handleRenameToken(message, cmd);
+ break;
+ case SubCommand::DeleteToken:
+ handleDeleteToken(message, cmd);
+ break;
+ case SubCommand::RequestToken:
+ handleRequestToken(message, cmd);
+ break;
+ case SubCommand::GetPendingTokenRequests:
+ handleGetPendingTokenRequests(cmd);
+ break;
+ case SubCommand::AnswerRequest:
+ handleAnswerRequest(message, cmd);
+ break;
+ case SubCommand::GetTokenList:
+ handleGetTokenList(cmd);
+ break;
+ case SubCommand::Login:
+ handleLogin(message, cmd);
+ break;
+ default:
+ return;
+ }
+}
+
+void JsonAPI::handleTokenRequired(const JsonApiCommand& cmd)
+{
+ bool isTokenRequired = !islocalConnection() || _authManager->isLocalAuthRequired();
+ QJsonObject response { { "required", isTokenRequired} };
+ sendSuccessDataReply(response, cmd);
+}
+
+void JsonAPI::handleAdminRequired(const JsonApiCommand& cmd)
+{
+ bool isAdminAuthRequired = true;
+ QJsonObject response { { "adminRequired", isAdminAuthRequired} };
+ sendSuccessDataReply(response, cmd);
+}
+
+void JsonAPI::handleNewPasswordRequired(const JsonApiCommand& cmd)
+{
+ QJsonObject response { { "newPasswordRequired", API::hasHyperionDefaultPw() } };
+ sendSuccessDataReply(response, cmd);
+}
+
+void JsonAPI::handleLogout(const JsonApiCommand& cmd)
+{
+ API::logout();
+ sendSuccessReply(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)) {
+ sendSuccessReply(cmd);
+ } else {
+ sendErrorReply("Failed to update user password", cmd);
+ }
+}
+
+void JsonAPI::handleCreateToken(const QJsonObject &message, const JsonApiCommand& cmd)
{
- Debug(_log,"");
- const QString &subc = message["subcommand"].toString().trimmed();
- const QString &id = message["id"].toString().trimmed();
- const QString &password = message["password"].toString().trimmed();
- const QString &newPassword = message["newPassword"].toString().trimmed();
const QString &comment = message["comment"].toString().trimmed();
+ AuthManager::AuthDefinition def;
+ const QString createTokenResult = API::createToken(comment, def);
+ if (createTokenResult.isEmpty()) {
+ QJsonObject newTok;
+ newTok["comment"] = def.comment;
+ newTok["id"] = def.id;
+ newTok["token"] = def.token;
- // catch test if auth is required
- if (subc == "tokenRequired")
- {
- QJsonObject req;
- req["required"] = !API::isAuthorized();
-
- sendSuccessDataReply(QJsonDocument(req), command + "-" + subc, tan);
- return;
+ sendSuccessDataReply(newTok, cmd);
+ } else {
+ sendErrorReply("Token creation failed", {createTokenResult}, cmd);
}
+}
- // catch test if admin auth is required
- if (subc == "adminRequired")
- {
- Debug(_log,"adminRequired: [%d]", !API::isAdminAuthorized());
- QJsonObject req;
- req["adminRequired"] = !API::isAdminAuthorized();
- sendSuccessDataReply(QJsonDocument(req), command + "-" + subc, tan);
- return;
+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()) {
+ sendSuccessReply(cmd);
+ } else {
+ sendErrorReply("Token rename failed", {renameTokenResult}, cmd);
}
+}
- // default hyperion password is a security risk, replace it asap
- if (subc == "newPasswordRequired")
- {
- QJsonObject req;
- req["newPasswordRequired"] = API::hasHyperionDefaultPw();
- sendSuccessDataReply(QJsonDocument(req), command + "-" + subc, tan);
- return;
+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()) {
+ sendSuccessReply(cmd);
+ } else {
+ sendErrorReply("Token deletion failed", {deleteTokenResult}, cmd);
}
+}
- // catch logout
- if (!_noListener && subc == "logout")
- {
- // disconnect all kind of data callbacks
- JsonAPI::stopDataConnections(); // TODO move to API
- API::logout();
- sendSuccessReply(command + "-" + subc, tan);
- return;
- }
-
- // change password
- if (subc == "newPassword")
- {
- // use password, newPassword
- if (API::isAdminAuthorized())
- {
- if (API::updateHyperionPassword(password, newPassword))
- {
- sendSuccessReply(command + "-" + subc, tan);
- return;
- }
- sendErrorReply("Failed to update user password", command + "-" + subc, tan);
- return;
- }
- sendErrorReply("No Authorization", command + "-" + subc, tan);
- return;
- }
-
- // token created from ui
- if (!_noListener && subc == "createToken")
- {
- // use comment
- // for user authorized sessions
- AuthManager::AuthDefinition def;
- const QString createTokenResult = API::createToken(comment, def);
- if (createTokenResult.isEmpty())
- {
- QJsonObject newTok;
- newTok["comment"] = def.comment;
- newTok["id"] = def.id;
- newTok["token"] = def.token;
-
- sendSuccessDataReply(QJsonDocument(newTok), command + "-" + subc, tan);
- return;
- }
- sendErrorReply(createTokenResult, command + "-" + subc, tan);
- return;
- }
-
- // rename Token
- if (subc == "renameToken")
- {
- // use id/comment
- const QString renameTokenResult = API::renameToken(id, comment);
- if (renameTokenResult.isEmpty())
- {
- sendSuccessReply(command + "-" + subc, tan);
- return;
- }
- sendErrorReply(renameTokenResult, command + "-" + subc, tan);
- return;
- }
-
- // delete token
- if (subc == "deleteToken")
- {
- // use id
- const QString deleteTokenResult = API::deleteToken(id);
- if (deleteTokenResult.isEmpty())
- {
- sendSuccessReply(command + "-" + subc, tan);
- return;
- }
- sendErrorReply(deleteTokenResult, command + "-" + subc, tan);
- return;
- }
-
- // catch token request
- if (!_noListener && subc == "requestToken")
- {
- // use id/comment
- const bool &acc = message["accept"].toBool(true);
- if (acc)
- API::setNewTokenRequest(comment, id, tan);
- else
- API::cancelNewTokenRequest(comment, id);
+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) {
+ API::setNewTokenRequest(comment, identifier, cmd.tan);
+ } else {
+ API::cancelNewTokenRequest(comment, identifier);
// client should wait for answer
- return;
}
+}
- // get pending token requests
- if (!_noListener && subc == "getPendingTokenRequests")
- {
- QVector vec;
- if (API::getPendingTokenRequests(vec))
+void JsonAPI::handleGetPendingTokenRequests(const JsonApiCommand& cmd)
+{
+ QVector vec;
+ if (API::getPendingTokenRequests(vec)) {
+ QJsonArray pendingTokeRequests;
+ for (const auto &entry : std::as_const(vec))
{
- QJsonArray arr;
- for (const auto &entry : std::as_const(vec))
- {
- QJsonObject obj;
- obj["comment"] = entry.comment;
- obj["id"] = entry.id;
- obj["timeout"] = int(entry.timeoutTime);
- arr.append(obj);
- }
- sendSuccessDataReply(QJsonDocument(arr), command + "-" + subc, tan);
+ QJsonObject obj;
+ obj["comment"] = entry.comment;
+ obj["id"] = entry.id;
+ obj["timeout"] = int(entry.timeoutTime);
+ obj["tan"] = entry.tan;
+ pendingTokeRequests.append(obj);
}
- else
+ sendSuccessDataReply(pendingTokeRequests, 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)) {
+ sendSuccessReply(cmd);
+ } else {
+ sendErrorReply("Unable to handle token acceptance or denial", cmd);
+ }
+}
+
+void JsonAPI::handleGetTokenList(const JsonApiCommand& cmd)
+{
+ QVector defVect;
+ if (API::getTokenList(defVect))
+ {
+ QJsonArray tokenList;
+ for (const auto &entry : std::as_const(defVect))
{
- sendErrorReply("No Authorization", command + "-" + subc, tan);
+ QJsonObject token;
+ token["comment"] = entry.comment;
+ token["id"] = entry.id;
+ token["last_use"] = entry.lastUse;
+
+ tokenList.append(token);
}
-
- return;
+ sendSuccessDataReply(tokenList, cmd);
}
+}
- // accept/deny token request
- if (!_noListener && subc == "answerRequest")
+void JsonAPI::handleLogin(const QJsonObject &message, const JsonApiCommand& cmd)
+{
+ const QString &token = message["token"].toString().trimmed();
+ if (!token.isEmpty())
{
- // use id
- const bool &accept = message["accept"].toBool(false);
- if (!API::handlePendingTokenRequest(id, accept))
- sendErrorReply("No Authorization", command + "-" + subc, tan);
- return;
- }
-
- // get token list
- if (subc == "getTokenList")
- {
- QVector defVect;
- if (API::getTokenList(defVect))
+ // userToken is longer than app token
+ if (token.size() > APP_TOKEN_LENGTH)
{
- QJsonArray tArr;
- for (const auto &entry : qAsConst(defVect))
- {
- QJsonObject subO;
- subO["comment"] = entry.comment;
- subO["id"] = entry.id;
- subO["last_use"] = entry.lastUse;
-
- tArr.append(subO);
+ if (API::isUserTokenAuthorized(token)) {
+ sendSuccessReply(cmd);
+ } else {
+ sendNoAuthorization(cmd);
}
- sendSuccessDataReply(QJsonDocument(tArr), command + "-" + subc, tan);
- return;
- }
- sendErrorReply("No Authorization", command + "-" + subc, tan);
- return;
- }
- // login
- if (!_noListener && subc == "login")
- {
- const QString &token = message["token"].toString().trimmed();
-
- qDebug() << "token: len: " << token.count() << " [" << token;
- qDebug() << "password: len: " << password.count() << " [" << password;
-
- // catch token
- if (!token.isEmpty())
- {
- // userToken is longer
- if (token.size() > 36)
- {
- Debug(_log,"isUserTokenAuthorized [%d]", API::isUserTokenAuthorized(token));
- if (API::isUserTokenAuthorized(token))
- sendSuccessReply(command + "-" + subc, tan);
- else
- sendErrorReply("No Authorization", command + "-" + subc, tan);
-
- return;
- }
- // usual app token is 36
- if (token.size() == 36)
- {
- Debug(_log,"isTokenAuthorized [%d]", API::isTokenAuthorized(token));
- if (API::isTokenAuthorized(token))
- {
- sendSuccessReply(command + "-" + subc, tan);
- }
- else
- sendErrorReply("No Authorization", command + "-" + subc, tan);
- }
- std::cout << "handleAuthorizeCommand [login] - _authorized [" << _authorized << "] _adminAuthorized [" << _adminAuthorized << "]" << std::endl;
return;
}
- // password
- // use password
- if (password.size() >= 8)
+ if (token.size() == APP_TOKEN_LENGTH)
{
- Debug(_log,"password: isUserAuthorized [%d] ", API::isUserAuthorized(token));
- QString userTokenRep;
- if (API::isUserAuthorized(password) && API::getUserToken(userTokenRep))
- {
- // Return the current valid Hyperion user token
- QJsonObject obj;
- obj["token"] = userTokenRep;
- sendSuccessDataReply(QJsonDocument(obj), command + "-" + subc, tan);
+ if (API::isTokenAuthorized(token)) {
+ sendSuccessReply(cmd);
+ } else {
+ sendNoAuthorization(cmd);
}
- else
- {
- sendErrorReply("No Authorization", command + "-" + subc, tan);
- }
- }
- else
- {
- sendErrorReply("Password too short", command + "-" + subc, tan);
}
return;
}
- if(_noListener)
+ // password
+ const QString &password = message["password"].toString().trimmed();
+ if (password.size() >= MIN_PASSWORD_LENGTH)
{
- sendErrorReply("Command not supported via single API calls using HTTP/S", command + "-" + subc, tan);
+ QString userTokenRep;
+ if (API::isUserAuthorized(password) && API::getUserToken(userTokenRep))
+ {
+ // Return the current valid Hyperion user token
+ QJsonObject response { { "token", userTokenRep } };
+ sendSuccessDataReply(response, cmd);
+ }
+ else
+ {
+ sendNoAuthorization(cmd);
+ }
}
else
{
- handleNotImplemented(command, tan);
+ sendErrorReply(QString("Password is too short. Minimum length: %1 characters").arg(MIN_PASSWORD_LENGTH), cmd);
}
}
-void JsonAPI::handleInstanceCommand(const QJsonObject &message, const QString &command, int tan)
+void JsonAPI::issueNewPendingTokenRequest(const QString &identifier, const QString &comment)
{
- const QString &subc = message["subcommand"].toString();
+ QJsonObject tokenRequest;
+ tokenRequest["comment"] = comment;
+ tokenRequest["id"] = identifier;
+ tokenRequest["timeout"] = static_cast(NEW_TOKEN_REQUEST_TIMEOUT.count());
+
+ sendNewRequest(tokenRequest, "authorize-tokenRequest");
+}
+
+void JsonAPI::handleTokenResponse(bool success, const QString &token, const QString &comment, const QString &identifier, const int &tan)
+{
+ const QString cmd = "authorize-requestToken";
+ QJsonObject result;
+ result["token"] = token;
+ result["comment"] = comment;
+ result["id"] = identifier;
+
+ if (success) {
+ sendSuccessDataReply(result, cmd, tan);
+ } else {
+ sendErrorReply("Token request timeout or denied", {}, cmd, tan);
+ }
+}
+
+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();
- if (subc == "switchTo")
- {
+ switch (cmd.subCommand) {
+ case SubCommand::SwitchTo:
if (handleInstanceSwitch(inst))
{
- QJsonObject obj;
- obj["instance"] = inst;
- sendSuccessDataReply(QJsonDocument(obj), command + "-" + subc, tan);
+ QJsonObject response { { "instance", inst } };
+ sendSuccessDataReply(response, cmd);
}
else
- sendErrorReply("Selected Hyperion instance isn't running", command + "-" + subc, tan);
- return;
- }
-
- if (subc == "startInstance")
- {
- //Only send update once
- weakConnect(this, &API::onStartInstanceResponse, [this, command, subc] (int tan)
{
- sendSuccessReply(command + "-" + subc, tan);
+ sendErrorReply("Selected Hyperion instance is not running", cmd);
+ }
+ break;
+
+ case SubCommand::StartInstance:
+ //Only send update once
+ weakConnect(this, &API::onStartInstanceResponse, [this, cmd] ()
+ {
+ sendSuccessReply(cmd);
});
- if (!API::startInstance(inst, tan))
- sendErrorReply("Can't start Hyperion instance index " + QString::number(inst), command + "-" + subc, tan);
-
- return;
- }
-
- if (subc == "stopInstance")
- {
+ if (!API::startInstance(inst, cmd.tan))
+ {
+ sendErrorReply("Cannot start Hyperion instance index " + QString::number(inst), cmd);
+ }
+ break;
+ case SubCommand::StopInstance:
// silent fail
API::stopInstance(inst);
- sendSuccessReply(command + "-" + subc, tan);
- return;
- }
+ sendSuccessReply(cmd);
+ break;
- if (subc == "deleteInstance")
- {
- QString replyMsg;
+ case SubCommand::DeleteInstance:
+ handleConfigRestoreCommand(message, cmd);
if (API::deleteInstance(inst, replyMsg))
- sendSuccessReply(command + "-" + subc, tan);
+ {
+ sendSuccessReply(cmd);
+ }
else
- sendErrorReply(replyMsg, command + "-" + subc, tan);
- return;
- }
+ {
+ sendErrorReply(replyMsg, cmd);
+ }
+ break;
- // create and save name requires name
- if (name.isEmpty())
- sendErrorReply("Name string required for this command", command + "-" + subc, tan);
+ case SubCommand::CreateInstance:
+ case SubCommand::SaveName:
+ // create and save name requires name
+ if (name.isEmpty()) {
+ sendErrorReply("Name string required for this command", cmd);
+ return;
+ }
- if (subc == "createInstance")
- {
- QString replyMsg = API::createInstance(name);
- if (replyMsg.isEmpty())
- sendSuccessReply(command + "-" + subc, tan);
- else
- sendErrorReply(replyMsg, command + "-" + subc, tan);
- return;
- }
+ if (cmd.subCommand == SubCommand::CreateInstance) {
+ replyMsg = API::createInstance(name);
+ } else {
+ replyMsg = setInstanceName(inst, name);
+ }
- if (subc == "saveName")
- {
- QString replyMsg = API::setInstanceName(inst, name);
- if (replyMsg.isEmpty())
- sendSuccessReply(command + "-" + subc, tan);
- else
- sendErrorReply(replyMsg, command + "-" + subc, tan);
- return;
+ if (replyMsg.isEmpty()) {
+ sendSuccessReply(cmd);
+ } else {
+ sendErrorReply(replyMsg, cmd);
+ }
+ break;
+ default:
+ break;
}
}
-void JsonAPI::handleLedDeviceCommand(const QJsonObject &message, const QString &command, int tan)
+void JsonAPI::handleLedDeviceCommand(const QJsonObject &message, const JsonApiCommand& cmd)
{
- Debug(_log, "message: [%s]", QString(QJsonDocument(message).toJson(QJsonDocument::Compact)).toUtf8().constData() );
-
- const QString &subc = message["subcommand"].toString().trimmed();
const QString &devType = message["ledDeviceType"].toString().trimmed();
+ const LedDeviceRegistry& ledDevices = LedDeviceWrapper::getDeviceMap();
- QString full_command = command + "-" + subc;
-
- // TODO: Validate that device type is a valid one
-
- {
- QJsonObject config;
- config.insert("type", devType);
- LedDevice* ledDevice = nullptr;
-
- if (subc == "discover")
- {
- ledDevice = LedDeviceFactory::construct(config);
- const QJsonObject ¶ms = message["params"].toObject();
- const QJsonObject devicesDiscovered = ledDevice->discover(params);
-
- Debug(_log, "response: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData() );
-
- sendSuccessDataReply(QJsonDocument(devicesDiscovered), full_command, tan);
- }
- else if (subc == "getProperties")
- {
- ledDevice = LedDeviceFactory::construct(config);
- const QJsonObject ¶ms = message["params"].toObject();
- const QJsonObject deviceProperties = ledDevice->getProperties(params);
-
- Debug(_log, "response: [%s]", QString(QJsonDocument(deviceProperties).toJson(QJsonDocument::Compact)).toUtf8().constData() );
-
- sendSuccessDataReply(QJsonDocument(deviceProperties), full_command, tan);
- }
- else if (subc == "identify")
- {
- ledDevice = LedDeviceFactory::construct(config);
- const QJsonObject ¶ms = message["params"].toObject();
- ledDevice->identify(params);
-
- sendSuccessReply(full_command, tan);
- }
- else if (subc == "addAuthorization")
- {
- ledDevice = LedDeviceFactory::construct(config);
- const QJsonObject& params = message["params"].toObject();
- const QJsonObject response = ledDevice->addAuthorization(params);
-
- Debug(_log, "response: [%s]", QString(QJsonDocument(response).toJson(QJsonDocument::Compact)).toUtf8().constData());
-
- sendSuccessDataReply(QJsonDocument(response), full_command, tan);
- }
- else
- {
- sendErrorReply("Unknown or missing subcommand", full_command, tan);
- }
-
- delete ledDevice;
+ 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);
+
+ switch (cmd.subCommand) {
+ case SubCommand::Discover:
+ handleLedDeviceDiscover(*ledDevice, message, cmd);
+ break;
+ case SubCommand::GetProperties:
+ handleLedDeviceGetProperties(*ledDevice, message, cmd);
+ break;
+ case SubCommand::Identify:
+ handleLedDeviceIdentify(*ledDevice, message, cmd);
+ break;
+ case SubCommand::AddAuthorization:
+ handleLedDeviceAddAuthorization(*ledDevice, message, cmd);
+ break;
+ default:
+ break;
+ }
+
+ delete ledDevice;
}
-void JsonAPI::handleInputSourceCommand(const QJsonObject& message, const QString& command, int tan)
+void JsonAPI::handleLedDeviceDiscover(LedDevice& ledDevice, const QJsonObject& message, const JsonApiCommand& cmd)
{
- DebugIf(verbose, _log, "message: [%s]", QString(QJsonDocument(message).toJson(QJsonDocument::Compact)).toUtf8().constData());
+ const QJsonObject ¶ms = message["params"].toObject();
+ const QJsonObject devicesDiscovered = ledDevice.discover(params);
+ Debug(_log, "response: [%s]", QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact).constData() );
+ sendSuccessDataReply(devicesDiscovered, cmd);
+}
- const QString& subc = message["subcommand"].toString().trimmed();
+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() );
+ sendSuccessDataReply(deviceProperties, 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)
+{
+ 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"};
- QString full_command = command + "-" + subc;
+ if (!sourceTypes.contains(sourceType)) {
+ sendErrorReply(QString("Unknown input source type: %1").arg(sourceType), cmd);
+ return;
+ }
- // TODO: Validate that source type is a valid one
- {
- if (subc == "discover")
- {
- QJsonObject inputSourcesDiscovered;
- inputSourcesDiscovered.insert("sourceType", sourceType);
- QJsonArray videoInputs;
- QJsonArray audioInputs;
+ if (cmd.subCommand == SubCommand::Discover) {
-#if defined(ENABLE_V4L2) || defined(ENABLE_MF)
+ const QJsonObject& params = message["params"].toObject();
+ QJsonObject inputSourcesDiscovered = JsonInfo().discoverSources(sourceType, params);
- if (sourceType == "video" )
- {
-#if defined(ENABLE_MF)
- MFGrabber* grabber = new MFGrabber();
-#elif defined(ENABLE_V4L2)
- V4L2Grabber* grabber = new V4L2Grabber();
-#endif
- QJsonObject params;
- videoInputs = grabber->discover(params);
- delete grabber;
- }
- else
-#endif
+ DebugIf(verbose, _log, "response: [%s]", QJsonDocument(inputSourcesDiscovered).toJson(QJsonDocument::Compact).constData());
-#if defined(ENABLE_AUDIO)
- if (sourceType == "audio")
- {
- AudioGrabber* grabber;
-#ifdef WIN32
- grabber = new AudioGrabberWindows();
-#endif
-
-#ifdef __linux__
- grabber = new AudioGrabberLinux();
-#endif
- QJsonObject params;
- audioInputs = grabber->discover(params);
- delete grabber;
- }
- else
-#endif
- {
- DebugIf(verbose, _log, "sourceType: [%s]", QSTRING_CSTR(sourceType));
-
- if (sourceType == "screen")
- {
- QJsonObject params;
-
- QJsonObject device;
- #ifdef ENABLE_QT
- QScopedPointer qtgrabber(new QtGrabber());
- device = qtgrabber->discover(params);
- if (!device.isEmpty() )
- {
- videoInputs.append(device);
- }
- #endif
-
- #ifdef ENABLE_DX
- QScopedPointer dxgrabber (new DirectXGrabber());
- device = dxgrabber->discover(params);
- if (!device.isEmpty() )
- {
- videoInputs.append(device);
- }
- #endif
-
- #ifdef ENABLE_X11
- QScopedPointer x11Grabber(new X11Grabber());
- device = x11Grabber->discover(params);
- if (!device.isEmpty() )
- {
- videoInputs.append(device);
- }
- #endif
-
- #ifdef ENABLE_XCB
- QScopedPointer xcbGrabber (new XcbGrabber());
- device = xcbGrabber->discover(params);
- if (!device.isEmpty() )
- {
- videoInputs.append(device);
- }
- #endif
-
- //Ignore FB for Amlogic, as it is embedded in the Amlogic grabber itself
- #if defined(ENABLE_FB) && !defined(ENABLE_AMLOGIC)
-
- QScopedPointer fbGrabber(new FramebufferFrameGrabber());
- device = fbGrabber->discover(params);
- if (!device.isEmpty() )
- {
- videoInputs.append(device);
- }
- #endif
-
- #if defined(ENABLE_DISPMANX)
- QScopedPointer dispmanx(new DispmanxFrameGrabber());
- if (dispmanx->isAvailable())
- {
- device = dispmanx->discover(params);
- if (!device.isEmpty() )
- {
- videoInputs.append(device);
- }
- }
- #endif
-
- #if defined(ENABLE_AMLOGIC)
- QScopedPointer amlGrabber(new AmlogicGrabber());
- device = amlGrabber->discover(params);
- if (!device.isEmpty() )
- {
- videoInputs.append(device);
- }
- #endif
-
- #if defined(ENABLE_OSX)
- QScopedPointer osxGrabber(new OsxFrameGrabber());
- device = osxGrabber->discover(params);
- if (!device.isEmpty() )
- {
- videoInputs.append(device);
- }
- #endif
- }
-
- }
- inputSourcesDiscovered["video_sources"] = videoInputs;
- inputSourcesDiscovered["audio_sources"] = audioInputs;
-
- DebugIf(verbose, _log, "response: [%s]", QString(QJsonDocument(inputSourcesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
-
- sendSuccessDataReply(QJsonDocument(inputSourcesDiscovered), full_command, tan);
- }
- else
- {
- sendErrorReply("Unknown or missing subcommand", full_command, tan);
- }
+ sendSuccessDataReply(inputSourcesDiscovered, cmd);
}
}
-void JsonAPI::handleServiceCommand(const QJsonObject &message, const QString &command, int tan)
+void JsonAPI::handleServiceCommand(const QJsonObject &message, const JsonApiCommand& cmd)
{
- DebugIf(verbose, _log, "message: [%s]", QString(QJsonDocument(message).toJson(QJsonDocument::Compact)).toUtf8().constData());
-
- const QString &subc = message["subcommand"].toString().trimmed();
- const QString type = message["serviceType"].toString().trimmed();
-
- QString full_command = command + "-" + subc;
-
- if (subc == "discover")
+ if (cmd.subCommand == SubCommand::Discover)
{
QByteArray serviceType;
-
- QJsonObject servicesDiscovered;
- QJsonObject servicesOfType;
- QJsonArray serviceList;
-
+ const QString type = message["serviceType"].toString().trimmed();
#ifdef ENABLE_MDNS
QString discoveryMethod("mDNS");
serviceType = MdnsServiceRegister::getServiceType(type);
@@ -1851,81 +1250,60 @@ void JsonAPI::handleServiceCommand(const QJsonObject &message, const QString &co
#endif
if (!serviceType.isEmpty())
{
+ QJsonArray serviceList;
#ifdef ENABLE_MDNS
QMetaObject::invokeMethod(MdnsBrowser::getInstance().data(), "browseForServiceType",
- Qt::QueuedConnection, Q_ARG(QByteArray, serviceType));
+ Qt::QueuedConnection, Q_ARG(QByteArray, serviceType));
serviceList = MdnsBrowser::getInstance().data()->getServicesDiscoveredJson(serviceType, MdnsServiceRegister::getServiceNameFilter(type), DEFAULT_DISCOVER_TIMEOUT);
#endif
+ QJsonObject servicesDiscovered;
+ QJsonObject servicesOfType;
+
servicesOfType.insert(type, serviceList);
servicesDiscovered.insert("discoveryMethod", discoveryMethod);
servicesDiscovered.insert("services", servicesOfType);
- sendSuccessDataReply(QJsonDocument(servicesDiscovered), full_command, tan);
+ sendSuccessDataReply(servicesDiscovered, cmd);
}
else
{
- sendErrorReply(QString("Discovery of service type [%1] via %2 not supported").arg(type, discoveryMethod), full_command, tan);
+ sendErrorReply(QString("Discovery of service type [%1] via %2 not supported").arg(type, discoveryMethod), cmd);
}
}
- else
- {
- sendErrorReply("Unknown or missing subcommand", full_command, tan);
- }
}
-void JsonAPI::handleSystemCommand(const QJsonObject &message, const QString &command, int tan)
+void JsonAPI::handleSystemCommand(const QJsonObject& /*message*/, const JsonApiCommand& cmd)
{
- DebugIf(verbose, _log, "message: [%s]", QString(QJsonDocument(message).toJson(QJsonDocument::Compact)).toUtf8().constData());
-
- const QString &subc = message["subcommand"].toString().trimmed();
-
- if (subc == "suspend")
- {
+ switch (cmd.subCommand) {
+ case SubCommand::Suspend:
emit signalEvent(Event::Suspend);
- sendSuccessReply(command + "-" + subc, tan);
- }
- else if (subc == "resume")
- {
+ break;
+ case SubCommand::Resume:
emit signalEvent(Event::Resume);
- sendSuccessReply(command + "-" + subc, tan);
- }
- else if (subc == "restart")
- {
+ break;
+ case SubCommand::Restart:
emit signalEvent(Event::Restart);
- sendSuccessReply(command + "-" + subc, tan);
- }
- else if (subc == "toggleSuspend")
- {
+ break;
+ case SubCommand::ToggleSuspend:
emit signalEvent(Event::ToggleSuspend);
- sendSuccessReply(command + "-" + subc, tan);
- }
- else if (subc == "idle")
- {
+ break;
+ case SubCommand::Idle:
emit signalEvent(Event::Idle);
- sendSuccessReply(command + "-" + subc, tan);
- }
- else if (subc == "resumeIdle")
- {
- emit signalEvent(Event::ResumeIdle);
- sendSuccessReply(command + "-" + subc, tan);
- }
- else if (subc == "toggleIdle")
- {
+ break;
+ case SubCommand::ToggleIdle:
emit signalEvent(Event::ToggleIdle);
- sendSuccessReply(command + "-" + subc, tan);
- }
- else
- {
- QString full_command = command + "-" + subc;
- sendErrorReply("Unknown or missing subcommand", full_command, tan);
+ break;
+ default:
+ return;
}
+ sendSuccessReply(cmd);
}
-void JsonAPI::handleNotImplemented(const QString &command, int tan)
+void JsonAPI::sendSuccessReply(const JsonApiCommand& cmd)
{
- sendErrorReply("Command not implemented", command, tan);
+ sendSuccessReply(cmd.toString(), cmd.tan);
}
void JsonAPI::sendSuccessReply(const QString &command, int tan)
@@ -1941,123 +1319,99 @@ void JsonAPI::sendSuccessReply(const QString &command, int tan)
emit callbackMessage(reply);
}
-void JsonAPI::sendSuccessDataReply(const QJsonDocument &doc, const QString &command, int tan)
+void JsonAPI::sendSuccessDataReply(const QJsonValue &infoData, const JsonApiCommand& cmd)
+{
+ sendSuccessDataReplyWithError(infoData, cmd.toString(), cmd.tan, {});
+}
+
+void JsonAPI::sendSuccessDataReply(const QJsonValue &infoData, const QString &command, int tan)
+{
+ sendSuccessDataReplyWithError(infoData, command, tan, {});
+}
+
+void JsonAPI::sendSuccessDataReplyWithError(const QJsonValue &infoData, const JsonApiCommand& cmd, const QStringList& errorDetails)
+{
+ sendSuccessDataReplyWithError(infoData, cmd.toString(), cmd.tan, errorDetails);
+}
+
+void JsonAPI::sendSuccessDataReplyWithError(const QJsonValue &infoData, const QString &command, int tan, const QStringList& errorDetails)
{
QJsonObject reply;
reply["instance"] = _hyperion->getInstanceIndex();
reply["success"] = true;
+
reply["command"] = command;
reply["tan"] = tan;
- if (doc.isArray())
- reply["info"] = doc.array();
- else
- reply["info"] = doc.object();
+ reply["info"] = infoData;
+
+ if (!errorDetails.isEmpty())
+ {
+ QJsonArray errorsArray;
+ for (const QString& errorString : errorDetails) {
+ QJsonObject errorObject;
+ errorObject["description"] = errorString;
+ errorsArray.append(errorObject);
+ }
+ reply["errorData"] = errorsArray;
+ }
emit callbackMessage(reply);
}
-void JsonAPI::sendErrorReply(const QString &error, const QString &command, int tan)
+void JsonAPI::sendNewRequest(const QJsonValue &infoData, const JsonApiCommand& cmd)
+{
+ sendSuccessDataReplyWithError(infoData, cmd.toString());
+}
+
+void JsonAPI::sendNewRequest(const QJsonValue &infoData, const QString &command)
+{
+ QJsonObject request;
+ request["command"] = command;
+ request["info"] = infoData;
+
+ emit callbackMessage(request);
+}
+
+void JsonAPI::sendErrorReply(const QString &error, const JsonApiCommand& cmd)
+{
+ sendErrorReply(error, {}, cmd.toString(), cmd.tan);
+}
+
+void JsonAPI::sendErrorReply(const QString &error, const QStringList& errorDetails, const JsonApiCommand& cmd)
+{
+ sendErrorReply(error, errorDetails, cmd.toString(), cmd.tan);
+}
+
+void JsonAPI::sendErrorReply(const QString &error, const QStringList& errorDetails, const QString &command, int tan)
{
// create reply
QJsonObject reply;
reply["instance"] = _hyperion->getInstanceIndex();
reply["success"] = false;
- reply["error"] = error;
+
reply["command"] = command;
reply["tan"] = tan;
- // send reply
+ reply["error"] = error;
+ if (!errorDetails.isEmpty())
+ {
+ QJsonArray errorsArray;
+ for (const QString& errorString : errorDetails) {
+ QJsonObject errorObject;
+ errorObject["description"] = errorString;
+ errorsArray.append(errorObject);
+ }
+ reply["errorData"] = errorsArray;
+ }
+
emit callbackMessage(reply);
}
-void JsonAPI::streamLedcolorsUpdate(const std::vector &ledColors)
+void JsonAPI::sendNoAuthorization(const JsonApiCommand& cmd)
{
- QJsonObject result;
- QJsonArray leds;
-
- for (const auto &color : ledColors)
- {
- leds << QJsonValue(color.red) << QJsonValue(color.green) << QJsonValue(color.blue);
- }
-
- result["leds"] = leds;
- _streaming_leds_reply["result"] = result;
-
- // send the result
- emit callbackMessage(_streaming_leds_reply);
+ sendErrorReply(NO_AUTHORIZATION, cmd);
}
-void JsonAPI::setImage(const Image &image)
-{
- QImage jpgImage((const uint8_t *)image.memptr(), image.width(), image.height(), 3 * image.width(), QImage::Format_RGB888);
- QByteArray ba;
- QBuffer buffer(&ba);
- buffer.open(QIODevice::WriteOnly);
- jpgImage.save(&buffer, "jpg");
-
- QJsonObject result;
- result["image"] = "data:image/jpg;base64," + QString(ba.toBase64());
- _streaming_image_reply["result"] = result;
- emit callbackMessage(_streaming_image_reply);
-}
-
-void JsonAPI::incommingLogMessage(const Logger::T_LOG_MESSAGE &msg)
-{
- QJsonObject result, message;
- QJsonArray messageArray;
-
- if (!_streaming_logging_activated)
- {
- _streaming_logging_activated = true;
- QMetaObject::invokeMethod(LoggerManager::getInstance().data(), "getLogMessageBuffer",
- Qt::DirectConnection,
- Q_RETURN_ARG(QJsonArray, messageArray),
- Q_ARG(Logger::LogLevel, _log->getLogLevel()));
- }
- else
- {
- message["loggerName"] = msg.loggerName;
- message["loggerSubName"] = msg.loggerSubName;
- message["function"] = msg.function;
- message["line"] = QString::number(msg.line);
- message["fileName"] = msg.fileName;
- message["message"] = msg.message;
- message["levelString"] = msg.levelString;
- message["utime"] = QString::number(msg.utime);
-
- messageArray.append(message);
- }
-
- result.insert("messages", messageArray);
- _streaming_logging_reply["result"] = result;
-
- // send the result
- emit callbackMessage(_streaming_logging_reply);
-}
-
-void JsonAPI::newPendingTokenRequest(const QString &id, const QString &comment)
-{
- QJsonObject obj;
- obj["comment"] = comment;
- obj["id"] = id;
- obj["timeout"] = 180000;
-
- sendSuccessDataReply(QJsonDocument(obj), "authorize-tokenRequest", 1);
-}
-
-void JsonAPI::handleTokenResponse(bool success, const QString &token, const QString &comment, const QString &id, const int &tan)
-{
- const QString cmd = "authorize-requestToken";
- QJsonObject result;
- result["token"] = token;
- result["comment"] = comment;
- result["id"] = id;
-
- if (success)
- sendSuccessDataReply(QJsonDocument(result), cmd, tan);
- else
- sendErrorReply("Token request timeout or denied", cmd, tan);
-}
void JsonAPI::handleInstanceStateChange(InstanceState state, quint8 instance, const QString& /*name */)
{
@@ -2068,24 +1422,45 @@ 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:
- default:
- break;
+ break;
}
}
void JsonAPI::stopDataConnections()
{
- LoggerManager::getInstance()->disconnect();
- _streaming_logging_activated = false;
_jsonCB->resetSubscriptions();
- // led stream colors
- disconnect(_hyperion, &Hyperion::rawLedColors, this, 0);
- _ledStreamTimer->stop();
- disconnect(_ledStreamConnection);
+ LoggerManager::getInstance()->disconnect();
+}
+
+QString JsonAPI::findCommand (const QString& jsonString)
+{
+ 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()) {
+ commandValue = match.captured(1);
+ }
+ return commandValue;
+}
+
+int JsonAPI::findTan (const QString& jsonString)
+{
+ int tanValue {0};
+ static QRegularExpression regex("\"tan\"\\s*:\\s*(\\d+)");
+ QRegularExpressionMatch match = regex.match(jsonString);
+
+ if (match.hasMatch()) {
+ QString valueStr = match.captured(1);
+ tanValue = valueStr.toInt();
+ }
+ return tanValue;
}
diff --git a/libsrc/api/JsonCB.cpp b/libsrc/api/JsonCB.cpp
deleted file mode 100644
index e3c4b32a..00000000
--- a/libsrc/api/JsonCB.cpp
+++ /dev/null
@@ -1,416 +0,0 @@
-// proj incl
-#include
-
-// hyperion
-#include
-
-// HyperionIManager
-#include
-// components
-
-#include
-// priorityMuxer
-
-#include
-
-// utils
-#include
-
-// qt
-#include
-#include
-
-// Image to led map helper
-#include
-
-using namespace hyperion;
-
-JsonCB::JsonCB(QObject* parent)
- : QObject(parent)
- , _hyperion(nullptr)
- , _componentRegister(nullptr)
- , _prioMuxer(nullptr)
-{
- _availableCommands << "components-update" << "priorities-update" << "imageToLedMapping-update"
- << "adjustment-update" << "videomode-update" << "settings-update" << "leds-update" << "instance-update" << "token-update";
-
- #if defined(ENABLE_EFFECTENGINE)
- _availableCommands << "effects-update";
- #endif
-
- qRegisterMetaType("InputsMap");
-}
-
-bool JsonCB::subscribeFor(const QString& type, bool unsubscribe)
-{
- if(!_availableCommands.contains(type))
- return false;
-
- if(unsubscribe)
- _subscribedCommands.removeAll(type);
- else
- _subscribedCommands << type;
-
- if(type == "components-update")
- {
- if(unsubscribe)
- disconnect(_componentRegister, &ComponentRegister::updatedComponentState, this, &JsonCB::handleComponentState);
- else
- connect(_componentRegister, &ComponentRegister::updatedComponentState, this, &JsonCB::handleComponentState, Qt::UniqueConnection);
- }
-
- if(type == "priorities-update")
- {
- if (unsubscribe)
- disconnect(_prioMuxer, &PriorityMuxer::prioritiesChanged, this, &JsonCB::handlePriorityUpdate);
- else
- connect(_prioMuxer, &PriorityMuxer::prioritiesChanged, this, &JsonCB::handlePriorityUpdate, Qt::UniqueConnection);
- }
-
- if(type == "imageToLedMapping-update")
- {
- if(unsubscribe)
- disconnect(_hyperion, &Hyperion::imageToLedsMappingChanged, this, &JsonCB::handleImageToLedsMappingChange);
- else
- connect(_hyperion, &Hyperion::imageToLedsMappingChanged, this, &JsonCB::handleImageToLedsMappingChange, Qt::UniqueConnection);
- }
-
- if(type == "adjustment-update")
- {
- if(unsubscribe)
- disconnect(_hyperion, &Hyperion::adjustmentChanged, this, &JsonCB::handleAdjustmentChange);
- else
- connect(_hyperion, &Hyperion::adjustmentChanged, this, &JsonCB::handleAdjustmentChange, Qt::UniqueConnection);
- }
-
- if(type == "videomode-update")
- {
- if(unsubscribe)
- disconnect(_hyperion, &Hyperion::newVideoMode, this, &JsonCB::handleVideoModeChange);
- else
- connect(_hyperion, &Hyperion::newVideoMode, this, &JsonCB::handleVideoModeChange, Qt::UniqueConnection);
- }
-
-#if defined(ENABLE_EFFECTENGINE)
- if(type == "effects-update")
- {
- if(unsubscribe)
- disconnect(_hyperion, &Hyperion::effectListUpdated, this, &JsonCB::handleEffectListChange);
- else
- connect(_hyperion, &Hyperion::effectListUpdated, this, &JsonCB::handleEffectListChange, Qt::UniqueConnection);
- }
-#endif
-
- if(type == "settings-update")
- {
- if(unsubscribe)
- disconnect(_hyperion, &Hyperion::settingsChanged, this, &JsonCB::handleSettingsChange);
- else
- connect(_hyperion, &Hyperion::settingsChanged, this, &JsonCB::handleSettingsChange, Qt::UniqueConnection);
- }
-
- if(type == "leds-update")
- {
- if(unsubscribe)
- disconnect(_hyperion, &Hyperion::settingsChanged, this, &JsonCB::handleLedsConfigChange);
- else
- connect(_hyperion, &Hyperion::settingsChanged, this, &JsonCB::handleLedsConfigChange, Qt::UniqueConnection);
- }
-
-
- if(type == "instance-update")
- {
- if(unsubscribe)
- disconnect(HyperionIManager::getInstance(), &HyperionIManager::change, this, &JsonCB::handleInstanceChange);
- else
- connect(HyperionIManager::getInstance(), &HyperionIManager::change, this, &JsonCB::handleInstanceChange, Qt::UniqueConnection);
- }
-
- if (type == "token-update")
- {
- if (unsubscribe)
- disconnect(AuthManager::getInstance(), &AuthManager::tokenChange, this, &JsonCB::handleTokenChange);
- else
- connect(AuthManager::getInstance(), &AuthManager::tokenChange, this, &JsonCB::handleTokenChange, Qt::UniqueConnection);
- }
-
- return true;
-}
-
-void JsonCB::resetSubscriptions()
-{
- for(const auto & entry : getSubscribedCommands())
- {
- subscribeFor(entry, true);
- }
-}
-
-void JsonCB::setSubscriptionsTo(Hyperion* hyperion)
-{
- assert(hyperion);
-
- // get current subs
- QStringList currSubs(getSubscribedCommands());
-
- // stop subs
- resetSubscriptions();
-
- // update pointer
- _hyperion = hyperion;
- _componentRegister = _hyperion->getComponentRegister();
- _prioMuxer = _hyperion->getMuxerInstance();
-
- // re-apply subs
- for(const auto & entry : currSubs)
- {
- subscribeFor(entry);
- }
-}
-
-void JsonCB::doCallback(const QString& cmd, const QVariant& data)
-{
- QJsonObject obj;
- obj["instance"] = _hyperion->getInstanceIndex();
- obj["command"] = cmd;
-
- if (data.userType() == QMetaType::QJsonArray)
- obj["data"] = data.toJsonArray();
- else
- obj["data"] = data.toJsonObject();
-
- emit newCallback(obj);
-}
-
-void JsonCB::handleComponentState(hyperion::Components comp, bool state)
-{
- QJsonObject data;
- data["name"] = componentToIdString(comp);
- data["enabled"] = state;
-
- doCallback("components-update", QVariant(data));
-}
-
-void JsonCB::handlePriorityUpdate(int currentPriority, const PriorityMuxer::InputsMap& activeInputs)
-{
- QJsonObject data;
- QJsonArray priorities;
- uint64_t now = QDateTime::currentMSecsSinceEpoch();
- QList activePriorities = activeInputs.keys();
-
- activePriorities.removeAll(PriorityMuxer::LOWEST_PRIORITY);
-
- for (int priority : std::as_const(activePriorities)) {
-
- const Hyperion::InputInfo& priorityInfo = activeInputs[priority];
-
- QJsonObject item;
- item["priority"] = priority;
-
- if (priorityInfo.timeoutTime_ms > 0 )
- {
- item["duration_ms"] = int(priorityInfo.timeoutTime_ms - now);
- }
-
- // owner has optional informations to the component
- if(!priorityInfo.owner.isEmpty())
- {
- item["owner"] = priorityInfo.owner;
- }
-
- item["componentId"] = QString(hyperion::componentToIdString(priorityInfo.componentId));
- item["origin"] = priorityInfo.origin;
- item["active"] = (priorityInfo.timeoutTime_ms >= -1);
- item["visible"] = (priority == currentPriority);
-
- if(priorityInfo.componentId == hyperion::COMP_COLOR && !priorityInfo.ledColors.empty())
- {
- QJsonObject LEDcolor;
-
- // add RGB Value to Array
- QJsonArray RGBValue;
- RGBValue.append(priorityInfo.ledColors.begin()->red);
- RGBValue.append(priorityInfo.ledColors.begin()->green);
- RGBValue.append(priorityInfo.ledColors.begin()->blue);
- LEDcolor.insert("RGB", RGBValue);
-
- uint16_t Hue;
- float Saturation;
- float Luminace;
-
- // add HSL Value to Array
- QJsonArray HSLValue;
- ColorSys::rgb2hsl(priorityInfo.ledColors.begin()->red,
- priorityInfo.ledColors.begin()->green,
- priorityInfo.ledColors.begin()->blue,
- Hue, Saturation, Luminace);
-
- HSLValue.append(Hue);
- HSLValue.append(Saturation);
- HSLValue.append(Luminace);
- LEDcolor.insert("HSL", HSLValue);
-
- item["value"] = LEDcolor;
- }
- priorities.append(item);
- }
-
- data["priorities"] = priorities;
- data["priorities_autoselect"] = _hyperion->sourceAutoSelectEnabled();
-
- doCallback("priorities-update", QVariant(data));
-}
-
-void JsonCB::handleImageToLedsMappingChange(int mappingType)
-{
- QJsonObject data;
- data["imageToLedMappingType"] = ImageProcessor::mappingTypeToStr(mappingType);
-
- doCallback("imageToLedMapping-update", QVariant(data));
-}
-
-void JsonCB::handleAdjustmentChange()
-{
- QJsonArray adjustmentArray;
- for (const QString& adjustmentId : _hyperion->getAdjustmentIds())
- {
- const ColorAdjustment * colorAdjustment = _hyperion->getAdjustment(adjustmentId);
- if (colorAdjustment == nullptr)
- {
- continue;
- }
-
- QJsonObject adjustment;
- adjustment["id"] = adjustmentId;
-
- QJsonArray whiteAdjust;
- whiteAdjust.append(colorAdjustment->_rgbWhiteAdjustment.getAdjustmentR());
- whiteAdjust.append(colorAdjustment->_rgbWhiteAdjustment.getAdjustmentG());
- whiteAdjust.append(colorAdjustment->_rgbWhiteAdjustment.getAdjustmentB());
- adjustment.insert("white", whiteAdjust);
-
- QJsonArray redAdjust;
- redAdjust.append(colorAdjustment->_rgbRedAdjustment.getAdjustmentR());
- redAdjust.append(colorAdjustment->_rgbRedAdjustment.getAdjustmentG());
- redAdjust.append(colorAdjustment->_rgbRedAdjustment.getAdjustmentB());
- adjustment.insert("red", redAdjust);
-
- QJsonArray greenAdjust;
- greenAdjust.append(colorAdjustment->_rgbGreenAdjustment.getAdjustmentR());
- greenAdjust.append(colorAdjustment->_rgbGreenAdjustment.getAdjustmentG());
- greenAdjust.append(colorAdjustment->_rgbGreenAdjustment.getAdjustmentB());
- adjustment.insert("green", greenAdjust);
-
- QJsonArray blueAdjust;
- blueAdjust.append(colorAdjustment->_rgbBlueAdjustment.getAdjustmentR());
- blueAdjust.append(colorAdjustment->_rgbBlueAdjustment.getAdjustmentG());
- blueAdjust.append(colorAdjustment->_rgbBlueAdjustment.getAdjustmentB());
- adjustment.insert("blue", blueAdjust);
-
- QJsonArray cyanAdjust;
- cyanAdjust.append(colorAdjustment->_rgbCyanAdjustment.getAdjustmentR());
- cyanAdjust.append(colorAdjustment->_rgbCyanAdjustment.getAdjustmentG());
- cyanAdjust.append(colorAdjustment->_rgbCyanAdjustment.getAdjustmentB());
- adjustment.insert("cyan", cyanAdjust);
-
- QJsonArray magentaAdjust;
- magentaAdjust.append(colorAdjustment->_rgbMagentaAdjustment.getAdjustmentR());
- magentaAdjust.append(colorAdjustment->_rgbMagentaAdjustment.getAdjustmentG());
- magentaAdjust.append(colorAdjustment->_rgbMagentaAdjustment.getAdjustmentB());
- adjustment.insert("magenta", magentaAdjust);
-
- QJsonArray yellowAdjust;
- yellowAdjust.append(colorAdjustment->_rgbYellowAdjustment.getAdjustmentR());
- yellowAdjust.append(colorAdjustment->_rgbYellowAdjustment.getAdjustmentG());
- yellowAdjust.append(colorAdjustment->_rgbYellowAdjustment.getAdjustmentB());
- adjustment.insert("yellow", yellowAdjust);
-
- adjustment["backlightThreshold"] = colorAdjustment->_rgbTransform.getBacklightThreshold();
- adjustment["backlightColored"] = colorAdjustment->_rgbTransform.getBacklightColored();
- adjustment["brightness"] = colorAdjustment->_rgbTransform.getBrightness();
- adjustment["brightnessCompensation"] = colorAdjustment->_rgbTransform.getBrightnessCompensation();
- adjustment["gammaRed"] = colorAdjustment->_rgbTransform.getGammaR();
- adjustment["gammaGreen"] = colorAdjustment->_rgbTransform.getGammaG();
- adjustment["gammaBlue"] = colorAdjustment->_rgbTransform.getGammaB();
-
- adjustmentArray.append(adjustment);
- }
-
- doCallback("adjustment-update", QVariant(adjustmentArray));
-}
-
-void JsonCB::handleVideoModeChange(VideoMode mode)
-{
- QJsonObject data;
- data["videomode"] = QString(videoMode2String(mode));
- doCallback("videomode-update", QVariant(data));
-}
-
-#if defined(ENABLE_EFFECTENGINE)
-void JsonCB::handleEffectListChange()
-{
- QJsonArray effectList;
- QJsonObject effects;
- const std::list & effectsDefinitions = _hyperion->getEffects();
- for (const EffectDefinition & effectDefinition : effectsDefinitions)
- {
- QJsonObject effect;
- effect["name"] = effectDefinition.name;
- effect["file"] = effectDefinition.file;
- effect["script"] = effectDefinition.script;
- effect["args"] = effectDefinition.args;
- effectList.append(effect);
- };
- effects["effects"] = effectList;
- doCallback("effects-update", QVariant(effects));
-}
-#endif
-
-void JsonCB::handleSettingsChange(settings::type type, const QJsonDocument& data)
-{
- QJsonObject dat;
- if(data.isObject())
- dat[typeToString(type)] = data.object();
- else
- dat[typeToString(type)] = data.array();
-
- doCallback("settings-update", QVariant(dat));
-}
-
-void JsonCB::handleLedsConfigChange(settings::type type, const QJsonDocument& data)
-{
- if(type == settings::LEDS)
- {
- QJsonObject dat;
- dat[typeToString(type)] = data.array();
- doCallback("leds-update", QVariant(dat));
- }
-}
-
-void JsonCB::handleInstanceChange()
-{
- QJsonArray arr;
-
- for(const auto & entry : HyperionIManager::getInstance()->getInstanceData())
- {
- QJsonObject obj;
- obj.insert("friendly_name", entry["friendly_name"].toString());
- obj.insert("instance", entry["instance"].toInt());
- obj.insert("running", entry["running"].toBool());
- arr.append(obj);
- }
- doCallback("instance-update", QVariant(arr));
-}
-
-void JsonCB::handleTokenChange(const QVector &def)
-{
- QJsonArray arr;
- for (const auto &entry : def)
- {
- QJsonObject sub;
- sub["comment"] = entry.comment;
- sub["id"] = entry.id;
- sub["last_use"] = entry.lastUse;
- arr.push_back(sub);
- }
- doCallback("token-update", QVariant(arr));
-}
diff --git a/libsrc/api/JsonCallbacks.cpp b/libsrc/api/JsonCallbacks.cpp
new file mode 100644
index 00000000..8f89b449
--- /dev/null
+++ b/libsrc/api/JsonCallbacks.cpp
@@ -0,0 +1,451 @@
+// proj incl
+#include
+#include
+#include
+
+// hyperion
+#include
+
+// HyperionIManager
+#include
+// components
+
+#include
+// priorityMuxer
+
+#include
+
+// utils
+#include
+
+// qt
+#include
+#include
+#include
+#include
+
+// Image to led map helper
+
+#include
+
+using namespace hyperion;
+
+JsonCallbacks::JsonCallbacks(Logger *log, const QString& peerAddress, QObject* parent)
+ : QObject(parent)
+ , _log (log)
+ , _hyperion(nullptr)
+ , _peerAddress (peerAddress)
+ , _componentRegister(nullptr)
+ , _prioMuxer(nullptr)
+ , _islogMsgStreamingActive(false)
+{
+ qRegisterMetaType("InputsMap");
+}
+
+bool JsonCallbacks::subscribe(const Subscription::Type cmd)
+{
+ switch (cmd) {
+ case Subscription::AdjustmentUpdate:
+ connect(_hyperion, &Hyperion::adjustmentChanged, this, &JsonCallbacks::handleAdjustmentChange);
+ break;
+ case Subscription::ComponentsUpdate:
+ connect(_componentRegister, &ComponentRegister::updatedComponentState, this, &JsonCallbacks::handleComponentState);
+ break;
+#if defined(ENABLE_EFFECTENGINE)
+ case Subscription::EffectsUpdate:
+ connect(_hyperion, &Hyperion::effectListUpdated, this, &JsonCallbacks::handleEffectListChange);
+ break;
+#endif
+ case Subscription::ImageToLedMappingUpdate:
+ connect(_hyperion, &Hyperion::imageToLedsMappingChanged, this, &JsonCallbacks::handleImageToLedsMappingChange);
+ break;
+ case Subscription::ImageUpdate:
+ connect(_hyperion, &Hyperion::currentImage, this, &JsonCallbacks::handleImageUpdate);
+ break;
+ case Subscription::InstanceUpdate:
+ connect(HyperionIManager::getInstance(), &HyperionIManager::change, this, &JsonCallbacks::handleInstanceChange);
+ break;
+ case Subscription::LedColorsUpdate:
+ connect(_hyperion, &Hyperion::rawLedColors, this, &JsonCallbacks::handleLedColorUpdate);
+ break;
+ case Subscription::LedsUpdate:
+ connect(_hyperion, &Hyperion::settingsChanged, this, &JsonCallbacks::handleLedsConfigChange);
+ break;
+ case Subscription::LogMsgUpdate:
+ if (!_islogMsgStreamingActive)
+ {
+ handleLogMessageUpdate (Logger::T_LOG_MESSAGE{}); // needed to trigger log sending
+ _islogMsgStreamingActive = true;
+ Debug(_log, "log streaming activated for client %s", _peerAddress.toStdString().c_str());
+ }
+ connect(LoggerManager::getInstance().data(), &LoggerManager::newLogMessage, this, &JsonCallbacks::handleLogMessageUpdate);
+ break;
+ case Subscription::PrioritiesUpdate:
+ connect(_prioMuxer, &PriorityMuxer::prioritiesChanged, this, &JsonCallbacks::handlePriorityUpdate);
+ break;
+ case Subscription::SettingsUpdate:
+ connect(_hyperion, &Hyperion::settingsChanged, this, &JsonCallbacks::handleSettingsChange);
+ break;
+ case Subscription::TokenUpdate:
+ connect(AuthManager::getInstance(), &AuthManager::tokenChange, this, &JsonCallbacks::handleTokenChange, Qt::AutoConnection);
+ break;
+ case Subscription::VideomodeUpdate:
+ connect(_hyperion, &Hyperion::newVideoMode, this, &JsonCallbacks::handleVideoModeChange);
+ break;
+
+ default:
+ return false;
+ }
+
+ _subscribedCommands.insert(cmd);
+
+ return true;
+}
+
+bool JsonCallbacks::subscribe(const QString& cmd)
+{
+ JsonApiSubscription subscription = ApiSubscriptionRegister::getSubscriptionInfo(cmd);
+ if (subscription.cmd == Subscription::Unknown)
+ {
+ return false;
+ }
+ return subscribe(subscription.cmd);
+}
+
+QStringList JsonCallbacks::subscribe(const QJsonArray& subscriptions)
+{
+ QJsonArray subsArr;
+ if (subscriptions.contains("all"))
+ {
+ for (const auto& entry : getCommands(false))
+ {
+ subsArr.append(entry);
+ }
+ }
+ else
+ {
+ subsArr = subscriptions;
+ }
+
+ QStringList invalidSubscriptions;
+ for (auto it = subsArr.begin(); it != subsArr.end(); ++it)
+ {
+ const QJsonValue& entry = *it;
+ if (!subscribe(entry.toString()))
+ {
+ invalidSubscriptions.append(entry.toString());
+ }
+ }
+ return invalidSubscriptions;
+}
+
+bool JsonCallbacks::unsubscribe(const Subscription::Type cmd)
+{
+ _subscribedCommands.remove(cmd);
+
+ switch (cmd) {
+ case Subscription::AdjustmentUpdate:
+ disconnect(_hyperion, &Hyperion::adjustmentChanged, this, &JsonCallbacks::handleAdjustmentChange);
+ break;
+ case Subscription::ComponentsUpdate:
+ disconnect(_componentRegister, &ComponentRegister::updatedComponentState, this, &JsonCallbacks::handleComponentState);
+ break;
+#if defined(ENABLE_EFFECTENGINE)
+ case Subscription::EffectsUpdate:
+ disconnect(_hyperion, &Hyperion::effectListUpdated, this, &JsonCallbacks::handleEffectListChange);
+ break;
+#endif
+ case Subscription::ImageToLedMappingUpdate:
+ disconnect(_hyperion, &Hyperion::imageToLedsMappingChanged, this, &JsonCallbacks::handleImageToLedsMappingChange);
+ break;
+ case Subscription::ImageUpdate:
+ disconnect(_hyperion, &Hyperion::currentImage, this, &JsonCallbacks::handleImageUpdate);
+ break;
+ case Subscription::InstanceUpdate:
+ disconnect(HyperionIManager::getInstance(), &HyperionIManager::change, this, &JsonCallbacks::handleInstanceChange);
+ break;
+ case Subscription::LedColorsUpdate:
+ disconnect(_hyperion, &Hyperion::rawLedColors, this, &JsonCallbacks::handleLedColorUpdate);
+ break;
+ case Subscription::LedsUpdate:
+ disconnect(_hyperion, &Hyperion::settingsChanged, this, &JsonCallbacks::handleLedsConfigChange);
+ break;
+ case Subscription::LogMsgUpdate:
+ disconnect(LoggerManager::getInstance().data(), &LoggerManager::newLogMessage, this, &JsonCallbacks::handleLogMessageUpdate);
+ if (_islogMsgStreamingActive)
+ {
+ _islogMsgStreamingActive = false;
+ Debug(_log, "log streaming deactivated for client %s", _peerAddress.toStdString().c_str());
+ }
+ break;
+ case Subscription::PrioritiesUpdate:
+ disconnect(_prioMuxer, &PriorityMuxer::prioritiesChanged, this, &JsonCallbacks::handlePriorityUpdate);
+ break;
+ case Subscription::SettingsUpdate:
+ disconnect(_hyperion, &Hyperion::settingsChanged, this, &JsonCallbacks::handleSettingsChange);
+ break;
+ case Subscription::TokenUpdate:
+ disconnect(AuthManager::getInstance(), &AuthManager::tokenChange, this, &JsonCallbacks::handleTokenChange);
+ break;
+ case Subscription::VideomodeUpdate:
+ disconnect(_hyperion, &Hyperion::newVideoMode, this, &JsonCallbacks::handleVideoModeChange);
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool JsonCallbacks::unsubscribe(const QString& cmd)
+{
+ JsonApiSubscription subscription = ApiSubscriptionRegister::getSubscriptionInfo(cmd);
+ if (subscription.cmd == Subscription::Unknown)
+ {
+ return false;
+ }
+ return unsubscribe(subscription.cmd);
+}
+
+QStringList JsonCallbacks::unsubscribe(const QJsonArray& subscriptions)
+{
+ QJsonArray subsArr;
+ if (subscriptions.contains("all"))
+ {
+ for (const auto& entry : getCommands(false))
+ {
+ subsArr.append(entry);
+ }
+ }
+ else
+ {
+ subsArr = subscriptions;
+ }
+
+ QStringList invalidSubscriptions;
+ for (auto it = subsArr.begin(); it != subsArr.end(); ++it)
+ {
+ const QJsonValue& entry = *it;
+ if (!unsubscribe(entry.toString()))
+ {
+ invalidSubscriptions.append(entry.toString());
+ }
+ }
+ return invalidSubscriptions;
+}
+
+void JsonCallbacks::resetSubscriptions()
+{
+ for (QSet::const_iterator it = _subscribedCommands.constBegin(); it != _subscribedCommands.constEnd(); ++it)
+ {
+ unsubscribe(*it);
+ }
+}
+
+void JsonCallbacks::setSubscriptionsTo(Hyperion* hyperion)
+{
+ assert(hyperion);
+
+ // get current subs
+ const QSet currSubs(_subscribedCommands);
+
+ // stop subs
+ resetSubscriptions();
+
+ // update pointer
+ _hyperion = hyperion;
+ _componentRegister = _hyperion->getComponentRegister();
+ _prioMuxer = _hyperion->getMuxerInstance();
+
+ // re-apply subs
+ for(const auto & entry : currSubs)
+ {
+ subscribe(entry);
+ }
+}
+
+QStringList JsonCallbacks::getCommands(bool fullList) const
+{
+ QStringList commands;
+ for (JsonApiSubscription subscription : ApiSubscriptionRegister::getSubscriptionLookup())
+ {
+ if (fullList || subscription.isAll)
+ {
+ commands << Subscription::toString(subscription.cmd);
+ }
+ }
+ return commands;
+}
+
+QStringList JsonCallbacks::getSubscribedCommands() const
+{
+ QStringList commands;
+ for (Subscription::Type cmd : _subscribedCommands)
+ {
+ commands << Subscription::toString(cmd);
+ }
+ return commands;
+}
+
+void JsonCallbacks::doCallback(Subscription::Type cmd, const QVariant& data)
+{
+ QJsonObject obj;
+ obj["instance"] = _hyperion->getInstanceIndex();
+ obj["command"] = Subscription::toString(cmd);
+
+ if (data.userType() == QMetaType::QJsonArray) {
+ obj["data"] = data.toJsonArray();
+ } else {
+ obj["data"] = data.toJsonObject();
+ }
+
+ emit newCallback(obj);
+}
+
+void JsonCallbacks::handleComponentState(hyperion::Components comp, bool state)
+{
+ QJsonObject data;
+ data["name"] = componentToIdString(comp);
+ data["enabled"] = state;
+
+ doCallback(Subscription::ComponentsUpdate, QVariant(data));
+}
+
+void JsonCallbacks::handlePriorityUpdate(int currentPriority, const PriorityMuxer::InputsMap& activeInputs)
+{
+ QJsonObject data;
+ data["priorities"] = JsonInfo::getPrioritiestInfo(currentPriority, activeInputs);
+ data["priorities_autoselect"] = _hyperion->sourceAutoSelectEnabled();
+
+ doCallback(Subscription::PrioritiesUpdate, QVariant(data));
+}
+
+void JsonCallbacks::handleImageToLedsMappingChange(int mappingType)
+{
+ QJsonObject data;
+ data["imageToLedMappingType"] = ImageProcessor::mappingTypeToStr(mappingType);
+
+ doCallback(Subscription::ImageToLedMappingUpdate, QVariant(data));
+}
+
+void JsonCallbacks::handleAdjustmentChange()
+{
+ doCallback(Subscription::AdjustmentUpdate, JsonInfo::getAdjustmentInfo(_hyperion,_log));
+}
+
+void JsonCallbacks::handleVideoModeChange(VideoMode mode)
+{
+ QJsonObject data;
+ data["videomode"] = QString(videoMode2String(mode));
+ doCallback(Subscription::VideomodeUpdate, QVariant(data));
+}
+
+#if defined(ENABLE_EFFECTENGINE)
+void JsonCallbacks::handleEffectListChange()
+{
+ QJsonObject effects;
+ effects["effects"] = JsonInfo::getEffects(_hyperion);
+ doCallback(Subscription::EffectsUpdate, QVariant(effects));
+}
+#endif
+
+void JsonCallbacks::handleSettingsChange(settings::type type, const QJsonDocument& data)
+{
+ QJsonObject dat;
+ if(data.isObject()) {
+ dat[typeToString(type)] = data.object();
+ } else {
+ dat[typeToString(type)] = data.array();
+ }
+
+ doCallback(Subscription::SettingsUpdate, QVariant(dat));
+}
+
+void JsonCallbacks::handleLedsConfigChange(settings::type type, const QJsonDocument& data)
+{
+ if(type == settings::LEDS)
+ {
+ QJsonObject dat;
+ dat[typeToString(type)] = data.array();
+ doCallback(Subscription::LedsUpdate, QVariant(dat));
+ }
+}
+
+void JsonCallbacks::handleInstanceChange()
+{
+ doCallback(Subscription::InstanceUpdate, JsonInfo::getInstanceInfo());
+}
+
+void JsonCallbacks::handleTokenChange(const QVector &def)
+{
+ QJsonArray arr;
+ for (const auto &entry : def)
+ {
+ QJsonObject sub;
+ sub["comment"] = entry.comment;
+ sub["id"] = entry.id;
+ sub["last_use"] = entry.lastUse;
+ arr.push_back(sub);
+ }
+ doCallback(Subscription::TokenUpdate, QVariant(arr));
+}
+
+void JsonCallbacks::handleLedColorUpdate(const std::vector &ledColors)
+{
+ QJsonObject result;
+ QJsonArray leds;
+
+ for (const auto &color : ledColors)
+ {
+ leds << QJsonValue(color.red) << QJsonValue(color.green) << QJsonValue(color.blue);
+ }
+ result["leds"] = leds;
+
+ doCallback(Subscription::LedColorsUpdate, QVariant(result));
+}
+
+void JsonCallbacks::handleImageUpdate(const Image &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");
+
+ QJsonObject result;
+ result["image"] = "data:image/jpg;base64," + QString(byteArray.toBase64());
+
+ doCallback(Subscription::ImageUpdate, QVariant(result));
+}
+
+void JsonCallbacks::handleLogMessageUpdate(const Logger::T_LOG_MESSAGE &msg)
+{
+ QJsonObject result;
+ QJsonObject message;
+ QJsonArray messageArray;
+
+ if (!_islogMsgStreamingActive)
+ {
+ _islogMsgStreamingActive = true;
+ QMetaObject::invokeMethod(LoggerManager::getInstance().data(), "getLogMessageBuffer",
+ Qt::DirectConnection,
+ Q_RETURN_ARG(QJsonArray, messageArray),
+ Q_ARG(Logger::LogLevel, _log->getLogLevel()));
+ }
+ else
+ {
+ message["loggerName"] = msg.loggerName;
+ message["loggerSubName"] = msg.loggerSubName;
+ message["function"] = msg.function;
+ message["line"] = QString::number(msg.line);
+ message["fileName"] = msg.fileName;
+ message["message"] = msg.message;
+ message["levelString"] = msg.levelString;
+ message["utime"] = QString::number(msg.utime);
+
+ messageArray.append(message);
+ }
+ result.insert("messages", messageArray);
+
+ doCallback(Subscription::LogMsgUpdate, QVariant(result));
+}
diff --git a/libsrc/api/JsonInfo.cpp b/libsrc/api/JsonInfo.cpp
new file mode 100644
index 00000000..e2a73ffe
--- /dev/null
+++ b/libsrc/api/JsonInfo.cpp
@@ -0,0 +1,620 @@
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include // Required to determine the cmake options
+
+#include
+#include
+
+
+QJsonArray JsonInfo::getAdjustmentInfo(const Hyperion* hyperion, Logger* log)
+{
+ QJsonArray adjustmentArray;
+ for (const QString &adjustmentId : hyperion->getAdjustmentIds())
+ {
+ const ColorAdjustment *colorAdjustment = hyperion->getAdjustment(adjustmentId);
+ if (colorAdjustment == nullptr)
+ {
+ Error(log, "Incorrect color adjustment id: %s", QSTRING_CSTR(adjustmentId));
+ continue;
+ }
+
+ QJsonObject adjustment;
+ adjustment["id"] = adjustmentId;
+
+ QJsonArray whiteAdjust;
+ whiteAdjust.append(colorAdjustment->_rgbWhiteAdjustment.getAdjustmentR());
+ whiteAdjust.append(colorAdjustment->_rgbWhiteAdjustment.getAdjustmentG());
+ whiteAdjust.append(colorAdjustment->_rgbWhiteAdjustment.getAdjustmentB());
+ adjustment.insert("white", whiteAdjust);
+
+ QJsonArray redAdjust;
+ redAdjust.append(colorAdjustment->_rgbRedAdjustment.getAdjustmentR());
+ redAdjust.append(colorAdjustment->_rgbRedAdjustment.getAdjustmentG());
+ redAdjust.append(colorAdjustment->_rgbRedAdjustment.getAdjustmentB());
+ adjustment.insert("red", redAdjust);
+
+ QJsonArray greenAdjust;
+ greenAdjust.append(colorAdjustment->_rgbGreenAdjustment.getAdjustmentR());
+ greenAdjust.append(colorAdjustment->_rgbGreenAdjustment.getAdjustmentG());
+ greenAdjust.append(colorAdjustment->_rgbGreenAdjustment.getAdjustmentB());
+ adjustment.insert("green", greenAdjust);
+
+ QJsonArray blueAdjust;
+ blueAdjust.append(colorAdjustment->_rgbBlueAdjustment.getAdjustmentR());
+ blueAdjust.append(colorAdjustment->_rgbBlueAdjustment.getAdjustmentG());
+ blueAdjust.append(colorAdjustment->_rgbBlueAdjustment.getAdjustmentB());
+ adjustment.insert("blue", blueAdjust);
+
+ QJsonArray cyanAdjust;
+ cyanAdjust.append(colorAdjustment->_rgbCyanAdjustment.getAdjustmentR());
+ cyanAdjust.append(colorAdjustment->_rgbCyanAdjustment.getAdjustmentG());
+ cyanAdjust.append(colorAdjustment->_rgbCyanAdjustment.getAdjustmentB());
+ adjustment.insert("cyan", cyanAdjust);
+
+ QJsonArray magentaAdjust;
+ magentaAdjust.append(colorAdjustment->_rgbMagentaAdjustment.getAdjustmentR());
+ magentaAdjust.append(colorAdjustment->_rgbMagentaAdjustment.getAdjustmentG());
+ magentaAdjust.append(colorAdjustment->_rgbMagentaAdjustment.getAdjustmentB());
+ adjustment.insert("magenta", magentaAdjust);
+
+ QJsonArray yellowAdjust;
+ yellowAdjust.append(colorAdjustment->_rgbYellowAdjustment.getAdjustmentR());
+ yellowAdjust.append(colorAdjustment->_rgbYellowAdjustment.getAdjustmentG());
+ yellowAdjust.append(colorAdjustment->_rgbYellowAdjustment.getAdjustmentB());
+ adjustment.insert("yellow", yellowAdjust);
+
+ adjustment["backlightThreshold"] = colorAdjustment->_rgbTransform.getBacklightThreshold();
+ adjustment["backlightColored"] = colorAdjustment->_rgbTransform.getBacklightColored();
+ adjustment["brightness"] = colorAdjustment->_rgbTransform.getBrightness();
+ adjustment["brightnessCompensation"] = colorAdjustment->_rgbTransform.getBrightnessCompensation();
+ adjustment["gammaRed"] = colorAdjustment->_rgbTransform.getGammaR();
+ adjustment["gammaGreen"] = colorAdjustment->_rgbTransform.getGammaG();
+ adjustment["gammaBlue"] = colorAdjustment->_rgbTransform.getGammaB();
+
+ adjustment["saturationGain"] = colorAdjustment->_okhsvTransform.getSaturationGain();
+ adjustment["brightnessGain"] = colorAdjustment->_okhsvTransform.getBrightnessGain();
+
+ adjustmentArray.append(adjustment);
+ }
+ return adjustmentArray;
+}
+
+QJsonArray JsonInfo::getPrioritiestInfo(const Hyperion* hyperion)
+{
+ return getPrioritiestInfo(hyperion->getCurrentPriority(), hyperion->getPriorityInfo());
+}
+
+QJsonArray JsonInfo::getPrioritiestInfo(int currentPriority, const PriorityMuxer::InputsMap& activeInputs)
+{
+ QJsonArray priorities;
+ int64_t now = QDateTime::currentMSecsSinceEpoch();
+
+ QList