move jsonrpc logic out of transport interface into where it belongs, jsonrpcserver
This commit is contained in:
parent
4768644c4e
commit
f75a0e7a31
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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 ¶ms)
|
||||
|
||||
Reference in New Issue
Block a user