- prepare general way to send (proto) messages. currently only incomming protomessages are forwarded

- begin impl. of json server


Former-commit-id: 8f9237cd57ada1e84dc05e60b9ad723e47fd57b1
This commit is contained in:
redpanther 2016-02-15 18:25:18 +01:00
parent 5dc59344c4
commit b01b5eb005
12 changed files with 287 additions and 104 deletions

View File

@ -13,6 +13,7 @@
// Hyperion includes // Hyperion includes
#include <hyperion/LedString.h> #include <hyperion/LedString.h>
#include <hyperion/PriorityMuxer.h> #include <hyperion/PriorityMuxer.h>
#include <hyperion/MessageForwarder.h>
// Effect engine includes // Effect engine includes
#include <effectengine/EffectDefinition.h> #include <effectengine/EffectDefinition.h>
@ -125,6 +126,10 @@ public slots:
/// Tell Hyperion that the transforms have changed and the leds need to be updated /// Tell Hyperion that the transforms have changed and the leds need to be updated
void transformsUpdated(); void transformsUpdated();
/// Returns MessageForwarder Object
/// @return instance of message forwarder object
MessageForwarder * getForwarder();
/// ///
/// Clears the given priority channel. This will switch the led-colors to the colors of the next /// Clears the given priority channel. This will switch the led-colors to the colors of the next
/// lower priority channel (or off if no more channels are set) /// lower priority channel (or off if no more channels are set)
@ -168,6 +173,7 @@ public:
static RgbChannelTransform * createRgbChannelTransform(const Json::Value& colorConfig); static RgbChannelTransform * createRgbChannelTransform(const Json::Value& colorConfig);
static LedDevice * createColorSmoothing(const Json::Value & smoothingConfig, LedDevice * ledDevice); static LedDevice * createColorSmoothing(const Json::Value & smoothingConfig, LedDevice * ledDevice);
static MessageForwarder * createMessageForwarder(const Json::Value & forwarderConfig);
signals: signals:
/// Signal which is emitted when a priority channel is actively cleared /// Signal which is emitted when a priority channel is actively cleared
@ -201,6 +207,9 @@ private:
/// Effect engine /// Effect engine
EffectEngine * _effectEngine; EffectEngine * _effectEngine;
// proto and json Message forwarder
MessageForwarder * _messageForwarder;
/// The timer for handling priority channel timeouts /// The timer for handling priority channel timeouts
QTimer _timer; QTimer _timer;
}; };

View File

@ -0,0 +1,31 @@
#pragma once
// STL includes
#include <vector>
#include <map>
#include <cstdint>
#include <limits>
// QT includes
#include <QList>
#include <QStringList>
// Utils includes
#include <utils/ColorRgb.h>
class MessageForwarder
{
public:
MessageForwarder();
~MessageForwarder();
void addJsonSlave(std::string slave);
void addProtoSlave(std::string slave);
void sendMessage();
QStringList getProtoSlaves();
private:
bool _running;
QStringList _protoSlaves;
};

View File

@ -6,12 +6,19 @@
// Qt includes // Qt includes
#include <QTcpServer> #include <QTcpServer>
#include <QSet> #include <QSet>
#include <QList>
#include <QStringList> #include <QStringList>
// Hyperion includes // Hyperion includes
#include <hyperion/Hyperion.h> #include <hyperion/Hyperion.h>
// forward decl
class ProtoClientConnection; class ProtoClientConnection;
class ProtoConnection;
namespace proto {
class HyperionRequest;
}
/// ///
/// This class creates a TCP server which accepts connections wich can then send /// This class creates a TCP server which accepts connections wich can then send
@ -28,7 +35,7 @@ public:
/// @param hyperion Hyperion instance /// @param hyperion Hyperion instance
/// @param port port number on which to start listening for connections /// @param port port number on which to start listening for connections
/// ///
ProtoServer(Hyperion * hyperion, uint16_t port = 19445, QStringList * forwardClientList = new QStringList() ); ProtoServer(Hyperion * hyperion, uint16_t port = 19445);
~ProtoServer(); ~ProtoServer();
/// ///
@ -48,6 +55,8 @@ private slots:
/// ///
void closedConnection(ProtoClientConnection * connection); void closedConnection(ProtoClientConnection * connection);
void newMessage(const proto::HyperionRequest * message);
private: private:
/// Hyperion instance /// Hyperion instance
Hyperion * _hyperion; Hyperion * _hyperion;
@ -58,4 +67,8 @@ private:
/// List with open connections /// List with open connections
QSet<ProtoClientConnection *> _openConnections; QSet<ProtoClientConnection *> _openConnections;
QStringList _forwardClients; QStringList _forwardClients;
/// Hyperion proto connection object for forwarding
QList<ProtoConnection*> _proxy_connections;
}; };

