Refactor Hyperion JSON-API (#1727)

This commit is contained in:
LordGrey
2024-05-08 22:06:32 +02:00
committed by GitHub
parent 94850d890a
commit cf287f5adb
64 changed files with 4203 additions and 2962 deletions

View File

@@ -2,8 +2,6 @@
#include <api/API.h>
// stl includes
#include <iostream>
#include <iterator>
// Qt includes
#include <QResource>
@@ -27,90 +25,91 @@
// ledmapping int <> string transform methods
#include <hyperion/ImageProcessor.h>
// api includes
#include <api/JsonCB.h>
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>("int64_t");
qRegisterMetaType<VideoMode>("VideoMode");
qRegisterMetaType<std::map<int, registerData>>("std::map<int,registerData>");
// 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();
// 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 (apiAuthRequired && _localConnection)
// For security we block external connections, if default PW is set
if (!_localConnection && API::hasHyperionDefaultPw())
{
_authorized = !_authManager->isLocalAuthRequired();
Warning(_log, "Non local network connect attempt identified, but default Hyperion passwort set! - Reject connection.");
emit forceClose();
}
// admin access is allowed, when the connection is local and the option for local admin isn't set. Con: All local connections get full access
if (_localConnection)
{
_adminAuthorized = !_authManager->isLocalAdminAuthRequired();
// just in positive direction
if (_adminAuthorized)
// if this is localConnection and network allows unauth locals
if ( _localConnection && !_authManager->isLocalAuthRequired())
{
_authorized = true;
}
// // 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<uint8_t> &ledColors, int timeout_ms, const QString &origin, hyperion::Components /*callerComp*/)
{
if (ledColors.size() % 3 == 0)
{
std::vector<ColorRgb> fledColors;
for (unsigned i = 0; i < ledColors.size(); i += 3)
{
_authorized = true;
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<ColorRgb>, fledColors), Q_ARG(int, timeout_ms), Q_ARG(QString, origin));
}
}
void API::setColor(int priority, const std::vector<uint8_t> &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<ColorRgb> 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<ColorRgb>, 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())
{
@@ -128,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<const QRgb *>(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<int>(img.width() * img.height() * 3));
for (int i = 0; i < img.height(); ++i)
{
const QRgb *scanline = reinterpret_cast<const QRgb *>(img.scanLine(i));
for (int j = 0; j < img.width(); ++j)
{
data.data.append(static_cast<char>(qRed(scanline[j])));
data.data.append(static_cast<char>(qGreen(scanline[j])));
data.data.append(static_cast<char>(qBlue(scanline[j])));
}
}
}
else
{
// check consistency of the size of the received data
if (static_cast<size_t>(data.data.size()) != static_cast<size_t>(data.width) * static_cast<size_t>(data.height) * 3)
{
replyMsg = "Size of image data does not match with the width and height";
return false;
}
}
// copy image
Image<ColorRgb> image(data.width, data.height);
memcpy(image.memptr(), data.data.data(), data.data.size());
// copy image
Image<ColorRgb> image(data.width, data.height);
memcpy(image.memptr(), data.data.data(), static_cast<size_t>(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<ColorRgb>, 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<ColorRgb>, 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<QVariantMap> API::getAllInstanceData()
QVector<QVariantMap> API::getAllInstanceData() const
{
QVector<QVariantMap> vec;
QMetaObject::invokeMethod(_instanceManager, "getInstanceData", Qt::DirectConnection, Q_RETURN_ARG(QVector<QVariantMap>, vec));
return vec;
QVector<QVariantMap> vec;
QMetaObject::invokeMethod(_instanceManager, "getInstanceData", Qt::DirectConnection, Q_RETURN_ARG(QVector<QVariantMap>, 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, "Hyperion"), 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<AuthManager::AuthDefinition> &def)
{
if (!_adminAuthorized)
return false;
QMetaObject::invokeMethod(_authManager, "getTokenList", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QVector<AuthManager::AuthDefinition>, def));
return true;
if (!_adminAuthorized)
{
return false;
}
QMetaObject::invokeMethod(_authManager, "getTokenList", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QVector<AuthManager::AuthDefinition>, def));
return true;
}
bool API::getPendingTokenRequests(QVector<AuthManager::AuthDefinition> &map)
{
if (!_adminAuthorized)
return false;
QMetaObject::invokeMethod(_authManager, "getPendingRequests", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QVector<AuthManager::AuthDefinition>, map));
return true;
if (!_adminAuthorized)
{
return false;
}
QMetaObject::invokeMethod(_authManager, "getPendingRequests", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QVector<AuthManager::AuthDefinition>, 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, "Hyperion"), 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, "Hyperion"), 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, "Hyperion"), Q_ARG(QString, "hyperion"));
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();
}

View File

@@ -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
)

View File

@@ -7,6 +7,12 @@
"required" : true,
"enum" : ["adjustment"]
},
"instance" : {
"type": "array",
"required": false,
"items" : {},
"minItems": 1
},
"tan" : {
"type" : "integer"
},

View File

@@ -7,6 +7,12 @@
"required" : true,
"enum" : ["clear"]
},
"instance" : {
"type": "array",
"required": false,
"items" : {},
"minItems": 1
},
"tan" : {
"type" : "integer"
},

View File

