mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2025-03-01 10:33:28 +00:00
ProtoBuffer, UDPListener ...
Protocol Buffer reimplemented to receive image data from third-party apps The status of the component "UDPListener" is now displayed correctly in WebUI Global signal names for WebUI added
This commit is contained in:
@@ -8,6 +8,7 @@ add_subdirectory(commandline)
|
||||
add_subdirectory(blackborder)
|
||||
add_subdirectory(jsonserver)
|
||||
add_subdirectory(flatbufserver)
|
||||
add_subdirectory(protoserver)
|
||||
add_subdirectory(bonjour)
|
||||
add_subdirectory(ssdp)
|
||||
add_subdirectory(boblightserver)
|
||||
|
@@ -31,7 +31,7 @@ public:
|
||||
/// @param timeout The timeout when a client is automatically disconnected and the priority unregistered
|
||||
/// @param parent The parent
|
||||
///
|
||||
explicit FlatBufferClient(QTcpSocket* socket, const int &timeout, QObject *parent = nullptr);
|
||||
explicit FlatBufferClient(QTcpSocket* socket, const int &timeout, QObject *parent = nullptr);
|
||||
|
||||
signals:
|
||||
///
|
||||
@@ -59,12 +59,12 @@ private slots:
|
||||
///
|
||||
/// @brief Is called whenever the socket got new data to read
|
||||
///
|
||||
void readyRead();
|
||||
void readyRead();
|
||||
|
||||
///
|
||||
/// @brief Is called when the socket closed the connection, also requests thread exit
|
||||
///
|
||||
void disconnected();
|
||||
void disconnected();
|
||||
|
||||
private:
|
||||
///
|
||||
|
@@ -62,8 +62,6 @@ void FlatBufferServer::newConnection()
|
||||
FlatBufferClient *client = new FlatBufferClient(socket, _timeout, this);
|
||||
// internal
|
||||
connect(client, &FlatBufferClient::clientDisconnected, this, &FlatBufferServer::clientDisconnected);
|
||||
// forward data
|
||||
//connect(clientThread, &FlatBufferClient::);
|
||||
_openConnections.append(client);
|
||||
}
|
||||
}
|
||||
|
@@ -53,7 +53,7 @@ void V4L2Wrapper::setSignalDetectionOffset(double verticalMin, double horizontal
|
||||
|
||||
void V4L2Wrapper::newFrame(const Image<ColorRgb> &image)
|
||||
{
|
||||
emit systemImage(image);
|
||||
emit systemImage(_grabberName, image);
|
||||
}
|
||||
|
||||
void V4L2Wrapper::readError(const char* err)
|
||||
|
@@ -13,8 +13,10 @@ CaptureCont::CaptureCont(Hyperion* hyperion)
|
||||
: QObject()
|
||||
, _hyperion(hyperion)
|
||||
, _systemCaptEnabled(false)
|
||||
, _systemCaptName()
|
||||
, _systemInactiveTimer(new QTimer(this))
|
||||
, _v4lCaptEnabled(false)
|
||||
, _v4lCaptName()
|
||||
, _v4lInactiveTimer(new QTimer(this))
|
||||
{
|
||||
// settings changes
|
||||
@@ -41,14 +43,24 @@ CaptureCont::~CaptureCont()
|
||||
{
|
||||
}
|
||||
|
||||
void CaptureCont::handleV4lImage(const Image<ColorRgb> & image)
|
||||
void CaptureCont::handleV4lImage(const QString& name, const Image<ColorRgb> & image)
|
||||
{
|
||||
if(_v4lCaptName != name)
|
||||
{
|
||||
_hyperion->registerInput(_v4lCaptPrio, hyperion::COMP_V4L, "System", name);
|
||||
_v4lCaptName = name;
|
||||
}
|
||||
_v4lInactiveTimer->start();
|
||||
_hyperion->setInputImage(_v4lCaptPrio, image);
|
||||
}
|
||||
|
||||
void CaptureCont::handleSystemImage(const Image<ColorRgb>& image)
|
||||
void CaptureCont::handleSystemImage(const QString& name, const Image<ColorRgb>& image)
|
||||
{
|
||||
if(_systemCaptName != name)
|
||||
{
|
||||
_hyperion->registerInput(_systemCaptPrio, hyperion::COMP_GRABBER, "System", name);
|
||||
_systemCaptName = name;
|
||||
}
|
||||
_systemInactiveTimer->start();
|
||||
_hyperion->setInputImage(_systemCaptPrio, image);
|
||||
}
|
||||
|
@@ -210,7 +210,7 @@ void MessageForwarder::forwardJsonMessage(const QJsonObject &message)
|
||||
}
|
||||
}
|
||||
|
||||
void MessageForwarder::forwardProtoMessage(const Image<ColorRgb> &image)
|
||||
void MessageForwarder::forwardProtoMessage(const QString& name, const Image<ColorRgb> &image)
|
||||
{
|
||||
if (_forwarder_enabled)
|
||||
{
|
||||
|
@@ -55,6 +55,10 @@
|
||||
{
|
||||
"$ref": "schema-flatbufServer.json"
|
||||
},
|
||||
"protoServer" :
|
||||
{
|
||||
"$ref": "schema-protoServer.json"
|
||||
},
|
||||
"boblightServer" :
|
||||
{
|
||||
"$ref": "schema-boblightServer.json"
|
||||
|
@@ -15,6 +15,7 @@
|
||||
<file alias="schema-forwarder.json">schema/schema-forwarder.json</file>
|
||||
<file alias="schema-jsonServer.json">schema/schema-jsonServer.json</file>
|
||||
<file alias="schema-flatbufServer.json">schema/schema-flatbufServer.json</file>
|
||||
<file alias="schema-protoServer.json">schema/schema-protoServer.json</file>
|
||||
<file alias="schema-boblightServer.json">schema/schema-boblightServer.json</file>
|
||||
<file alias="schema-udpListener.json">schema/schema-udpListener.json</file>
|
||||
<file alias="schema-webConfig.json">schema/schema-webConfig.json</file>
|
||||
|
36
libsrc/hyperion/schema/schema-protoServer.json
Normal file
36
libsrc/hyperion/schema/schema-protoServer.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"type" : "object",
|
||||
"required" : true,
|
||||
"title" : "edt_conf_pbs_heading_title",
|
||||
"properties" :
|
||||
{
|
||||
"enable" :
|
||||
{
|
||||
"type" : "boolean",
|
||||
"required" : true,
|
||||
"title" : "edt_conf_general_enable_title",
|
||||
"default" : true,
|
||||
"propertyOrder" : 1
|
||||
},
|
||||
"port" :
|
||||
{
|
||||
"type" : "integer",
|
||||
"required" : true,
|
||||
"title" : "edt_conf_general_port_title",
|
||||
"minimum" : 1024,
|
||||
"maximum" : 65535,
|
||||
"default" : 19445
|
||||
},
|
||||
"timeout" :
|
||||
{
|
||||
"type" : "integer",
|
||||
"required" : true,
|
||||
"title" : "edt_conf_pbs_timeout_title",
|
||||
"append" : "edt_append_s",
|
||||
"minimum" : 1,
|
||||
"default" : 5,
|
||||
"propertyOrder" : 3
|
||||
}
|
||||
},
|
||||
"additionalProperties" : false
|
||||
}
|
44
libsrc/protoserver/CMakeLists.txt
Normal file
44
libsrc/protoserver/CMakeLists.txt
Normal file
@@ -0,0 +1,44 @@
|
||||
|
||||
# Define the current source locations
|
||||
set(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/protoserver)
|
||||
set(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/protoserver)
|
||||
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${PROTOBUF_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
set(ProtoServer_PROTOS ${CURRENT_SOURCE_DIR}/message.proto )
|
||||
|
||||
protobuf_generate_cpp(ProtoServer_PROTO_SRCS ProtoServer_PROTO_HDRS ${ProtoServer_PROTOS} )
|
||||
|
||||
### Split protoclient from protoserver as protoserver relates to HyperionDaemon and standalone capture binarys can't link to it
|
||||
|
||||
add_library(protoclient
|
||||
${CURRENT_SOURCE_DIR}/ProtoClientConnection.h
|
||||
${CURRENT_SOURCE_DIR}/ProtoClientConnection.cpp
|
||||
${ProtoServer_PROTO_SRCS}
|
||||
${ProtoServer_PROTO_HDRS}
|
||||
)
|
||||
|
||||
add_library(protoserver
|
||||
${CURRENT_HEADER_DIR}/ProtoServer.h
|
||||
${CURRENT_SOURCE_DIR}/ProtoServer.cpp
|
||||
)
|
||||
|
||||
# disable warnings for auto generated proto files, we can't change the files ....
|
||||
SET_SOURCE_FILES_PROPERTIES ( ${ProtoServer_PROTO_SRCS} ${ProtoServer_PROTO_HDRS} ${ProtoServer_PROTOS} PROPERTIES COMPILE_FLAGS -w )
|
||||
|
||||
target_link_libraries(protoclient
|
||||
hyperion
|
||||
hyperion-utils
|
||||
protobuf
|
||||
Qt5::Gui
|
||||
)
|
||||
|
||||
target_link_libraries(protoserver
|
||||
hyperion
|
||||
hyperion-utils
|
||||
protoclient
|
||||
Qt5::Gui
|
||||
)
|
238
libsrc/protoserver/ProtoClientConnection.cpp
Normal file
238
libsrc/protoserver/ProtoClientConnection.cpp
Normal file
@@ -0,0 +1,238 @@
|
||||
// project includes
|
||||
#include "ProtoClientConnection.h"
|
||||
|
||||
// qt
|
||||
#include <QTcpSocket>
|
||||
#include <QHostAddress>
|
||||
#include <QTimer>
|
||||
#include <QRgb>
|
||||
|
||||
// Hyperion includes
|
||||
#include <hyperion/Hyperion.h>
|
||||
|
||||
|
||||
|
||||
ProtoClientConnection::ProtoClientConnection(QTcpSocket* socket, const int &timeout, QObject *parent)
|
||||
: QObject(parent)
|
||||
, _log(Logger::getInstance("PROTOSERVER"))
|
||||
, _socket(socket)
|
||||
, _clientAddress(socket->peerAddress().toString())
|
||||
, _timeoutTimer(new QTimer(this))
|
||||
, _timeout(timeout * 1000)
|
||||
, _priority()
|
||||
, _hyperion(Hyperion::getInstance())
|
||||
{
|
||||
// timer setup
|
||||
_timeoutTimer->setSingleShot(true);
|
||||
_timeoutTimer->setInterval(_timeout);
|
||||
connect(_timeoutTimer, &QTimer::timeout, this, &ProtoClientConnection::forceClose);
|
||||
|
||||
// connect socket signals
|
||||
connect(_socket, &QTcpSocket::readyRead, this, &ProtoClientConnection::readyRead);
|
||||
connect(_socket, &QTcpSocket::disconnected, this, &ProtoClientConnection::disconnected);
|
||||
}
|
||||
|
||||
void ProtoClientConnection::readyRead()
|
||||
{
|
||||
_receiveBuffer += _socket->readAll();
|
||||
|
||||
// check if we can read a message size
|
||||
if (_receiveBuffer.size() <= 4)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// read the message size
|
||||
uint32_t messageSize =
|
||||
((_receiveBuffer[0]<<24) & 0xFF000000) |
|
||||
((_receiveBuffer[1]<<16) & 0x00FF0000) |
|
||||
((_receiveBuffer[2]<< 8) & 0x0000FF00) |
|
||||
((_receiveBuffer[3] ) & 0x000000FF);
|
||||
|
||||
// check if we can read a complete message
|
||||
if ((uint32_t) _receiveBuffer.size() < messageSize + 4)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// read a message
|
||||
proto::HyperionRequest message;
|
||||
if (!message.ParseFromArray(_receiveBuffer.data() + 4, messageSize))
|
||||
{
|
||||
sendErrorReply("Unable to parse message");
|
||||
}
|
||||
|
||||
// handle the message
|
||||
handleMessage(message);
|
||||
|
||||
// remove message data from buffer
|
||||
_receiveBuffer = _receiveBuffer.mid(messageSize + 4);
|
||||
}
|
||||
|
||||
void ProtoClientConnection::forceClose()
|
||||
{
|
||||
_socket->close();
|
||||
}
|
||||
|
||||
void ProtoClientConnection::disconnected()
|
||||
{
|
||||
Debug(_log, "Socket Closed");
|
||||
_socket->deleteLater();
|
||||
_hyperion->clear(_priority);
|
||||
emit clientDisconnected();
|
||||
}
|
||||
|
||||
void ProtoClientConnection::handleMessage(const proto::HyperionRequest & message)
|
||||
{
|
||||
switch (message.command())
|
||||
{
|
||||
case proto::HyperionRequest::COLOR:
|
||||
if (!message.HasExtension(proto::ColorRequest::colorRequest))
|
||||
{
|
||||
sendErrorReply("Received COLOR command without ColorRequest");
|
||||
break;
|
||||
}
|
||||
handleColorCommand(message.GetExtension(proto::ColorRequest::colorRequest));
|
||||
break;
|
||||
case proto::HyperionRequest::IMAGE:
|
||||
if (!message.HasExtension(proto::ImageRequest::imageRequest))
|
||||
{
|
||||
sendErrorReply("Received IMAGE command without ImageRequest");
|
||||
break;
|
||||
}
|
||||
handleImageCommand(message.GetExtension(proto::ImageRequest::imageRequest));
|
||||
break;
|
||||
case proto::HyperionRequest::CLEAR:
|
||||
if (!message.HasExtension(proto::ClearRequest::clearRequest))
|
||||
{
|
||||
sendErrorReply("Received CLEAR command without ClearRequest");
|
||||
break;
|
||||
}
|
||||
handleClearCommand(message.GetExtension(proto::ClearRequest::clearRequest));
|
||||
break;
|
||||
case proto::HyperionRequest::CLEARALL:
|
||||
handleClearallCommand();
|
||||
break;
|
||||
default:
|
||||
handleNotImplemented();
|
||||
}
|
||||
}
|
||||
|
||||
void ProtoClientConnection::handleColorCommand(const proto::ColorRequest &message)
|
||||
{
|
||||
// extract parameters
|
||||
int priority = message.priority();
|
||||
int duration = message.has_duration() ? message.duration() : -1;
|
||||
ColorRgb color;
|
||||
color.red = qRed(message.rgbcolor());
|
||||
color.green = qGreen(message.rgbcolor());
|
||||
color.blue = qBlue(message.rgbcolor());
|
||||
|
||||
// make sure the prio is registered before setColor()
|
||||
if(priority != _priority)
|
||||
{
|
||||
_hyperion->clear(_priority);
|
||||
_hyperion->registerInput(priority, hyperion::COMP_PROTOSERVER, "Proto@"+_clientAddress);
|
||||
_priority = priority;
|
||||
}
|
||||
|
||||
// set output
|
||||
_hyperion->setColor(_priority, color, duration);
|
||||
|
||||
// send reply
|
||||
sendSuccessReply();
|
||||
}
|
||||
|
||||
void ProtoClientConnection::handleImageCommand(const proto::ImageRequest &message)
|
||||
{
|
||||
// extract parameters
|
||||
int priority = message.priority();
|
||||
int duration = message.has_duration() ? message.duration() : -1;
|
||||
int width = message.imagewidth();
|
||||
int height = message.imageheight();
|
||||
const std::string & imageData = message.imagedata();
|
||||
|
||||
// make sure the prio is registered before setInput()
|
||||
if(priority != _priority)
|
||||
{
|
||||
_hyperion->clear(_priority);
|
||||
_hyperion->registerInput(priority, hyperion::COMP_PROTOSERVER, "Proto@"+_clientAddress);
|
||||
_priority = priority;
|
||||
}
|
||||
|
||||
// check consistency of the size of the received data
|
||||
if ((int) imageData.size() != width*height*3)
|
||||
{
|
||||
sendErrorReply("Size of image data does not match with the width and height");
|
||||
return;
|
||||
}
|
||||
|
||||
// create ImageRgb
|
||||
Image<ColorRgb> image(width, height);
|
||||
memcpy(image.memptr(), imageData.c_str(), imageData.size());
|
||||
|
||||
_hyperion->setInputImage(_priority, image, duration);
|
||||
|
||||
// send reply
|
||||
sendSuccessReply();
|
||||
}
|
||||
|
||||
|
||||
void ProtoClientConnection::handleClearCommand(const proto::ClearRequest &message)
|
||||
{
|
||||
// extract parameters
|
||||
int priority = message.priority();
|
||||
|
||||
// clear priority
|
||||
_hyperion->clear(priority);
|
||||
// send reply
|
||||
sendSuccessReply();
|
||||
}
|
||||
|
||||
void ProtoClientConnection::handleClearallCommand()
|
||||
{
|
||||
// clear priority
|
||||
_hyperion->clearall();
|
||||
|
||||
// send reply
|
||||
sendSuccessReply();
|
||||
}
|
||||
|
||||
|
||||
void ProtoClientConnection::handleNotImplemented()
|
||||
{
|
||||
sendErrorReply("Command not implemented");
|
||||
}
|
||||
|
||||
void ProtoClientConnection::sendMessage(const google::protobuf::Message &message)
|
||||
{
|
||||
std::string serializedReply = message.SerializeAsString();
|
||||
uint32_t size = serializedReply.size();
|
||||
uint8_t sizeData[] = {uint8_t(size >> 24), uint8_t(size >> 16), uint8_t(size >> 8), uint8_t(size)};
|
||||
_socket->write((const char *) sizeData, sizeof(sizeData));
|
||||
_socket->write(serializedReply.data(), serializedReply.length());
|
||||
_socket->flush();
|
||||
}
|
||||
|
||||
void ProtoClientConnection::sendSuccessReply()
|
||||
{
|
||||
// create reply
|
||||
proto::HyperionReply reply;
|
||||
reply.set_type(proto::HyperionReply::REPLY);
|
||||
reply.set_success(true);
|
||||
|
||||
// send reply
|
||||
sendMessage(reply);
|
||||
}
|
||||
|
||||
void ProtoClientConnection::sendErrorReply(const std::string &error)
|
||||
{
|
||||
// create reply
|
||||
proto::HyperionReply reply;
|
||||
reply.set_type(proto::HyperionReply::REPLY);
|
||||
reply.set_success(false);
|
||||
reply.set_error(error);
|
||||
|
||||
// send reply
|
||||
sendMessage(reply);
|
||||
}
|
135
libsrc/protoserver/ProtoClientConnection.h
Normal file
135
libsrc/protoserver/ProtoClientConnection.h
Normal file
@@ -0,0 +1,135 @@
|
||||
#pragma once
|
||||
|
||||
// util
|
||||
#include <utils/Logger.h>
|
||||
#include <utils/Image.h>
|
||||
#include <utils/ColorRgb.h>
|
||||
#include <utils/Components.h>
|
||||
|
||||
// protobuffer PROTO
|
||||
#include "message.pb.h"
|
||||
|
||||
class QTcpSocket;
|
||||
class QTimer;
|
||||
class Hyperion;
|
||||
|
||||
namespace proto {
|
||||
class HyperionRequest;
|
||||
}
|
||||
|
||||
///
|
||||
/// The Connection object created by a ProtoServer when a new connection is established
|
||||
///
|
||||
class ProtoClientConnection : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
///
|
||||
/// @brief Construct the client
|
||||
/// @param socket The socket
|
||||
/// @param timeout The timeout when a client is automatically disconnected and the priority unregistered
|
||||
/// @param parent The parent
|
||||
///
|
||||
explicit ProtoClientConnection(QTcpSocket* socket, const int &timeout, QObject *parent);
|
||||
|
||||
signals:
|
||||
///
|
||||
/// @brief Emits whenever the client disconnected
|
||||
///
|
||||
void clientDisconnected();
|
||||
|
||||
public slots:
|
||||
///
|
||||
/// @brief close the socket and call disconnected()
|
||||
///
|
||||
void forceClose();
|
||||
|
||||
private slots:
|
||||
///
|
||||
/// @brief Is called whenever the socket got new data to read
|
||||
///
|
||||
void readyRead();
|
||||
|
||||
///
|
||||
/// @brief Is called when the socket closed the connection, also requests thread exit
|
||||
///
|
||||
void disconnected();
|
||||
|
||||
private:
|
||||
///
|
||||
/// Handle an incoming Proto message
|
||||
///
|
||||
/// @param message the incoming message as string
|
||||
///
|
||||
void handleMessage(const proto::HyperionRequest &message);
|
||||
|
||||
///
|
||||
/// Handle an incoming Proto Color message
|
||||
///
|
||||
/// @param message the incoming message
|
||||
///
|
||||
void handleColorCommand(const proto::ColorRequest & message);
|
||||
|
||||
///
|
||||
/// Handle an incoming Proto Image message
|
||||
///
|
||||
/// @param message the incoming message
|
||||
///
|
||||
void handleImageCommand(const proto::ImageRequest & message);
|
||||
|
||||
///
|
||||
/// Handle an incoming Proto Clear message
|
||||
///
|
||||
/// @param message the incoming message
|
||||
///
|
||||
void handleClearCommand(const proto::ClearRequest & message);
|
||||
|
||||
///
|
||||
/// Handle an incoming Proto Clearall message
|
||||
///
|
||||
void handleClearallCommand();
|
||||
|
||||
///
|
||||
/// Handle an incoming Proto message of unknown type
|
||||
///
|
||||
void handleNotImplemented();
|
||||
|
||||
///
|
||||
/// Send a message to the connected client
|
||||
///
|
||||
/// @param message The Proto message to send
|
||||
///
|
||||
void sendMessage(const google::protobuf::Message &message);
|
||||
|
||||
///
|
||||
/// Send a standard reply indicating success
|
||||
///
|
||||
void sendSuccessReply();
|
||||
|
||||
///
|
||||
/// Send an error message back to the client
|
||||
///
|
||||
/// @param error String describing the error
|
||||
///
|
||||
void sendErrorReply(const std::string & error);
|
||||
|
||||
private:
|
||||
Logger*_log;
|
||||
|
||||
/// The TCP-Socket that is connected tot the Proto-client
|
||||
QTcpSocket* _socket;
|
||||
|
||||
/// address of client
|
||||
const QString _clientAddress;
|
||||
|
||||
QTimer*_timeoutTimer;
|
||||
int _timeout;
|
||||
int _priority;
|
||||
|
||||
/// Link to Hyperion for writing led-values to a priority channel
|
||||
Hyperion* _hyperion;
|
||||
|
||||
/// The buffer used for reading data from the socket
|
||||
QByteArray _receiveBuffer;
|
||||
};
|
104
libsrc/protoserver/ProtoServer.cpp
Normal file
104
libsrc/protoserver/ProtoServer.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
#include <protoserver/ProtoServer.h>
|
||||
#include "ProtoClientConnection.h"
|
||||
|
||||
// qt
|
||||
#include <QJsonObject>
|
||||
#include <QTcpServer>
|
||||
#include <QTcpSocket>
|
||||
|
||||
ProtoServer::ProtoServer(const QJsonDocument& config, QObject* parent)
|
||||
: QObject(parent)
|
||||
, _server(new QTcpServer(this))
|
||||
, _log(Logger::getInstance("PROTOSERVER"))
|
||||
, _timeout(5000)
|
||||
, _config(config)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ProtoServer::~ProtoServer()
|
||||
{
|
||||
stopServer();
|
||||
delete _server;
|
||||
}
|
||||
|
||||
void ProtoServer::initServer()
|
||||
{
|
||||
connect(_server, &QTcpServer::newConnection, this, &ProtoServer::newConnection);
|
||||
|
||||
// apply config
|
||||
handleSettingsUpdate(settings::PROTOSERVER, _config);
|
||||
}
|
||||
|
||||
void ProtoServer::handleSettingsUpdate(const settings::type& type, const QJsonDocument& config)
|
||||
{
|
||||
if(type == settings::PROTOSERVER)
|
||||
{
|
||||
const QJsonObject& obj = config.object();
|
||||
|
||||
quint16 port = obj["port"].toInt(19445);
|
||||
|
||||
// port check
|
||||
if(_server->serverPort() != port)
|
||||
{
|
||||
stopServer();
|
||||
_port = port;
|
||||
}
|
||||
|
||||
// new timeout just for new connections
|
||||
_timeout = obj["timeout"].toInt(5000);
|
||||
// enable check
|
||||
obj["enable"].toBool(true) ? startServer() : stopServer();
|
||||
}
|
||||
}
|
||||
|
||||
void ProtoServer::newConnection()
|
||||
{
|
||||
while(_server->hasPendingConnections())
|
||||
{
|
||||
if(QTcpSocket * socket = _server->nextPendingConnection())
|
||||
{
|
||||
Debug(_log, "New connection from %s", QSTRING_CSTR(socket->peerAddress().toString()));
|
||||
ProtoClientConnection * client = new ProtoClientConnection(socket, _timeout, this);
|
||||
// internal
|
||||
connect(client, &ProtoClientConnection::clientDisconnected, this, &ProtoServer::clientDisconnected);
|
||||
_openConnections.append(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProtoServer::clientDisconnected()
|
||||
{
|
||||
ProtoClientConnection* client = qobject_cast<ProtoClientConnection*>(sender());
|
||||
client->deleteLater();
|
||||
_openConnections.removeAll(client);
|
||||
}
|
||||
|
||||
void ProtoServer::startServer()
|
||||
{
|
||||
if(!_server->isListening())
|
||||
{
|
||||
if(!_server->listen(QHostAddress::Any, _port))
|
||||
{
|
||||
Error(_log,"Failed to bind port %d", _port);
|
||||
}
|
||||
else
|
||||
{
|
||||
Info(_log,"Started on port %d", _port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProtoServer::stopServer()
|
||||
{
|
||||
if(_server->isListening())
|
||||
{
|
||||
// close client connections
|
||||
for(const auto& client : _openConnections)
|
||||
{
|
||||
client->forceClose();
|
||||
}
|
||||
_server->close();
|
||||
Info(_log, "Stopped");
|
||||
}
|
||||
}
|
80
libsrc/protoserver/message.proto
Normal file
80
libsrc/protoserver/message.proto
Normal file
@@ -0,0 +1,80 @@
|
||||
package proto;
|
||||
|
||||
message HyperionRequest {
|
||||
enum Command {
|
||||
COLOR = 1;
|
||||
IMAGE = 2;
|
||||
CLEAR = 3;
|
||||
CLEARALL = 4;
|
||||
}
|
||||
|
||||
// command specification
|
||||
required Command command = 1;
|
||||
|
||||
// extensions to define all specific requests
|
||||
extensions 10 to 100;
|
||||
}
|
||||
|
||||
message ColorRequest {
|
||||
extend HyperionRequest {
|
||||
optional ColorRequest colorRequest = 10;
|
||||
}
|
||||
|
||||
// priority to use when setting the color
|
||||
required int32 priority = 1;
|
||||
|
||||
// integer value containing the rgb color (0x00RRGGBB)
|
||||
required int32 RgbColor = 2;
|
||||
|
||||
// duration of the request (negative results in infinite)
|
||||
optional int32 duration = 3;
|
||||
}
|
||||
|
||||
message ImageRequest {
|
||||
extend HyperionRequest {
|
||||
optional ImageRequest imageRequest = 11;
|
||||
}
|
||||
|
||||
// priority to use when setting the image
|
||||
required int32 priority = 1;
|
||||
|
||||
// width of the image
|
||||
required int32 imagewidth = 2;
|
||||
|
||||
// height of the image
|
||||
required int32 imageheight = 3;
|
||||
|
||||
// image data
|
||||
required bytes imagedata = 4;
|
||||
|
||||
// duration of the request (negative results in infinite)
|
||||
optional int32 duration = 5;
|
||||
}
|
||||
|
||||
message ClearRequest {
|
||||
extend HyperionRequest {
|
||||
optional ClearRequest clearRequest = 12;
|
||||
}
|
||||
|
||||
// priority which need to be cleared
|
||||
required int32 priority = 1;
|
||||
}
|
||||
|
||||
message HyperionReply {
|
||||
enum Type {
|
||||
REPLY = 1;
|
||||
VIDEO = 2;
|
||||
}
|
||||
|
||||
// Identifies which field is filled in.
|
||||
required Type type = 1;
|
||||
|
||||
// flag indication success or failure
|
||||
optional bool success = 2;
|
||||
|
||||
// string indicating the reason for failure (if applicable)
|
||||
optional string error = 3;
|
||||
|
||||
// Proto Messages for video mode
|
||||
optional int32 video = 4;
|
||||
}
|
@@ -5,6 +5,7 @@
|
||||
#include <bonjour/bonjourserviceregister.h>
|
||||
|
||||
// hyperion includes
|
||||
#include <hyperion/Hyperion.h>
|
||||
#include "HyperionConfig.h"
|
||||
|
||||
// qt includes
|
||||
@@ -22,6 +23,9 @@ UDPListener::UDPListener(const QJsonDocument& config) :
|
||||
_isActive(false),
|
||||
_listenPort(0)
|
||||
{
|
||||
// listen for component change
|
||||
connect(Hyperion::getInstance(), &Hyperion::componentStateChanged, this, &UDPListener::componentStateChanged);
|
||||
|
||||
// init
|
||||
handleSettingsUpdate(settings::UDPLISTENER, config);
|
||||
}
|
||||
@@ -70,6 +74,8 @@ void UDPListener::start()
|
||||
_serviceRegister->registerService("_hyperiond-udp._udp", _listenPort);
|
||||
}
|
||||
}
|
||||
|
||||
Hyperion::getInstance()->getComponentRegister().componentStateChanged(COMP_UDPLISTENER, _isActive);
|
||||
}
|
||||
|
||||
void UDPListener::stop()
|
||||
@@ -80,7 +86,7 @@ void UDPListener::stop()
|
||||
_server->close();
|
||||
_isActive = false;
|
||||
Info(_log, "Stopped");
|
||||
// emit clearGlobalPriority(_priority, hyperion::COMP_UDPLISTENER);
|
||||
Hyperion::getInstance()->getComponentRegister().componentStateChanged(COMP_UDPLISTENER, _isActive);
|
||||
}
|
||||
|
||||
void UDPListener::componentStateChanged(const hyperion::Components component, bool enable)
|
||||
|
Reference in New Issue
Block a user