View File

@ -1,66 +1,68 @@
# Define the current source locations # Define the current source locations
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/hyperion) SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/hyperion)
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/hyperion) SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/hyperion)
# Group the headers that go through the MOC compiler # Group the headers that go through the MOC compiler
SET(Hyperion_QT_HEADERS SET(Hyperion_QT_HEADERS
${CURRENT_HEADER_DIR}/Hyperion.h ${CURRENT_HEADER_DIR}/Hyperion.h
${CURRENT_HEADER_DIR}/MessageForwarder.h
${CURRENT_SOURCE_DIR}/LinearColorSmoothing.h
) ${CURRENT_SOURCE_DIR}/LinearColorSmoothing.h
)
SET(Hyperion_HEADERS
${CURRENT_HEADER_DIR}/ImageProcessor.h SET(Hyperion_HEADERS
${CURRENT_HEADER_DIR}/ImageProcessorFactory.h ${CURRENT_HEADER_DIR}/ImageProcessor.h
${CURRENT_HEADER_DIR}/ImageToLedsMap.h ${CURRENT_HEADER_DIR}/ImageProcessorFactory.h
${CURRENT_HEADER_DIR}/LedString.h ${CURRENT_HEADER_DIR}/ImageToLedsMap.h
${CURRENT_HEADER_DIR}/PriorityMuxer.h ${CURRENT_HEADER_DIR}/LedString.h
${CURRENT_HEADER_DIR}/PriorityMuxer.h
${CURRENT_SOURCE_DIR}/MultiColorTransform.h
) ${CURRENT_SOURCE_DIR}/MultiColorTransform.h
)
SET(Hyperion_SOURCES
${CURRENT_SOURCE_DIR}/Hyperion.cpp SET(Hyperion_SOURCES
${CURRENT_SOURCE_DIR}/ImageProcessor.cpp ${CURRENT_SOURCE_DIR}/Hyperion.cpp
${CURRENT_SOURCE_DIR}/ImageProcessorFactory.cpp ${CURRENT_SOURCE_DIR}/ImageProcessor.cpp
${CURRENT_SOURCE_DIR}/LedString.cpp ${CURRENT_SOURCE_DIR}/ImageProcessorFactory.cpp
${CURRENT_SOURCE_DIR}/PriorityMuxer.cpp ${CURRENT_SOURCE_DIR}/LedString.cpp
${CURRENT_SOURCE_DIR}/PriorityMuxer.cpp
${CURRENT_SOURCE_DIR}/ImageToLedsMap.cpp
${CURRENT_SOURCE_DIR}/MultiColorTransform.cpp ${CURRENT_SOURCE_DIR}/ImageToLedsMap.cpp
${CURRENT_SOURCE_DIR}/LinearColorSmoothing.cpp ${CURRENT_SOURCE_DIR}/MultiColorTransform.cpp
) ${CURRENT_SOURCE_DIR}/LinearColorSmoothing.cpp
${CURRENT_SOURCE_DIR}/MessageForwarder.cpp
set(Hyperion_RESOURCES )
${CURRENT_SOURCE_DIR}/resource.qrc
) set(Hyperion_RESOURCES
${CURRENT_SOURCE_DIR}/resource.qrc
if(ENABLE_QT5) )
QT5_WRAP_CPP(Hyperion_HEADERS_MOC ${Hyperion_QT_HEADERS})
QT5_ADD_RESOURCES(Hyperion_RESOURCES_RCC ${Hyperion_RESOURCES} OPTIONS "-no-compress") if(ENABLE_QT5)
else(ENABLE_QT5) QT5_WRAP_CPP(Hyperion_HEADERS_MOC ${Hyperion_QT_HEADERS})
QT4_WRAP_CPP(Hyperion_HEADERS_MOC ${Hyperion_QT_HEADERS}) QT5_ADD_RESOURCES(Hyperion_RESOURCES_RCC ${Hyperion_RESOURCES} OPTIONS "-no-compress")
QT4_ADD_RESOURCES(Hyperion_RESOURCES_RCC ${Hyperion_RESOURCES} OPTIONS "-no-compress") else(ENABLE_QT5)
endif(ENABLE_QT5) QT4_WRAP_CPP(Hyperion_HEADERS_MOC ${Hyperion_QT_HEADERS})
QT4_ADD_RESOURCES(Hyperion_RESOURCES_RCC ${Hyperion_RESOURCES} OPTIONS "-no-compress")
add_library(hyperion endif(ENABLE_QT5)
${Hyperion_HEADERS}
${Hyperion_QT_HEADERS} add_library(hyperion
${Hyperion_HEADERS_MOC} ${Hyperion_HEADERS}
${Hyperion_SOURCES} ${Hyperion_QT_HEADERS}
${Hyperion_RESOURCES_RCC} ${Hyperion_HEADERS_MOC}
) ${Hyperion_SOURCES}
${Hyperion_RESOURCES_RCC}
if(ENABLE_QT5) )
qt5_use_modules(hyperion Widgets)
endif(ENABLE_QT5) if(ENABLE_QT5)
qt5_use_modules(hyperion Widgets)
target_link_libraries(hyperion endif(ENABLE_QT5)
blackborder
hyperion-utils target_link_libraries(hyperion
leddevice blackborder
effectengine hyperion-utils
serialport leddevice
${QT_LIBRARIES} effectengine
) serialport
${QT_LIBRARIES}
)

