From 41ac48501b9070c6ca31fee324218dfd8e05466d Mon Sep 17 00:00:00 2001 From: Loïc Collignon Date: Tue, 17 Apr 2018 15:27:14 +0200 Subject: Added a Qt's websocket client to AFB into helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This add a single Qt class to serve as a client to Application Framework Binder. It's optional, not enabled by default. To enable you have to set AFB_HELPERS_QTWSCLIENT to ON. Change-Id: Ia0759a95688e48183e6661082693c410a575b14b Signed-off-by: Loïc Collignon --- qafbwebsocketclient.cpp | 173 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 qafbwebsocketclient.cpp (limited to 'qafbwebsocketclient.cpp') diff --git a/qafbwebsocketclient.cpp b/qafbwebsocketclient.cpp new file mode 100644 index 0000000..c4eb8ae --- /dev/null +++ b/qafbwebsocketclient.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2018 Iot.Bzh + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "qafbwebsocketclient.h" +#include +#include +#include + +/*! + * \brief Default constructor. + * \param parent Parent object. + */ +QAfbWebsocketClient::QAfbWebsocketClient(QObject* parent) + : QObject{parent} + , m_nextCallId{0} +{ + connect(&m_socket, SIGNAL(connected()), this, SLOT(onSocketConnected())); + connect(&m_socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected())); + connect(&m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onSocketError(QAbstractSocket::SocketError))); + connect(&m_socket, SIGNAL(textMessageReceived(QString)), this, SLOT(onSocketTextReceived(QString))); +} + +/*! + * \brief Get last error code. + * \return Return the last error code. + */ +QAbstractSocket::SocketError QAfbWebsocketClient::error() const +{ + return m_socket.error(); +} + +/*! + * \brief Get last error as a string. + * \return Return the last error as a string. + */ +QString QAfbWebsocketClient::errorString() const +{ + return m_socket.errorString(); +} + +/*! + * \brief Check if connection is ready or not. + * \return Return \c true if the connected is ready to read and write, \c false otherwise. + */ +bool QAfbWebsocketClient::isValid() const +{ + return m_socket.isValid(); +} +/*! + * \brief Open the connection. + * \param u Url to connect to. + */ +void QAfbWebsocketClient::open(const QUrl& u) +{ + m_socket.open(u); +} + +/*! + * \brief Close the connection. + */ +void QAfbWebsocketClient::close() +{ + m_socket.close(); +} + +/*! + * \brief Call an api's verb with an argument. + * \param api Api to call. + * \param verb Verb to call. + * \param arg Argument to pass. + */ +void QAfbWebsocketClient::call(const QString& api, const QString& verb, const QJsonValue& arg, closure_t closure) +{ + QString callId = QString::number(m_nextCallId); + m_closures[callId] = closure; + + QJsonArray msg; + msg.append(2); // Call + msg.append(callId); + msg.append(api + "/" + verb); + msg.append(arg); + + m_nextCallId++; + + QJsonDocument value; + value.setArray(msg); + + sendTextMessage(value.toJson(QJsonDocument::Compact)); +} + +/*! + * \brief Send a text message over the websocket. + * \param msg Message to send. + * This is use for test only, you should not use this method as + * it sent text as-is, so you have to follow the binder's + * protocol by your self. + */ +void QAfbWebsocketClient::sendTextMessage(QString msg) +{ + m_socket.sendTextMessage(msg); + qDebug() << "WebSocket Text Sent: " << msg; + emit textSent(msg); +} + +/*! + * \brief Called when socket signals to be connected. + */ +void QAfbWebsocketClient::onSocketConnected() +{ + emit connected(); +} + +/*! + * \brief Called when socket signals to be disconnected. + */ +void QAfbWebsocketClient::onSocketDisconnected() +{ + emit disconnected(); +} + +/*! + * \brief Called when socket signals an error. + * \param e Error code. + */ +void QAfbWebsocketClient::onSocketError(QAbstractSocket::SocketError e) +{ + emit error(e); +} + +/*! + * \brief Called when socket signals a received text. + * \param msg Message received. + */ +void QAfbWebsocketClient::onSocketTextReceived(QString msg) +{ + emit textReceived(msg); + qDebug() << "WebSocket Text Received: " << msg; + + QJsonDocument doc = QJsonDocument::fromJson(msg.toUtf8()); + QJsonArray arr = doc.array(); + + switch(arr[0].toInt()) + { + case 3: // RetOK + case 4: // RetErr + { + auto it = m_closures.find(arr[1].toString()); + if (it != m_closures.end()) + { + closure_t closure = *it; + m_closures.erase(it); + closure(arr[0].toInt() == 3, arr[2]); + } + break; + } + case 5: // Events + emit event(arr[1].toString(), arr[2].toObject()["data"]); + break; + } +} -- cgit 1.2.3-korg