From f75a0e7a3163d2d1a5126931832db2c105f55837 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Sat, 29 Jul 2017 16:08:31 +0200 Subject: [PATCH] move jsonrpc logic out of transport interface into where it belongs, jsonrpcserver --- server/bluetoothserver.cpp | 2 +- server/jsonrpc/jsonrpcserver.cpp | 50 +++++++++++++++++++++++++----- server/jsonrpc/jsonrpcserver.h | 2 +- server/tcpserver.cpp | 2 +- server/transportinterface.cpp | 52 -------------------------------- server/transportinterface.h | 5 +-- server/websocketserver.cpp | 2 +- tests/auto/mocktcpserver.cpp | 42 +------------------------- 8 files changed, 48 insertions(+), 109 deletions(-) diff --git a/server/bluetoothserver.cpp b/server/bluetoothserver.cpp index 3640cfbb..10dbad61 100644 --- a/server/bluetoothserver.cpp +++ b/server/bluetoothserver.cpp @@ -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(); } } diff --git a/server/jsonrpc/jsonrpcserver.cpp b/server/jsonrpc/jsonrpcserver.cpp index 9ac66d58..e020f48d 100644 --- a/server/jsonrpc/jsonrpcserver.cpp +++ b/server/jsonrpc/jsonrpcserver.cpp @@ -154,10 +154,9 @@ QHash 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(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 validationResult = handler->validateParams(method, params); if (!validationResult.first) { interface->sendErrorResponse(clientId, commandId, "Invalid params: " + validationResult.second); diff --git a/server/jsonrpc/jsonrpcserver.h b/server/jsonrpc/jsonrpcserver.h index 58f55068..b3a441ef 100644 --- a/server/jsonrpc/jsonrpcserver.h +++ b/server/jsonrpc/jsonrpcserver.h @@ -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 ¶ms); diff --git a/server/tcpserver.cpp b/server/tcpserver.cpp index 7688f29a..8254f32a 100644 --- a/server/tcpserver.cpp +++ b/server/tcpserver.cpp @@ -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(); } } diff --git a/server/transportinterface.cpp b/server/transportinterface.cpp index 7ff86696..00d63714 100644 --- a/server/transportinterface.cpp +++ b/server/transportinterface.cpp @@ -72,8 +72,6 @@ #include "transportinterface.h" #include "loggingcategories.h" -#include "jsonhandler.h" -#include "guhcore.h" #include @@ -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); -} - } diff --git a/server/transportinterface.h b/server/transportinterface.h index 129662f7..d9efe39f 100644 --- a/server/transportinterface.h +++ b/server/transportinterface.h @@ -41,13 +41,10 @@ public: void sendResponse(const QUuid &clientId, int commandId, const QVariantMap ¶ms = 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; diff --git a/server/websocketserver.cpp b/server/websocketserver.cpp index f08389f7..3ffc6d5d 100644 --- a/server/websocketserver.cpp +++ b/server/websocketserver.cpp @@ -152,7 +152,7 @@ void WebSocketServer::onTextMessageReceived(const QString &message) { QWebSocket *client = qobject_cast(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) diff --git a/tests/auto/mocktcpserver.cpp b/tests/auto/mocktcpserver.cpp index dfc605e1..59c92c58 100644 --- a/tests/auto/mocktcpserver.cpp +++ b/tests/auto/mocktcpserver.cpp @@ -61,47 +61,7 @@ QList 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 ¶ms)