Windows compilation support (#738)

* Disable AVAHI

* Replace SysInfo backport with Qt SysInfo

* Update vscode config

* Update LedDevices

* Update Logger

* Update hyperiond

* Update hyperion-remote

* Exclude avahi

* Empty definition for Process

* PythonInit path broken

* Exclude PiBlaster and link ws2_32

* more avahi

* resolve ui bug

* Update Compile howto

* JsonAPI QtGrabber missing

* fix error

* ssize_t replacement

* Nope, doesn't work

* Adjust compile description and verify winSDK

* Update ci script

* Update ci script

* Update ci

* Update ci script

* update Logger

* Update PythonInit

* added Azure & GitHub Actions, Logger, PythonInit

* resolve merge conflicts

* revert ssize_t in FadeCandy

* look at registry for QT5 & use find_package(Python) if cmake >= 3.12

* second try

* another try

* and yet another test

* qt5 registry search undone

* Package creation test

* finished package creation. only fine tuning is required :-)

Signed-off-by: Paulchen-Panther <Paulchen-Panter@protonmail.com>

* Dependencies for Windows finished

Signed-off-by: Paulchen-Panther <Paulchen-Panter@protonmail.com>

* use 'add_definitions()' until CMake 3.12

Signed-off-by: Paulchen-Panther <Paulchen-Panter@protonmail.com>

* Update .github/workflows/pull-request.yml

Co-Authored-By: Paulchen Panther <16664240+Paulchen-Panther@users.noreply.github.com>

* Update cmake/Dependencies.cmake

Co-Authored-By: brindosch <edeltraud70@gmx.de>

* fix typo/ add VCINSTALLDIR var

* fix again

* Undo change again (Not working)

* fix QT grabber

Signed-off-by: Paulchen-Panther <Paulchen-Panter@protonmail.com>

* first NSIS test

Signed-off-by: Paulchen-Panther <Paulchen-Panter@protonmail.com>

* Update NSIS package

* surprise :-)

Signed-off-by: Paulchen-Panther <Paulchen-Panter@protonmail.com>

* Update NSIS package

* fix: NSIS .bmps

* Add nsis templates

* Force windows gui app

* fix: QSysInfo required Qt5.6, now it's 5.4 again

* Update: Remove platform component and adjust package name

* Add macOS as system name

* Update docs

* fix: Allow gh actions ci also for forks with branches

* Add ReadMe docs, mention windows, add vscode linux debug config

* fix: readme visual

* reduce/hide banner/copyright/log message

Infos here: https://docs.microsoft.com/de-de/visualstudio/msbuild/msbuild-command-line-reference?view=vs-2019#switches

* Fix PythonInit

* vscode: Add runner task

* fix(vscode): compiler path gcc ver independent

* fix azure

* vscode: add windows run tasks

* move process detection

* main: add windows process detection

* Azure file shredder

* Update docs

Co-authored-by: Paulchen Panther <16664240+Paulchen-Panther@users.noreply.github.com>
Co-authored-by: Paulchen-Panther <Paulchen-Panter@protonmail.com>
This commit is contained in:
brindosch
2020-05-12 19:51:19 +02:00
committed by GitHub
parent 598b404f38
commit 510bb903ae
69 changed files with 3184 additions and 871 deletions

View File

@@ -9,7 +9,6 @@ add_subdirectory(blackborder)
add_subdirectory(jsonserver)
add_subdirectory(flatbufserver)
add_subdirectory(protoserver)
add_subdirectory(bonjour)
add_subdirectory(ssdp)
add_subdirectory(boblightserver)
add_subdirectory(leddevice)
@@ -20,3 +19,7 @@ add_subdirectory(webserver)
add_subdirectory(db)
add_subdirectory(api)
add_subdirectory(python)
if(ENABLE_AVAHI)
add_subdirectory(bonjour)
endif()

View File