@@ -7,6 +7,12 @@
"required" : true,
"enum" : ["clearall"]
},
"instance" : {
"type": "array",
"required": false,
"items" : {},
"minItems": 1
},
"tan" : {
"type" : "integer"
}

View File

@@ -7,6 +7,12 @@
"required" : true,
"enum" : ["color"]
},
"instance" : {
"type": "array",
"required": false,
"items" : {},
"minItems": 1
},
"tan" : {
"type" : "integer"
},

View File

@@ -9,6 +9,12 @@
"required" : true,
"enum" : ["componentstate"]
},
"instance" : {
"type": "array",
"required": false,
"items" : {},
"minItems": 1
},
"tan" : {
"type" : "integer"
},

View File

@@ -12,6 +12,11 @@
"required" : true,
"enum" : ["getconfig","getschema","setconfig","restoreconfig","reload"]
},
"instance" : {
"type" : "integer",
"minimum": 0,
"maximum": 255
},
"tan" : {
"type" : "integer"
},

View File

@@ -7,6 +7,11 @@
"required" : true,
"enum" : ["create-effect"]
},
"instance" : {
"type" : "integer",
"minimum": 0,
"maximum": 255
},
"tan" : {
"type" : "integer"
},

View File

@@ -8,6 +8,11 @@
"required" : true,
"enum" : ["delete-effect"]
},
"instance" : {
"type" : "integer",
"minimum": 0,
"maximum": 255
},
"tan" : {
"type" : "integer"
},

View File

@@ -7,6 +7,12 @@
"required" : true,
"enum" : ["effect"]
},
"instance" : {
"type": "array",
"required": false,
"items" : {},
"minItems": 1
},
"tan" : {
"type" : "integer"
},

View File

@@ -7,6 +7,12 @@
"required" : true,
"enum" : ["image"]
},
"instance" : {
"type": "array",
"required": false,
"items" : {},
"minItems": 1
},
"tan" : {
"type" : "integer"
},

View File

@@ -7,21 +7,18 @@
"required" : true,
"enum" : ["ledcolors"]
},
"instance" : {
"type" : "integer",
"minimum": 0,
"maximum": 255
},
"tan" : {
"type" : "integer"
},
"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"]
}
},

View File

@@ -7,6 +7,9 @@
"required" : true,
"enum" : ["leddevice"]
},
"instance" : {
"type" : "integer"
},
"tan" : {
"type" : "integer"
},

View File

@@ -7,6 +7,12 @@
"required" : true,
"enum" : ["processing"]
},
"instance" : {
"type": "array",
"required": false,
"items" : {},
"minItems": 1
},
"tan" : {
"type" : "integer"
},

View File

@@ -7,6 +7,25 @@
"required" : true,
"enum" : ["serverinfo"]
},
"subcommand": {
"type": "string",
"enum": ["getInfo", "subscribe", "unsubscribe", "getSubscriptions", "getSubscriptionCommands"]
},
"instance" : {
"type" : "integer",
"minimum": 0,
"maximum": 255
},
"data": {
"type": ["null", "array"],
"properties": {
"subscriptions": {
"type": "array",
"items": {}
}
},
"additionalProperties": false
},
"subscribe" : {
"type" : "array"
},

View File

@@ -7,6 +7,12 @@
"required" : true,
"enum" : ["sourceselect"]
},
"instance" : {
"type": "array",
"required": false,
"items" : {},
"minItems": 1
},
"tan" : {
"type" : "integer"
},

File diff suppressed because it is too large Load Diff

View File

@@ -1,416 +0,0 @@
// proj incl
#include <api/JsonCB.h>
// hyperion
#include <hyperion/Hyperion.h>
// HyperionIManager
#include <hyperion/HyperionIManager.h>
// components
#include <hyperion/ComponentRegister.h>
// priorityMuxer
#include <hyperion/PriorityMuxer.h>
// utils
#include <utils/ColorSys.h>
// qt
#include <QDateTime>
#include <QVariant>
// Image to led map helper
#include <hyperion/ImageProcessor.h>
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<PriorityMuxer::InputsMap>("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<int> 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<EffectDefinition> & 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<AuthManager::AuthDefinition> &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));
}

View File

