added skeleton for the json connection server

This commit is contained in:
johan 2013-08-17 15:39:29 +02:00
parent 2c97353a11
commit 16c260b3dc
9 changed files with 269 additions and 17 deletions

View File

@ -0,0 +1,36 @@
#pragma once
// system includes
#include <cstdint>
// Qt includes
#include <QTcpServer>
#include <QSet>
// Hyperion includes
#include <hyperion/Hyperion.h>
class JsonClientConnection;
class JsonServer : public QObject
{
Q_OBJECT
public:
JsonServer(Hyperion * hyperion, uint16_t port = 19444);
~JsonServer();
uint16_t getPort() const;
private slots:
void newConnection();
void closedConnection(JsonClientConnection * connection);
private:
Hyperion * _hyperion;
QTcpServer _server;
QSet<JsonClientConnection *> _openConnections;
};

View File

@ -4,4 +4,5 @@ SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include)
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc) SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc)
add_subdirectory(hyperion) add_subdirectory(hyperion)
add_subdirectory(jsonserver)
add_subdirectory(utils) add_subdirectory(utils)

View File

@ -0,0 +1,36 @@
# Define the current source locations
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/jsonserver)
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/jsonserver)
# Group the headers that go through the MOC compiler
SET(JsonServer_QT_HEADERS
${CURRENT_HEADER_DIR}/JsonServer.h
${CURRENT_SOURCE_DIR}/JsonClientConnection.h
)
SET(JsonServer_HEADERS
)
SET(JsonServer_SOURCES
${CURRENT_SOURCE_DIR}/JsonServer.cpp
${CURRENT_SOURCE_DIR}/JsonClientConnection.cpp
)
qt4_wrap_cpp(JsonServer_HEADERS_MOC ${JsonServer_QT_HEADERS})
add_library(jsonserver
${JsonServer_HEADERS}
${JsonServer_QT_HEADERS}
${JsonServer_HEADERS_MOC}
${JsonServer_SOURCES}
)
target_link_libraries(jsonserver
hyperion
jsoncpp)
qt4_use_modules(jsonserver
Core
Gui
Network)

View File

@ -0,0 +1,77 @@
// stl includes
#include <iostream>
#include "JsonClientConnection.h"
JsonClientConnection::JsonClientConnection(QTcpSocket *socket) :
QObject(),
_socket(socket)
{
connect(_socket, SIGNAL(disconnected()), this, SLOT(socketClosed()));
connect(_socket, SIGNAL(readyRead()), this, SLOT(readData()));
}
JsonClientConnection::~JsonClientConnection()
{
delete _socket;
}
void JsonClientConnection::readData()
{
_receiveBuffer += _socket->readAll();
int bytes = _receiveBuffer.indexOf('\n') + 1;
if (bytes != 0)
{
// create message string
std::string message(_receiveBuffer.data(), bytes);
// remove message data from buffer
_receiveBuffer = _receiveBuffer.mid(bytes);
// handle message
handleMessage(message);
}
}
void JsonClientConnection::socketClosed()
{
emit connectionClosed(this);
}
void JsonClientConnection::handleMessage(const std::string &message)
{
Json::Reader reader;
Json::Value messageRoot;
if (!reader.parse(message, messageRoot, false))
{
sendErrorReply("Error while parsing json: " + reader.getFormattedErrorMessages());
return;
}
handleNotImplemented(messageRoot);
}
void JsonClientConnection::handleNotImplemented(const Json::Value & message)
{
sendErrorReply("Command not implemented");
}
void JsonClientConnection::sendMessage(const Json::Value &message)
{
Json::FastWriter writer;
std::string serializedReply = writer.write(message);
_socket->write(serializedReply.data(), serializedReply.length());
}
void JsonClientConnection::sendErrorReply(const std::string &error)
{
// create reply
Json::Value reply;
reply["success"] = false;
reply["error"] = error;
// send reply
sendMessage(reply);
}

View File

@ -0,0 +1,39 @@
#pragma once
// stl includes
#include <string>
// Qt includes
#include <QByteArray>
#include <QTcpSocket>
// jsoncpp includes
#include <json/json.h>
class JsonClientConnection : public QObject
{
Q_OBJECT
public:
JsonClientConnection(QTcpSocket * socket);
~JsonClientConnection();
signals:
void connectionClosed(JsonClientConnection * connection);
private slots:
void readData();
void socketClosed();
private:
void handleMessage(const std::string & message);
void handleNotImplemented(const Json::Value & message);
void sendMessage(const Json::Value & message);
void sendErrorReply(const std::string & error);
private:
QTcpSocket * _socket;
QByteArray _receiveBuffer;
};

View File