@@ -13,6 +13,7 @@
#include <QBuffer>
#include <QByteArray>
#include <QTimer>
#include <QHostInfo>
// hyperion includes
#include <leddevice/LedDeviceWrapper.h>
@@ -26,7 +27,9 @@
#include <utils/JsonUtils.h>
// bonjour wrapper
#ifdef ENABLE_AVAHI
#include <bonjour/bonjourbrowserwrapper.h>
#endif
// ledmapping int <> string transform methods
#include <hyperion/ImageProcessor.h>
@@ -469,9 +472,8 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const QString
QJsonObject grabbers;
QJsonArray availableGrabbers;
QJsonObject availableProperties;
#if defined(ENABLE_DISPMANX) || defined(ENABLE_V4L2) || defined(ENABLE_FB) || defined(ENABLE_AMLOGIC) || defined(ENABLE_OSX) || defined(ENABLE_X11)
#if defined(ENABLE_DISPMANX) || defined(ENABLE_V4L2) || defined(ENABLE_FB) || defined(ENABLE_AMLOGIC) || defined(ENABLE_OSX) || defined(ENABLE_X11) || defined(ENABLE_QT)
// get available grabbers
//grabbers["active"] = ????;
@@ -535,7 +537,8 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const QString
// add sessions
QJsonArray sessions;
for (auto session : BonjourBrowserWrapper::getInstance()->getAllServices())
#ifdef ENABLE_AVAHI
for (auto session: BonjourBrowserWrapper::getInstance()->getAllServices())
{
if (session.port < 0)
continue;
@@ -549,7 +552,7 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const QString
sessions.append(item);
}
info["sessions"] = sessions;
#endif
// add instance info
QJsonArray instanceInfo;
for (const auto &entry : API::getAllInstanceData())

View File

@@ -10,8 +10,9 @@
#include <hyperion/ComponentRegister.h>
// bonjour wrapper
#ifdef ENABLE_AVAHI
#include <bonjour/bonjourbrowserwrapper.h>
#endif
// priorityMuxer
#include <hyperion/PriorityMuxer.h>
@@ -21,6 +22,7 @@
// qt
#include <QDateTime>
#include <QVariant>
// Image to led map helper
#include <hyperion/ImageProcessor.h>
@@ -31,7 +33,9 @@ JsonCB::JsonCB(QObject* parent)
: QObject(parent)
, _hyperion(nullptr)
, _componentRegister(nullptr)
#ifdef ENABLE_AVAHI
, _bonjour(BonjourBrowserWrapper::getInstance())
#endif
, _prioMuxer(nullptr)
{
_availableCommands << "components-update" << "sessions-update" << "priorities-update" << "imageToLedMapping-update"
@@ -58,10 +62,12 @@ bool JsonCB::subscribeFor(const QString& type, const bool & unsubscribe)
if(type == "sessions-update")
{
#ifdef ENABLE_AVAHI
if(unsubscribe)
disconnect(_bonjour, &BonjourBrowserWrapper::browserChange, this, &JsonCB::handleBonjourChange);
else
connect(_bonjour, &BonjourBrowserWrapper::browserChange, this, &JsonCB::handleBonjourChange, Qt::UniqueConnection);
#endif
}
if(type == "priorities-update")
@@ -188,7 +194,7 @@ void JsonCB::handleComponentState(const hyperion::Components comp, const bool st
doCallback("components-update", QVariant(data));
}
#ifdef ENABLE_AVAHI
void JsonCB::handleBonjourChange(const QMap<QString,BonjourRecord>& bRegisters)
{
QJsonArray data;
@@ -207,7 +213,7 @@ void JsonCB::handleBonjourChange(const QMap<QString,BonjourRecord>& bRegisters)
doCallback("sessions-update", QVariant(data));
}
#endif
void JsonCB::handlePriorityUpdate()
{
QJsonObject data;

View File

@@ -1,9 +1,16 @@
set(Python_ADDITIONAL_VERSIONS 3.5)
find_package(PythonLibs 3.5 REQUIRED)
if (NOT CMAKE_VERSION VERSION_LESS "3.12")
find_package(Python3 COMPONENTS Interpreter Development REQUIRED)
else()
find_package (PythonLibs ${PYTHON_VERSION_STRING} EXACT) # Maps PythonLibs to the PythonInterp version of the main cmake
endif()
# Include the python directory. Also include the parent (which is for example /usr/include)
# which may be required when it is not includes by the (cross-) compiler by default.
include_directories(${PYTHON_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}/..)
if (NOT CMAKE_VERSION VERSION_LESS "3.12")
include_directories(${Python3_INCLUDE_DIRS} ${Python3_INCLUDE_DIRS}/..)
else()
include_directories(${PYTHON_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}/..)
endif()
# Define the current source locations
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/effectengine)
@@ -31,5 +38,10 @@ target_link_libraries(effectengine
python
Qt5::Core
Qt5::Gui
${PYTHON_LIBRARIES}
)
if (NOT CMAKE_VERSION VERSION_LESS "3.12")
target_link_libraries( effectengine ${Python3_LIBRARIES} )
else()
target_link_libraries( effectengine ${PYTHON_LIBRARIES} )
endif()

View File

@@ -100,8 +100,17 @@ int QtGrabber::grabFrame(Image<ColorRgb> & image)
}
QPixmap originalPixmap = _screen->grabWindow(0, _src_x, _src_y, _src_x_max, _src_y_max);
QPixmap resizedPixmap = originalPixmap.scaled(_width,_height);
QImage img = resizedPixmap.toImage().convertToFormat( QImage::Format_RGB888);
memcpy(image.memptr(), img.bits(),(size_t) _width*_height*3);
QImage imageFrame = resizedPixmap.toImage().convertToFormat( QImage::Format_RGB888);
for (int y=0; y<imageFrame.height(); ++y)
for (int x=0; x<imageFrame.width(); ++x)
{
QColor inPixel(imageFrame.pixel(x,y));
ColorRgb & outPixel = image(x,y);
outPixel.red = inPixel.red();
outPixel.green = inPixel.green();
outPixel.blue = inPixel.blue();
}
return 0;
}