@@ -0,0 +1,459 @@
#include <api/JsonCallbacks.h>
#include <api/JsonInfo.h>
#include <api/JsonApiSubscription.h>
#include <hyperion/Hyperion.h>
#include <hyperion/HyperionIManager.h>
#include <events/EventHandler.h>
#include <hyperion/ComponentRegister.h>
#include <hyperion/PriorityMuxer.h>
#include <utils/ColorSys.h>
#include <hyperion/ImageProcessor.h>
#include <QDateTime>
#include <QVariant>
#include <QImage>
#include <QBuffer>
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<PriorityMuxer::InputsMap>("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::EventUpdate:
connect(EventHandler::getInstance().data(), &EventHandler::signalEvent, this, &JsonCallbacks::handleEventUpdate);
break;
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::EventUpdate:
disconnect(EventHandler::getInstance().data(), &EventHandler::signalEvent, this, &JsonCallbacks::handleEventUpdate);
break;
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()
{
const QSet<Subscription::Type> currentSubscriptions = _subscribedCommands;
for (QSet<Subscription::Type>::const_iterator it = currentSubscriptions.constBegin(); it != currentSubscriptions.constEnd(); ++it)
{
unsubscribe(*it);
}
}
void JsonCallbacks::setSubscriptionsTo(Hyperion* hyperion)
{
assert(hyperion);
// get current subs
const QSet<Subscription::Type> 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["command"] = Subscription::toString(cmd);
if (Subscription::isInstanceSpecific(cmd))
{
obj["instance"] = _hyperion->getInstanceIndex();
}
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<AuthManager::AuthDefinition> &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<ColorRgb> &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<ColorRgb> &image)
{
QImage jpgImage(reinterpret_cast<const uchar*>(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));
}
void JsonCallbacks::handleEventUpdate(const Event &event)
{
QJsonObject result;
result["event"] = eventToString(event);
doCallback(Subscription::EventUpdate, QVariant(result));
}

620
libsrc/api/JsonInfo.cpp Normal file
View File

@@ -0,0 +1,620 @@
#include <api/JsonInfo.h>
#include <api/API.h>
#include <utils/ColorSys.h>
#include <hyperion/GrabberWrapper.h>
#include <leddevice/LedDeviceWrapper.h>
#include <utils/SysInfo.h>
#include <hyperion/AuthManager.h>
#include <QCoreApplication>
#include <QApplication>
#include <HyperionConfig.h> // Required to determine the cmake options
#include <hyperion/GrabberWrapper.h>
#include <grabber/GrabberConfig.h>
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<int> activePriorities = activeInputs.keys();
activePriorities.removeAll(PriorityMuxer::LOWEST_PRIORITY);
for(int priority : std::as_const(activePriorities))
{
const PriorityMuxer::InputInfo priorityInfo = activeInputs.value(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(static_cast<double>(Hue));
HSLValue.append(static_cast<double>(Saturation));
HSLValue.append(static_cast<double>(Luminace));
LEDcolor.insert("HSL", HSLValue);
item["value"] = LEDcolor;
}
(priority == currentPriority)
? priorities.prepend(item)
: priorities.append(item);
}
return priorities;
}
QJsonArray JsonInfo::getEffects(const Hyperion* hyperion)
{
QJsonArray effects;
#if defined(ENABLE_EFFECTENGINE)
// collect effect info
const std::list<EffectDefinition> &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);
}
#endif
return effects;
}
QJsonObject JsonInfo::getAvailableLedDevices()
{
// get available led devices
QJsonObject ledDevices;
QJsonArray availableLedDevices;
for (const auto& dev : LedDeviceWrapper::getDeviceMap())
{
availableLedDevices.append(dev.first);
}
ledDevices["available"] = availableLedDevices;
return ledDevices;
}
QJsonArray JsonInfo::getAvailableScreenGrabbers()
{
QJsonArray availableScreenGrabbers;
for (const auto& grabber : GrabberWrapper::availableGrabbers(GrabberTypeFilter::SCREEN))
{
availableScreenGrabbers.append(grabber);
}
return availableScreenGrabbers;
}
QJsonArray JsonInfo::getAvailableVideoGrabbers()
{
QJsonArray availableVideoGrabbers;
for (const auto& grabber : GrabberWrapper::availableGrabbers(GrabberTypeFilter::VIDEO))
{
availableVideoGrabbers.append(grabber);
}
return availableVideoGrabbers;
}
QJsonArray JsonInfo::getAvailableAudioGrabbers()
{
QJsonArray availableAudioGrabbers;
for (const auto& grabber : GrabberWrapper::availableGrabbers(GrabberTypeFilter::AUDIO))
{
availableAudioGrabbers.append(grabber);
}
return availableAudioGrabbers;
}
QJsonObject JsonInfo::getGrabbers(const Hyperion* hyperion)
{
QJsonObject grabbers;
// SCREEN
QJsonObject screenGrabbers;
if (GrabberWrapper::getInstance() != nullptr)
{
const QStringList activeGrabbers = GrabberWrapper::getInstance()->getActive(hyperion->getInstanceIndex(), GrabberTypeFilter::SCREEN);
QJsonArray activeGrabberNames;
for (const auto& grabberName : activeGrabbers)
{
activeGrabberNames.append(grabberName);
}
screenGrabbers["active"] = activeGrabberNames;
}
screenGrabbers["available"] = getAvailableScreenGrabbers();
// VIDEO
QJsonObject videoGrabbers;
if (GrabberWrapper::getInstance() != nullptr)
{
const QStringList activeGrabbers = GrabberWrapper::getInstance()->getActive(hyperion->getInstanceIndex(), GrabberTypeFilter::VIDEO);
QJsonArray activeGrabberNames;
for (const auto& grabberName : activeGrabbers)
{
activeGrabberNames.append(grabberName);
}
videoGrabbers["active"] = activeGrabberNames;
}
videoGrabbers["available"] = getAvailableVideoGrabbers();
// AUDIO
QJsonObject audioGrabbers;
if (GrabberWrapper::getInstance() != nullptr)
{
const QStringList activeGrabbers = GrabberWrapper::getInstance()->getActive(hyperion->getInstanceIndex(), GrabberTypeFilter::AUDIO);
QJsonArray activeGrabberNames;
for (const auto& grabberName : activeGrabbers)
{
activeGrabberNames.append(grabberName);
}
audioGrabbers["active"] = activeGrabberNames;
}
audioGrabbers["available"] = getAvailableAudioGrabbers() ;
grabbers.insert("screen", screenGrabbers);
grabbers.insert("video", videoGrabbers);
grabbers.insert("audio", audioGrabbers);
return grabbers;
}
QJsonObject JsonInfo::getCecInfo()
{
QJsonObject cecInfo;
#if defined(ENABLE_CEC)
cecInfo["enabled"] = true;
#else
cecInfo["enabled"] = false;
#endif
return cecInfo;
}
QJsonArray JsonInfo::getServices()
{
// 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 (!getAvailableScreenGrabbers().isEmpty() || !getAvailableVideoGrabbers().isEmpty() || services.contains("flatbuffer") || services.contains("protobuffer"))
{
services.append("borderdetection");
}
return services;
}
QJsonArray JsonInfo::getComponents(const Hyperion* hyperion)
{
// get available components
QJsonArray component;
std::map<hyperion::Components, bool> 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);
}
return component;
}
QJsonArray JsonInfo::getInstanceInfo()
{
QJsonArray instanceInfo;
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());
instanceInfo.append(obj);
}
return instanceInfo;
}
QJsonArray JsonInfo::getTransformationInfo(const Hyperion* hyperion)
{
// TRANSFORM INFORMATION (DEFAULT VALUES)
QJsonArray transformArray;
for (const QString &transformId : hyperion->getAdjustmentIds())
{
QJsonObject transform;
QJsonArray blacklevel;
QJsonArray whitelevel;
QJsonArray gamma;
QJsonArray 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);
}
return transformArray;
}
QJsonArray JsonInfo::getActiveEffects(const Hyperion* hyperion)
{
// ACTIVE EFFECT INFO
QJsonArray activeEffects;
#if defined(ENABLE_EFFECTENGINE)
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);
}
}
#endif
return activeEffects;
}
QJsonArray JsonInfo::getActiveColors(const Hyperion* hyperion)
{
// 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;
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(static_cast<double>(Hue));
HSLValue.append(static_cast<double>(Saturation));
HSLValue.append(static_cast<double>(Luminace));
LEDcolor.insert("HSL Value", HSLValue);
activeLedColors.append(LEDcolor);
}
}
return activeLedColors;
}
QJsonObject JsonInfo::getSystemInfo(const Hyperion* hyperion)
{
QJsonObject info;
SysInfo::HyperionSysInfo data = SysInfo::get();
QJsonObject systemInfo;
systemInfo["kernelType"] = data.kernelType;
systemInfo["kernelVersion"] = data.kernelVersion;
systemInfo["architecture"] = data.architecture;
systemInfo["cpuModelName"] = data.cpuModelName;
systemInfo["cpuModelType"] = data.cpuModelType;
systemInfo["cpuHardware"] = data.cpuHardware;
systemInfo["cpuRevision"] = data.cpuRevision;
systemInfo["wordSize"] = data.wordSize;
systemInfo["productType"] = data.productType;
systemInfo["productVersion"] = data.productVersion;
systemInfo["prettyName"] = data.prettyName;
systemInfo["hostName"] = data.hostName;
systemInfo["domainName"] = data.domainName;
systemInfo["isUserAdmin"] = data.isUserAdmin;
systemInfo["qtVersion"] = data.qtVersion;
#if defined(ENABLE_EFFECTENGINE)
systemInfo["pyVersion"] = data.pyVersion;
#endif
info["system"] = systemInfo;
QJsonObject hyperionInfo;
hyperionInfo["version"] = QString(HYPERION_VERSION);
hyperionInfo["build"] = QString(HYPERION_BUILD_ID);
hyperionInfo["gitremote"] = QString(HYPERION_GIT_REMOTE);
hyperionInfo["time"] = QString(__DATE__ " " __TIME__);
hyperionInfo["id"] = AuthManager::getInstance()->getID();
hyperionInfo["rootPath"] = HyperionIManager::getInstance()->getRootPath();
hyperionInfo["readOnlyMode"] = hyperion->getReadOnlyMode();
QCoreApplication* app = QCoreApplication::instance();
hyperionInfo["isGuiMode"] = qobject_cast<QApplication*>(app) != nullptr;
info["hyperion"] = hyperionInfo;
return info;
}
QJsonObject JsonInfo::discoverSources(const QString& sourceType, const QJsonObject& params)
{
QJsonObject inputSourcesDiscovered;
inputSourcesDiscovered.insert("sourceType", sourceType);
if (sourceType == "video") {
QJsonArray videoInputs = discoverVideoInputs(params);
inputSourcesDiscovered["video_sources"] = videoInputs;
} else if (sourceType == "audio") {
QJsonArray audioInputs = discoverAudioInputs(params);
inputSourcesDiscovered["audio_sources"] = audioInputs;
} else if (sourceType == "screen") {
QJsonArray screenInputs = discoverScreenInputs(params);
inputSourcesDiscovered["video_sources"] = screenInputs;
}
return inputSourcesDiscovered;
}
template<typename GrabberType>
void JsonInfo::discoverGrabber(QJsonArray& inputs, const QJsonObject& params) const
{
GrabberType grabber;
QJsonValue discoveryResult = grabber.discover(params);
if (discoveryResult.isArray())
{
inputs = discoveryResult.toArray();
}
else
{
if (!discoveryResult.toObject().isEmpty())
{
inputs.append(discoveryResult);
}
}
}
QJsonArray JsonInfo::discoverVideoInputs(const QJsonObject& params) const
{
QJsonArray videoInputs;
#ifdef ENABLE_V4L2
discoverGrabber<V4L2Grabber>(videoInputs, params);
#endif
#ifdef ENABLE_MF
discoverGrabber<MFGrabber>(videoInputs, params);
#endif
return videoInputs;
}
QJsonArray JsonInfo::discoverAudioInputs(const QJsonObject& params) const
{
QJsonArray audioInputs;
#ifdef ENABLE_AUDIO
#ifdef WIN32
discoverGrabber<AudioGrabberWindows>(audioInputs, params);
#endif
#ifdef __linux__audioInputs
discoverGrabber<AudioGrabberLinux>(audioInputs, params);
#endif
#endif
return audioInputs;
}
QJsonArray JsonInfo::discoverScreenInputs(const QJsonObject& params) const
{
QJsonArray screenInputs;
#ifdef ENABLE_QT
discoverGrabber<QtGrabber>(screenInputs, params);
#endif
#ifdef ENABLE_DX
discoverGrabber<DirectXGrabber>(screenInputs, params);
#endif
#ifdef ENABLE_X11
discoverGrabber<X11Grabber>(screenInputs, params);
#endif
#ifdef ENABLE_XCB
discoverGrabber<XcbGrabber>(screenInputs, params);
#endif
#if defined(ENABLE_FB) && !defined(ENABLE_AMLOGIC)
discoverGrabber<FramebufferFrameGrabber>(screenInputs, params);
#endif
#ifdef ENABLE_DISPMANX
discoverGrabber<DispmanxFrameGrabber>(screenInputs, params);
#endif
#ifdef ENABLE_AMLOGIC
discoverGrabber<AmlogicGrabber>(screenInputs, params);
#endif
#ifdef ENABLE_OSX
discoverGrabber<OsxFrameGrabber>(screenInputs, params);
#endif
return screenInputs;
}

