move jsonrpc logic out of transport interface into where it belongs, jsonrpcserver

This commit is contained in:
Michael Zanetti 2017-07-29 16:08:31 +02:00
parent 4768644c4e
commit f75a0e7a31
8 changed files with 48 additions and 109 deletions

View File

@ -130,7 +130,7 @@ void BluetoothServer::readData()
message.append(dataLine);
if (dataLine.endsWith('\n')) {
qCDebug(dcConnection()) << "Bluetooth data received:" << message;
validateMessage(m_clientList.key(client), message);
emit dataAvailable(m_clientList.key(client), message);
message.clear();
}
}

View File

@ -154,10 +154,9 @@ QHash<QString, JsonHandler *> JsonRPCServer::handlers() const
/*! Register a new \l{TransportInterface} to the JSON server. The \a enabled flag indivates if the given \a interface sould be enebeld on startup. */
void JsonRPCServer::registerTransportInterface(TransportInterface *interface, const bool &enabled)
{
// Now set up the logic
connect(interface, SIGNAL(clientConnected(const QUuid &)), this, SLOT(clientConnected(const QUuid &)));
connect(interface, SIGNAL(clientDisconnected(const QUuid &)), this, SLOT(clientDisconnected(const QUuid &)));
connect(interface, SIGNAL(dataAvailable(QUuid, QString, QString, QVariantMap)), this, SLOT(processData(QUuid, QString, QString, QVariantMap)));
connect(interface, &TransportInterface::clientConnected, this, &JsonRPCServer::clientConnected);
connect(interface, &TransportInterface::clientDisconnected, this, &JsonRPCServer::clientDisconnected);
connect(interface, &TransportInterface::dataAvailable, this, &JsonRPCServer::processData);
if (enabled)
QMetaObject::invokeMethod(interface, "startServer", Qt::QueuedConnection);
@ -179,15 +178,50 @@ void JsonRPCServer::setup()
registerHandler(new NetworkManagerHandler(this));
}
void JsonRPCServer::processData(const QUuid &clientId, const QString &targetNamespace, const QString &method, const QVariantMap &message)
void JsonRPCServer::processData(const QUuid &clientId, const QByteArray &data)
{
TransportInterface *interface = qobject_cast<TransportInterface *>(sender());
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
// Note: id, targetNamespace and method already checked in TcpServer
int commandId = message.value("id").toInt();
QVariantMap params = message.value("params").toMap();
if(error.error != QJsonParseError::NoError) {
qCWarning(dcJsonRpc) << "Failed to parse JSON data" << data << ":" << error.errorString();
interface->sendErrorResponse(clientId, -1, QString("Failed to parse JSON data: %1").arg(error.errorString()));
return;
}
QVariantMap message = jsonDoc.toVariant().toMap();
bool success;
int commandId = message.value("id").toInt(&success);
if (!success) {
qCWarning(dcJsonRpc) << "Error parsing command. Missing \"id\":" << message;
interface->sendErrorResponse(clientId, commandId, "Error parsing command. Missing 'id'");
return;
}
QStringList commandList = message.value("method").toString().split('.');
if (commandList.count() != 2) {
qCWarning(dcJsonRpc) << "Error parsing method.\nGot:" << message.value("method").toString() << "\nExpected: \"Namespace.method\"";
interface->sendErrorResponse(clientId, commandId, QString("Error parsing method. Got: '%1'', Expected: 'Namespace.method'").arg(message.value("method").toString()));
return;
}
QString targetNamespace = commandList.first();
QString method = commandList.last();
JsonHandler *handler = m_handlers.value(targetNamespace);
if (!handler) {
interface->sendErrorResponse(clientId, commandId, "No such namespace");
return;
}
if (!handler->hasMethod(method)) {
interface->sendErrorResponse(clientId, commandId, "No such method");
return;
}
QVariantMap params = message.value("params").toMap();
QPair<bool, QString> validationResult = handler->validateParams(method, params);
if (!validationResult.first) {
interface->sendErrorResponse(clientId, commandId, "Invalid params: " + validationResult.second);

View File

@ -60,7 +60,7 @@ private slots:
void clientConnected(const QUuid &clientId);
void clientDisconnected(const QUuid &clientId);
void processData(const QUuid &clientId, const QString &targetNamespace, const QString &method, const QVariantMap &message);
void processData(const QUuid &clientId, const QByteArray &data);
void sendNotification(const QVariantMap &params);

View File

@ -113,7 +113,7 @@ void TcpServer::readPackage()
qCDebug(dcTcpServer) << "Line in:" << dataLine;
message.append(dataLine);
if (dataLine.endsWith('\n')) {
validateMessage(m_clientList.key(client), message);
emit dataAvailable(m_clientList.key(client), message);
message.clear();
}
}

View File

@ -72,8 +72,6 @@
#include "transportinterface.h"
#include "loggingcategories.h"
#include "jsonhandler.h"
#include "guhcore.h"
#include <QJsonDocument>
@ -116,54 +114,4 @@ void TransportInterface::sendErrorResponse(const QUuid &clientId, int commandId,
sendData(clientId, errorResponse);
}
/*! Validates the given \a data from the client with the id \a clientId. If the validation was
* successfull, the signal \l{dataAvailable()} will be emitted, otherwise an error response
* will be sent to the client.
*
* \sa dataAvailable()
*/
void TransportInterface::validateMessage(const QUuid &clientId, const QByteArray &data)
{
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
if(error.error != QJsonParseError::NoError) {
qCWarning(dcJsonRpc) << "Failed to parse JSON data" << data << ":" << error.errorString();
sendErrorResponse(clientId, -1, QString("Failed to parse JSON data: %1").arg(error.errorString()));
return;
}
QVariantMap message = jsonDoc.toVariant().toMap();
bool success;
int commandId = message.value("id").toInt(&success);
if (!success) {
qCWarning(dcJsonRpc) << "Error parsing command. Missing \"id\":" << message;
sendErrorResponse(clientId, commandId, "Error parsing command. Missing 'id'");
return;
}
QStringList commandList = message.value("method").toString().split('.');
if (commandList.count() != 2) {
qCWarning(dcJsonRpc) << "Error parsing method.\nGot:" << message.value("method").toString() << "\nExpected: \"Namespace.method\"";
sendErrorResponse(clientId, commandId, QString("Error parsing method. Got: '%1'', Expected: 'Namespace.method'").arg(message.value("method").toString()));
return;
}
QString targetNamespace = commandList.first();
QString method = commandList.last();
JsonHandler *handler = GuhCore::instance()->jsonRPCServer()->handlers().value(targetNamespace);
if (!handler) {
sendErrorResponse(clientId, commandId, "No such namespace");
return;
}
if (!handler->hasMethod(method)) {
sendErrorResponse(clientId, commandId, "No such method");
return;
}
emit dataAvailable(clientId, targetNamespace, method, message);
}
}