View File

@ -267,12 +267,39 @@ LedDevice * Hyperion::createColorSmoothing(const Json::Value & smoothingConfig,
} }
MessageForwarder * Hyperion::createMessageForwarder(const Json::Value & forwarderConfig)
{
MessageForwarder * forwarder = new MessageForwarder();
if ( ! forwarderConfig.isNull() )
{
if ( ! forwarderConfig["json"].isNull() && forwarderConfig["json"].isArray() )
{
for (const Json::Value& addr : forwarderConfig["json"])
forwarder->addJsonSlave(addr.asString());
}
if ( ! forwarderConfig["proto"].isNull() && forwarderConfig["proto"].isArray() )
{
for (const Json::Value& addr : forwarderConfig["proto"])
forwarder->addProtoSlave(addr.asString());
}
}
return forwarder;
}
MessageForwarder * Hyperion::getForwarder()
{
return _messageForwarder;
}
Hyperion::Hyperion(const Json::Value &jsonConfig) : Hyperion::Hyperion(const Json::Value &jsonConfig) :
_ledString(createLedString(jsonConfig["leds"], createColorOrder(jsonConfig["device"]))), _ledString(createLedString(jsonConfig["leds"], createColorOrder(jsonConfig["device"]))),
_muxer(_ledString.leds().size()), _muxer(_ledString.leds().size()),
_raw2ledTransform(createLedColorsTransform(_ledString.leds().size(), jsonConfig["color"])), _raw2ledTransform(createLedColorsTransform(_ledString.leds().size(), jsonConfig["color"])),
_device(LedDeviceFactory::construct(jsonConfig["device"])), _device(LedDeviceFactory::construct(jsonConfig["device"])),
_effectEngine(nullptr), _effectEngine(nullptr),
_messageForwarder(createMessageForwarder(jsonConfig["forwarder"])),
_timer() _timer()
{ {
if (!_raw2ledTransform->verifyTransforms()) if (!_raw2ledTransform->verifyTransforms())
@ -314,6 +341,9 @@ Hyperion::~Hyperion()
// delete the color transform // delete the color transform
delete _raw2ledTransform; delete _raw2ledTransform;
// delete the message forwarder
delete _messageForwarder;
} }
unsigned Hyperion::getLedCount() const unsigned Hyperion::getLedCount() const

View File