View File

@@ -103,7 +103,7 @@ QString EffectFileHandler::saveEffect(const QJsonObject& message)
if (it != effectsSchemas.end())
{
if (!JsonUtils::validate("EffectFileHandler", message["args"].toObject(), it->schemaFile, _log))
if (!JsonUtils::validate("EffectFileHandler", message["args"].toObject(), it->schemaFile, _log).first)
{
return "Error during arg validation against schema, please consult the Hyperion Log";
}
@@ -298,12 +298,12 @@ bool EffectFileHandler::loadEffectDefinition(const QString& path, const QString&
// Read and parse the effect json config file
QJsonObject configEffect;
if (!JsonUtils::readFile(fileName, configEffect, _log)) {
if (!JsonUtils::readFile(fileName, configEffect, _log).first) {
return false;
}
// validate effect config with effect schema(path)
if (!JsonUtils::validate(fileName, configEffect, ":effect-schema", _log)) {
if (!JsonUtils::validate(fileName, configEffect, ":effect-schema", _log).first) {
return false;
}
@@ -335,7 +335,7 @@ bool EffectFileHandler::loadEffectSchema(const QString& path, const QString& sch
{
// Read and parse the effect schema file
QJsonObject schemaEffect;
if (!JsonUtils::readFile(schemaFilePath, schemaEffect, _log))
if (!JsonUtils::readFile(schemaFilePath, schemaEffect, _log).first)
{
return false;
}

View File

@@ -144,7 +144,7 @@ void EventHandler::handleEvent(Event event)
{
QObject *senderObj = QObject::sender();
QString senderObjectClass;
if (senderObj)
if (senderObj != nullptr)
{
senderObjectClass = senderObj->metaObject()->className();
} else
@@ -179,13 +179,19 @@ void EventHandler::handleEvent(Event event)
break;
case Event::Reload:
emit signalEvent(Event::Reload);
Process::restartHyperion(10);
break;
case Event::Restart:
emit signalEvent(Event::Restart);
Process::restartHyperion(11);
break;
case Event::Quit:
emit signalEvent(Event::Quit);
break;
default:
Error(_log,"Unkonwn Event '%d' received", event);
break;

View File

@@ -35,7 +35,7 @@ OsEventHandlerBase::OsEventHandlerBase()
_log = Logger::getInstance("EVENTS-OS");
QCoreApplication* app = QCoreApplication::instance();
if (!qobject_cast<QApplication*>(app))
if (qobject_cast<QApplication*>(app) == nullptr)
{
_isService = true;
}
@@ -46,6 +46,7 @@ OsEventHandlerBase::OsEventHandlerBase()
OsEventHandlerBase::~OsEventHandlerBase()
{
quit();
QObject::disconnect(this, &OsEventHandlerBase::signalEvent, EventHandler::getInstance().data(), &EventHandler::handleEvent);
OsEventHandlerBase::unregisterLockHandler();
@@ -130,6 +131,11 @@ void OsEventHandlerBase::lock(bool isLocked)
}
}
void OsEventHandlerBase::quit()
{
emit signalEvent(Event::Quit);
}
#if defined(_WIN32)
OsEventHandlerWindows* OsEventHandlerWindows::getInstance()

View File

@@ -15,7 +15,6 @@ AuthManager::AuthManager(QObject *parent, bool readonlyMode)
, _authTable(new AuthTable("", this, readonlyMode))
, _metaTable(new MetaTable(this, readonlyMode))
, _pendingRequests()
, _authRequired(true)
, _timer(new QTimer(this))
, _authBlockTimer(new QTimer(this))
{
@@ -36,13 +35,13 @@ AuthManager::AuthManager(QObject *parent, bool readonlyMode)
connect(_authBlockTimer, &QTimer::timeout, this, &AuthManager::checkAuthBlockTimeout);
// init with default user and password
if (!_authTable->userExist("Hyperion"))
if (!_authTable->userExist(hyperion::DEFAULT_USER))
{
_authTable->createUser("Hyperion", "hyperion");
_authTable->createUser(hyperion::DEFAULT_USER, hyperion::DEFAULT_PASSWORD);
}
// update Hyperion user token on startup
_authTable->setUserToken("Hyperion");
_authTable->setUserToken(hyperion::DEFAULT_USER);
}
AuthManager::AuthDefinition AuthManager::createToken(const QString &comment)
@@ -201,6 +200,8 @@ QVector<AuthManager::AuthDefinition> AuthManager::getPendingRequests() const
def.comment = entry.comment;
def.id = entry.id;
def.timeoutTime = entry.timeoutTime - QDateTime::currentMSecsSinceEpoch();
def.tan = entry.tan;
def.caller = nullptr;
finalVec.append(def);
}
return finalVec;
@@ -208,20 +209,26 @@ QVector<AuthManager::AuthDefinition> AuthManager::getPendingRequests() const
bool AuthManager::renameToken(const QString &id, const QString &comment)
{
if (_authTable->renameToken(id, comment))
if (_authTable->idExist(id))
{
emit tokenChange(getTokenList());
return true;
if (_authTable->renameToken(id, comment))
{
emit tokenChange(getTokenList());
return true;
}
}
return false;
}
bool AuthManager::deleteToken(const QString &id)
{
if (_authTable->deleteToken(id))
if (_authTable->idExist(id))
{
emit tokenChange(getTokenList());
return true;
if (_authTable->deleteToken(id))
{
emit tokenChange(getTokenList());
return true;
}
}
return false;
}
@@ -231,9 +238,7 @@ void AuthManager::handleSettingsUpdate(settings::type type, const QJsonDocument
if (type == settings::NETWORK)
{
const QJsonObject &obj = config.object();
_authRequired = obj["apiAuth"].toBool(true);
_localAuthRequired = obj["localApiAuth"].toBool(false);
_localAdminAuthRequired = obj["localAdminAuth"].toBool(true);
}
}

View File

@@ -550,6 +550,11 @@ QList<int> Hyperion::getActivePriorities() const
return _muxer->getPriorities();
}
Hyperion::InputsMap Hyperion::getPriorityInfo() const
{
return _muxer->getInputInfo();
}
Hyperion::InputInfo Hyperion::getPriorityInfo(int priority) const
{
return _muxer->getInputInfo(priority);

View File

@@ -45,6 +45,11 @@ QVector<QVariantMap> HyperionIManager::getInstanceData() const
return instances;
}
QList<quint8> HyperionIManager::getRunningInstanceIdx() const
{
return _runningInstances.keys();
}
void HyperionIManager::startAll()
{
for(const auto & entry : _instanceTable->getAllInstances(true))

View File

@@ -128,6 +128,11 @@ bool PriorityMuxer::hasPriority(int priority) const
return (priority == PriorityMuxer::LOWEST_PRIORITY) ? true : _activeInputs.contains(priority);
}
PriorityMuxer::InputsMap PriorityMuxer::getInputInfo() const
{
return _activeInputs;
}
PriorityMuxer::InputInfo PriorityMuxer::getInputInfo(int priority) const
{
auto elemIt = _activeInputs.constFind(priority);

View File

@@ -52,7 +52,7 @@ SettingsManager::SettingsManager(quint8 instance, QObject* parent, bool readonly
// get default config
QJsonObject defaultConfig;
if (!JsonUtils::readFile(":/hyperion_default.config", defaultConfig, _log))
if (!JsonUtils::readFile(":/hyperion_default.config", defaultConfig, _log).first)
{
throw std::runtime_error("Failed to read default config");
}

View File

@@ -4,26 +4,13 @@
"required" : true,
"properties" :
{
"apiAuth" :
{
"type" : "boolean",
"title" : "edt_conf_net_apiAuth_title",
"required" : true,
"default" : true,
"propertyOrder" : 1
},
"internetAccessAPI" :
{
"type" : "boolean",
"title" : "edt_conf_net_internetAccessAPI_title",
"required" : true,
"default" : false,
"options": {
"dependencies": {
"apiAuth": true
}
},
"propertyOrder" : 2
"propertyOrder" : 1
},
"restirctedInternetAccessAPI" :
{
@@ -36,7 +23,7 @@
"internetAccessAPI": true
}
},
"propertyOrder" : 3
"propertyOrder" : 2
},
"ipWhitelist" :
{
@@ -53,7 +40,7 @@
"restirctedInternetAccessAPI": true
}
},
"propertyOrder" : 4
"propertyOrder" : 3
},
"localApiAuth" :
{
@@ -66,15 +53,7 @@
"apiAuth": true
}
},
"propertyOrder" : 5
},
"localAdminAuth" :
{
"type" : "boolean",
"title" : "edt_conf_net_localAdminAuth_title",
"required" : true,
"default" : true,
"propertyOrder" : 5
"propertyOrder" : 4
}
},
"additionalProperties" : false

