22 #include <QJsonDocument> 48 : m_authenticated(false),
49 m_notification(false),
54 m_parentLock(new QMutex()),
57 m_positionalParameters(),
69 : m_authenticated(false),
75 m_parentLock(new QMutex()),
78 m_positionalParameters(),
87 : m_authenticated(Authenticated),
93 m_parentLock(
new QMutex()),
96 m_positionalParameters(),
100 ParseJSONObject(Object);
107 : m_authenticated(Authenticated),
108 m_notification(
true),
113 m_parentLock(new QMutex()),
114 m_validParent(false),
116 m_positionalParameters(),
122 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Unknown websocket subprotocol"));
127 QJsonDocument doc = QJsonDocument::fromJson(Data);
131 ProcessNullContent(Data.contains(
"method"));
135 LOG(VB_GENERAL, LOG_DEBUG, QString(Data));
140 ParseJSONObject(doc.object());
144 else if (doc.isArray())
146 ProcessBatchCall(doc.array());
151 TorcRPCRequest::~TorcRPCRequest()
156 void TorcRPCRequest::ProcessBatchCall(
const QJsonArray &Array)
160 object.insert(QStringLiteral(
"code"), -32600);
161 object.insert(QStringLiteral(
"message"), QStringLiteral(
"Invalid request"));
162 error.insert(QStringLiteral(
"error"),
object);
163 error.insert(QStringLiteral(
"jsonrpc"), QStringLiteral(
"2.0"));
164 error.insert(QStringLiteral(
"id"), QJsonValue());
169 m_serialisedData = QJsonDocument(error).toJson();
170 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Invalid request - empty array"));
176 result.append(
"[\r\n");
179 QJsonArray::const_iterator it = Array.constBegin();
180 for ( ; it != Array.constEnd(); ++it)
183 if (!(*it).isObject())
185 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Invalid request - not an object"));
186 result.append(QJsonDocument(error).toJson());
193 if (!request->
GetData().isEmpty())
198 result.append(
",\r\n");
199 result.append(request->
GetData());
205 result.append(
"\r\n]");
209 m_serialisedData = result;
212 void TorcRPCRequest::ProcessNullContent(
bool HasMethod)
221 error.insert(QStringLiteral(
"code"), -32700);
222 error.insert(QStringLiteral(
"message"), QStringLiteral(
"Parse error"));
223 object.insert(QStringLiteral(
"error"), error);
224 object.insert(QStringLiteral(
"jsonrpc"), QStringLiteral(
"2.0"));
225 object.insert(QStringLiteral(
"id"), QJsonValue());
226 m_serialisedData = QJsonDocument(
object).toJson();
227 LOG(VB_GENERAL, LOG_INFO, QString(m_serialisedData));
230 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Error parsing JSON-RPC data"));
234 void TorcRPCRequest::ParseJSONObject(
const QJsonObject &Object)
237 int id = (Object.contains(QStringLiteral(
"id")) && !Object[QStringLiteral(
"id")].isNull()) ? (
int)Object[QStringLiteral(
"id")].toDouble() : -1;
238 bool isrequest = Object.contains(QStringLiteral(
"method"));
239 bool isresult = Object.contains(QStringLiteral(
"result"));
240 bool iserror = Object.contains(QStringLiteral(
"error"));
242 if ((
int)isrequest + (
int)isresult + (
int)iserror != 1)
244 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Ambiguous RPC request/response"));
251 QString method = Object[QStringLiteral(
"method")].toString();
253 bool handled =
false;
256 if (!QMetaObject::invokeMethod(m_parent,
"HandleNotification", Qt::DirectConnection,
257 Q_RETURN_ARG(
bool, handled), Q_ARG(QString, method)))
259 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Failed to invoke 'HandleNotification' in request parent"));
271 result.insert(QStringLiteral(
"jsonrpc"), QStringLiteral(
"2.0"));
272 result.insert(QStringLiteral(
"id"),
id);
273 m_serialisedData = QJsonDocument::fromVariant(result).toJson();
275 else if (Object.contains(QStringLiteral(
"id")))
277 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Request contains invalid id"));
283 m_reply = Object.value(QStringLiteral(
"result")).toVariant();
289 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Received result with no id"));
300 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Received error with no id"));
302 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"JSON-RPC error"));
308 return m_notification;
314 QMutexLocker locker(m_parentLock);
316 if (!m_parent || !m_validParent || m_state &
Cancelled)
319 QMetaObject::invokeMethod(m_parent,
"RequestReady", Q_ARG(
TorcRPCRequest*,
this));
329 QMutexLocker locker(m_parentLock);
332 m_validParent = m_parent !=
nullptr;
334 if (m_parent && m_parent->metaObject()->indexOfMethod(QMetaObject::normalizedSignature(
"RequestReady(TorcRPCRequest*)")) < 0)
336 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Request's parent does not have RequestReady method - request WILL fail"));
337 m_validParent =
false;
350 object.insert(QStringLiteral(
"jsonrpc"), QStringLiteral(
"2.0"));
351 object.insert(QStringLiteral(
"method"), m_method);
354 if (!m_parameters.isEmpty())
357 for (
int i = 0; i < m_parameters.size(); ++i)
358 params.insert(m_parameters[i].first, QJsonValue::fromVariant(m_parameters[i].second));
359 object.insert(QStringLiteral(
"params"), params);
361 else if (!m_positionalParameters.isEmpty())
365 for (
int i = 0; i < m_positionalParameters.size(); ++i)
366 params.append(QJsonValue::fromVariant(m_positionalParameters[i]));
367 object.insert(QStringLiteral(
"params"), params);
371 object.insert(QStringLiteral(
"id"), m_id);
373 QJsonDocument doc(
object);
374 m_serialisedData = doc.toJson();
377 LOG(VB_NETWORK, LOG_DEBUG, QString(m_serialisedData));
379 return m_serialisedData;
404 m_parameters.append(QPair<QString,QVariant>(Name, Value));
414 m_positionalParameters.append(Value);
454 return m_positionalParameters;
459 return m_serialisedData;
TorcRPCRequest(const QString &Method, QObject *Parent)
Creates an RPC request owned by the given Parent.
QByteArray & GetData(void)
static void HandleRequest(const QString &PeerAddress, int PeerPort, const QString &LocalAddress, int LocalPort, TorcHTTPRequest &Request)
void SetParent(QObject *Parent)
Set the parent for the request.
virtual bool DownRef(void)
void AddState(int State)
Progress the state for this request.
A class encapsulating a Remote Procedure Call.
void NotifyParent(void)
Signal to the parent that the request is ready (but may be errored).
QString GetMethod(void) const
void AddPositionalParameter(const QVariant &Value)
Add a positional parameter.
const QList< QVariant > & GetPositionalParameters(void) const
bool IsNotification(void) const
QByteArray & SerialiseRequest(TorcWebSocketReader::WSSubProtocol Protocol)
Serialise the request for the given protocol.
const QList< QPair< QString, QVariant > > & GetParameters(void) const
const QVariant & GetReply(void) const
#define LOG(_MASK_, _LEVEL_, _STRING_)
void SetReply(const QVariant &Reply)
QObject * GetParent(void) const
void AddParameter(const QString &Name, const QVariant &Value)
Add Parameter and value to list of call parameters.
void SetID(int ID)
Set the unique ID for this request.