mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2025-03-01 10:33:28 +00:00
Refactor Hyperion JSON-API (#1727)
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
@@ -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
|
||||
)
|
||||
|
||||
|
@@ -7,6 +7,12 @@
|
||||
"required" : true,
|
||||
"enum" : ["adjustment"]
|
||||
},
|
||||
"instance" : {
|
||||
"type": "array",
|
||||
"required": false,
|
||||
"items" : {},
|
||||
"minItems": 1
|
||||
},
|
||||
"tan" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
|
@@ -7,6 +7,12 @@
|
||||
"required" : true,
|
||||
"enum" : ["clear"]
|
||||
},
|
||||
"instance" : {
|
||||
"type": "array",
|
||||
"required": false,
|
||||
"items" : {},
|
||||
"minItems": 1
|
||||
},
|
||||
"tan" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
|
@@ -7,6 +7,12 @@
|
||||
"required" : true,
|
||||
"enum" : ["clearall"]
|
||||
},
|
||||
"instance" : {
|
||||
"type": "array",
|
||||
"required": false,
|
||||
"items" : {},
|
||||
"minItems": 1
|
||||
},
|
||||
"tan" : {
|
||||
"type" : "integer"
|
||||
}
|
||||
|
@@ -7,6 +7,12 @@
|
||||
"required" : true,
|
||||
"enum" : ["color"]
|
||||
},
|
||||
"instance" : {
|
||||
"type": "array",
|
||||
"required": false,
|
||||
"items" : {},
|
||||
"minItems": 1
|
||||
},
|
||||
"tan" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
|
@@ -9,6 +9,12 @@
|
||||
"required" : true,
|
||||
"enum" : ["componentstate"]
|
||||
},
|
||||
"instance" : {
|
||||
"type": "array",
|
||||
"required": false,
|
||||
"items" : {},
|
||||
"minItems": 1
|
||||
},
|
||||
"tan" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
|
@@ -12,6 +12,11 @@
|
||||
"required" : true,
|
||||
"enum" : ["getconfig","getschema","setconfig","restoreconfig","reload"]
|
||||
},
|
||||
"instance" : {
|
||||
"type" : "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 255
|
||||
},
|
||||
"tan" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
|
@@ -7,6 +7,11 @@
|
||||
"required" : true,
|
||||
"enum" : ["create-effect"]
|
||||
},
|
||||
"instance" : {
|
||||
"type" : "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 255
|
||||
},
|
||||
"tan" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
|
@@ -8,6 +8,11 @@
|
||||
"required" : true,
|
||||
"enum" : ["delete-effect"]
|
||||
},
|
||||
"instance" : {
|
||||
"type" : "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 255
|
||||
},
|
||||
"tan" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
|
@@ -7,6 +7,12 @@
|
||||
"required" : true,
|
||||
"enum" : ["effect"]
|
||||
},
|
||||
"instance" : {
|
||||
"type": "array",
|
||||
"required": false,
|
||||
"items" : {},
|
||||
"minItems": 1
|
||||
},
|
||||
"tan" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
|
@@ -7,6 +7,12 @@
|
||||
"required" : true,
|
||||
"enum" : ["image"]
|
||||
},
|
||||
"instance" : {
|
||||
"type": "array",
|
||||
"required": false,
|
||||
"items" : {},
|
||||
"minItems": 1
|
||||
},
|
||||
"tan" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
|
@@ -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"]
|
||||
}
|
||||
},
|
||||
|
||||
|
@@ -7,6 +7,9 @@
|
||||
"required" : true,
|
||||
"enum" : ["leddevice"]
|
||||
},
|
||||
"instance" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
"tan" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
|
@@ -7,6 +7,12 @@
|
||||
"required" : true,
|
||||
"enum" : ["processing"]
|
||||
},
|
||||
"instance" : {
|
||||
"type": "array",
|
||||
"required": false,
|
||||
"items" : {},
|
||||
"minItems": 1
|
||||
},
|
||||
"tan" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
|
@@ -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"
|
||||
},
|
||||
|
@@ -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
@@ -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));
|
||||
}
|
459
libsrc/api/JsonCallbacks.cpp
Normal file
459
libsrc/api/JsonCallbacks.cpp
Normal 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
620
libsrc/api/JsonInfo.cpp
Normal 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;
|
||||
}
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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()
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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))
|
||||
|
@@ -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);
|
||||
|
@@ -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");
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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");
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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())
|
||||
|
Reference in New Issue
Block a user