View File

@@ -193,11 +193,17 @@ QJsonObject LedDeviceWrapper::getLedDeviceSchemas()
}
QJsonObject schema;
if(!JsonUtils::parse(schemaPath, data, schema, Logger::getInstance("LEDDEVICE")))
QPair<bool, QStringList> parsingResult = JsonUtils::parse(schemaPath, data, schema, Logger::getInstance("LEDDEVICE"));
if (!parsingResult.first)
{
throw std::runtime_error("ERROR: JSON schema wrong of file: " + item.toStdString());
QStringList errorList = parsingResult.second;
for (const auto& errorMessage : errorList) {
Debug(Logger::getInstance("LEDDEVICE"), "JSON parse error: %s ", QSTRING_CSTR(errorMessage));
}
throw std::runtime_error("ERROR: JSON schema is wrong for file: " + item.toStdString());
}
schemaJson = schema;
schemaJson["title"] = QString("edt_dev_spec_header_title");

View File

@@ -8,25 +8,26 @@
#include <QRegularExpression>
#include <QJsonObject>
#include <QJsonParseError>
#include <QStringList>
namespace JsonUtils {
bool readFile(const QString& path, QJsonObject& obj, Logger* log, bool ignError)
QPair<bool, QStringList> readFile(const QString& path, QJsonObject& obj, Logger* log, bool ignError)
{
QString data;
if(!FileUtils::readFile(path, data, log, ignError))
return false;
{
return qMakePair(false, QStringList(QString("Error reading file: %1").arg(path)));
}
if(!parse(path, data, obj, log))
return false;
return true;
QPair<bool, QStringList> parsingResult = JsonUtils::parse(path, data, obj, log);
return parsingResult;
}
bool readSchema(const QString& path, QJsonObject& obj, Logger* log)
{
QJsonObject schema;
if(!readFile(path, schema, log))
if(!readFile(path, schema, log).first)
return false;
if(!resolveRefs(schema, obj, log))
@@ -35,80 +36,89 @@ namespace JsonUtils {
return true;
}
bool parse(const QString& path, const QString& data, QJsonObject& obj, Logger* log)
QPair<bool, QStringList> parse(const QString& path, const QString& data, QJsonObject& obj, Logger* log)
{
QJsonDocument doc;
if(!parse(path, data, doc, log))
return false;
QPair<bool, QStringList> parsingResult = JsonUtils::parse(path, data, doc, log);
obj = doc.object();
return true;
return parsingResult;
}
bool parse(const QString& path, const QString& data, QJsonArray& arr, Logger* log)
QPair<bool, QStringList> parse(const QString& path, const QString& data, QJsonArray& arr, Logger* log)
{
QJsonDocument doc;
if(!parse(path, data, doc, log))
return false;
QPair<bool, QStringList> parsingResult = JsonUtils::parse(path, data, doc, log);
arr = doc.array();
return true;
return parsingResult;
}
bool parse(const QString& path, const QString& data, QJsonDocument& doc, Logger* log)
QPair<bool, QStringList> parse(const QString& path, const QString& data, QJsonDocument& doc, Logger* log)
{
//remove Comments in data
QString cleanData = data;
QStringList errorList;
QJsonParseError error;
doc = QJsonDocument::fromJson(cleanData.toUtf8(), &error);
doc = QJsonDocument::fromJson(data.toUtf8(), &error);
if (error.error != QJsonParseError::NoError)
{
// report to the user the failure and their locations in the document.
int errorLine(0), errorColumn(0);
int errorLine = 1;
int errorColumn = 1;
for( int i=0, count=qMin( error.offset,cleanData.size()); i<count; ++i )
int lastNewlineIndex = data.lastIndexOf("\n", error.offset - 1);
if (lastNewlineIndex != -1)
{
++errorColumn;
if(data.at(i) == '\n' )
{
errorColumn = 0;
++errorLine;
}
errorColumn = error.offset - lastNewlineIndex ;
}
Error(log, "Failed to parse json data from %s: Error: %s at Line: %i, Column: %i, Data: '%s'", QSTRING_CSTR(path), QSTRING_CSTR(error.errorString()), errorLine, errorColumn, QSTRING_CSTR(data));
return false;
errorLine += data.left(error.offset).count('\n');
const QString errorMessage = QString("JSON parse error: %1, line: %2, column: %3, Data: '%4'")
.arg(error.errorString())
.arg(errorLine)
.arg(errorColumn)
.arg(data);
errorList.push_back(errorMessage);
Error(log, "%s", QSTRING_CSTR(errorMessage));
return qMakePair(false, errorList);
}
return true;
return qMakePair(true, errorList);
}
bool validate(const QString& file, const QJsonObject& json, const QString& schemaPath, Logger* log)
QPair<bool, QStringList> validate(const QString& file, const QJsonObject& json, const QString& schemaPath, Logger* log)
{
// get the schema data
QJsonObject schema;
if(!readFile(schemaPath, schema, log))
return false;
if(!validate(file, json, schema, log))
return false;
return true;
QPair<bool, QStringList> readResult = readFile(schemaPath, schema, log);
if(!readResult.first)
{
return readResult;
}
QPair<bool, QStringList> validationResult = validate(file, json, schema, log);
return validationResult;
}
bool validate(const QString& file, const QJsonObject& json, const QJsonObject& schema, Logger* log)
QPair<bool, QStringList> validate(const QString& file, const QJsonObject& json, const QJsonObject& schema, Logger* log)
{
QStringList errorList;
QJsonSchemaChecker schemaChecker;
schemaChecker.setSchema(schema);
if (!schemaChecker.validate(json).first)
{
const QStringList & errors = schemaChecker.getMessages();
for (auto & error : errors)
const QStringList &errors = schemaChecker.getMessages();
for (const auto& error : errors)
{
Error(log, "While validating schema against json data of '%s':%s", QSTRING_CSTR(file), QSTRING_CSTR(error));
QString errorMessage = QString("JSON parse error: %1")
.arg(error);
errorList.push_back(errorMessage);
Error(log, "%s", QSTRING_CSTR(errorMessage));
}
return false;
return qMakePair(false, errorList);
}
return true;
return qMakePair(true, errorList);
}
bool write(const QString& filename, const QJsonObject& json, Logger* log)

View File

@@ -1,13 +1,15 @@
#include <utils/NetOrigin.h>
#include <QJsonObject>
#include <QNetworkInterface>
NetOrigin* NetOrigin::instance = nullptr;
NetOrigin::NetOrigin(QObject* parent, Logger* log)
: QObject(parent)
, _log(log)
, _internetAccessAllowed(false)
, _isInternetAccessAllowed(false)
, _isInternetAccessRestricted(false)
, _ipWhitelist()
{
NetOrigin::instance = this;
@@ -15,37 +17,73 @@ NetOrigin::NetOrigin(QObject* parent, Logger* log)
bool NetOrigin::accessAllowed(const QHostAddress& address, const QHostAddress& local) const
{
if(_internetAccessAllowed)
return true;
bool isAllowed {false};
if(_ipWhitelist.contains(address)) // v4 and v6
return true;
if(!isLocalAddress(address, local))
if(isLocalAddress(address, local))
{
Warning(_log,"Client connection with IP address '%s' has been rejected! It's not whitelisted, access denied.",QSTRING_CSTR(address.toString()));
return false;
isAllowed = true;
}
return true;
else
{
if(_isInternetAccessAllowed)
{
if (!_isInternetAccessRestricted)
{
isAllowed = true;
}
else
{
for (const QHostAddress &listAddress : _ipWhitelist)
{
if (address.isEqual(listAddress))
{
isAllowed = true;
break;
}
}
WarningIf(!isAllowed, _log,"Client connection from IP address '%s' has been rejected! It's not whitelisted.",QSTRING_CSTR(address.toString()));
}
}
}
return isAllowed;
}
bool NetOrigin::isLocalAddress(const QHostAddress& address, const QHostAddress& local) const
bool NetOrigin::isLocalAddress(const QHostAddress& ipAddress, const QHostAddress& /*local*/) const
{
if(address.protocol() == QAbstractSocket::IPv4Protocol)
QHostAddress address = ipAddress;
if (address.isLoopback() || address.isLinkLocal())
{
if(!address.isInSubnet(local, 24)) // 255.255.255.xxx; IPv4 0-32
{
return false;
return true;
}
//Convert to IPv4 to check, if an IPv6 address is an IPv4 mapped address
QHostAddress ipv4Address(address.toIPv4Address());
if (ipv4Address != QHostAddress::AnyIPv4) // ipv4Address is not "0.0.0.0"
{
address = ipv4Address;
}
QList<QNetworkInterface> allInterfaces = QNetworkInterface::allInterfaces();
for (const QNetworkInterface &networkInterface : allInterfaces) {
QList<QNetworkAddressEntry> addressEntries = networkInterface.addressEntries();
for (const QNetworkAddressEntry &localNetworkAddressEntry : addressEntries) {
QHostAddress localIP = localNetworkAddressEntry.ip();
if(localIP.protocol() != QAbstractSocket::NetworkLayerProtocol::IPv4Protocol)
{
continue;
}
bool isInSubnet = address.isInSubnet(localIP, localNetworkAddressEntry.prefixLength());
if (isInSubnet)
{
return true;
}
}
}
else if(address.protocol() == QAbstractSocket::IPv6Protocol)
{
if(!address.isInSubnet(local, 64)) // 2001:db8:abcd:0012:XXXX:XXXX:XXXX:XXXX; IPv6 0-128
{
return false;
}
}
return true;
return false;
}
void NetOrigin::handleSettingsUpdate(settings::type type, const QJsonDocument& config)
@@ -53,16 +91,19 @@ void NetOrigin::handleSettingsUpdate(settings::type type, const QJsonDocument& c
if(type == settings::NETWORK)
{
const QJsonObject& obj = config.object();
_internetAccessAllowed = obj["internetAccessAPI"].toBool(false);
_isInternetAccessAllowed = obj["internetAccessAPI"].toBool(false);
_isInternetAccessRestricted = obj["restirctedInternetAccessAPI"].toBool(false);
const QJsonArray arr = obj["ipWhitelist"].toArray();
const QJsonArray& arr = obj["ipWhitelist"].toArray();
_ipWhitelist.clear();
_ipWhitelist.clear();
for(const auto& e : arr)
for(const auto& item : std::as_const(arr))
{
const QString& entry = e.toString("");
const QString& entry = item.toString("");
if(entry.isEmpty())
{
continue;
}
QHostAddress host(entry);
if(host.isNull())