diff --git a/include/utils/ColorRgb.h b/include/utils/ColorRgb.h index ae4d3145f..901b000ce 100644 --- a/include/utils/ColorRgb.h +++ b/include/utils/ColorRgb.h @@ -4,6 +4,7 @@ #include #include +#include #include /// diff --git a/include/utils/Process.h b/include/utils/Process.h index fcd06a4da..f8da8e65b 100644 --- a/include/utils/Process.h +++ b/include/utils/Process.h @@ -5,7 +5,7 @@ namespace Process { -void restartHyperion(bool asNewProcess=false); +void restartHyperion(int exitCode = 0); QByteArray command_exec(const QString& cmd, const QByteArray& data = {}); } diff --git a/libsrc/api/JsonAPI.cpp b/libsrc/api/JsonAPI.cpp index 104fd9011..0901d5cf5 100644 --- a/libsrc/api/JsonAPI.cpp +++ b/libsrc/api/JsonAPI.cpp @@ -992,7 +992,7 @@ void JsonAPI::handleConfigCommand(const QJsonObject &message, const QString &com { Debug(_log, "Restarting due to RPC command"); - Process::restartHyperion(); + Process::restartHyperion(10); sendSuccessReply(command + "-" + subcommand, tan); } @@ -1427,7 +1427,7 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject &message, const QString & if (!token.isEmpty()) { // userToken is longer - if (token.count() > 36) + if (token.size() > 36) { if (API::isUserTokenAuthorized(token)) sendSuccessReply(command + "-" + subc, tan); @@ -1437,7 +1437,7 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject &message, const QString & return; } // usual app token is 36 - if (token.count() == 36) + if (token.size() == 36) { if (API::isTokenAuthorized(token)) { @@ -1451,7 +1451,7 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject &message, const QString & // password // use password - if (password.count() >= 8) + if (password.size() >= 8) { QString userTokenRep; if (API::isUserAuthorized(password) && API::getUserToken(userTokenRep)) diff --git a/libsrc/api/JsonCB.cpp b/libsrc/api/JsonCB.cpp index 23d1c7dc3..5c35b77bb 100644 --- a/libsrc/api/JsonCB.cpp +++ b/libsrc/api/JsonCB.cpp @@ -171,6 +171,7 @@ void JsonCB::setSubscriptionsTo(Hyperion* hyperion) void JsonCB::doCallback(const QString& cmd, const QVariant& data) { QJsonObject obj; + obj["instance"] = _hyperion->getInstanceIndex(); obj["command"] = cmd; if (data.userType() == QMetaType::QJsonArray) diff --git a/libsrc/grabber/video/mediafoundation/MFGrabber.cpp b/libsrc/grabber/video/mediafoundation/MFGrabber.cpp index aa017d8d2..5e67e6ef5 100644 --- a/libsrc/grabber/video/mediafoundation/MFGrabber.cpp +++ b/libsrc/grabber/video/mediafoundation/MFGrabber.cpp @@ -537,7 +537,7 @@ void MFGrabber::process_image(const void *frameImageBuffer, int size) Error(_log, "Frame too small: %d != %d", size, _frameByteSize); else if (_threadManager != nullptr) { - for (int i = 0; i < _threadManager->_threadCount; i++) + for (unsigned long i = 0; i < _threadManager->_threadCount; i++) { if (!_threadManager->_threads[i]->isBusy()) { diff --git a/libsrc/leddevice/LedDevice.cpp b/libsrc/leddevice/LedDevice.cpp index 7d5fd05d6..6e1796d99 100644 --- a/libsrc/leddevice/LedDevice.cpp +++ b/libsrc/leddevice/LedDevice.cpp @@ -67,8 +67,6 @@ LedDevice::LedDevice(const QJsonObject& deviceConfig, QObject* parent) LedDevice::~LedDevice() { - this->stopEnableAttemptsTimer(); - this->stopRefreshTimer(); } void LedDevice::start() @@ -97,6 +95,7 @@ void LedDevice::start() void LedDevice::stop() { Debug(_log, "Stop device"); + this->stopEnableAttemptsTimer(); this->disable(); this->stopRefreshTimer(); Info(_log, " Stopped LedDevice '%s'", QSTRING_CSTR(_activeDeviceType)); diff --git a/libsrc/leddevice/dev_serial/LedDeviceAdalight.cpp b/libsrc/leddevice/dev_serial/LedDeviceAdalight.cpp index 1fdc11b34..d3b9dccec 100644 --- a/libsrc/leddevice/dev_serial/LedDeviceAdalight.cpp +++ b/libsrc/leddevice/dev_serial/LedDeviceAdalight.cpp @@ -95,9 +95,9 @@ void LedDeviceAdalight::prepareHeader() case Adalight::AWA: _bufferLength += 7; - [[clang::fallthrough]]; + [[fallthrough]]; case Adalight::ADA: - [[clang::fallthrough]]; + [[fallthrough]]; default: totalLedCount -= 1; _ledBuffer.resize(static_cast(_bufferLength), 0x00); diff --git a/libsrc/python/PythonInit.cpp b/libsrc/python/PythonInit.cpp index 2da6b1612..10560f1ce 100644 --- a/libsrc/python/PythonInit.cpp +++ b/libsrc/python/PythonInit.cpp @@ -29,47 +29,122 @@ PythonInit::PythonInit() // register modules EffectModule::registerHyperionExtensionModule(); +#if (PY_VERSION_HEX >= 0x03080000) + PyStatus status; + PyConfig config; + PyConfig_InitPythonConfig(&config); +#endif + #if defined(ENABLE_DEPLOY_DEPENDENCIES) + + Debug(Logger::getInstance("DAEMON"), "Initializing Python config"); // Set Program name wchar_t programName[] = L"Hyperion"; - Py_SetProgramName(programName); - // set Python module path when exists - QString py_path = QDir::cleanPath(qApp->applicationDirPath() + "/../lib/python" + STRINGIFY(PYTHON_VERSION_MAJOR) + "." + STRINGIFY(PYTHON_VERSION_MINOR)); - QString py_file = QDir::cleanPath(qApp->applicationDirPath() + "/python" + STRINGIFY(PYTHON_VERSION_MAJOR) + STRINGIFY(PYTHON_VERSION_MINOR) + ".zip"); - QString py_framework = QDir::cleanPath(qApp->applicationDirPath() + "/../Frameworks/Python.framework/Versions/Current/lib/python" + STRINGIFY(PYTHON_VERSION_MAJOR) + "." + STRINGIFY(PYTHON_VERSION_MINOR)); - - if (QFile(py_file).exists() || QDir(py_path).exists() || QDir(py_framework).exists() ) +#if (PY_VERSION_HEX >= 0x03080000) + status = PyConfig_SetString(&config, &config.program_name, programName); + if (PyStatus_Exception(status)) { + goto exception; + } + else +#else + Py_SetProgramName(programName); +#endif { - Py_NoSiteFlag++; - if (QFile(py_file).exists()) // Windows - { - Py_SetPythonHome(Py_DecodeLocale(py_file.toLatin1().data(), nullptr)); - Py_SetPath(Py_DecodeLocale(py_file.toLatin1().data(), nullptr)); - } - else if (QDir(py_path).exists()) // Linux - { - QStringList python_paths; - python_paths.append(QDir(py_path).absolutePath()); - python_paths.append(QDir(py_path + "/lib-dynload").absolutePath()); - QVector joined_paths(python_paths.join(":").size() + 1, 0); - python_paths.join(":").toWCharArray(joined_paths.data()); - Py_SetPath(joined_paths.data()); - py_path = QDir::cleanPath(qApp->applicationDirPath() + "/../"); - Py_SetPythonHome(Py_DecodeLocale(py_path.toLatin1().data(), nullptr)); - } - else if (QDir(py_framework).exists()) // macOS + // set Python module path when exists + QString py_path = QDir::cleanPath(qApp->applicationDirPath() + "/../lib/python" + STRINGIFY(PYTHON_VERSION_MAJOR) + "." + STRINGIFY(PYTHON_VERSION_MINOR)); + QString py_file = QDir::cleanPath(qApp->applicationDirPath() + "/python" + STRINGIFY(PYTHON_VERSION_MAJOR) + STRINGIFY(PYTHON_VERSION_MINOR) + ".zip"); + QString py_framework = QDir::cleanPath(qApp->applicationDirPath() + "/../Frameworks/Python.framework/Versions/Current/lib/python" + STRINGIFY(PYTHON_VERSION_MAJOR) + "." + STRINGIFY(PYTHON_VERSION_MINOR)); + + if (QFile(py_file).exists() || QDir(py_path).exists() || QDir(py_framework).exists()) { - QStringList python_paths; - python_paths.append(QDir(py_framework).absolutePath()); - python_paths.append(QDir(py_framework + "/lib-dynload").absolutePath()); - QVector joined_paths(python_paths.join(":").size() + 1, 0); - python_paths.join(":").toWCharArray(joined_paths.data()); - Py_SetPath(joined_paths.data()); - py_framework = QDir::cleanPath(qApp->applicationDirPath() + "/../Frameworks/Python.framework/Versions/Current"); - Py_SetPythonHome(Py_DecodeLocale(py_framework.toLatin1().data(), nullptr)); + Py_NoSiteFlag++; + if (QFile(py_file).exists()) // Windows + { +#if (PY_VERSION_HEX >= 0x03080000) + status = PyConfig_SetBytesString(&config, &config.home, QSTRING_CSTR(py_file)); + if (PyStatus_Exception(status)) { + goto exception; + } + config.module_search_paths_set = 1; + status = PyWideStringList_Append(&config.module_search_paths, const_cast(py_file.toStdWString().c_str())); + if (PyStatus_Exception(status)) { + goto exception; + } +#else + Py_SetPythonHome(Py_DecodeLocale(py_file.toLatin1().data(), nullptr)); + Py_SetPath(Py_DecodeLocale(py_file.toLatin1().data(), nullptr)); +#endif + } + else if (QDir(py_path).exists()) // Linux + { +#if (PY_VERSION_HEX >= 0x03080000) + status = PyConfig_SetBytesString(&config, &config.home, QSTRING_CSTR(QDir::cleanPath(qApp->applicationDirPath() + "/../"))); + if (PyStatus_Exception(status)) { + goto exception; + } + + config.module_search_paths_set = 1; + status = PyWideStringList_Append(&config.module_search_paths, const_cast(QDir(py_path).absolutePath().toStdWString().c_str())); + if (PyStatus_Exception(status)) { + goto exception; + } + + status = PyWideStringList_Append(&config.module_search_paths, const_cast(QDir(py_path + "/lib-dynload").absolutePath().toStdWString().c_str())); + if (PyStatus_Exception(status)) { + goto exception; + } +#else + QStringList python_paths; + python_paths.append(QDir(py_path).absolutePath()); + python_paths.append(QDir(py_path + "/lib-dynload").absolutePath()); + QVector joined_paths(python_paths.join(":").size() + 1, 0); + python_paths.join(":").toWCharArray(joined_paths.data()); + Py_SetPath(joined_paths.data()); + py_path = QDir::cleanPath(qApp->applicationDirPath() + "/../"); + Py_SetPythonHome(Py_DecodeLocale(py_path.toLatin1().data(), nullptr)); +#endif + } + else if (QDir(py_framework).exists()) // macOS + { +#if (PY_VERSION_HEX >= 0x03080000) + status = PyConfig_SetBytesString(&config, &config.home, QSTRING_CSTR(QDir::cleanPath(qApp->applicationDirPath() + "/../Frameworks/Python.framework/Versions/Current"))); + if (PyStatus_Exception(status)) { + goto exception; + } + + config.module_search_paths_set = 1; + status = PyWideStringList_Append(&config.module_search_paths, const_cast(QDir(py_framework).absolutePath().toStdWString().c_str())); + if (PyStatus_Exception(status)) { + goto exception; + } + + status = PyWideStringList_Append(&config.module_search_paths, const_cast(QDir(py_framework + "/lib-dynload").absolutePath().toStdWString().c_str())); + if (PyStatus_Exception(status)) { + goto exception; + } +#else + QStringList python_paths; + python_paths.append(QDir(py_framework).absolutePath()); + python_paths.append(QDir(py_framework + "/lib-dynload").absolutePath()); + QVector joined_paths(python_paths.join(":").size() + 1, 0); + python_paths.join(":").toWCharArray(joined_paths.data()); + Py_SetPath(joined_paths.data()); + py_framework = QDir::cleanPath(qApp->applicationDirPath() + "/../Frameworks/Python.framework/Versions/Current"); + Py_SetPythonHome(Py_DecodeLocale(py_framework.toLatin1().data(), nullptr)); +#endif + } } } + +#endif + +#if (PY_VERSION_HEX >= 0x03080000) + status = Py_InitializeFromConfig(&config); + if (PyStatus_Exception(status)) { + goto exception; + } + PyConfig_Clear(&config); #endif // init Python @@ -86,6 +161,15 @@ PythonInit::PythonInit() #endif mainThreadState = PyEval_SaveThread(); + return; + +#if (PY_VERSION_HEX >= 0x03080000) +exception: + Error(Logger::getInstance("DAEMON"), "Initializing Python config failed with error [%s]", status.err_msg); + PyConfig_Clear(&config); + + throw std::runtime_error("Initializing Python failed!"); +#endif } PythonInit::~PythonInit() diff --git a/libsrc/utils/Process.cpp b/libsrc/utils/Process.cpp index 232ef6a3f..9fdd72642 100644 --- a/libsrc/utils/Process.cpp +++ b/libsrc/utils/Process.cpp @@ -7,7 +7,7 @@ namespace Process { -void restartHyperion(bool asNewProcess) +void restartHyperion(int exitCode) { Logger* log = Logger::getInstance("Process"); Info(log, "Restarting hyperion ..."); @@ -18,7 +18,8 @@ void restartHyperion(bool asNewProcess) QProcess::startDetached(QCoreApplication::applicationFilePath(), arguments); - QCoreApplication::quit(); + //Exit with non-zero code to ensure service deamon restarts hyperion + QCoreApplication::exit(exitCode); } QByteArray command_exec(const QString& /*cmd*/, const QByteArray& /*data*/) @@ -42,9 +43,15 @@ QByteArray command_exec(const QString& /*cmd*/, const QByteArray& /*data*/) #include #include +#include + +#include +#include + namespace Process { -void restartHyperion(bool asNewProcess) + +void restartHyperion(int exitCode) { Logger* log = Logger::getInstance("Process"); Info(log, "Restarting hyperion ..."); @@ -60,10 +67,11 @@ void restartHyperion(bool asNewProcess) QProcess::startDetached(QCoreApplication::applicationFilePath(), arguments); - QCoreApplication::quit(); + //Exit with non-zero code to ensure service deamon restarts hyperion + QCoreApplication::exit(exitCode); } -QByteArray command_exec(const QString& cmd, const QByteArray& data) +QByteArray command_exec(const QString& cmd, const QByteArray& /*data*/) { char buffer[128]; QString result; @@ -73,7 +81,7 @@ QByteArray command_exec(const QString& cmd, const QByteArray& data) { while (!feof(pipe.get())) { - if (fgets(buffer, 128, pipe.get()) != NULL) + if (fgets(buffer, 128, pipe.get()) != nullptr) result += buffer; } } diff --git a/src/hyperiond/systray.cpp b/src/hyperiond/systray.cpp index 55c34869b..41e1f1c20 100644 --- a/src/hyperiond/systray.cpp +++ b/src/hyperiond/systray.cpp @@ -79,7 +79,7 @@ void SysTray::createTrayIcon() restartAction = new QAction(tr("&Restart"), this); restartAction->setIcon(QPixmap(":/restart.svg")); - connect(restartAction, &QAction::triggered, this , [=](){ Process::restartHyperion(); }); + connect(restartAction, &QAction::triggered, this , [=](){ Process::restartHyperion(11); }); suspendAction = new QAction(tr("&Suspend"), this); suspendAction->setIcon(QPixmap(":/suspend.svg"));