View File

@@ -22,9 +22,12 @@ target_link_libraries(hyperion
flatbufserver
flatbuffers
leddevice
bonjour
boblightserver
effectengine
database
${QT_LIBRARIES}
)
if (ENABLE_AVAHI)
target_link_libraries(hyperion bonjour)
endif ()

View File

@@ -2,7 +2,6 @@
// STL includes
#include <exception>
#include <sstream>
#include <unistd.h>
// QT includes
#include <QString>

View File

@@ -1,6 +1,5 @@
// STL includes
#include <cstring>
#include <unistd.h>
#include <iostream>
// hyperion includes

View File

@@ -6,7 +6,9 @@
#include "JsonClientConnection.h"
// bonjour include
#ifdef ENABLE_AVAHI
#include <bonjour/bonjourserviceregister.h>
#endif
#include <utils/NetOrigin.h>
// qt includes
@@ -49,7 +51,7 @@ void JsonServer::start()
return;
}
Info(_log, "Started on port %d", _port);
#ifdef ENABLE_AVAHI
if(_serviceRegister == nullptr)
{
_serviceRegister = new BonjourServiceRegister(this);
@@ -61,6 +63,7 @@ void JsonServer::start()
_serviceRegister = new BonjourServiceRegister(this);
_serviceRegister->registerService("_hyperiond-json._tcp", _port);
}
#endif
}
void JsonServer::stop()

View File

@@ -27,7 +27,7 @@ FILE ( GLOB Leddevice_SOURCES
"${CURRENT_SOURCE_DIR}/dev_other/*.cpp"
)
if ( ENABLE_OSX )
if ( ENABLE_OSX OR WIN32 )
list(REMOVE_ITEM Leddevice_SOURCES "${CURRENT_SOURCE_DIR}/dev_other/LedDevicePiBlaster.h")
list(REMOVE_ITEM Leddevice_SOURCES "${CURRENT_SOURCE_DIR}/dev_other/LedDevicePiBlaster.cpp")
endif()
@@ -87,9 +87,13 @@ target_link_libraries(leddevice
${CMAKE_THREAD_LIBS_INIT}
Qt5::Network
Qt5::SerialPort
ssdp
ssdp
)
if(WIN32)
target_link_libraries(leddevice ws2_32)
endif()
if(ENABLE_TINKERFORGE)
target_link_libraries(leddevice tinkerforge)
endif()

View File

@@ -1,5 +1,11 @@
#include "LedDeviceFadeCandy.h"
// https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types#ssize-t
#if defined(_MSC_VER)
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#endif
static const signed MAX_NUM_LEDS = 10000; // OPC can handle 21845 leds - in theory, fadecandy device should handle 10000 leds
static const unsigned OPC_SET_PIXELS = 0; // OPC command codes
static const unsigned OPC_SYS_EX = 255; // OPC command codes

