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);
|
message.append(dataLine);
|
||||||
if (dataLine.endsWith('\n')) {
|
if (dataLine.endsWith('\n')) {
|
||||||
qCDebug(dcConnection()) << "Bluetooth data received:" << message;
|
qCDebug(dcConnection()) << "Bluetooth data received:" << message;
|
||||||
validateMessage(m_clientList.key(client), message);
|
emit dataAvailable(m_clientList.key(client), message);
|
||||||
message.clear();
|
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. */
|
/*! 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)
|
void JsonRPCServer::registerTransportInterface(TransportInterface *interface, const bool &enabled)
|
||||||
{
|
{
|
||||||
// Now set up the logic
|
connect(interface, &TransportInterface::clientConnected, this, &JsonRPCServer::clientConnected);
|
||||||
connect(interface, SIGNAL(clientConnected(const QUuid &)), this, SLOT(clientConnected(const QUuid &)));
|
connect(interface, &TransportInterface::clientDisconnected, this, &JsonRPCServer::clientDisconnected);
|
||||||
connect(interface, SIGNAL(clientDisconnected(const QUuid &)), this, SLOT(clientDisconnected(const QUuid &)));
|
connect(interface, &TransportInterface::dataAvailable, this, &JsonRPCServer::processData);
|
||||||
connect(interface, SIGNAL(dataAvailable(QUuid, QString, QString, QVariantMap)), this, SLOT(processData(QUuid, QString, QString, QVariantMap)));
|
|
||||||
|
|
||||||
if (enabled)
|
if (enabled)
|
||||||
QMetaObject::invokeMethod(interface, "startServer", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(interface, "startServer", Qt::QueuedConnection);
|
||||||
@ -179,15 +178,50 @@ void JsonRPCServer::setup()
|
|||||||
registerHandler(new NetworkManagerHandler(this));
|
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());
|
TransportInterface *interface = qobject_cast<TransportInterface *>(sender());
|
||||||
|
QJsonParseError error;
|
||||||
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
|
||||||
|
|
||||||
// Note: id, targetNamespace and method already checked in TcpServer
|
if(error.error != QJsonParseError::NoError) {
|
||||||
int commandId = message.value("id").toInt();
|
qCWarning(dcJsonRpc) << "Failed to parse JSON data" << data << ":" << error.errorString();
|
||||||
QVariantMap params = message.value("params").toMap();
|
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);
|
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);
|
QPair<bool, QString> validationResult = handler->validateParams(method, params);
|
||||||
if (!validationResult.first) {
|
if (!validationResult.first) {
|
||||||
interface->sendErrorResponse(clientId, commandId, "Invalid params: " + validationResult.second);
|
interface->sendErrorResponse(clientId, commandId, "Invalid params: " + validationResult.second);
|
||||||
|
|||||||
@ -60,7 +60,7 @@ private slots:
|
|||||||
void clientConnected(const QUuid &clientId);
|
void clientConnected(const QUuid &clientId);
|
||||||
void clientDisconnected(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);
|
void sendNotification(const QVariantMap ¶ms);
|
||||||
|
|
||||||
|
|||||||
@ -113,7 +113,7 @@ void TcpServer::readPackage()
|
|||||||
qCDebug(dcTcpServer) << "Line in:" << dataLine;
|
qCDebug(dcTcpServer) << "Line in:" << dataLine;
|
||||||
message.append(dataLine);
|
message.append(dataLine);
|
||||||
if (dataLine.endsWith('\n')) {
|
if (dataLine.endsWith('\n')) {
|
||||||
validateMessage(m_clientList.key(client), message);
|
emit dataAvailable(m_clientList.key(client), message);
|
||||||
message.clear();
|
message.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -72,8 +72,6 @@
|
|||||||
|
|
||||||
#include "transportinterface.h"
|
#include "transportinterface.h"
|
||||||
#include "loggingcategories.h"
|
#include "loggingcategories.h"
|
||||||
#include "jsonhandler.h"
|
|
||||||
#include "guhcore.h"
|
|
||||||
|
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
|
|
||||||
@ -116,54 +114,4 @@ void TransportInterface::sendErrorResponse(const QUuid &clientId, int commandId,
|
|||||||
sendData(clientId, errorResponse);
|
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 sendResponse(const QUuid &clientId, int commandId, const QVariantMap ¶ms = QVariantMap());
|
||||||
void sendErrorResponse(const QUuid &clientId, int commandId, const QString &error);
|
void sendErrorResponse(const QUuid &clientId, int commandId, const QString &error);
|
||||||
|
|
||||||
protected:
|
|
||||||
void validateMessage(const QUuid &clientId, const QByteArray &data);
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void clientConnected(const QUuid &clientId);
|
void clientConnected(const QUuid &clientId);
|
||||||
void clientDisconnected(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:
|
public slots:
|
||||||
virtual bool startServer() = 0;
|
virtual bool startServer() = 0;
|
||||||
|
|||||||
@ -152,7 +152,7 @@ void WebSocketServer::onTextMessageReceived(const QString &message)
|
|||||||
{
|
{
|
||||||
QWebSocket *client = qobject_cast<QWebSocket *>(sender());
|
QWebSocket *client = qobject_cast<QWebSocket *>(sender());
|
||||||
qCDebug(dcWebSocketServer) << "Text message from" << client->peerAddress().toString() << ":" << message;
|
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)
|
void WebSocketServer::onClientError(QAbstractSocket::SocketError error)
|
||||||
|
|||||||
@ -61,47 +61,7 @@ QList<MockTcpServer *> MockTcpServer::servers()
|
|||||||
|
|
||||||
void MockTcpServer::injectData(const QUuid &clientId, const QByteArray &data)
|
void MockTcpServer::injectData(const QUuid &clientId, const QByteArray &data)
|
||||||
{
|
{
|
||||||
QJsonParseError error;
|
emit dataAvailable(clientId, data);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MockTcpServer::sendResponse(const QUuid &clientId, int commandId, const QVariantMap ¶ms)
|
void MockTcpServer::sendResponse(const QUuid &clientId, int commandId, const QVariantMap ¶ms)
|
||||||
|
|||||||
Reference in New Issue
Block a user