View File

@ -41,13 +41,10 @@ public:
void sendResponse(const QUuid &clientId, int commandId, const QVariantMap &params = QVariantMap());
void sendErrorResponse(const QUuid &clientId, int commandId, const QString &error);
protected:
void validateMessage(const QUuid &clientId, const QByteArray &data);
signals:
void clientConnected(const QUuid &clientId);
void clientDisconnected(const QUuid &clientId);
void dataAvailable(const QUuid &clientId, const QString &targetNamespace, const QString &method, const QVariantMap &message);
void dataAvailable(const QUuid &clientId, const QByteArray &data);
public slots:
virtual bool startServer() = 0;

View File

@ -152,7 +152,7 @@ void WebSocketServer::onTextMessageReceived(const QString &message)
{
QWebSocket *client = qobject_cast<QWebSocket *>(sender());
qCDebug(dcWebSocketServer) << "Text message from" << client->peerAddress().toString() << ":" << message;
validateMessage(m_clientList.key(client), message.toUtf8());
emit dataAvailable(m_clientList.key(client), message.toUtf8());
}
void WebSocketServer::onClientError(QAbstractSocket::SocketError error)

View File

@ -61,47 +61,7 @@ QList<MockTcpServer *> MockTcpServer::servers()
void MockTcpServer::injectData(const QUuid &clientId, const QByteArray &data)
{
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
if(error.error != QJsonParseError::NoError) {
qCWarning(dcJsonRpc) << "Failed to parse JSON data" << data << ":" << error.errorString();
sendErrorResponse(clientId, -1, QString("Failed to parse JSON data: %1").arg(error.errorString()));
return;
}
QVariantMap message = jsonDoc.toVariant().toMap();
bool success;
int commandId = message.value("id").toInt(&success);
if (!success) {
qCWarning(dcJsonRpc) << "Error parsing command. Missing \"id\":" << message;
sendErrorResponse(clientId, commandId, "Error parsing command. Missing 'id'");
return;
}
QStringList commandList = message.value("method").toString().split('.');
if (commandList.count() != 2) {
qCWarning(dcJsonRpc) << "Error parsing method.\nGot:" << message.value("method").toString() << "\nExpected: \"Namespace.method\"";
sendErrorResponse(clientId, commandId, QString("Error parsing method. Got: '%1'', Expected: 'Namespace.method'").arg(message.value("method").toString()));
return;
}
QString targetNamespace = commandList.first();
QString method = commandList.last();
JsonHandler *handler = GuhCore::instance()->jsonRPCServer()->handlers().value(targetNamespace);
if (!handler) {
sendErrorResponse(clientId, commandId, "No such namespace");
return;
}
if (!handler->hasMethod(method)) {
sendErrorResponse(clientId, commandId, "No such method");
return;
}
emit dataAvailable(clientId, targetNamespace, method, message);
emit dataAvailable(clientId, data);
}
void MockTcpServer::sendResponse(const QUuid &clientId, int commandId, const QVariantMap &params)