View File

@@ -1,4 +1,9 @@
#ifdef _WIN32
#include <winsock.h>
#else
#include <arpa/inet.h>
#endif
#include <QHostInfo>
// hyperion local includes

View File

@@ -20,6 +20,7 @@ const ushort ARTNET_DEFAULT_PORT = 6454;
// http://stackoverflow.com/questions/16396013/artnet-packet-structure
typedef union
{
#pragma pack(push, 1)
struct {
char ID[8]; // "Art-Net"
uint16_t OpCode; // See Doc. Table 1 - OpCodes eg. 0x5000 OpOutput / OpDmx
@@ -30,7 +31,8 @@ typedef union
uint8_t Net; // high universe (not used)
uint16_t Length; // data length (2 - 512)
uint8_t Data[ DMX_MAX ]; // universe data
} __attribute__((packed));
};
#pragma pack(pop)
uint8_t raw[ 18 + DMX_MAX ];

View File

@@ -1,4 +1,9 @@
#ifdef _WIN32
#include <winsock.h>
#else
#include <arpa/inet.h>
#endif
#include <QHostInfo>
// hyperion local includes

View File

@@ -48,6 +48,7 @@ const ushort E131_DEFAULT_PORT = 5568;
/* E1.31 Packet Structure */
typedef union
{
#pragma pack(push, 1)
struct
{
/* Root Layer */
@@ -76,7 +77,8 @@ typedef union
uint16_t address_increment;
uint16_t property_value_count;
uint8_t property_values[513];
} __attribute__((packed));
};
#pragma pack(pop)
uint8_t raw[638];
} e131_packet_t;

View File

@@ -6,7 +6,6 @@
#include <exception>
// Linux includes
#include <fcntl.h>
#include <sys/ioctl.h>
#include <QStringList>
#include <QUdpSocket>

View File

@@ -1,6 +1,8 @@
#include "LedDeviceDMX.h"
#include <QSerialPort>
#ifndef _WIN32
#include <time.h>
#endif
LedDeviceDMX::LedDeviceDMX(const QJsonObject &deviceConfig)
: ProviderRs232()
@@ -80,9 +82,14 @@ int LedDeviceDMX::write(const std::vector<ColorRgb> &ledValues)
}
_rs232Port.setBreakEnabled(true);
// Note Windows: There is no concept of ns sleeptime, the closest possible is 1ms but requested is 0,000176ms
#ifndef _WIN32
nanosleep((const struct timespec[]){{0, 176000L}}, NULL); // 176 uSec break time
#endif
_rs232Port.setBreakEnabled(false);
#ifndef _WIN32
nanosleep((const struct timespec[]){{0, 12000L}}, NULL); // 176 uSec make after break time
#endif
#undef uberdebug
#ifdef uberdebug

View File