@ -0,0 +1,34 @@
#include <hyperion/MessageForwarder.h>
MessageForwarder::MessageForwarder() :
_running(false)
{
}
MessageForwarder::~MessageForwarder()
{
}
void MessageForwarder::addJsonSlave(std::string slave)
{
std::cout << slave << std::endl;
}
void MessageForwarder::addProtoSlave(std::string slave)
{
_protoSlaves << QString(slave.c_str());
}
void MessageForwarder::sendMessage()
{
if ( ! _running )
return;
}
QStringList MessageForwarder::getProtoSlaves()
{
return _protoSlaves;
}

View File

@ -250,8 +250,22 @@ void JsonClientConnection::handleMessage(const std::string &messageString)
handleNotImplemented(); handleNotImplemented();
} }
void JsonClientConnection::forwardJsonMessage(const Json::Value & message)
{
QTcpSocket client;
client.connectToHost(QHostAddress("127.0.0.1"), 19444);
if ( client.waitForConnected(500) )
{
sendMessage(message,&client);
client.close();
}
}
void JsonClientConnection::handleColorCommand(const Json::Value &message) void JsonClientConnection::handleColorCommand(const Json::Value &message)
{ {
forwardJsonMessage(message);
// extract parameters // extract parameters
int priority = message["priority"].asInt(); int priority = message["priority"].asInt();
int duration = message.get("duration", -1).asInt(); int duration = message.get("duration", -1).asInt();
@ -289,6 +303,8 @@ void JsonClientConnection::handleColorCommand(const Json::Value &message)
void JsonClientConnection::handleImageCommand(const Json::Value &message) void JsonClientConnection::handleImageCommand(const Json::Value &message)
{ {
forwardJsonMessage(message);
// extract parameters // extract parameters
int priority = message["priority"].asInt(); int priority = message["priority"].asInt();
int duration = message.get("duration", -1).asInt(); int duration = message.get("duration", -1).asInt();
@ -320,6 +336,8 @@ void JsonClientConnection::handleImageCommand(const Json::Value &message)
void JsonClientConnection::handleEffectCommand(const Json::Value &message) void JsonClientConnection::handleEffectCommand(const Json::Value &message)
{ {
forwardJsonMessage(message);
// extract parameters // extract parameters
int priority = message["priority"].asInt(); int priority = message["priority"].asInt();
int duration = message.get("duration", -1).asInt(); int duration = message.get("duration", -1).asInt();
@ -418,6 +436,8 @@ void JsonClientConnection::handleServerInfoCommand(const Json::Value &)
void JsonClientConnection::handleClearCommand(const Json::Value &message) void JsonClientConnection::handleClearCommand(const Json::Value &message)
{ {
forwardJsonMessage(message);
// extract parameters // extract parameters
int priority = message["priority"].asInt(); int priority = message["priority"].asInt();
@ -428,8 +448,10 @@ void JsonClientConnection::handleClearCommand(const Json::Value &message)
sendSuccessReply(); sendSuccessReply();
} }
void JsonClientConnection::handleClearallCommand(const Json::Value &) void JsonClientConnection::handleClearallCommand(const Json::Value & message)
{ {
forwardJsonMessage(message);
// clear priority // clear priority
_hyperion->clearall(); _hyperion->clearall();
@ -530,10 +552,51 @@ void JsonClientConnection::sendMessage(const Json::Value &message)
response.append(serializedReply.c_str(), serializedReply.length()); response.append(serializedReply.c_str(), serializedReply.length());
_socket->write(response.data(), response.length()); _socket->write(response.data(), response.length());
} }
} }
void JsonClientConnection::sendMessage(const Json::Value & message, QTcpSocket * socket)
{
// serialize message (FastWriter already appends a newline)
std::string serializedMessage = Json::FastWriter().write(message);
// write message
socket->write(serializedMessage.c_str());
if (!socket->waitForBytesWritten())
{
//std::cout << "Error while writing data to host" << std::endl;
return;
}
// read reply data
QByteArray serializedReply;
while (!serializedReply.contains('\n'))
{
// receive reply
if (!socket->waitForReadyRead())
{
//std::cout << "Error while reading data from host" << std::endl;
return;
}
serializedReply += socket->readAll();
}
int bytes = serializedReply.indexOf('\n') + 1; // Find the end of message
// parse reply data
Json::Reader jsonReader;
Json::Value reply;
if (!jsonReader.parse(serializedReply.constData(), serializedReply.constData() + bytes, reply))
{
//std::cout << "Error while parsing reply: invalid json" << std::endl;
return;
}
}
void JsonClientConnection::sendSuccessReply() void JsonClientConnection::sendSuccessReply()
{ {
// create reply // create reply

View File

@ -124,6 +124,7 @@ private:
/// @param message The JSON message to send /// @param message The JSON message to send
/// ///
void sendMessage(const Json::Value & message); void sendMessage(const Json::Value & message);
void sendMessage(const Json::Value & message, QTcpSocket * socket);
/// ///
/// Send a standard reply indicating success /// Send a standard reply indicating success
@ -147,6 +148,11 @@ private:
/// ///
void handleWebSocketFrame(); void handleWebSocketFrame();
///
/// forward json message
///
void forwardJsonMessage(const Json::Value & message);
private: private:
/// ///
/// Check if a JSON messag is valid according to a given JSON schema /// Check if a JSON messag is valid according to a given JSON schema

View File

@ -20,7 +20,7 @@
// project includes // project includes
#include "ProtoClientConnection.h" #include "ProtoClientConnection.h"
ProtoClientConnection::ProtoClientConnection(QTcpSocket *socket, Hyperion * hyperion, QStringList forwardClientList) : ProtoClientConnection::ProtoClientConnection(QTcpSocket *socket, Hyperion * hyperion) :
QObject(), QObject(),
_socket(socket), _socket(socket),
_imageProcessor(ImageProcessorFactory::getInstance().newImageProcessor()), _imageProcessor(ImageProcessorFactory::getInstance().newImageProcessor()),
@ -30,22 +30,11 @@ ProtoClientConnection::ProtoClientConnection(QTcpSocket *socket, Hyperion * hype
// connect internal signals and slots // connect internal signals and slots
connect(_socket, SIGNAL(disconnected()), this, SLOT(socketClosed())); connect(_socket, SIGNAL(disconnected()), this, SLOT(socketClosed()));
connect(_socket, SIGNAL(readyRead()), this, SLOT(readData())); connect(_socket, SIGNAL(readyRead()), this, SLOT(readData()));
for (int i = 0; i < forwardClientList.size(); ++i) {
std::cout << "Proto forward to " << forwardClientList.at(i).toLocal8Bit().constData() << std::endl;
ProtoConnection* p = new ProtoConnection("127.0.0.1:19445");
p->setSkipReply(true);
_proxy_connections << p;
}
} }
ProtoClientConnection::~ProtoClientConnection() ProtoClientConnection::~ProtoClientConnection()
{ {
delete _socket; delete _socket;
while (!_proxy_connections.isEmpty())
delete _proxy_connections.takeFirst();
} }
void ProtoClientConnection::readData() void ProtoClientConnection::readData()
@ -93,8 +82,7 @@ void ProtoClientConnection::socketClosed()
void ProtoClientConnection::handleMessage(const proto::HyperionRequest & message) void ProtoClientConnection::handleMessage(const proto::HyperionRequest & message)
{ {
// forward messages // forward messages
for (int i = 0; i < _proxy_connections.size(); ++i) emit newMessage(&message);
_proxy_connections.at(i)->sendMessage(message);
switch (message.command()) switch (message.command())
{ {

View File

@ -30,7 +30,7 @@ public:
/// @param socket The Socket object for this connection /// @param socket The Socket object for this connection
/// @param hyperion The Hyperion server /// @param hyperion The Hyperion server
/// ///
ProtoClientConnection(QTcpSocket * socket, Hyperion * hyperion, QStringList forwardClientList); ProtoClientConnection(QTcpSocket * socket, Hyperion * hyperion);
/// ///
/// Destructor /// Destructor
@ -43,6 +43,7 @@ signals:
/// @param connection This connection object /// @param connection This connection object
/// ///
void connectionClosed(ProtoClientConnection * connection); void connectionClosed(ProtoClientConnection * connection);
void newMessage(const proto::HyperionRequest * message);
private slots: private slots:
/// ///
@ -125,8 +126,4 @@ private:
/// The buffer used for reading data from the socket /// The buffer used for reading data from the socket
QByteArray _receiveBuffer; QByteArray _receiveBuffer;
/// Hyperion proto connection object for forwarding
QList<ProtoConnection*> _proxy_connections;
}; };

View File

@ -2,17 +2,27 @@
#include <stdexcept> #include <stdexcept>
// project includes // project includes
#include <hyperion/MessageForwarder.h>
#include <protoserver/ProtoServer.h> #include <protoserver/ProtoServer.h>
#include "protoserver/ProtoConnection.h"
#include "ProtoClientConnection.h" #include "ProtoClientConnection.h"
ProtoServer::ProtoServer(Hyperion *hyperion, uint16_t port, QStringList * forwardClientList) : ProtoServer::ProtoServer(Hyperion *hyperion, uint16_t port) :
QObject(), QObject(),
_hyperion(hyperion), _hyperion(hyperion),
_server(), _server(),
_openConnections() _openConnections()
{ {
for (int i = 0; i < forwardClientList->size(); ++i)
_forwardClients << forwardClientList->at(i); MessageForwarder * forwarder = hyperion->getForwarder();
QStringList slaves = forwarder->getProtoSlaves();
for (int i = 0; i < slaves.size(); ++i) {
std::cout << "Proto forward to " << slaves.at(i).toLocal8Bit().constData() << std::endl;
ProtoConnection* p = new ProtoConnection(slaves.at(i).toLocal8Bit().constData());
p->setSkipReply(true);
_proxy_connections << p;
}
if (!_server.listen(QHostAddress::Any, port)) if (!_server.listen(QHostAddress::Any, port))
{ {
@ -28,6 +38,9 @@ ProtoServer::~ProtoServer()
foreach (ProtoClientConnection * connection, _openConnections) { foreach (ProtoClientConnection * connection, _openConnections) {
delete connection; delete connection;
} }
while (!_proxy_connections.isEmpty())
delete _proxy_connections.takeFirst();
} }
uint16_t ProtoServer::getPort() const uint16_t ProtoServer::getPort() const
@ -42,14 +55,22 @@ void ProtoServer::newConnection()
if (socket != nullptr) if (socket != nullptr)
{ {
std::cout << "New proto connection" << std::endl; std::cout << "New proto connection" << std::endl;
ProtoClientConnection * connection = new ProtoClientConnection(socket, _hyperion, _forwardClients); ProtoClientConnection * connection = new ProtoClientConnection(socket, _hyperion);
_openConnections.insert(connection); _openConnections.insert(connection);
// register slot for cleaning up after the connection closed // register slot for cleaning up after the connection closed
connect(connection, SIGNAL(connectionClosed(ProtoClientConnection*)), this, SLOT(closedConnection(ProtoClientConnection*))); connect(connection, SIGNAL(connectionClosed(ProtoClientConnection*)), this, SLOT(closedConnection(ProtoClientConnection*)));
connect(connection, SIGNAL(newMessage(const proto::HyperionRequest*)), this, SLOT(newMessage(const proto::HyperionRequest*)));
} }
} }
void ProtoServer::newMessage(const proto::HyperionRequest * message)
{
for (int i = 0; i < _proxy_connections.size(); ++i)
_proxy_connections.at(i)->sendMessage(*message);
}
void ProtoServer::closedConnection(ProtoClientConnection *connection) void ProtoServer::closedConnection(ProtoClientConnection *connection)
{ {
std::cout << "Proto connection closed" << std::endl; std::cout << "Proto connection closed" << std::endl;

View File

@ -369,18 +369,7 @@ int main(int argc, char** argv)
if (config.isMember("protoServer")) if (config.isMember("protoServer"))
{ {
const Json::Value & protoServerConfig = config["protoServer"]; const Json::Value & protoServerConfig = config["protoServer"];
QStringList forwardClientList; protoServer = new ProtoServer(&hyperion, protoServerConfig["port"].asUInt() );
if ( ! protoServerConfig["forward"].isNull() && protoServerConfig["forward"].isArray() )
{
for (const Json::Value& client : protoServerConfig["forward"])
{
forwardClientList << client.asString().c_str();
std::cout << client.asString() << std::endl;
}
}
protoServer = new ProtoServer(&hyperion, protoServerConfig["port"].asUInt(), &forwardClientList );
std::cout << "Proto server created and started on port " << protoServer->getPort() << std::endl; std::cout << "Proto server created and started on port " << protoServer->getPort() << std::endl;
} }
#endif #endif