@ -0,0 +1,57 @@
// system includes
#include <stdexcept>
// project includes
#include <jsonserver/JsonServer.h>
#include "JsonClientConnection.h"
JsonServer::JsonServer(Hyperion *hyperion, uint16_t port) :
QObject(),
_hyperion(hyperion),
_server(),
_openConnections()
{
if (!_server.listen(QHostAddress::Any, port))
{
throw std::runtime_error("Json server could not bind to port");
}
// Set trigger for incoming connections
connect(&_server, SIGNAL(newConnection()), this, SLOT(newConnection()));
}
JsonServer::~JsonServer()
{
foreach (JsonClientConnection * connection, _openConnections) {
delete connection;
}
}
uint16_t JsonServer::getPort() const
{
return _server.serverPort();
}
void JsonServer::newConnection()
{
std::cout << "New incoming json connection" << std::endl;
QTcpSocket * socket = _server.nextPendingConnection();
if (socket != nullptr)
{
JsonClientConnection * connection = new JsonClientConnection(socket);
_openConnections.insert(connection);
// register slot for cleaning up after the connection closed
connect(connection, SIGNAL(connectionClosed(JsonClientConnection*)), this, SLOT(closedConnection(JsonClientConnection*)));
}
}
void JsonServer::closedConnection(JsonClientConnection *connection)
{
std::cout << "Json connection closed" << std::endl;
_openConnections.remove(connection);
// schedule to delete the connection object
connection->deleteLater();
}

View File

@ -6,7 +6,8 @@ add_executable(hyperiond
hyperion-d.cpp) hyperion-d.cpp)
target_link_libraries(hyperiond target_link_libraries(hyperiond
hyperion) hyperion
jsonserver)
# Find the libPNG # Find the libPNG
find_package(PNG QUIET) find_package(PNG QUIET)

View File

@ -9,6 +9,9 @@
#include <hyperion/DispmanxWrapper.h> #include <hyperion/DispmanxWrapper.h>
#include <hyperion/Hyperion.h> #include <hyperion/Hyperion.h>
// JsonServer includes
#include <jsonserver/JsonServer.h>
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
// Initialising QCoreApplication // Initialising QCoreApplication
@ -16,9 +19,9 @@ int main(int argc, char** argv)
std::cout << "QCoreApplication initialised" << std::endl; std::cout << "QCoreApplication initialised" << std::endl;
// Select config and schema file // Select config and schema file
const std::string homeDir = getenv("RASPILIGHT_HOME"); //const std::string homeDir = getenv("RASPILIGHT_HOME");
const std::string schemaFile = homeDir + "/hyperion.schema.json"; const std::string schemaFile = "hyperion.schema.json";
const std::string configFile = homeDir + "/hyperion.config.json"; const std::string configFile = "hyperion.config.json";
// Load configuration and check against the schema at the same time // Load configuration and check against the schema at the same time
Json::Value config; Json::Value config;
@ -36,6 +39,9 @@ int main(int argc, char** argv)
dispmanx.start(); dispmanx.start();
std::cout << "Frame grabber created and started" << std::endl; std::cout << "Frame grabber created and started" << std::endl;
JsonServer jsonServer(&hyperion);
std::cout << "Json server created and started on port " << jsonServer.getPort() << std::endl;
app.exec(); app.exec();
std::cout << "Application closed" << std::endl; std::cout << "Application closed" << std::endl;
} }

View File

@ -210,16 +210,15 @@ void JsonConnection::setTransform(ColorTransformValues *threshold, ColorTransfor
Json::Value JsonConnection::sendMessage(const Json::Value & message) Json::Value JsonConnection::sendMessage(const Json::Value & message)
{ {
// serialize message (FastWriter already appends a newline)
std::string serializedMessage = Json::FastWriter().write(message);
// print command if requested // print command if requested
if (_printJson) if (_printJson)
{ {
std::cout << "Command: " << message << std::endl; std::cout << "Command: " << serializedMessage;
} }
// serialize message (FastWriter already appends a newline
Json::FastWriter jsonWriter;
std::string serializedMessage = jsonWriter.write(message);
// write message // write message
_socket.write(serializedMessage.c_str()); _socket.write(serializedMessage.c_str());
if (!_socket.waitForBytesWritten()) if (!_socket.waitForBytesWritten())
@ -241,6 +240,12 @@ Json::Value JsonConnection::sendMessage(const Json::Value & message)
} }
int bytes = serializedReply.indexOf('\n') + 1; // Find the end of message int bytes = serializedReply.indexOf('\n') + 1; // Find the end of message
// print reply if requested
if (_printJson)
{
std::cout << "Reply: " << std::string(serializedReply.data(), bytes);
}
// parse reply data // parse reply data
Json::Reader jsonReader; Json::Reader jsonReader;
Json::Value reply; Json::Value reply;
@ -249,12 +254,6 @@ Json::Value JsonConnection::sendMessage(const Json::Value & message)
throw std::runtime_error("Error while parsing reply: invalid json"); throw std::runtime_error("Error while parsing reply: invalid json");
} }
// print reply if requested
if (_printJson)
{
std::cout << "Reply:" << reply << std::endl;
}
return reply; return reply;
} }
@ -271,12 +270,12 @@ bool JsonConnection::parseReply(const Json::Value &reply)
} }
catch (const std::runtime_error &) catch (const std::runtime_error &)
{ {
// Some json paring error: ignore and set parsing error // Some json parsing error: ignore and set parsing error
} }
if (!success) if (!success)
{ {
throw std::runtime_error("Error while paring reply: " + reason); throw std::runtime_error("Error while executing command: " + reason);
} }
return success; return success;