@@ -1,8 +1,14 @@
find_package(PythonLibs 3.5 REQUIRED)
# Include the python directory. Also include the parent (which is for example /usr/include)
# which may be required when it is not includes by the (cross-) compiler by default.
include_directories(${PYTHON_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}/..)
if (NOT CMAKE_VERSION VERSION_LESS "3.12")
find_package(Python3 COMPONENTS Interpreter Development REQUIRED)
include_directories(${Python3_INCLUDE_DIRS} ${Python3_INCLUDE_DIRS}/..)
add_compile_definitions(PYTHON_VERSION_MAJOR_MINOR=${Python3_VERSION_MAJOR}${Python3_VERSION_MINOR})
else()
find_package (PythonLibs ${PYTHON_VERSION_STRING} EXACT) # Maps PythonLibs to the PythonInterp version of the main cmake
include_directories(${PYTHON_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}/..)
add_definitions(-DPYTHON_VERSION_MAJOR_MINOR=${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR})
endif()
# Define the current source locations
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/python)
@@ -17,5 +23,10 @@ add_library(python
target_link_libraries(python
effectengine
hyperion-utils
${PYTHON_LIBRARIES}
)
if (NOT CMAKE_VERSION VERSION_LESS "3.12")
target_link_libraries( python ${Python3_LIBRARIES} )
else()
target_link_libraries( python ${PYTHON_LIBRARIES} )
endif()

View File

@@ -15,19 +15,31 @@
// modules to init
#include <effectengine/EffectModule.h>
#ifdef _WIN32
#define STRINGIFY2(x) #x
#define STRINGIFY(x) STRINGIFY2(x)
#endif
PythonInit::PythonInit()
{
// register modules
EffectModule::registerHyperionExtensionModule();
// set Python module path when exists
const wchar_t *pythonPath = Py_DecodeLocale((QDir::cleanPath(qApp->applicationDirPath() + "/../lib/python")).toLatin1().data(), nullptr);
if(QDir(QString::fromWCharArray(pythonPath)).exists())
wchar_t *pythonPath = Py_DecodeLocale((QDir::cleanPath(qApp->applicationDirPath() + "/../lib/python")).toLatin1().data(), nullptr);
#ifdef _WIN32
pythonPath = Py_DecodeLocale((QDir::cleanPath(qApp->applicationDirPath())).toLatin1().data(), nullptr);
pythonPath = wcscat(pythonPath, L"/python" STRINGIFY(PYTHON_VERSION_MAJOR_MINOR) ".zip");
if(QFile(QString::fromWCharArray(pythonPath)).exists())
#else
if(QDir(QString::fromWCharArray(pythonPath)).exists())
#endif
{
Py_NoSiteFlag++;
Py_SetPath(pythonPath);
PyMem_RawFree(pythonPath);
}
delete pythonPath;
// init Python
Debug(Logger::getInstance("DAEMON"), "Initializing Python interpreter");

View File

@@ -3,13 +3,21 @@
#include <iostream>
#include <algorithm>
#include <syslog.h>
#ifndef _WIN32
#include <syslog.h>
#elif _WIN32
#include <windows.h>
#include <Shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")
#endif
#include <QFileInfo>
#include <time.h>
static const char * LogLevelStrings[] = { "", "DEBUG", "INFO", "WARNING", "ERROR" };
#ifndef _WIN32
static const int LogLevelSysLog[] = { LOG_DEBUG, LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERR };
#endif
static unsigned int loggerCount = 0;
static unsigned int loggerId = 0;
@@ -99,8 +107,19 @@ Logger::Logger ( QString name, LogLevel minLevel )
{
#ifdef __GLIBC__
const char* _appname_char = program_invocation_short_name;
#else
#elif !defined(_WIN32)
const char* _appname_char = getprogname();
#else
char fileName[MAX_PATH];
char *_appname_char;
HINSTANCE hinst = GetModuleHandle(NULL);
if (GetModuleFileNameA(hinst, fileName, sizeof(fileName)))
{
_appname_char = PathFindFileName(fileName);
*(PathFindExtension(fileName)) = 0;
}
else
_appname_char = "unknown";
#endif
_appname = QString(_appname_char).toLower();
@@ -108,7 +127,9 @@ Logger::Logger ( QString name, LogLevel minLevel )
if (_syslogEnabled && loggerCount == 1 )
{
#ifndef _WIN32
openlog (_appname_char, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL0);
#endif
}
}
@@ -116,8 +137,10 @@ Logger::~Logger()
{
//Debug(this, "logger '%s' destroyed", QSTRING_CSTR(_name) );
loggerCount--;
#ifndef _WIN32
if ( loggerCount == 0 )
closelog();
#endif
}
void Logger::Message(LogLevel level, const char* sourceFile, const char* func, unsigned int line, const char* fmt, ...)
@@ -142,8 +165,10 @@ void Logger::Message(LogLevel level, const char* sourceFile, const char* func, u
std::cout << QString("[" + repMsg.appName + " " + repMsg.loggerName + "] <" + LogLevelStrings[repMsg.level] + "> " + repMsg.message).toStdString() << std::endl;
#ifndef _WIN32
if ( _syslogEnabled && repMsg.level >= Logger::WARNING )
syslog (LogLevelSysLog[repMsg.level], "Previous line repeats %d times", _repeatCount);
#endif
_repeatCount = 0;
};
@@ -185,10 +210,10 @@ void Logger::Message(LogLevel level, const char* sourceFile, const char* func, u
}
std::cout << QString("[" + _appname + " " + _name + "] <" + LogLevelStrings[level] + "> " + location + msg).toStdString() << std::endl;
#ifndef _WIN32
if ( _syslogEnabled && level >= Logger::WARNING )
syslog (LogLevelSysLog[level], "%s", msg);
#endif
_repeatMessage = logMsg;
}
}

