mDNS Support (#1452)

* Allow build, if no grabbers are enabled

* Align available functions to right Qt version

* Update to next development version

* Align available functions to right Qt version

* fix workflows (apt/nightly)

* Disable QNetworkConfigurationManager deprecation warnings

* Initial go on Smart Pointers

* Add Deallocation

* Correct QT_WARNING_DISABLE_DEPRECATED (available since 5.9)

* Cluster Build Variables

* Hyperion Light

* Address build warnings

* Hyperion Light - UI

* Update Protobuf to latest master

* Removed compiler warnings

* Added restart ability to systray

* Correct Protobuf

* Ignore 'no-return' warning on protobuf build

* hyperion-remote: Fix auto discovery of hyperion server

* Fix Qt version override

* Update changelog

* Remove Grabber Components, if no Grabber exists

* Standalone Grabber - Fix fps default

* Remote Control - Have Source Selction accrosswhole screen

* Enable Blackborder detection only, if relevant input sources available

* Enable Blackborder detection only, if relevant input sources available

* Remote UI - rearrange containers

* Checkout

* Fix compilation on windows

* Re-added qmdnsengine template cmake

* chrono added for linux

* Removed existing AVAHI/Bonjour, allow to enable/disable mDNS

* hyperiond macos typo fix

* Fix macOS Bundle build

* Fix macOS bundle info details

* Correct CMake files

* Removed existing AVAHI/Bonjour (2)

* Share hyperion's services via mDNS

* Add mDNS Browser and mDNS for LED-Devices

* Support mDNS discovery for standalone grabbers

* Remove ZLib Dependency & Cleanup

* mDNS - hanle 2.local2 an ".local." domains equally

* Hue - Link discovery to bridge class, workaround port 443 for mDNS discovery

* Fix save button state when switching between devices

* Removed sessions (of other hyperions)

* mDNS Publisher - Simplify service naming

* mDNS refactoring & Forwarder discovery

* mDNS Updates to use device service name

* Consistency of standalone grabbers with mDNS Service Registry

* Merge branch 'hyperion-project:master' into mDNS

* Start JSON and WebServers only after Instance 0 is available

* Remove bespoke qDebug Output again

* MDNS updates and refactor Forwarder

* Minor updates

* Upgrade to CMake 3.1

* typo

* macOS fix

* Correct merge

* - Remove dynamic linker flag from standalone dispmanX Grabber
- Added ability to use system qmdns libs

* Cec handler library will load at runtime

* typo fix

* protobuf changes

* mDNS changes for Windows/macOS

* test window build qmdnsengine

* absolute path to protobuf cmake dir

* Rework Hue Wizard supporting mDNS

* LED-Devices - Retry support + Refactoring (excl. Hue)

* LED-Devices - Refactoring/Retry support Hue + additional alignments

* Address LGTM findings

* Fix CI-Build, revert test changes

* Build Windows in Release mode to avoid python problem

* Correct that WebServerObject is available earlier

* Ensure that instance name in logs for one instance are presented

* Update content LEDs

* Rework mDNS Address lookup

* Fix LED UI

* Fix for non mDNS Services (ignore default port)

* Disbale device when now input is available

* Revert back some updates, ensure last color is updated when switched on

* Handle reopening case and changed IP, port for API-calls

* Add UPD-DDP Device

* WLED support for DDP

* Fix printout

* LEDDevice - Allow more retries, udapte defaults

* LED-Net Devices - Select Custom device, if configured

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:
LordGrey
2022-05-01 19:42:47 +02:00
committed by GitHub
parent 3ef4ebc1a4
commit e9936e131b
148 changed files with 5885 additions and 4459 deletions

View File

@@ -14,6 +14,7 @@
#include <QBuffer>
#include <QByteArray>
#include <QTimer>
#include <QThread>
// hyperion includes
#include <utils/jsonschema/QJsonFactory.h>
@@ -23,9 +24,6 @@
#include <utils/ColorSys.h>
#include <utils/Process.h>
// bonjour wrapper
#include <bonjour/bonjourbrowserwrapper.h>
// ledmapping int <> string transform methods
#include <hyperion/ImageProcessor.h>
@@ -44,17 +42,13 @@ API::API(Logger *log, bool localConnection, QObject *parent)
// Init
_log = log;
_authManager = AuthManager::getInstance();
_instanceManager = HyperionIManager::getInstance();
_instanceManager = HyperionIManager::getInstance();
_localConnection = localConnection;
_authorized = false;
_adminAuthorized = false;
_hyperion = _instanceManager->getHyperionInstance(0);
_currInstanceIndex = 0;
// TODO FIXME
// report back current registers when a Hyperion instance request it
//connect(ApiSync::getInstance(), &ApiSync::requestActiveRegister, this, &API::requestActiveRegister, Qt::QueuedConnection);
// 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)
@@ -73,7 +67,7 @@ API::API(Logger *log, bool localConnection, QObject *parent)
void API::init()
{
assert(_hyperion);
_hyperion = _instanceManager->getHyperionInstance(0);
bool apiAuthRequired = _authManager->isAuthRequired();
@@ -336,13 +330,6 @@ void API::stopInstance(quint8 index)
QMetaObject::invokeMethod(_instanceManager, "stopInstance", Qt::QueuedConnection, Q_ARG(quint8, index));
}
void API::requestActiveRegister(QObject *callerInstance)
{
// TODO FIXME
//if (_activeRegisters.size())
// QMetaObject::invokeMethod(ApiSync::getInstance(), "answerActiveRegister", Qt::QueuedConnection, Q_ARG(QObject *, callerInstance), Q_ARG(MapRegister, _activeRegisters));
}
bool API::deleteInstance(quint8 index, QString &replyMsg)
{
if (_adminAuthorized)

View File

@@ -13,7 +13,7 @@
"subcommand": {
"type" : "string",
"required" : true,
"enum" : ["discover","getProperties","identify"]
"enum": [ "discover", "getProperties", "identify", "addAuthorization" ]
},
"ledDeviceType": {
"type" : "string",

View File

@@ -0,0 +1,28 @@
{
"type":"object",
"required":true,
"properties":{
"command": {
"type" : "string",
"required" : true,
"enum" : ["service"]
},
"tan" : {
"type" : "integer"
},
"subcommand": {
"type" : "string",
"required" : true,
"enum" : ["discover"]
},
"serviceType": {
"type" : "string",
"required" : true
},
"params": {
"type" : "object",
"required" : false
}
},
"additionalProperties": false
}

View File

@@ -5,7 +5,7 @@
"command": {
"type" : "string",
"required" : true,
"enum": [ "color", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "adjustment", "sourceselect", "config", "componentstate", "ledcolors", "logging", "processing", "sysinfo", "videomode", "authorize", "instance", "leddevice", "inputsource", "transform", "correction", "temperature" ]
"enum": [ "color", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "adjustment", "sourceselect", "config", "componentstate", "ledcolors", "logging", "processing", "sysinfo", "videomode", "authorize", "instance", "leddevice", "inputsource", "service", "transform", "correction", "temperature" ]
}
}
}

View File

@@ -22,6 +22,7 @@
<file alias="schema-instance">JSONRPC_schema/schema-instance.json</file>
<file alias="schema-leddevice">JSONRPC_schema/schema-leddevice.json</file>
<file alias="schema-inputsource">JSONRPC_schema/schema-inputsource.json</file>
<file alias="schema-service">JSONRPC_schema/schema-service.json</file>
<!-- The following schemas are derecated but used to ensure backward compatibility with hyperion Classic remote control-->
<file alias="schema-transform">JSONRPC_schema/schema-hyperion-classic.json</file>
<file alias="schema-correction">JSONRPC_schema/schema-hyperion-classic.json</file>

View File

@@ -63,11 +63,6 @@
#include <utils/Process.h>
#include <utils/JsonUtils.h>
// bonjour wrapper
#ifdef ENABLE_AVAHI
#include <bonjour/bonjourbrowserwrapper.h>
#endif
// ledmapping int <> string transform methods
#include <hyperion/ImageProcessor.h>
@@ -77,6 +72,15 @@
// auth manager
#include <hyperion/AuthManager.h>
#ifdef ENABLE_MDNS
// mDNS discover
#include <mdns/MdnsBrowser.h>
#include <mdns/MdnsServiceRegister.h>
#else
// ssdp discover
#include <ssdp/SSDPDiscover.h>
#endif
using namespace hyperion;
// Constants
@@ -98,8 +102,6 @@ void JsonAPI::initialize()
{
// init API, REQUIRED!
API::init();
// Initialise jsonCB with current instance
_jsonCB->setSubscriptionsTo(_hyperion);
// setup auth interface
connect(this, &API::onPendingTokenRequest, this, &JsonAPI::newPendingTokenRequest);
@@ -112,7 +114,12 @@ void JsonAPI::initialize()
connect(_jsonCB, &JsonCB::newCallback, this, &JsonAPI::callbackMessage);
// notify hyperion about a jsonMessageForward
connect(this, &JsonAPI::forwardJsonMessage, _hyperion, &Hyperion::forwardJsonMessage);
if (_hyperion != nullptr)
{
// Initialise jsonCB with current instance
_jsonCB->setSubscriptionsTo(_hyperion);
connect(this, &JsonAPI::forwardJsonMessage, _hyperion, &Hyperion::forwardJsonMessage);
}
}
bool JsonAPI::handleInstanceSwitch(quint8 inst, bool forced)
@@ -180,6 +187,12 @@ void JsonAPI::handleMessage(const QString &messageString, const QString &httpAut
return;
}
proceed:
if (_hyperion == nullptr)
{
sendErrorReply("Service Unavailable", command, tan);
return;
}
// switch over all possible commands and handle them
if (command == "color")
handleColorCommand(message, command, tan);
@@ -221,6 +234,8 @@ proceed:
handleLedDeviceCommand(message, command, tan);
else if (command == "inputsource")
handleInputSourceCommand(message, command, tan);
else if (command == "service")
handleServiceCommand(message, command, tan);
// BEGIN | The following commands are deprecated but used to ensure backward compatibility with hyperion Classic remote control
else if (command == "clearall")
@@ -627,6 +642,11 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const QString
services.append("protobuffer");
#endif
#if defined(ENABLE_MDNS)
services.append("mDNS");
#endif
services.append("SSDP");
if (!availableScreenGrabbers.isEmpty() || !availableVideoGrabbers.isEmpty() || services.contains("flatbuffer") || services.contains("protobuffer"))
{
services.append("borderdetection");
@@ -649,24 +669,6 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const QString
info["components"] = component;
info["imageToLedMappingType"] = ImageProcessor::mappingTypeToStr(_hyperion->getLedMappingType());
// add sessions
QJsonArray sessions;
#ifdef ENABLE_AVAHI
for (auto session: BonjourBrowserWrapper::getInstance()->getAllServices())
{
if (session.port < 0)
continue;
QJsonObject item;
item["name"] = session.serviceName;
item["type"] = session.registeredType;
item["domain"] = session.replyDomain;
item["host"] = session.hostName;
item["address"] = session.address;
item["port"] = session.port;
sessions.append(item);
}
info["sessions"] = sessions;
#endif
// add instance info
QJsonArray instanceInfo;
for (const auto &entry : API::getAllInstanceData())
@@ -1571,6 +1573,16 @@ void JsonAPI::handleLedDeviceCommand(const QJsonObject &message, const QString &
sendSuccessReply(full_command, tan);
}
else if (subc == "addAuthorization")
{
ledDevice = LedDeviceFactory::construct(config);
const QJsonObject& params = message["params"].toObject();
const QJsonObject response = ledDevice->addAuthorization(params);
Debug(_log, "response: [%s]", QString(QJsonDocument(response).toJson(QJsonDocument::Compact)).toUtf8().constData());
sendSuccessDataReply(QJsonDocument(response), full_command, tan);
}
else
{
sendErrorReply("Unknown or missing subcommand", full_command, tan);
@@ -1725,6 +1737,55 @@ void JsonAPI::handleInputSourceCommand(const QJsonObject& message, const QString
}
}
void JsonAPI::handleServiceCommand(const QJsonObject &message, const QString &command, int tan)
{
DebugIf(verbose, _log, "message: [%s]", QString(QJsonDocument(message).toJson(QJsonDocument::Compact)).toUtf8().constData());
const QString &subc = message["subcommand"].toString().trimmed();
const QString type = message["serviceType"].toString().trimmed();
QString full_command = command + "-" + subc;
if (subc == "discover")
{
QByteArray serviceType;
QJsonObject servicesDiscovered;
QJsonObject servicesOfType;
QJsonArray serviceList;
#ifdef ENABLE_MDNS
QString discoveryMethod("mDNS");
serviceType = MdnsServiceRegister::getServiceType(type);
#else
QString discoveryMethod("ssdp");
#endif
if (!serviceType.isEmpty())
{
#ifdef ENABLE_MDNS
QMetaObject::invokeMethod(&MdnsBrowser::getInstance(), "browseForServiceType",
Qt::QueuedConnection, Q_ARG(QByteArray, serviceType));
serviceList = MdnsBrowser::getInstance().getServicesDiscoveredJson(serviceType, MdnsServiceRegister::getServiceNameFilter(type), DEFAULT_DISCOVER_TIMEOUT);
#endif
servicesOfType.insert(type, serviceList);
servicesDiscovered.insert("discoveryMethod", discoveryMethod);
servicesDiscovered.insert("services", servicesOfType);
sendSuccessDataReply(QJsonDocument(servicesDiscovered), full_command, tan);
}
else
{
sendErrorReply(QString("Discovery of service type [%1] via %2 not supported").arg(type, discoveryMethod), full_command, tan);
}
}
else
{
sendErrorReply("Unknown or missing subcommand", full_command, tan);
}
}
void JsonAPI::handleNotImplemented(const QString &command, int tan)
{
sendErrorReply("Command not implemented", command, tan);

View File

@@ -9,10 +9,6 @@
// components
#include <hyperion/ComponentRegister.h>
// bonjour wrapper
#ifdef ENABLE_AVAHI
#include <bonjour/bonjourbrowserwrapper.h>
#endif
// priorityMuxer
#include <hyperion/PriorityMuxer.h>
@@ -33,12 +29,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"
_availableCommands << "components-update" << "priorities-update" << "imageToLedMapping-update"
<< "adjustment-update" << "videomode-update" << "settings-update" << "leds-update" << "instance-update" << "token-update";
#if defined(ENABLE_EFFECTENGINE)
@@ -66,16 +59,6 @@ bool JsonCB::subscribeFor(const QString& type, bool unsubscribe)
connect(_componentRegister, &ComponentRegister::updatedComponentState, this, &JsonCB::handleComponentState, Qt::UniqueConnection);
}
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")
{
if (unsubscribe)
@@ -208,26 +191,6 @@ void JsonCB::handleComponentState(hyperion::Components comp, bool state)
doCallback("components-update", QVariant(data));
}
#ifdef ENABLE_AVAHI
void JsonCB::handleBonjourChange(const QMap<QString,BonjourRecord>& bRegisters)
{
QJsonArray data;
for (const auto & session: bRegisters)
{
if (session.port<0) continue;
QJsonObject item;
item["name"] = session.serviceName;
item["type"] = session.registeredType;
item["domain"] = session.replyDomain;
item["host"] = session.hostName;
item["address"]= session.address;
item["port"] = session.port;
data.append(item);
}
doCallback("sessions-update", QVariant(data));
}
#endif
void JsonCB::handlePriorityUpdate(int currentPriority, const PriorityMuxer::InputsMap& activeInputs)
{