View File

@@ -1,3 +1,19 @@
#ifdef _WIN32
#include <utils/Logger.h>
#include <QString>
#include <QByteArray>
namespace Process {
void restartHyperion(bool asNewProcess){}
QByteArray command_exec(QString cmd, QByteArray data)
{
return QSTRING_CSTR(QString());
}
};
#else
#include <utils/Process.h>
#include <utils/Logger.h>
@@ -55,3 +71,5 @@ QByteArray command_exec(QString cmd, QByteArray data)
}
};
#endif

View File

@@ -58,9 +58,9 @@ void RgbChannelAdjustment::apply(uint8_t input, uint8_t brightness, uint8_t & re
if (!_initialized[input])
{
_mapping[RED ][input] = qMin( ((_brightness * input * _adjust[RED ]) / 65025), UINT8_MAX);
_mapping[GREEN][input] = qMin( ((_brightness * input * _adjust[GREEN]) / 65025), UINT8_MAX);
_mapping[BLUE ][input] = qMin( ((_brightness * input * _adjust[BLUE ]) / 65025), UINT8_MAX);
_mapping[RED ][input] = qMin( ((_brightness * input * _adjust[RED ]) / 65025), (int)UINT8_MAX);
_mapping[GREEN][input] = qMin( ((_brightness * input * _adjust[GREEN]) / 65025), (int)UINT8_MAX);
_mapping[BLUE ][input] = qMin( ((_brightness * input * _adjust[BLUE ]) / 65025), (int)UINT8_MAX);
_initialized[input] = true;
}
red = _mapping[RED ][input];

View File

@@ -2,34 +2,21 @@
#include <QHostInfo>
#include <QSysInfo>
#include <iostream>
#include <sys/utsname.h>
#include "HyperionConfig.h"
#include <stdlib.h>
#include <limits.h>
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
SysInfo* SysInfo::_instance = nullptr;
SysInfo::SysInfo()
: QObject()
{
SysInfo::QUnixOSVersion v;
findUnixOsVersion(v);
_sysinfo.kernelType = kernelType();
_sysinfo.kernelVersion = kernelVersion();
_sysinfo.architecture = currentCpuArchitecture();
_sysinfo.kernelType = QSysInfo::kernelType();
_sysinfo.kernelVersion = QSysInfo::kernelVersion();
_sysinfo.architecture = QSysInfo::currentCpuArchitecture();
_sysinfo.wordSize = QString::number(QSysInfo::WordSize);
_sysinfo.productType = v.productType;
_sysinfo.productVersion = v.productVersion;
_sysinfo.prettyName = v.prettyName;
_sysinfo.productType = QSysInfo::productType();
_sysinfo.productVersion = QSysInfo::productVersion();
_sysinfo.prettyName = QSysInfo::prettyProductName();
_sysinfo.hostName = QHostInfo::localHostName();
_sysinfo.domainName = QHostInfo::localDomainName();
_sysinfo.domainName = QHostInfo::localDomainName();
}
SysInfo::~SysInfo()
@@ -40,259 +27,6 @@ SysInfo::HyperionSysInfo SysInfo::get()
{
if ( SysInfo::_instance == nullptr )
SysInfo::_instance = new SysInfo();
return SysInfo::_instance->_sysinfo;
}
QString SysInfo::kernelType()
{
#if defined(Q_OS_WIN)
return QStringLiteral("winnt");
#elif defined(Q_OS_UNIX)
struct utsname u;
if (uname(&u) == 0)
return QString::fromLatin1(u.sysname).toLower();
#endif
return QString();
}
QString SysInfo::kernelVersion()
{
struct utsname u;
if (uname(&u) == 0)
return QString::fromLocal8Bit(u.release).toLower();
return QString();
}
QString SysInfo::machineHostName()
{
#if defined(Q_OS_LINUX)
// gethostname(3) on Linux just calls uname(2), so do it ourselves and avoid a memcpy
struct utsname u;
if (uname(&u) == 0)
return QString::fromLocal8Bit(u.nodename);
#else
char hostName[512];
if (gethostname(hostName, sizeof(hostName)) == -1)
return QString();
hostName[sizeof(hostName) - 1] = '\0';
return QString::fromLocal8Bit(hostName);
#endif
return QString();
}
QString SysInfo::currentCpuArchitecture()
{
#if defined(Q_OS_UNIX)
long ret = -1;
struct utsname u;
if (ret == -1)
ret = uname(&u);
// we could use detectUnixVersion() above, but we only need a field no other function does
if (ret != -1)
{
// the use of QT_BUILD_INTERNAL here is simply to ensure all branches build
// as we don't often build on some of the less common platforms
# if defined(Q_PROCESSOR_ARM)
if (strcmp(u.machine, "aarch64") == 0)
return QStringLiteral("arm64");
if (strncmp(u.machine, "armv", 4) == 0)
return QStringLiteral("arm");
# endif
# if defined(Q_PROCESSOR_POWER)
// harmonize "powerpc" and "ppc" to "power"
if (strncmp(u.machine, "ppc", 3) == 0)
return QLatin1String("power") + QLatin1String(u.machine + 3);
if (strncmp(u.machine, "powerpc", 7) == 0)
return QLatin1String("power") + QLatin1String(u.machine + 7);
if (strcmp(u.machine, "Power Macintosh") == 0)
return QLatin1String("power");
# endif
# if defined(Q_PROCESSOR_X86)
// harmonize all "i?86" to "i386"
if (strlen(u.machine) == 4 && u.machine[0] == 'i' && u.machine[2] == '8' && u.machine[3] == '6')
return QStringLiteral("i386");
if (strcmp(u.machine, "amd64") == 0) // Solaris
return QStringLiteral("x86_64");
# endif
return QString::fromLatin1(u.machine);
}
#endif
return QString();
}
bool SysInfo::findUnixOsVersion(SysInfo::QUnixOSVersion &v)
{
if (readEtcOsRelease(v))
return true;
if (readEtcLsbRelease(v))
return true;
#if defined(Q_OS_LINUX)
if (readEtcRedHatRelease(v))
return true;
if (readEtcDebianVersion(v))
return true;
#endif
return false;
}
QByteArray SysInfo::getEtcFileFirstLine(const char *fileName)
{
QByteArray buffer = getEtcFileContent(fileName);
if (buffer.isEmpty())
return QByteArray();
const char *ptr = buffer.constData();
int eol = buffer.indexOf("\n");
return QByteArray(ptr, eol).trimmed();
}
bool SysInfo::readEtcRedHatRelease(SysInfo::QUnixOSVersion &v)
{
// /etc/redhat-release analysed should be a one line file
// the format of its content is <Vendor_ID release Version>
// i.e. "Red Hat Enterprise Linux Workstation release 6.5 (Santiago)"
QByteArray line = getEtcFileFirstLine("/etc/redhat-release");
if (line.isEmpty())
return false;
v.prettyName = QString::fromLatin1(line);
const char keyword[] = "release ";
int releaseIndex = line.indexOf(keyword);
v.productType = QString::fromLatin1(line.mid(0, releaseIndex)).remove(QLatin1Char(' '));
int spaceIndex = line.indexOf(' ', releaseIndex + strlen(keyword));
v.productVersion = QString::fromLatin1(line.mid(releaseIndex + strlen(keyword),
spaceIndex > -1 ? spaceIndex - releaseIndex - int(strlen(keyword)) : -1));
return true;
}
bool SysInfo::readEtcDebianVersion(SysInfo::QUnixOSVersion &v)
{
// /etc/debian_version analysed should be a one line file
// the format of its content is <Release_ID/sid>
// i.e. "jessie/sid"
QByteArray line = getEtcFileFirstLine("/etc/debian_version");
if (line.isEmpty())
return false;
v.productType = QStringLiteral("Debian");
v.productVersion = QString::fromLatin1(line);
return true;
}
QString SysInfo::unquote(const char *begin, const char *end)
{
if (*begin == '"') {
Q_ASSERT(end[-1] == '"');
return QString::fromLatin1(begin + 1, end - begin - 2);
}
return QString::fromLatin1(begin, end - begin);
}
QByteArray SysInfo::getEtcFileContent(const char *filename)
{
// we're avoiding QFile here
int fd = open(filename, O_RDONLY);
if (fd == -1)
return QByteArray();
struct stat sbuf;
if (::fstat(fd, &sbuf) == -1) {
close(fd);
return QByteArray();
}
QByteArray buffer(sbuf.st_size, Qt::Uninitialized);
buffer.resize(read(fd, buffer.data(), sbuf.st_size));
close(fd);
return buffer;
}
bool SysInfo::readEtcFile(SysInfo::QUnixOSVersion &v, const char *filename,
const QByteArray &idKey, const QByteArray &versionKey, const QByteArray &prettyNameKey)
{
QByteArray buffer = getEtcFileContent(filename);
if (buffer.isEmpty())
return false;
const char *ptr = buffer.constData();
const char *end = buffer.constEnd();
const char *eol;
QByteArray line;
for ( ; ptr != end; ptr = eol + 1) {
// find the end of the line after ptr
eol = static_cast<const char *>(memchr(ptr, '\n', end - ptr));
if (!eol)
eol = end - 1;
line.setRawData(ptr, eol - ptr);
if (line.startsWith(idKey)) {
ptr += idKey.length();
v.productType = unquote(ptr, eol);
continue;
}
if (line.startsWith(prettyNameKey)) {
ptr += prettyNameKey.length();
v.prettyName = unquote(ptr, eol);
continue;
}
if (line.startsWith(versionKey)) {
ptr += versionKey.length();
v.productVersion = unquote(ptr, eol);
continue;
}
}
return true;
}
bool SysInfo::readEtcOsRelease(SysInfo::QUnixOSVersion &v)
{
return readEtcFile(v, "/etc/os-release", QByteArrayLiteral("ID="),
QByteArrayLiteral("VERSION_ID="), QByteArrayLiteral("PRETTY_NAME="));
}
bool SysInfo::readEtcLsbRelease(SysInfo::QUnixOSVersion &v)
{
bool ok = readEtcFile(v, "/etc/lsb-release", QByteArrayLiteral("DISTRIB_ID="),
QByteArrayLiteral("DISTRIB_RELEASE="), QByteArrayLiteral("DISTRIB_DESCRIPTION="));
if (ok && (v.prettyName.isEmpty() || v.prettyName == v.productType)) {
// some distributions have redundant information for the pretty name,
// so try /etc/<lowercasename>-release
// we're still avoiding QFile here
QByteArray distrorelease = "/etc/" + v.productType.toLatin1().toLower() + "-release";
int fd = open(distrorelease, O_RDONLY);
if (fd != -1) {
struct stat sbuf;
if (::fstat(fd, &sbuf) != -1 && sbuf.st_size > v.prettyName.length()) {
// file apparently contains interesting information
QByteArray buffer(sbuf.st_size, Qt::Uninitialized);
buffer.resize(read(fd, buffer.data(), sbuf.st_size));
v.prettyName = QString::fromLatin1(buffer.trimmed());
}
close(fd);
}
}
// some distributions have a /etc/lsb-release file that does not provide the values
// we are looking for, i.e. DISTRIB_ID, DISTRIB_RELEASE and DISTRIB_DESCRIPTION.
// Assuming that neither DISTRIB_ID nor DISTRIB_RELEASE were found, or contained valid values,
// returning false for readEtcLsbRelease will allow further /etc/<lowercasename>-release parsing.
return ok && !(v.productType.isEmpty() && v.productVersion.isEmpty());
}

View File

@@ -6,8 +6,9 @@
#include <QJsonObject>
// bonjour
#ifdef ENABLE_AVAHI
#include <bonjour/bonjourserviceregister.h>
#endif
// netUtil
#include <utils/NetUtils.h>
@@ -56,7 +57,7 @@ void WebServer::onServerStarted (quint16 port)
_inited= true;
Info(_log, "Started on port %d name '%s'", port ,_server->getServerName().toStdString().c_str());
#ifdef ENABLE_AVAHI
if(_serviceRegister == nullptr)
{
_serviceRegister = new BonjourServiceRegister(this);
@@ -68,6 +69,7 @@ void WebServer::onServerStarted (quint16 port)
_serviceRegister = new BonjourServiceRegister(this);
_serviceRegister->registerService("_hyperiond-http._tcp", port);
}
#endif
emit stateChange(true);
}